1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2 3<html> 4 <head> 5 <meta name="generator" content="HTML Tidy, see www.w3.org"> 6 <title>Job File Format Conversion with Filters</title> 7 <meta name="GENERATOR" content= 8 "Modular DocBook HTML Stylesheet Version 1.7"> 9 <link rel="HOME" title=" LPRng Reference Manual" href= 10 "index.htm"> 11 <link rel="UP" title="Print Spooling Tutorial " href= 12 "tutorial.htm"> 13 <link rel="PREVIOUS" title="Print Job Filters" href= 14 "printjobfilters.htm"> 15 <link rel="NEXT" title="Printcap Basics" href="x3103.htm"> 16 </head> 17 18 <body class="SECT1" bgcolor="#FFFFFF" text="#000000" link= 19 "#0000FF" vlink="#840084" alink="#0000FF"> 20 <div class="NAVHEADER"> 21 <table summary="Header navigation table" width="100%" border= 22 "0" cellpadding="0" cellspacing="0"> 23 <tr> 24 <th colspan="3" align="center">LPRng Reference Manual: 5 25 Sep 2003 (For LPRng-3.8.22)</th> 26 </tr> 27 28 <tr> 29 <td width="10%" align="left" valign="bottom"><a href= 30 "printjobfilters.htm" accesskey="P">Prev</a></td> 31 32 <td width="80%" align="center" valign="bottom">Chapter 4. 33 Print Spooling Tutorial</td> 34 35 <td width="10%" align="right" valign="bottom"><a href= 36 "x3103.htm" accesskey="N">Next</a></td> 37 </tr> 38 </table> 39 <hr align="LEFT" width="100%"> 40 </div> 41 42 <div class="SECT1"> 43 <h1 class="SECT1"><a name="JOBFILEFORMATCONVERSION">4.10. Job 44 File Format Conversion with Filters</a></h1> 45 46 <p>One of the major problems that face new users to UNIX 47 printing is when they have a printer that has a proprietary 48 print job format such as the HP DeskJet series of printers. 49 The solution to this problem is quite simple: generate your 50 output in PostScript, and then use the <a href= 51 "installation.htm#GHOSTSCRIPT">GhostScript</a> program to 52 convert the GhostScript output to a format compatible with 53 your printer.</p> 54 55 <div class="INFORMALEXAMPLE"> 56 <a name="AEN2761"></a> 57<pre class="SCREEN"> 58 lp:filter=/usr/local/lib/filters/myfilter:... 59 60 /tmp/myfilter: 61 62 #!/bin/sh 63 /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ 64 -sOutputFile=- - && exit 0 65 exit 2 66</pre> 67 </div> 68 <br> 69 <br> 70 71 <p>This simple <span class="emphasis"><i class= 72 "EMPHASIS">tutorial</i></span> example suffers from some 73 serious problems. If you accidentally send a non-PostScript 74 file to the printer GhostScript will detect this and exit 75 with an error message but only after trying to interpret the 76 input file as PostScript. If the input file was a text file, 77 this can result in literally thousands of error messages and 78 hundreds of pages of useless output.</p> 79 80 <p>In order to make a more robust filter we need to meet the 81 following minimum requirements:</p> 82 83 <ol type="1"> 84 <li> 85 <p>The file type should be determined, and only files 86 that are PostScript should be passed to GhostScript.</p> 87 </li> 88 89 <li> 90 <p>We may have some conversion routines that can convert 91 files into PostScript files and then we can send them to 92 GhostScript for raster conversion.</p> 93 </li> 94 95 <li> 96 <p>If we cannot convert a file, then we should simply 97 terminate the printing and cause the spooler to remove 98 the job.</p> 99 </li> 100 </ol> 101 <br> 102 <br> 103 104 <p>The <b class="APPLICATION">ifhp</b> Print Filter program 105 is a companion to the <b class="APPLICATION">LPRng</b> 106 software and does this type of operation. If you are using 107 Linux, then you may find the <span class="emphasis"><i class= 108 "EMPHASIS">RedHat Print Filters</i></span> (<a href= 109 "http://www.debian.org" target= 110 "_top">http://www.debian.org</a>) installed and in use on 111 your system. The <span class="emphasis"><i class= 112 "EMPHASIS">magicfilter</i></span> developed by H. Peter Anvin 113 <a href="http://www.debian.org" target= 114 "_top">http://www.debian.org</a> is distributed with Debian 115 Linux. The <b class="APPLICATION">apsfilter</b> by Andreas 116 Klemm <a href="http://www.freebsd.org/~andreas/index.html" 117 target="_top">http://www.freebsd.org/~andreas/index.html</a> 118 is also widely used, although now most of its functionality 119 is directly available in <b class="APPLICATION">LPRng</b>. 120 Finally, the <b class="APPLICATION">a2ps</b> (Ascii to 121 PostScript) converter by <a href="demaille@inf.enst.fr" 122 target="_top">Akim Demaille</a> and <a href="santana@st.com" 123 target="_top">Miguel Santana</a> is available from <a href= 124 "www-inf.enst.fr/~demaille/a2ps" target= 125 "_top">www-inf.enst.fr/~demaille/a2ps</a>. This package 126 provides a very nice set of facilities for massaging, 127 mangling, bending, twisting, and being downright nasty with 128 text or other files.</p> 129 130 <div class="SECT2"> 131 <h2 class="SECT2"><a name="AEN2787">4.10.1. Simple Filter 132 with File Format Detection</a></h2> 133 134 <p>Since this is a tutorial, we will demonstrate a simple 135 way to make your own <span class="emphasis"><i class= 136 "EMPHASIS">multi-format</i></span> print filter, and 137 provide insight into how more complex filters work.</p> 138 139 <p>The <a href="installation.htm#FILEPROG">file</a> utility 140 developed by Ian F. Darwin uses a database of file 141 signatures to determine what the contents of a file are. 142 For example:</p> 143 144 <div class="INFORMALEXAMPLE"> 145 <a name="AEN2793"></a> 146<pre class="SCREEN"> 147 <samp class="PROMPT">h4: {191} %</samp> <kbd class= 148"USERINPUT">cd /tmp</kbd> 149 <samp class="PROMPT">h4: {192} %</samp> <kbd class= 150"USERINPUT">echo hi >hi</kbd> 151 <samp class="PROMPT">h4: {193} %</samp> <kbd class= 152"USERINPUT">gzip -c hi >hi.gz</kbd> 153 <samp class="PROMPT">h4: {194} %</samp> <kbd class= 154"USERINPUT">echo "%!PS-Adobe-3.0" >test.ps</kbd> 155 <samp class="PROMPT">h4: {195} %</samp> <kbd class= 156"USERINPUT">gzip -c test.ps >test.ps.gz</kbd> 157 <samp class="PROMPT">h4: {196} %</samp> <kbd class= 158"USERINPUT">file hi hi.gz test.ps test.ps.gz</kbd> 159 hi: ASCII text 160 hi.gz: gzip compressed data, deflated 161 test.ps: PostScript document text conforming at level 3.0 162 test.ps.gz: gzip compressed data, deflated 163 <samp class="PROMPT">h4: {197} %</samp> <kbd class= 164"USERINPUT">file - <test.ps</kbd> 165 standard input: PostScript document text conforming at level 3.0 166</pre> 167 </div> 168 <br> 169 <br> 170 171 <p>If we are given a file, we can now use <b class= 172 "APPLICATION">file</b> to recognize the file type and if 173 the file type is suitable for our printer we can send it to 174 the printer, otherwise we can reject it. The following is a 175 simple yet very powerful shell script that does this.</p> 176 177 <div class="INFORMALEXAMPLE"> 178 <a name="AEN2811"></a> 179<pre class="SCREEN"> 180 #!/bin/sh 181 # set up converters 182 gs="/usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ 183 -sOutputFile=/dev/fd/3 - 3>&1 1>&2" 184 a2ps="/usr/local/bin/a2ps -q -B -1 -M Letter --borders=no -o-" 185 decompress="" 186 # get the file type 187 type=`file - | tr A-Z a-z | sed -e 's/ */_/g'`; 188 echo TYPE $type >&2 189 case "$type" in 190 *gzip_compressed* ) decompress="gunzip -c |" compressed="compressed" ;; 191 esac 192 193 # we need to rewind the file 194 perl -e "seek STDIN, 0, 0;" 195 196 if test "X$decompress" != "X" ; then 197 type=`$decompress head | file - | tr A-Z a-z | sed -e 's/ */_/g'`; 198 echo COMPRESSED TYPE $type >&2 199 # we need to rewind the file 200 perl -e "seek STDIN, 0, 0;" 201 fi 202 case "$type" in 203 *postscript* ) process="$gs" ;; 204 *text* ) process="$a2ps | $gs" ;; 205 * ) 206 echo "Cannot print type $compressed '$type'" >&2 207 # exit with JREMOVE status 208 exit 3 209 ;; 210 esac 211 # in real life, replace 'echo' with 'exec' 212 echo "$decompress $process" 213 # exit with JABORT if this fails 214 exit 2 215</pre> 216 </div> 217 <br> 218 <br> 219 220 <p>Copy this to the <tt class="FILENAME">/tmp/majik</tt> 221 file, and give it <var class="LITERAL">0755</var> 222 (executable) permissions. Here is an example of the output 223 of the script:</p> 224 225 <div class="INFORMALEXAMPLE"> 226 <a name="AEN2816"></a> 227<pre class="SCREEN"> 228 <samp class="PROMPT">h4: {198} %</samp> <kbd class= 229"USERINPUT">/tmp/majik <test.ps.gz</kbd> 230 TYPE standard_input:_gzip_compressed_data,_deflated... 231 COMPRESSED TYPE standard_input:_postscript_document_level_3.0 232 gunzip -c | /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ 233 -sOutputFile=/dev/fd/3 - 3>&1 1>&2 234 <samp class="PROMPT">h4: {199} %</samp> <kbd class= 235"USERINPUT">/tmp/majik </tmp/hi</kbd> 236 TYPE standard_input:_ascii_text 237 /usr/local/bin/a2ps -q -B -1 -M Letter --borders=no -o- \ 238 | /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ 239 -sOutputFile=/dev/fd/3 - 3>&1 1>&2 240</pre> 241 </div> 242 <br> 243 <br> 244 245 <p>The first part of the script sets up a standard set of 246 commands that we will use in the various conversions. A 247 full blown package for conversion would use a database or 248 setup file to get these values. We then use the <b class= 249 "APPLICATION">file</b> utility to determine the input file 250 type. The output of the <b class="APPLICATION">file</b> 251 utility is translated to lower case and multiple blanks and 252 tabs are removed.</p> 253 254 <p>We use a simple shell <var class="LITERAL">case</var> 255 statement to determine if we have a compressed file and get 256 a decompression program to use. We reapply the <b class= 257 "APPLICATION">file</b> utility to the decompressed file (if 258 it was compressed) and get the file type.</p> 259 260 <p>Finally we use another <var class="LITERAL">case</var> 261 statement to get the output converter and then we run the 262 command. For tutorial purposes, we use an <tt class= 263 "COMMAND">echo</tt> rather than an <tt class= 264 "COMMAND">exec</tt> so we can see the actual command, 265 rather than the output.</p> 266 267 <p>Just for completeness, here is <b class= 268 "APPLICATION">majikperl</b>:</p> 269 270 <div class="INFORMALEXAMPLE"> 271 <a name="AEN2834"></a> 272<pre class="SCREEN"> 273 #!/usr/bin/perl 274 eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' 275 if $running_under_some_shell; 276 # this emulates #! processing on NIH machines. 277 # (remove #! line above if indigestible) 278 my($gs) = "/usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ 279 -sOutputFile=/dev/fd/3 - 3>&1 1>&2"; 280 my($a2ps)="/usr/local/bin/a2ps -q -B -1 -M Letter --borders=no -o-"; 281 282 my($decompress,$compressed,$process,$type); 283 $decompress=$compressed=$process=$type=""; 284 285 # get the file type 286 $type = ` file - `; 287 $type =~ tr /A-Z/a-z/; 288 $type =~ s/\s+/_/g; 289 print STDERR "TYPE $type\n"; 290 ($decompress,$compressed) = ("gunzip -c |", "gzipped") 291 if( $type =~ /gzip_compressed/ ); 292 print STDERR "decompress $decompress\n"; 293 unless( seek STDIN, 0, 0 ){ 294 print "seek STDIN failed - $!\n"; exit 2; } 295 if( $decompress ne "" ){ 296 $type = ` $decompress file - `; 297 $type =~ tr /A-Z/a-z/; 298 $type =~ s/\s+/_/g; 299 print STDERR "COMPRESSED TYPE $type\n"; 300 unless( seek STDIN, 0, 0 ){ 301 print "seek STDIN failed - $!\n"; exit 2; } 302 } 303 $_ = $type; 304 if( /postscript/ ){ 305 $process="$gs"; 306 } elsif( /_text_/ ){ 307 $process="$a2ps | $gs" ;; 308 } else { 309 print STDERR "Cannot print $compressed '$type'" >&2; 310 # JREMOVE 311 exit 3; 312 } 313 exec "$decompress $process"; 314 print "exec failed - $!\n"; 315 exit 2; 316</pre> 317 </div> 318 <br> 319 <br> 320 </div> 321 322 <div class="SECT2"> 323 <h2 class="SECT2"><a name="AEN2836">4.10.2. The <b class= 324 "APPLICATION">ifhp</b> Filter</a></h2> 325 326 <p>The <a href="secftp.htm">ifhp</a> Print Filter is the 327 companion print filter supplied with <b class= 328 "APPLICATION">LPRng</b> and is normally installed together 329 with the <b class="APPLICATION">LPRng</b> software. <b 330 class="APPLICATION">Ifhp</b> supports a wide range of 331 PostScript, PCL, text, and raster printers, and can be 332 configured to support almost any type of printer with a 333 stream based interface. It provides diagnostic and error 334 information as well as accounting information. It 335 recognizes a wide range of file types by using the <b 336 class="APPLICATION">file</b> utility and the pattern 337 matching technique demonstrated in the previous section, 338 and can do selective conversions from one format to 339 others.</p> 340 341 <p>The <a href="x291.htm#POSTSCRIPT">PostScript</a> and <a 342 href="x291.htm#PCL">PCL</a> printer job languages are 343 supported by most printer manufacturers. However, in order 344 to have a job printed correctly the following steps must be 345 taken.</p> 346 347 <ol type="1"> 348 <li> 349 <p>The printer must be put into a known <span class= 350 "emphasis"><i class="EMPHASIS">initial</i></span> state 351 by sending it the appropriate reset strings or 352 performing a correct set of IO operations.</p> 353 </li> 354 355 <li> 356 <p>If accounting is being done, then the printer 357 accounting information must be obtained and recorded. 358 See <a href="accountingref.htm">Accounting</a> for more 359 information about <b class="APPLICATION">LPRng</b> 360 support for accounting.</p> 361 </li> 362 363 <li> 364 <p>The file to be printed must be checked to see if it 365 is compatible with the printer, and if not, a format 366 conversion program invoked to convert it to the 367 required format.</p> 368 </li> 369 370 <li> 371 <p>If the user selects a set of printer specific 372 options such as landscape mode, duplex printing, 373 multiple copies, or special paper, the appropriate 374 commands must be sent to the printer to select these 375 options.</p> 376 </li> 377 378 <li> 379 <p>The file must be transferred to the printer and the 380 printer is monitored for any error conditions.</p> 381 </li> 382 383 <li> 384 <p>Any required end of job commands are sent to the 385 printer, and the printer monitored for error conditions 386 while the job finishes printing.</p> 387 </li> 388 389 <li> 390 <p>If accounting is being done, the printer accounting 391 information such as page count and time used must be 392 obtained and recorded. See <a href= 393 "accountingref.htm">Accounting</a> for more information 394 about <b class="APPLICATION">LPRng</b> support for 395 accounting.</p> 396 </li> 397 </ol> 398 <br> 399 <br> 400 401 <p>The <b class="APPLICATION">ifhp</b> filter uses the <tt 402 class="FILENAME">ifhp.conf</tt> configuration file to 403 determine the actions and commands appropriate for various 404 models of printers. See the <b class="APPLICATION">ifhp</b> 405 documentation for details about the format and contents of 406 this file. This file contains entries for a large number of 407 PostScript, PJL, and other printers. The default printer 408 used by <b class="APPLICATION">ifhp</b> is the HP LaserJet 409 4M Plus which supports PostScript, PCL, and PJL. The 410 commands and formats used by this printer is compatible 411 with a large number of other HP printers.</p> 412 413 <p>We will demonstrate how to add the <b class= 414 "APPLICATION">ifhp</b> filter to your printcap entry. Find 415 the path to the <b class="APPLICATION">ifhp</b> filter 416 using the <b class="APPLICATION">find</b> command as we did 417 in the previous exercise. Modify the printcap as shown 418 below and use <tt class="COMMAND">lpc lpd</tt> to restart 419 <b class="APPLICATION">lpd</b>.</p> 420 421 <div class="INFORMALEXAMPLE"> 422 <a name="AEN2879"></a> 423<pre class="SCREEN"> 424 lp:sd=/var/spool/lpd/%P 425 :force_localhost 426 :lp=/tmp/lp 427 :ifhp=model=default 428 # modify the path to ifhp appropriately 429 :filter=/usr/local/libexec/filters/ifhp 430</pre> 431 </div> 432 <br> 433 <br> 434 435 <p>Now print the <tt class="FILENAME">/tmp/hi</tt> and then 436 display <tt class="FILENAME">/tmp/lp</tt> using a text 437 editor such as <b class="APPLICATION">vi</b> or <b class= 438 "APPLICATION">emacs</b> that shows control characters:</p> 439 440 <div class="INFORMALEXAMPLE"> 441 <a name="AEN2886"></a> 442<pre class="SCREEN"> 443 <samp class="PROMPT">h4: {200} %</samp> <kbd class= 444"USERINPUT">cp /dev/null /tmp/lp</kbd> 445 <samp class="PROMPT">h4: {201} %</samp> <kbd class= 446"USERINPUT">lpr /tmp/hi</kbd> 447 <samp class="PROMPT">h4: {202} %</samp> <kbd class= 448"USERINPUT">vi /tmp/lp</kbd> 449 ^[%-12345X@PJL 450 @PJL JOB NAME = "PID 405" DISPLAY = "papowell" 451 @PJL RDYMSG DISPLAY = "papowell" 452 @PJL USTATUSOFF 453 @PJL USTATUS JOB = ON 454 @PJL USTATUS DEVICE = ON 455 @PJL USTATUS PAGE = ON 456 @PJL USTATUS TIMED = 10 457 @PJL ENTER LANGUAGE = PCL 458 ^]E^]&^]&k2G^]&s0C^]&l0O^]9^](s0P^](s10.00H^](s4099Thi 459 ^]E^]%-12345X@PJL 460 @PJL RDYMSG DISPLAY = "papowell" 461 @PJL EOJ NAME = "PID 405" 462 @PJL USTATUSOFF 463 @PJL USTATUS JOB = ON 464 @PJL USTATUS DEVICE = ON 465 @PJL USTATUS PAGE = ON 466 @PJL USTATUS TIMED = 10 467 @PJL RDYMSG DISPLAY = "" 468 ^[%-12345X 469</pre> 470 </div> 471 <br> 472 <br> 473 474 <p>The output now contains all of the control sequences and 475 setup codes needed to print a text file on the default 476 printer. The <var class="LITERAL">:ifhp=model=default</var> 477 printcap entry is used by <b class="APPLICATION">ifhp</b> 478 to get the information it needs to perform its operation. 479 The following options are commonly provided in the <var 480 class="LITERAL">:ifhp=</var> option to configure the <b 481 class="APPLICATION">ifhp</b> filter.</p> 482 483 <div class="TABLE"> 484 <a name="IFHPOPTS"></a> 485 486 <p><b>Table 4-3. :ifhp= Options</b></p> 487 488 <table border="1" frame="border" rules="all" class= 489 "CALSTABLE"> 490 <col> 491 <col> 492 493 <thead> 494 <tr> 495 <th>Option</th> 496 497 <th>Purpose</th> 498 </tr> 499 </thead> 500 501 <tbody> 502 <tr> 503 <td><var class="LITERAL">model=</var><span class= 504 "emphasis"><i class="EMPHASIS">name</i></span></td> 505 506 <td>Use <span class="emphasis"><i class= 507 "EMPHASIS">name</i></span> entry in <var class= 508 "LITERAL">ifhp.conf</var></td> 509 </tr> 510 511 <tr> 512 <td><var class="LITERAL">status</var> or <var 513 class="LITERAL">status@</var></td> 514 515 <td>Printer does or does not provide status 516 information</td> 517 </tr> 518 519 <tr> 520 <td><var class="LITERAL">sync</var>, <var class= 521 "LITERAL">sync@</var>, <var class= 522 "LITERAL">sync=</var><span class="emphasis"><i 523 class="EMPHASIS">(ps|pjl)</i></span> </td> 524 525 <td>Printer does or does not indicate ready to 526 operate at start of job, or use PostScript or PJL 527 code sequence to determine if printer is 528 ready.</td> 529 </tr> 530 531 <tr> 532 <td><var class="LITERAL">pagecount</var>, <var 533 class="LITERAL">pagecount@</var>, <var class= 534 "LITERAL">pagecount=</var><span class="emphasis"><i 535 class="EMPHASIS">(ps|pjl)</i></span> </td> 536 537 <td>Printer does or does not have pagecount 538 support, or use PostScript or PJL code sequence to 539 determine pagecount.</td> 540 </tr> 541 542 <tr> 543 <td><var class="LITERAL">waitend</var>, <var class= 544 "LITERAL">waitend@</var>, <var class= 545 "LITERAL">waitend=</var><span class="emphasis"><i 546 class="EMPHASIS">(ps|pjl)</i></span> </td> 547 548 <td>Wait or do not wait for end of job, or send 549 PostScript or PJL code sequence to have printer 550 report end of job.</td> 551 </tr> 552 </tbody> 553 </table> 554 </div> 555 556 <p>The <var class="LITERAL">model=</var><span class= 557 "emphasis"><i class="EMPHASIS">name</i></span> entry is 558 used to specify the configuration entry in the <var class= 559 "LITERAL">ifhp.conf</var> file to be used by <b class= 560 "APPLICATION">ifhp</b>. This entry usually has all of the 561 specific information needed by the <b class= 562 "APPLICATION">ifhp</b> filter.</p> 563 564 <p>The <var class="LITERAL">status</var> option is the most 565 common option usually provided in a printcap entry. This 566 option is needed when the communication with the printer is 567 <span class="emphasis"><i class= 568 "EMPHASIS">write-only</i></span> and no status information 569 will be returned. If a printer normally supports returning 570 status information then the <var class= 571 "LITERAL">ifhp.conf</var> configuration entry will indicate 572 this and the <b class="APPLICATION">ifhp</b> filter will 573 try to get status. When no status is returned it will 574 either terminate operation after a timeout or sit in an 575 endless loop waiting for status. By specifying <var class= 576 "LITERAL">status@</var> you will suppress getting status. 577 This also has the effect of doing <var class= 578 "LITERAL">sync@</var>, <var class= 579 "LITERAL">pagecount@</var>, and <var class= 580 "LITERAL">waitend@</var></p> 581 582 <p>The <var class="LITERAL">sync</var> option is used to 583 cause <b class="APPLICATION">ifhp</b> to wait for an <span 584 class="emphasis"><i class="EMPHASIS">end of job</i></span> 585 indication from the printer before starting the next job. 586 This is usually done in order to make sure that all jobs 587 have been flushed from a printer before starting another 588 job. If you specify <var class="LITERAL">sync@</var> then 589 you may get slightly faster startup but at the expense of 590 losing the ends of previous print jobs.</p> 591 592 <p>The <var class="LITERAL">pagecount</var> option is used 593 to cause <b class="APPLICATION">ifhp</b> to get the value 594 of a hardware pagecounter from the printer. If your printer 595 supports such an item then the <var class= 596 "LITERAL">ifhp.conf</var> configuration option usually 597 indicates this. However, it takes a small amount of time to 598 get the pagecounter information from the printer and you 599 may not need it. Use <var class="LITERAL">sync@</var> if 600 you do not want page counts.</p> 601 602 <p>Finally, <var class="LITERAL">waitend</var> option is 603 used to cause <b class="APPLICATION">ifhp</b> to wait for 604 an <span class="emphasis"><i class="EMPHASIS">end of 605 job</i></span> indication from the printer before exiting. 606 If you specify <var class="LITERAL">waitend@</var> then the 607 filter will exit immediately after sending the job, but you 608 will possibly lose any error information or status reports 609 from the printer.</p> 610 611 <p>For a complete list of all of the <b class= 612 "APPLICATION">ifhp</b> options please see the IFHP 613 documentation.</p> 614 </div> 615 616 <div class="SECT2"> 617 <h2 class="SECT2"><a name="JAGGIES">4.10.3. The Jaggies - 618 LF to CR-LF Conversion With lpf</a></h2> 619 620 <p>When printing to vintage hard copy devices or to 621 printers that support a <span class="emphasis"><i class= 622 "EMPHASIS">text</i></span> mode, many UNIX users discover 623 that their output suffers from a case of the jaggies.</p> 624 625 <div class="INFORMALEXAMPLE"> 626 <a name="AEN2977"></a> 627<pre class="SCREEN"> 628 Input file: 629 630 This is 631 a nice day 632 633 Output: 634 635 This is 636 a nice day 637</pre> 638 </div> 639 <br> 640 <br> 641 642 <p>UNIX systems terminate lines with a single <acronym 643 class="ACRONYM">NL</acronym> (new line) character. This 644 causes the printer to move down one line on the printing 645 page but does not change its horizontal position and print 646 the next character at the left margin. This is done by 647 using the <acronym class="ACRONYM">CR</acronym> (carriage 648 return) character. You need to convert the single <acronym 649 class="ACRONYM">NL</acronym> to a <var class= 650 "LITERAL">CR-LF</var> combination and the <b class= 651 "APPLICATION">lpf</b> filter supplied with <b class= 652 "APPLICATION">LPRng</b> does this.</p> 653 654 <p>First, locate the <b class="APPLICATION">lpf</b> filter. 655 You can find it by using the command:</p> 656 657 <div class="INFORMALEXAMPLE"> 658 <a name="AEN2988"></a> 659<pre class="SCREEN"> 660 <samp class="PROMPT">h9: {160} %</samp> <kbd class= 661"USERINPUT">find /usr/ -type f -name lpf -print</kbd> 662 /usr/libexec/lpr/lpf 663</pre> 664 </div> 665 <br> 666 <br> 667 668 <p>We will first see what the output is like without <b 669 class="APPLICATION">lpf</b>, and then see what it does. 670 Modify the <b class="APPLICATION">lp</b> printcap entry as 671 shown below and then use <tt class="COMMAND">lpc 672 restart</tt> to restart the <b class="APPLICATION">lpd</b> 673 server.</p> 674 675 <div class="INFORMALEXAMPLE"> 676 <a name="AEN2997"></a> 677<pre class="SCREEN"> 678 lp:sd=/var/spool/lpd/%P 679 :force_localhost 680 :lp=/tmp/lp 681</pre> 682 </div> 683 <br> 684 <br> 685 686 <p>Print a file and view the output using the following 687 commands. If you do not have the <b class= 688 "APPLICATION">od</b> (octal dump) program, try using <b 689 class="APPLICATION">hexdump</b> or some other appropriate 690 program that displays the numerical contents of the 691 file.</p> 692 693 <div class="INFORMALEXAMPLE"> 694 <a name="AEN3002"></a> 695<pre class="SCREEN"> 696 <samp class="PROMPT">h4: {203} %</samp> <kbd class= 697"USERINPUT">cp /dev/null /tmp/lp</kbd> 698 <samp class="PROMPT">h4: {204} %</samp> <kbd class= 699"USERINPUT">lpr /tmp/hi</kbd> 700 <samp class="PROMPT">h4: {205} %</samp> <kbd class= 701"USERINPUT">od -bc /tmp/lp</kbd> 702 0000000 150 151 012 703 h i \n 704 0000003 705</pre> 706 </div> 707 <br> 708 <br> 709 710 <p>Now we will use the <b class="APPLICATION">lpf</b> 711 filter. Modify the printcap as shown below and use <tt 712 class="COMMAND">lpc reread</tt> to cause <b class= 713 "APPLICATION">lpd</b> to reread the configuration 714 information.</p> 715 716 <div class="INFORMALEXAMPLE"> 717 <a name="AEN3014"></a> 718<pre class="SCREEN"> 719 lp:sd=/var/spool/lpd/%P 720 :force_localhost 721 :lp=/tmp/lp 722 # modify the path to lpf appropriately 723 :filter=/usr/local/libexec/filters/lpf 724</pre> 725 </div> 726 <br> 727 <br> 728 729 <p>Now reprint the file:</p> 730 731 <div class="INFORMALEXAMPLE"> 732 <a name="AEN3017"></a> 733<pre class="SCREEN"> 734 <samp class="PROMPT">h4: {206} %</samp> <kbd class= 735"USERINPUT">cp /dev/null /tmp/lp</kbd> 736 <samp class="PROMPT">h4: {207} %</samp> <kbd class= 737"USERINPUT">lpr /tmp/hi</kbd> 738 <samp class="PROMPT">h4: {208} %</samp> <kbd class= 739"USERINPUT">od -bc /tmp/lp</kbd> 740 od -bc /tmp/lp 741 0000000 150 151 015 012 742 h i \r \n 743 0000004 744</pre> 745 </div> 746 <br> 747 <br> 748 749 <p>As you see, <b class="APPLICATION">lpf</b> changes the 750 <var class="LITERAL">LF</var> to a <var class= 751 "LITERAL">CR-LF</var> sequence.</p> 752 </div> 753 754 <div class="SECT2"> 755 <h2 class="SECT2"><a name="AEN3029">4.10.4. Store and 756 Forward Spool Queues</a></h2> 757 758 <p>Up to now we have assumed that associated with each 759 spool queue is a hardware printing device. When a job is 760 sent to the spool queue the <b class="APPLICATION">lpd</b> 761 server will take actions to filter it and then send it to 762 the printing device.</p> 763 764 <p>However, we can also have <span class="emphasis"><i 765 class="EMPHASIS">store and forward</i></span> spool queues. 766 These queue act to simply buffer jobs and then forward them 767 to another spooler. The following printcap entry shows how 768 you can specify a store and forward queue.</p> 769 770 <div class="INFORMALEXAMPLE"> 771 <a name="AEN3035"></a> 772<pre class="SCREEN"> 773 # store and forward using classical BSD :rm:rp 774 lp:rp=pr:rm=host 775 :sd=/var/spool/lpd/%P 776 :server 777 # store and forward using <b class= 778"APPLICATION">LPRng</b> lp=pr@host 779 lp:lp=pr@host 780 :sd=/var/spool/lpd/%P 781 :server 782</pre> 783 </div> 784 <br> 785 <br> 786 787 <p>The legacy <var class="LITERAL">:rp</var> (remote 788 printer) and <var class="LITERAL">:rm</var> (remote host) 789 format can be used to specify the print queue and 790 destination host for jobs sent to this queue. The <b class= 791 "APPLICATION">LPRng</b> <var class= 792 "LITERAL">:lp=pr@host</var> format serves the same 793 function, and has precedence over the <var class= 794 "LITERAL">:rm:rp</var> form.</p> 795 796 <p>Edit the printcap file so it has contents indicated 797 below, use <tt class="COMMAND">checkpc -f</tt> to check the 798 printcap, and then use <tt class="COMMAND">lpc reread</tt> 799 to restart the <b class="APPLICATION">lpd</b> server.</p> 800 801 <div class="INFORMALEXAMPLE"> 802 <a name="AEN3048"></a> 803<pre class="SCREEN"> 804 lp:force_localhost 805 lp:server 806 :sd=/var/spool/lpd/%P 807 :lp=lp2@localhost 808 lp2:force_localhost 809 lp2:server 810 :sd=/var/spool/lpd/%P 811 :lp=/tmp/lp2 812</pre> 813 </div> 814 Execute the following commands to print the <tt class= 815 "FILENAME">/tmp/hi</tt> file and observe the results: 816 817 <div class="INFORMALEXAMPLE"> 818 <a name="AEN3051"></a> 819<pre class="SCREEN"> 820 <samp class="PROMPT">h4: {209} %</samp> <kbd class= 821"USERINPUT">lpr /tmp/hi</kbd> 822 <samp class="PROMPT">h4: {210} %</samp> <kbd class= 823"USERINPUT">lpq -lll</kbd> 824 Printer: lp@h4 (dest lp2@localhost) 825 Queue: no printable jobs in queue 826 Status: sending control file 'cfA029h4.private' \ 827 to lp2@localhost at 09:39:57.719 828 Status: completed sending 'cfA029h4.private' \ 829 to lp2@localhost at 09:39:57.724 830 Status: sending data file 'dfA029h4.private' \ 831 to lp2@localhost at 09:39:57.727 832 Status: completed sending 'dfA029h4.private' \ 833 to lp2@localhost at 09:39:57.925 834 Status: done job 'papowell@h4+29' transfer \ 835 to lp2@localhost at 09:39:57.926 836 Status: subserver pid 29031 exit status 'JSUCC' at 09:39:57.953 837 Status: lp@h4.private: job 'papowell@h4+29' printed at 09:39:57.961 838 Status: job 'papowell@h4+29' removed at 09:39:57.993 839 Printer: lp2@h4 840 Queue: no printable jobs in queue 841 Status: no banner at 09:39:58.054 842 Status: printing data file 'dfA029h4.private', size 3 at 09:39:58.054 843 Status: printing done 'papowell@h4+29' at 09:39:58.054 844 Status: accounting at end at 09:39:58.054 845 Status: finished 'papowell@h4+29', status 'JSUCC' at 09:39:58.054 846 Status: subserver pid 29033 exit status 'JSUCC' at 09:39:58.056 847 Status: lp2@h4.private: job 'papowell@h4+29' printed at 09:39:58.056 848 Status: job 'papowell@h4+29' removed at 09:39:58.069 849</pre> 850 </div> 851 <br> 852 <br> 853 854 <p>As we see from the status, our job was sent to the <var 855 class="LITERAL">lp</var> spool queue first. It was store 856 there and then the <b class="APPLICATION">lpd</b> server 857 transferred it to the <var class="LITERAL">lp2</var> spool 858 queue, where it was printed to the file <tt class= 859 "FILENAME">/tmp/lp2</tt>.</p> 860 </div> 861 862 <div class="SECT2"> 863 <h2 class="SECT2"><a name="AEN3062">4.10.5. Filtering Job 864 Files In Transit</a></h2> 865 866 <p>One of the major problems with store and forward 867 operation is that the destination spool queue may not 868 actually be a spool queue - it can be a printer. Many 869 network printers provide an RFC1179 compatible network 870 interface and act, for job forwarding purposes, like a host 871 running a limited capability BSD print spooler.</p> 872 873 <p>By adding a filter to the printcap information we can 874 modify the format of a job file so that it is compatible 875 with the destination printer.</p> 876 877 <p>Edit the printcap and <tt class= 878 "FILENAME">/tmp/testf</tt> files so they have the contents 879 indicated below, give <tt class="FILENAME">/tmp/testf</tt> 880 executable permissions, use <tt class="COMMAND">checkpc 881 -f</tt> to check the printcap, and then use <tt class= 882 "COMMAND">lpc reread</tt> to restart the <b class= 883 "APPLICATION">lpd</b> server.</p> 884 885 <div class="INFORMALEXAMPLE"> 886 <a name="AEN3072"></a> 887<pre class="SCREEN"> 888 # set /tmp/testf to contain the following 889 # and chmod 755 /tmp/testf 890 #!/bin/sh 891 echo TESTF $0 $@ 892 /bin/cat 893 exit 0 894 895 # printcap 896 lp:force_localhost 897 lp:server 898 :sd=/var/spool/lpd/%P 899 :lp=lp2@localhost 900 :filter=/tmp/testf 901 :bq_format=ffl 902 lp2:force_localhost 903 lp2:server 904 :sd=/var/spool/lpd/%P 905 :lp=/tmp/lp2 906</pre> 907 </div> 908 Execute the following commands to print the <tt class= 909 "FILENAME">/tmp/hi</tt> file and observe the results: 910 911 <div class="INFORMALEXAMPLE"> 912 <a name="AEN3075"></a> 913<pre class="SCREEN"> 914 <samp class="PROMPT">h4: {211} %</samp> <kbd class= 915"USERINPUT">lpr /tmp/hi</kbd> 916 <samp class="PROMPT">h4: {212} %</samp> <kbd class= 917"USERINPUT">lpq -llll</kbd> 918 <samp class="PROMPT">h4: {213} %</samp> <kbd class= 919"USERINPUT">lpq -llll</kbd> 920 Printer: lp@h4 (dest lp2@localhost) 921 Queue: no printable jobs in queue 922 Status: no banner at 09:55:53.681 923 Status: printing data file 'dfA086h4.private', size 3, \ 924 IF filter 'testf' at 09:55:53.683 925 Status: IF filter finished at 09:55:53.713 926 Status: printing done 'papowell@h4+86' at 09:55:53.714 927 Status: sending job 'papowell@h4+86' to lp2@localhost at 09:55:53.734 928 Status: connecting to 'localhost', attempt 1 at 09:55:53.735 929 Status: connected to 'localhost' at 09:55:53.739 930 Status: requesting printer lp2@localhost at 09:55:53.740 931 Status: sending control file 'cfA086h4.private' 932 to lp2@localhost at 09:55:53.752 933 Status: completed sending 'cfA086h4.private' 934 to lp2@localhost at 09:55:53.757 935 Status: sending data file 'dfA086h4.private' 936 to lp2@localhost at 09:55:53.758 937 Status: completed sending 'dfA086h4.private' 938 to lp2@localhost at 09:55:53.939 939 Status: done job 'papowell@h4+86' transfer 940 to lp2@localhost at 09:55:53.940 941 Status: subserver pid 29088 exit status 'JSUCC' at 09:55:53.980 942 Status: lp@h4.private: job 'papowell@h4+86' printed at 09:55:53.983 943 Status: job 'papowell@h4+86' removed at 09:55:53.998 944 Printer: lp2@h4 945 Queue: no printable jobs in queue 946 Status: subserver pid 29092 starting at 09:55:54.005 947 Status: accounting at start at 09:55:54.005 948 Status: opening device '/tmp/lp2' at 09:55:54.005 949 Status: printing job 'papowell@h4+86' at 09:55:54.005 950 Status: no banner at 09:55:54.006 951 Status: printing data file 'dfA086h4.private', size 298 at 09:55:54.006 952 Status: printing done 'papowell@h4+86' at 09:55:54.006 953 Status: accounting at end at 09:55:54.006 954 Status: finished 'papowell@h4+86', status 'JSUCC' at 09:55:54.006 955 Status: subserver pid 29092 exit status 'JSUCC' at 09:55:54.008 956 Status: lp2@h4.private: job 'papowell@h4+86' printed at 09:55:54.008 957 Status: job 'papowell@h4+86' removed at 09:55:54.020 958</pre> 959 </div> 960 <br> 961 <br> 962 963 <p>We have displayed a bit more status information so that 964 we can see what the actions the <var class= 965 "LITERAL">lp</var> queue carries out. It first <span class= 966 "emphasis"><i class="EMPHASIS">processes</i></span> the job 967 data file using the <b class="APPLICATION">testf</b> filter 968 and puts the results in a temporary file. Then it sends the 969 contents of the temporary file to the <var class= 970 "LITERAL">lp2</var> queue. The <var class= 971 "LITERAL">lp2</var> queue receives the converted job file 972 and then prints it to the <tt class= 973 "FILENAME">/tmp/lp2</tt> file in turn.</p> 974 975 <p>By default, each file in a job is processed by a print 976 file and the processed output is then sent to the 977 destintion as individual job files, each with the format 978 specified by the value of the <var class= 979 "LITERAL">bq_format</var> (default <var class= 980 "LITERAL">f</var>) option. The <var class= 981 "LITERAL">bq_format</var> option has the format <var class= 982 "LITERAL">iOiO...d</var>; each <var class="LITERAL">i</var> 983 is the original format and the corresponding <var class= 984 "LITERAL">O</var> is the output format. If there is an odd 985 number of characters then the last unmatched character is 986 used as the default format, otherwise no translation is 987 done. For example, <var class="LITERAL">flrfl</var> will 988 cause the <var class="LITERAL">f</var> format to be mapped 989 to <var class="LITERAL">l</var>, <var class= 990 "LITERAL">r</var> to <var class="LITERAL">f</var>, and any 991 others to <var class="LITERAL">l</var>.</p> 992 </div> 993 </div> 994 995 <div class="NAVFOOTER"> 996 <hr align="LEFT" width="100%"> 997 998 <table summary="Footer navigation table" width="100%" border= 999 "0" cellpadding="0" cellspacing="0"> 1000 <tr> 1001 <td width="33%" align="left" valign="top"><a href= 1002 "printjobfilters.htm" accesskey="P">Prev</a></td> 1003 1004 <td width="34%" align="center" valign="top"><a href= 1005 "index.htm" accesskey="H">Home</a></td> 1006 1007 <td width="33%" align="right" valign="top"><a href= 1008 "x3103.htm" accesskey="N">Next</a></td> 1009 </tr> 1010 1011 <tr> 1012 <td width="33%" align="left" valign="top">Print Job 1013 Filters</td> 1014 1015 <td width="34%" align="center" valign="top"><a href= 1016 "tutorial.htm" accesskey="U">Up</a></td> 1017 1018 <td width="33%" align="right" valign="top">Printcap 1019 Basics</td> 1020 </tr> 1021 </table> 1022 </div> 1023 </body> 1024</html> 1025 1026