commit b7af16450c64d7e9f0009b837f3173efb0a9af0e Author: Peter De Wachter Date: Sat Dec 21 23:40:34 2013 +0100 brlaser version 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65d9b94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# +# Autotools +# +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache +/build-aux +/config.* +/configure +/stamp-* +.deps/ +.dirstamp + +# +# Binaries +# +/rastertobrlaser +/brlaser.drv +*.o diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6d84a2a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,18 @@ +ACLOCAL_AMFLAGS = -I m4 + +filter_PROGRAMS = rastertobrlaser +filterdir = $(CUPS_SERVERBIN)/filter + +drv_DATA = brlaser.drv +drvdir = $(CUPS_DATADIR)/drv + +rastertobrlaser_SOURCES = \ + src/main.cc \ + src/debug.h \ + src/debug.cc \ + src/job.h \ + src/job.cc \ + src/line.h \ + src/line.cc +rastertobrlaser_CPPFLAGS = $(CUPS_CFLAGS) +rastertobrlaser_LDADD = $(CUPS_LIBS) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..e325f07 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +srcdir=`dirname "$0"` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd "$srcdir" + +autoreconf --force -v --install || exit 1 +cd "$ORIGDIR" || exit $? + +if test -z "$NOCONFIGURE"; then + exec "$srcdir"/configure "$@" +fi + diff --git a/brlaser.drv.in b/brlaser.drv.in new file mode 100644 index 0000000..90846a3 --- /dev/null +++ b/brlaser.drv.in @@ -0,0 +1,83 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +// Include standard font and media definitions +#include +#include + +// List the fonts that are supported, in this case all standard fonts... +Font * + +// Manufacturer and driver version. +Manufacturer "Brother" +Version @VERSION@ + +// Each filter provided by the driver... +Filter application/vnd.cups-raster 33 rastertobrlaser + +// Supported resolutions. +// The 1200dpi mode is weird: we need to send 1200x1200dpi raster +// data, but Brother only advertises 1200x600dpi. I wonder what +// is going on there. +Resolution k 1 0 0 0 "300dpi/300 DPI" +*Resolution k 1 0 0 0 "600dpi/600 DPI" +Resolution k 1 0 0 0 "1200dpi/1200HQ" + +// Supported page sizes. +HWMargins 8 8 8 16 +*MediaSize A4 +MediaSize A5 +MediaSize A6 +MediaSize B5 +MediaSize B6 +MediaSize EnvC5 +MediaSize EnvMonarch +MediaSize EnvPRC5 +MediaSize Executive +MediaSize Legal +MediaSize Letter + +// Input trays. Numbers must match the filter source code. +*InputSlot 0 "Auto/Auto-select" +InputSlot 1 "Tray1/Tray 1" +InputSlot 2 "Tray2/Tray 2" +InputSlot 3 "Tray3/Tray 3" +InputSlot 4 "MPTray/MP Tray" +InputSlot 5 "Manual/Manual" + +// Media types. +*MediaType 0 "PLAIN/Plain paper" +MediaType 1 "THIN/Thin paper" +MediaType 2 "THICK/Thick paper" +MediaType 3 "THICKER/Thicker paper" +MediaType 4 "BOND/Bond paper" +MediaType 5 "TRANS/Transparencies" +MediaType 6 "ENV/Envelopes" +MediaType 7 "ENV-THICK/Thick envelopes" +MediaType 8 "ENV-THIN/Thin envelopes" + +Option "brlaserEconomode/Toner save mode" Boolean AnySetup 10 + *Choice False/Off "<>setpagedevice" + Choice True/On "<>setpagedevice" + + +{ + ModelName "DCP-7030" + Attribute "NickName" "" "Brother DCP-7030, using @PACKAGE@ v@VERSION@" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7030;CLS:PRINTER;" + PCFileName "br7030.ppd" +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..22201e1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,57 @@ +# This file is part of the brlaser printer driver. +# +# Copyright 2013 Peter De Wachter +# +# brlaser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# brlaser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with brlaser. If not, see . + +AC_PREREQ(2.68) +AC_INIT([brlaser], [1], [pdewacht@gmail.com], [brlaser], + [https://github.com/pdewacht/brlaser]) + +AC_CONFIG_SRCDIR([src/line.cc]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_LANG([C++]) + +AM_INIT_AUTOMAKE([1.11.1 foreign subdir-objects dist-xz -Wall -Werror]) +AM_MAINTAINER_MODE([enable]) +AM_SILENT_RULES([yes]) + +AC_PROG_CXX +AX_CXX_COMPILE_STDCXX_11 +AX_CXXFLAGS_WARN_ALL + +dnl Use cups-config to detect the CUPS configuration. +AC_PATH_PROG(CUPS_CONFIG, cups-config) +AS_IF([test -z "$CUPS_CONFIG"], + [AC_MSG_ERROR(["cups-config" command not found. Please install the CUPS development package.])]) +CUPS_CFLAGS=`"$CUPS_CONFIG" --cflags` +CUPS_LIBS=`"$CUPS_CONFIG" --image --libs` +CUPS_SERVERBIN=`"$CUPS_CONFIG" --serverbin` +CUPS_DATADIR=`"$CUPS_CONFIG" --datadir` +AC_SUBST(CUPS_CFLAGS) +AC_SUBST(CUPS_LIBS) +AC_SUBST(CUPS_SERVERBIN) +AC_SUBST(CUPS_DATADIR) + +dnl 'cups-config --libs' lists a lot of libs we don't need/want, +dnl try to figure out whether the linker knows about --as-needed. +AC_ARG_ENABLE([as-needed], + AC_HELP_STRING([--disable-as-needed], [disable overlinking protection])) +AS_IF([test "x$enable_as_needed" != "xno"], + [AX_APPEND_LINK_FLAGS([-Wl,--as-needed])]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile brlaser.drv]) +AC_OUTPUT diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..1d38b76 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,69 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_APPEND_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl +AS_VAR_SET_IF(FLAGS, + [case " AS_VAR_GET(FLAGS) " in + *" $1 "*) + AC_RUN_LOG([: FLAGS already contains $1]) + ;; + *) + AC_RUN_LOG([: FLAGS="$FLAGS $1"]) + AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"]) + ;; + esac], + [AS_VAR_SET(FLAGS,["$1"])]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_append_link_flags.m4 b/m4/ax_append_link_flags.m4 new file mode 100644 index 0000000..4fc4337 --- /dev/null +++ b/m4/ax_append_link_flags.m4 @@ -0,0 +1,61 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the linker works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is +# used. During the check the flag is always added to the linker's flags. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. +# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_APPEND_LINK_FLAGS], +[for flag in $1; do + AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3]) +done +])dnl AX_APPEND_LINK_FLAGS diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4 new file mode 100644 index 0000000..0fa3e18 --- /dev/null +++ b/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result +# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default. +# +# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX, +# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and +# Intel compilers. For a given compiler, the Fortran flags are much more +# experimental than their C equivalents. +# +# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# NOTE: These macros depend on AX_APPEND_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2010 Rhys Ulerich +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 14 + +AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" +ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-warn all % -warn all" dnl Intel + "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done +FLAGS="$ac_save_[]FLAGS" +]) +AS_VAR_POPDEF([FLAGS])dnl +AC_REQUIRE([AX_APPEND_FLAG]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;; + *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +])dnl AX_FLAGS_WARN_ALL +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C]) +]) + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C++]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C++]) +]) + +AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([Fortran]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([Fortran]) +]) diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4 new file mode 100644 index 0000000..db899dd --- /dev/null +++ b/m4/ax_check_link_flag.m4 @@ -0,0 +1,73 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 3 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000..af37acd --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,133 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) diff --git a/src/debug.cc b/src/debug.cc new file mode 100644 index 0000000..ee3c193 --- /dev/null +++ b/src/debug.cc @@ -0,0 +1,106 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "debug.h" +#include +#include + +namespace { + +template +void dump(const char *name, const T &value) { + std::cerr << "DEBUG: page header: " << name << " = " << value << '\n'; +} + +template +void dump(const char *name, const T (&value)[N]) { + std::cerr << "DEBUG: page header: " << name << " ="; + for (int i = 0; i < N; ++i) { + std::cerr << ' ' << value[i]; + } + std::cerr << '\n'; +} + +void dump(const char *name, const char *value) { + std::cerr << "DEBUG: page header: " << name << " = \"" << value << "\"\n"; +} + +template +void dump(const char *name, const char (&value)[N][M]) { + std::cerr << "DEBUG: page header: " << name << " ="; + for (int i = 0; i < N; ++i) { + std::cerr << " \"" << value[i] << '"'; + } + std::cerr << '\n'; +} + +} // namespace + + +void dump_page_header(const cups_page_header2_t &h) { +#define d(f) dump(#f, h.f) + d(MediaClass); + d(MediaColor); + d(MediaType); + d(OutputType); + d(AdvanceDistance); + d(AdvanceMedia); + d(Collate); + d(CutMedia); + d(Duplex); + d(HWResolution); + d(ImagingBoundingBox); + d(InsertSheet); + d(Jog); + d(LeadingEdge); + d(Margins); + d(ManualFeed); + d(MediaPosition); + d(MediaWeight); + d(MirrorPrint); + d(NegativePrint); + d(NumCopies); + d(Orientation); + d(OutputFaceUp); + d(PageSize); + d(Separations); + d(TraySwitch); + d(Tumble); + d(cupsWidth); + d(cupsHeight); + d(cupsMediaType); + d(cupsBitsPerColor); + d(cupsBitsPerPixel); + d(cupsBytesPerLine); + d(cupsColorOrder); + d(cupsColorSpace); + d(cupsCompression); + d(cupsRowCount); + d(cupsRowFeed); + d(cupsRowStep); + d(cupsNumColors); + d(cupsBorderlessScalingFactor); + d(cupsPageSize); + d(cupsImagingBBox); + d(cupsInteger); + d(cupsReal); + d(cupsString); + d(cupsMarkerType); + d(cupsRenderingIntent); + d(cupsPageSizeName); +#undef d +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..d1eff52 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,25 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef DEBUG_H +#define DEBUG_H + +#include + +void dump_page_header(const cups_page_header2_t &h); + +#endif diff --git a/src/job.cc b/src/job.cc new file mode 100644 index 0000000..5336463 --- /dev/null +++ b/src/job.cc @@ -0,0 +1,152 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "job.h" +#include +#include +#include +#include "line.h" + +using std::vector; + +namespace { + +class block { + public: + void add_line(vector &&line) { + assert(!line.empty()); + line_bytes_ += line.size(); + lines_.push_back(line); + } + + bool line_fits(unsigned size) { + return lines_.size() != max_lines_per_block_ + && line_bytes_ + size < max_block_size_; + } + + void flush(FILE *f) { + if (line_bytes_) { + fprintf(f, "%dw%c%c", + line_bytes_ + 2, 0, + static_cast(lines_.size())); + for (auto &line : lines_) { + fwrite(line.data(), 1, line.size(), f); + } + line_bytes_ = 0; + lines_.clear(); + } + } + + private: + const unsigned max_block_size_ = 16350; + const unsigned max_lines_per_block_ = 128; + + vector> lines_; + int line_bytes_ = 0; +}; + +} // namespace + +job::job(FILE *out, const std::string &job_name) + : out_(out), + job_name_(job_name), + page_params_() { + // Delete dubious characters from job name + std::replace_if(job_name_.begin(), job_name_.end(), [](char c) { + return c < 32 || c >= 127 || c == '"' || c == '\\'; + }, ' '); + + begin_job(); +} + +job::~job() { + end_job(); +} + +void job::begin_job() { + for (int i = 0; i < 128; ++i) { + putc(0, out_); + } + fprintf(out_, "\033%%-12345X@PJL\n"); + fprintf(out_, "@PJL JOB NAME=\"%s\"\n", job_name_.c_str()); +} + +void job::end_job() { + fprintf(out_, "\033%%-12345X@PJL\n"); + fprintf(out_, "@PJL EOJ NAME=\"%s\"\n", job_name_.c_str()); + fprintf(out_, "\033%%-12345X\n"); +} + +void job::write_page_header() { + fprintf(out_, "\033%%-12345X@PJL\n"); + if (page_params_.resolution != 1200) { + fprintf(out_, "@PJL SET RAS1200MODE = FALSE\n"); + fprintf(out_, "@PJL SET RESOLUTION = %d\n", page_params_.resolution); + } else { + fprintf(out_, "@PJL SET RAS1200MODE = TRUE\n"); + fprintf(out_, "@PJL SET RESOLUTION = 600\n"); + } + fprintf(out_, "@PJL SET ECONOMODE = %s\n", + page_params_.economode ? "ON" : "OFF"); + fprintf(out_, "@PJL SET SOURCETRAY = %s\n", + page_params_.sourcetray.c_str()); + fprintf(out_, "@PJL SET MEDIATYPE = %s\n", + page_params_.mediatype.c_str()); + fprintf(out_, "@PJL SET PAPER = %s\n", + page_params_.papersize.c_str()); + fprintf(out_, "@PJL SET PAGEPROTECT = AUTO\n"); + fprintf(out_, "@PJL SET ORIENTATION = PORTRAIT\n"); + fprintf(out_, "@PJL ENTER LANGUAGE = PCL\n"); +} + +void job::encode_page(const page_params &page_params, + int num_copies, + int lines, + int linesize, + nextline_fn nextline) { + if (!(page_params_ == page_params)) { + page_params_ = page_params; + write_page_header(); + } + + vector line(linesize); + vector reference(linesize); + block block; + + if (!nextline(line.data())) { + return; + } + block.add_line(encode_line(line)); + std::swap(line, reference); + + fputs("\033E", out_); + fprintf(out_, "\033&l%dX", std::max(1, num_copies)); + fputs("\033*b1030m", out_); + + for (int i = 1; i < lines && nextline(line.data()); ++i) { + vector encoded = encode_line(line, reference); + if (!block.line_fits(encoded.size())) { + block.flush(out_); + } + block.add_line(std::move(encoded)); + std::swap(line, reference); + } + + block.flush(out_); + fputs("1030M\f", out_); + fflush(out_); +} diff --git a/src/job.h b/src/job.h new file mode 100644 index 0000000..e3e6d5d --- /dev/null +++ b/src/job.h @@ -0,0 +1,64 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef JOB_H +#define JOB_H + +#include +#include +#include + +struct page_params { + int resolution; + bool economode; + std::string sourcetray; + std::string mediatype; + std::string papersize; + + bool operator==(const page_params &o) const { + return resolution == o.resolution + && economode == o.economode + && sourcetray == o.sourcetray + && mediatype == o.mediatype + && papersize == o.papersize; + } +}; + +class job { + public: + typedef bool (*nextline_fn)(uint8_t *buf); + + explicit job(FILE *out, const std::string &job_name); + ~job(); + + void encode_page(const page_params ¶ms, + int num_copies, + int lines, + int linesize, + nextline_fn nextline); + + private: + void begin_job(); + void end_job(); + void write_page_header(); + + FILE *out_; + std::string job_name_; + page_params page_params_; +}; + +#endif // JOB_H diff --git a/src/line.cc b/src/line.cc new file mode 100644 index 0000000..6489118 --- /dev/null +++ b/src/line.cc @@ -0,0 +1,191 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "line.h" +#include +#include +using std::vector; + +namespace { + +void write_overflow(int value, vector *out) { + if (value >= 0) { + if (value < 255) { + out->push_back(value); + } else { + out->insert(out->end(), value / 255, 255); + out->push_back(value % 255); + } + } +} + +template +void write_substitute(int offset, + Iterator first, + Iterator last, + vector *out) { + assert(offset >= 0); + assert(offset < 10000); + assert(first != last); + + const int offset_max = 15; + const int count_max = 7; + int count = std::distance(first, last) - 1; + + int offset_low = std::min(offset, offset_max); + int count_low = std::min(count, count_max); + out->push_back((offset_low << 3) | count_low); + write_overflow(offset - offset_max, out); + write_overflow(count - count_max, out); + out->insert(out->end(), first, last); +} + +void write_repeat(int offset, int count, int value, vector *out) { + assert(offset >= 0); + assert(offset < 10000); + assert(count >= 2); + assert(count < 10000); + + const int offset_max = 3; + const int count_max = 31; + count -= 2; + + int offset_low = std::min(offset, offset_max); + int count_low = std::min(count, count_max); + out->push_back(128 | (offset_low << 5) | count_low); + write_overflow(offset - offset_max, out); + write_overflow(count - count_max, out); + out->push_back(value); +} + + +bool all_zeros(const vector &buf) { + return std::none_of(buf.begin(), buf.end(), [](uint8_t b) { return b; }); +} + +template +int skip_to_next_mismatch(Iterator1 *first1, + Iterator1 last1, + Iterator2 *first2) { + auto mismatch_it = std::mismatch(*first1, last1, *first2); + int skipped = std::distance(*first1, mismatch_it.first); + *first1 = mismatch_it.first; + *first2 = mismatch_it.second; + return skipped; +} + +template +int repeat_length(Iterator first, Iterator last) { + if (first != last) { + auto k = *first; + auto mismatch = std::find_if(std::next(first), last, + [=](decltype(k) x) { return x != k; }); + return std::distance(first, mismatch); + } + return 0; +} + +template +int substitute_length(Iterator1 first1, Iterator1 last1, Iterator2 first2) { + if (first1 != last1) { + Iterator1 it1 = first1; + Iterator2 it2 = first2; + Iterator1 next1 = std::next(first1); + Iterator2 next2 = std::next(first2); + Iterator1 prev1 = first1; + while (next1 != last1) { + if ((*it1 == *it2 && *next1 == *next2)) { + return std::distance(first1, it1); + } + if (*it1 == *next1 && *it1 == *prev1) { + return std::distance(first1, prev1); + } + prev1 = it1; + it1 = next1; it2 = next2; + ++next1; ++next2; + } + } + return std::distance(first1, last1); +} + +size_t reserve_size(const vector &line) { + // Big enough to store the line uncompressed together with an Substitute + // command with many overflow bytes. + return line.size() + 16; +} + +} // namespace + +vector encode_line(const vector &line, + const vector &reference) { + assert(line.size() == reference.size()); + if (all_zeros(line)) { + return vector(1, 0xFF); + } + + vector output; + output.reserve(reserve_size(line)); + output.push_back(0); // first byte is the edit count + + const uint8_t max_edits = 254; + int num_edits = 0; + + auto line_it = line.begin(); + auto ref_it = reference.begin(); + while (1) { + int offset = skip_to_next_mismatch(&line_it, line.end(), &ref_it); + if (line_it == line.end()) { + // No more differences, we're done. + break; + } + + if (++num_edits == max_edits) { + // We've run out of edits. Just output the rest of the line in a big + // substitute command. + write_substitute(offset, line_it, line.end(), &output); + break; + } + + int s = substitute_length(line_it, line.end(), ref_it); + if (s > 0) { + write_substitute(offset, line_it, std::next(line_it, s), &output); + line_it += s; + ref_it += s; + } else { + int r = repeat_length(line_it, line.end()); + assert(r >= 2); + write_repeat(offset, r, *line_it, &output); + line_it += r; + ref_it += r; + } + } + + assert(num_edits <= max_edits); + output[0] = num_edits; + return output; +} + +vector encode_line(const vector &line) { + if (all_zeros(line)) { + return vector(1, 0xFF); + } + vector buf; + buf.reserve(reserve_size(line)); + buf.push_back(1); + write_substitute(0, line.begin(), line.end(), &buf); + return buf; +} diff --git a/src/line.h b/src/line.h new file mode 100644 index 0000000..d9d8716 --- /dev/null +++ b/src/line.h @@ -0,0 +1,31 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef LINE_H +#define LINE_H + +#include +#include + +std::vector encode_line( + const std::vector &line, + const std::vector &reference); + +std::vector encode_line( + const std::vector &line); + +#endif // LINE_H diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..8663238 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,194 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "job.h" +#include "debug.h" + +namespace { + +volatile sig_atomic_t interrupted = 0; + +void sigterm_handler(int sig) { + interrupted = 1; +} + + +cups_raster_t *ras; +cups_page_header2_t header; + +bool next_line(uint8_t *buf) { + if (interrupted) { + return false; + } + unsigned bytes = header.cupsBytesPerLine; + return cupsRasterReadPixels(ras, buf, bytes) == bytes; +} + +// POSIX says the second argument of iconv has type 'char **', but +// some systems have 'const char **'. This class is used to work +// around this incompatibility. +class sloppy_ptr { + public: + explicit sloppy_ptr(const char **ptr): ptr_(ptr) { } + operator const char **() { return ptr_; } + operator char **() { return const_cast(ptr_); } + private: + const char **ptr_; +}; + +std::string ascii_job_name(const char *job_name, const char *charset) { + if (job_name && charset) { + iconv_t cd = iconv_open("ASCII//TRANSLIT//IGNORE", charset); + if (cd != (iconv_t) -1) { + char ascii[80]; + const char *in_ptr = job_name; + size_t in_left = strlen(job_name); + char *out_ptr = ascii; + size_t out_left = sizeof(ascii) - 1; + while (in_left > 0) { + size_t err = iconv(cd, + sloppy_ptr(&in_ptr), &in_left, + &out_ptr, &out_left); + if (err == (size_t) -1) { + break; + } + } + *out_ptr = 0; + iconv_close(cd); + return ascii; + } + } + return "CUPS"; +} + +page_params build_page_params() { + static const std::array sources = { + "AUTO", "T1", "T2", "T3", "MP", "MANUAL" + }; + static const std::map sizes = { + { "A4", "A4" }, + { "A5", "A5" }, + { "A6", "A6" }, + { "B5", "B5" }, + { "B6", "B6" }, + { "EnvC5", "C5" }, + { "EnvMonarch", "MONARCH" }, + { "EnvPRC5", "DL" }, + { "Executive", "EXECUTIVE" }, + { "Legal", "LEGAL" }, + { "Letter", "LETTER" } + }; + + page_params p = { }; + p.resolution = header.HWResolution[0]; + p.economode = header.cupsInteger[10]; + p.mediatype = header.MediaType; + + if (header.MediaPosition < sources.size()) + p.sourcetray = sources[header.MediaPosition]; + else + p.sourcetray = sources[0]; + + auto size_it = sizes.find(header.cupsPageSizeName); + if (size_it != sizes.end()) + p.papersize = size_it->second; + else + p.papersize = "A4"; + + return p; +} + +} // namespace + + + +int main(int argc, char *argv[]) { + fprintf(stderr, "INFO: %s version %s\n", PACKAGE, VERSION); + + if (argc != 6 && argc != 7) { + fprintf(stderr, "ERROR: %s job-id user title copies options [file]\n", argv[0]); + fprintf(stderr, "INFO: This program is a CUPS filter. It is not intended to be run manually.\n"); + return 1; + } + // const char *job_id = argv[1]; + // const char *job_user = argv[2]; + const char *job_name = argv[3]; + // const int job_copies = atoi(argv[4]); + // const char *job_options = argv[5]; + const char *job_filename = argv[6]; + const char *job_charset = getenv("CHARSET"); + + setlocale(LC_ALL, ""); + + signal(SIGTERM, sigterm_handler); + signal(SIGPIPE, SIG_IGN); + + int fd = 0; + if (job_filename) { + fd = open(job_filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "ERROR: Unable to open raster file\n"); + return 1; + } + } + + ras = cupsRasterOpen(fd, CUPS_RASTER_READ); + if (!ras) { + fprintf(stderr, "ERROR: Can't read raster data\n"); + return 1; + } + + int pages = 0; + { + job job(stdout, ascii_job_name(job_name, job_charset)); + while (!interrupted && cupsRasterReadHeader2(ras, &header)) { + if (pages == 0) { + dump_page_header(header); + } + job.encode_page(build_page_params(), + header.NumCopies, + header.cupsHeight, + header.cupsBytesPerLine, + next_line); + fprintf(stderr, "PAGE: %d %d\n", ++pages, header.NumCopies); + } + } + if (pages == 0) { + fprintf(stderr, "ERROR: No pages were found."); + return 1; + } + + fflush(stdout); + if (ferror(stdout)) { + fprintf(stderr, "ERROR: Could not write print data\n"); + return 1; + } + return 0; +}