$ copy sys$input: HEADERS_STR.PS $DECK/DOLLARS="#M#O#E#SOFT" %% headers_str - print text with headers on LaserWriter % % R. Watson 25-Sep-1986 % 1. revision: 21-AUG-1994 H. Moerchen % change for A4 papersize % change to ISOLatin1Encoding /EOF { linecount 0 ne column 0 ne or { % if we've printed a line /column ncolumns def % force page out newpage } if } def /XCR { /xpos xmargin def %%%was leftmargin } def /XLF {newline} def /XFF { topmargin lineh sub ypos ne { % if not top of page newpage } if } def %% XSTR % % prints a line of text from the stack % /XSTR { /line exch def % get text line length 1 ge { % show the line xpos ypos moveto wrap { 0 1 line length 1 sub { line 2 -1 roll 1 getinterval dup stringwidth pop currentpoint pop add squish add xlimit gt {/wrapping true def newline xpos ypos moveto /wrapping false def} if squish 0 3 -1 roll ashow } for } { squish 0 line ashow } ifelse /xpos currentpoint pop def % save current x position } if } def %% newline - move down 1 line. % /newline { /linecount linecount 1 add def % advance line count ypos lineh sub /ypos exch def % debit y pos on page ypos ypos .1 mul add bottommargin lt linecount linelimit gt or { % if bottom of page newpage newline } if } def %% newpage - initialize for a new page. % /newpage { /linecount 0 def % reset line count /ypos topmargin lineh sub def % reset line on page /column column 1 add def % advance column column ncolumns lt { % if not last column /xmargin columnwidth column mul leftmargin add def /xpos xmargin def /xlimit xlimit columnwidth add def } { /column 0 def % reset column title { % if title leftmargin topmargin titlemargin add moveto % setup header currentfont % save current font /Helvetica-Bold-ISO findfont 12 scalefont setfont filename show pagewidth 1.5 inch sub topmargin titlemargin add moveto % page number (page ) show page 10 5 string cvrs show setfont % restore font } if showpage landscape wrapping not { page % save this saveobj restore % flush vm /saveobj save def /page exch def % restore this } if alternate page 1 and 1 eq and {/temp leftmargin def /leftmargin rightmargin def /rightmargin temp def} if /page page 1 add def % advance page number /xmargin leftmargin def % reset left side /xpos xmargin def /xlimit leftmargin columnwidth add def } ifelse } def %% landscape - set landscape mode % /landscape { wide { %% 8.5 inch 0 translate 90 rotate 210 mm 0 translate 90 rotate } if } def %% inch . % % convert to inches % /inch { 72. mul} def %% mm . % % convert to mm % /mm { 72. 25.4 div mul} def %% point . % % convert to points % /point { } def %% executable initialization. % initgraphics currentdict /formname known not {/formname (2UP) def} if formname (2UP) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide true (.wide .w .param3)] % landscape mode [/title false (.title .param4)] % title [/ncolumns 2 (.ncolumns .param5)] % number of columns [/linelimit 66 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if formname (LETTER) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide false (.wide .w .param3)] % landscape mode [/title false (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 77 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if formname (LANDSCAPE) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide true (.wide .w .param3)] % landscape mode [/title false (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 66 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if formname (HEADERS) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide false (.wide .w .param3)] % landscape mode [/title true (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 77 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if formname (BANNER) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 194 (.fsize .fs .param2)] % font size [/wide true (.wide .w .param3)] % landscape mode [/title false (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 1 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Helvetica-Bold-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap true (.wrap)] % set wrap mode ] def } if formname (SWEDISH) eq { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide false (.wide .w .param3)] % landscape mode [/title false (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 66 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish true (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if currentdict /table known not { /table [ [/#copies 1 (.nc .ncopies .param1)] % number of copies [/fsizetmp 0 (.fsize .fs .param2)] % font size [/wide false (.wide .w .param3)] % landscape mode [/title true (.title .param4)] % title [/ncolumns 1 (.ncolumns .param5)] % number of columns [/linelimit 66 (.linelimit .nlines .param6)] % lines per page [/hdr () (.hdr .header. param7)] % page header [/font (Courier-ISO) (.font .param8)] % font [/topmargin -1 (.topmargin .top .param9)] % topmargin [/leftmargin -1 (.leftmargin .left .param10)] % leftmargin [/rightmargin -1 (.rightmargin .right .param11)] % rightmargin [/bottommargin -1 (.bottommargin .bottom .param12)] % bottommargin [/alternate false (.alternate .param13)] % alternate [/lpp 0 (.lpp .param14)] % lines per page to fill between top/bot [/swedish false (.swedish)] % set swedish mode [/wrap false (.wrap)] % set wrap mode ] def } if table { % apply defaults /ta exch def % save array ta 0 get % key ta 1 get % default value def % define default value } forall currentdict /parser known {parser} if % if user inputs % if the user specified a string for /hdr then use it, also imply title true hdr length 0 ne {/filename hdr def /title true def} if currentdict /filename known not {/filename () def} if %filename (_DUA0:[]) anchorsearch {pop /filename exch def} {pop} ifelse %cleanup filename ([]) search {pop pop /filename exch def} {pop} ifelse /inp currentfile def % define files wide { leftmargin 0 lt {/leftmargin 20 mm def} {/leftmargin leftmargin mm def} ifelse topmargin 0 lt {/topmargin 190 mm def} {/topmargin 210 topmargin sub mm def} ifelse bottommargin 0 lt {/bottommargin 7 mm def} {/bottommargin bottommargin mm def} ifelse rightmargin 0 lt {/rightmargin 10 mm def} {/rightmargin rightmargin mm def} ifelse currentdict /fsize known not {/fsize 9 point def} if fsizetmp 0 ne {/fsize fsizetmp def} if /pagewidth 297 mm def /squish -0.3 def /titlemargin 0 def } { leftmargin 0 lt {/leftmargin 20 mm def} {/leftmargin leftmargin mm def} ifelse topmargin 0 lt {/topmargin 277 mm def} {/topmargin 297 topmargin sub mm def} ifelse rightmargin 0 lt {/rightmargin 10 mm def} {/rightmargin rightmargin mm def} ifelse bottommargin 0 lt {/bottommargin 20 mm def} {/bottommargin bottommargin mm def} ifelse currentdict /fsize known not {/fsize 7 point def} if fsizetmp 0 ne {/fsize fsizetmp def} if /pagewidth 210 mm def /squish -0.3 def /titlemargin .185 inch def } ifelse lpp 0 eq { /lineh fsize point def % line height /lineh lineh 1.2 sub def } { /lineh topmargin bottommargin sub fsize sub lpp 1 sub div def /topmargin topmargin lineh add fsize sub def } ifelse /linecount 0 def /column 0 def /columnwidth pagewidth leftmargin sub rightmargin sub ncolumns div def /ibuf 200 string def % input buffer /page 1 def % page number /xpos leftmargin def /xmargin leftmargin def /ypos topmargin def /xlimit leftmargin columnwidth add def /wrapping false def % mark % CREATE ISOLatin1Encoding if not there already /ISOLatin1Encoding 8#000 1 8#054 {StandardEncoding exch get} for /minus 8#056 1 8#217 {StandardEncoding exch get} for /dotlessi 8#301 1 8#317 {StandardEncoding exch get} for /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis /ISOLatin1Encoding where not {256 array astore def} if cleartomark % %% change encoding vector - red book 5.6.1 /Helvetica-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def currentdict % push dict to operand stack end % reverse of begin /Helvetica-Bold-ISO exch definefont pop %% /Courier findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def currentdict % push dict to operand stack end % reverse of begin /Courier-ISO exch definefont pop %% % The following section of code makes a new font with a backspace % character defined. The width of the backspace character is % the negative of the width of an underscore character. /selectfont { dup findfont % select the font %lineh scalefont setfont % find width of an underscore % (_) stringwidth pop 100 mul /uwid exch def % % find the width of a character in the font coordinate system. % add back in the scaled amount that squish will offset us so we % end up in the right place after a backspace % 1000 scalefont setfont (_) stringwidth pop 2000 squish mul fsize div add /uwid exch def findfont % copy the font dup length 1 add dict /newdict exch def % leaving room for a Metrics entry { exch dup /FID ne { % if not /FID dup /Encoding eq { % if /Encoding copy the entry exch dup length array copy newdict 3 1 roll put } { exch newdict 3 1 roll put % else just use the object } ifelse } { pop pop % dump /FID } ifelse } forall 1 dict begin % create Metrics dictionary /backspace uwid neg def % define backspace width newdict /Metrics currentdict put end newdict begin % set encoding for backspace Encoding 8 /backspace put swedish { Encoding 16#7b /aring put % { Encoding 16#7d /adieresis put % } Encoding 16#7c /odieresis put % | Encoding 16#5b /Aring put % [ Encoding 16#5d /Adieresis put % ] Encoding 16#5c /Odieresis put % \ } if end /xfont newdict definefont pop % define the new font /xfont findfont fsize scalefont setfont % select the new font } def font selectfont landscape /saveobj save def #M#O#E#SOFT $ copy sys$input: LASER.C $DECK/DOLLARS="#M#O#E#SOFT" /*** LASER - A Single-Threaded Asynchronous Symbiont to driver_ * an Apple LaserWriter * * Copyright 1987-1990, The University of Texas at Austin * * Author: * Rick Watson * The University of Texas Computation Center, 512/471-3241 * internet: watson@utadnx.cc.utexas.edu bitnet: watson@utadnx * uucp: ...!cs.utexas.edu!ut-emx!rick span: utspan::utadnx::watson * * Revised: * Steve Roseman * lusgr@vax1.cc.lehigh.edu * * Mark London * mrl@tardis.pfc.mit.edu * * Tony Brack * brack@agrajag.yorku.ca * * This user-writter symbiont is tailored specifically to the Apple * LaserWriter and similar PostScript printers. It has the following * features: * * 1. Page counting is done by reading the page count from the * laserwriter at the beginning and the end of each file. * This mechanism also "synchronizes" the user job with the * laserwriter. If the laserwriter does not respond to the * first request for a page count, the symbiont notifies the * operator, and continues to poll the laserwriter. This is * useful if the laserwriter is being shared with MAC users. * * 2. Parameters may be passed to postscript modules in the setup * library via 2 mechanisms. The text from a $PRINT /NOTE= * command will be sent first. * * The /PARAMETER switch may also be used. Each entry can be * one of two formats. An entry without the "=" character in * it is sent as (param) . An entry with the * "=" character in is is sent as () . * The parameters are defined in an array called /param. * Example: /PARAMETER=(1,SIZE=5,"str=(a+b)") generates: * /param [(param1) 1 (size) 5 (str) (a+b)] def * All alphabetics are forced to lower case. Using the /PARAMETER * switch forces sending PARSER from LASER.TLB as part of the * PostScript program sent to the printer. Look at * other files in LASER.TLB for examples of using the PARSER * module. * * 3. If the name of a setup module ends with "_HEX" the file to * be printed is "hexified" to the laser printer. This is useful * for sending bitimage files to the laserwriter. * * 4. A log of responses from the laserwriter is created if * /PARAMETER=MESSAGE=KEEP is specified . This is * useful for debugging postscript programs. The file is created * as .LASER_LOG. These files are automatically * deleted if empty. * * 5. A "%%[ Flushing:" response from the printer will abort the * current file. * * 6. Spooled files: Spooled files normally default to FORMS=LETTER * if the recommended queue initialize procedure is followed. * By specifying special filenames, the user can override the * forms used, and pass parameters to the setup module. * The syntax is: "_._" * where is the name of a form to use and * is of the form: -[_...]. * (Note the use of "-" instead of "=" for a separator.) * For example: $ copy zeta.plt alw:_zeta._ncopies-5_scale-2 * (The kludge of the century, huh?) * * Outputs (in the following order) to the laserwriter: * * 1. "/note def\r\n". * 2. /param definition and library module PARSER if /parameter switch * present * 3. If the setup module is "HEADERS", the string "/filename * def" and "/formname def" * 3. The first file or forms setup module if specified. * 4. The file to be printed itself. If the setup module name ends in * "_HEX" the file is hex-ified to the printer instead. * * where: is the string from $PRINT /NOTE= * is the string from $PRINT /PARAM=(""...) * is the file specification for the file to print. * * Limitations, bugs, etc: * * 1. No checkpointing is done. * 2. $PRINT/COPIES=n sends the job to the LaserWriter n times. This * is not optimal, but is how the job controller handles things. * It makes sense for most printers. Multiple copy handling is * better handled in most of the postscript setup files. Also * /note="/#copies n def" will usually work. * 3. $PRINT/SPACE=n is not implemented. * 4. /BURST is identical to /FLAG. * 5. Does not handle lists of setup modules. * * Recommended device setup: * * $ define/system/exec/trans=(concealed,terminal) alw : ! laser * $ set term /perm /speed=9600 /nomodem /notype /nohang alw * $ set term /perm /hostsync /pasthru /ttsync /eightbit /nobroad alw * $ set term /perm /noauto alw * $ set prot=o:rwlp /dev alw * $ set device /spooled=(ALW,sys$sysdevice:) alw * * Recommended queue initialize: * * $ initialize/queue/start - * /default=(noburst,nofeed,noflag,notrailer,form=headers) - * /separate=(noburst,noflag,trailer) - * /library=laser /form=letter - * /processor=laser /on=alw: alw * * NOTE: change /separate=(...trailer) to (...flag) if your laser printer * stacks right side up. * * Revisions: * * 15-Jul-1991 T. Brack - Converted header file inclusions to be compatible * with and use those provided by VAXC 3.2 * 11-Sep-1991 T. Brack - Added code to retrieve the queue name * - Added support for calling TCP/IP served devices * with /ON="TCP%servername:port" (a.k.a. cisco * & MultiNET) * 01-Oct-1991 T. Brack - Moved the cancel from before the test for end of * job, to inside it so we don't cancel Inputs from * a printer we're still interested in * - Replace postlaserread and laser_read_ast with * "new improved" versions, making local data static * and performing internal interpretation of break * characters (needed for TCP/IP) * - Replaced numerous calls to SYS$SNDOPR with a more * "C" friendly routine. Also fixes bugs in string * length computations. * - Prefix OPCOM messages with the queue name * - Add "reason" messages to some of the new error * messages - should retrofit more later. * - Use the UCX compatible TCP/IP interface of * MultiNET 3.0 and don't rely on TGV's NLPn: * kluge, so that we are portable and don't have * to do lots of translations - haven't tested it * with UCX though... * - Added conditional compiles for MultiNET so that * we can check for error codes and signal them * since vmserrno IS MultiNET specific * 03-Oct-1991 T. Brack - removed the aforementioned $CANCEL completely, * since the $DASSGN takes care of it anyway * - it is not sufficent to retry "connect()" calls, * the "socket()" call must also be repeated for * retries to work... make it so number 1! * 09-Oct-1991 T. Brack - deassign the channel after failed connect attempts * for MultiNET * 07-Nov-1991 T. Brack - rewrote openuserlog() so that it puts files in the * user's default directory instead of wherever it came * from. Only if we can't find his default directory do * we put it in LASER$LOG. * - changed the log file extension to "LOG-PS" so that * people can search for *.LOG*... a minor point! * 9/25/92 MRL - Fixed BRACK's new laser_read_ast which did * not work with non-tcp connection properly. * - Fixed getdvi to work with spooled device. * - Added hook to allow sharing of tcp device. * - Added hook to allow using it without device * being able to respond. * - Added BYPASS privs, as could not print * files without system access protection. * - STOP/QUEUE/RESET now properly causes a * disconnection of the LTA device. * - An abnormal LTA disconnection now simply * causes the job to abort rather than the * symbiont stopping. * - Changed code so that the read qio is only * canceled and reissued when necessary. * This was causing LTA queues to stall. * 31-AUG-1994 H. Moerchen - support 8-bit characters * */ #include descrip #include dcdef #include dvidef #include errno #include fscndef #include prvdef #include rms #include in #include iodef #include lbrdef #include netdb #include opcdef #include quidef #include ttdef #include ctype #include socket #include ssdef #include stddef #include stdio #include stdlib #include uaidef #include brkdef #include lnmdef #include "iosb" #include "itemlist" #include "returncodes" #include "smbdef.h" typedef unsigned char UCHAR; /* Moerchen 31-AUG-94 */ #define TRUE 1 #define FALSE 0 #define DEBUG FALSE #if MULTINET #include "multinet_root:[multinet.include]errno.h" #endif #if DEBUG FILE debug; #endif #define MAXITEMS 60 /* max expected items from jobctl */ #define min(a,b) ( ((a)<(b)) ? (a) : (b) ) #define max(a,b) ( ((a)>(b)) ? (a) : (b) ) #define WRITELASER(p1,p2) {if (!io_aborted) {\ stat = sys$qiow(0,laserchan, IO$_WRITEPBLK, &w_iosb, 0, 0,\ p1, p2, 0, 0, 0, 0);if (!(stat & 1 && w_iosb.status & 1)) \ {io_aborted = !(stat & 1) ? stat : w_iosb.status; \ if (!stop_task) stop_task = io_aborted; return FALSE;} iocount++;}} #define WRITELASERBUF(p1,p2) {{if (!io_aborted) olen = p2;while (olen > 0)\ {stat = sys$qiow(0,laserchan, IO$_WRITEPBLK, &w_iosb, 0, 0,\ p1+p2-olen, min(1536,olen), 0, 0, 0, 0);if (!(stat & 1 && w_iosb.status & 1)) \ {io_aborted = !(stat & 1) ? stat : w_iosb.status; \ if (!stop_task) stop_task = stat; return FALSE;} olen -= min(1536,olen);\ iocount++;}}} #define WRITESTRING(p1) WRITELASER(p1,strlen(p1)) short laserchan; /* laserwriter channel */ globalvalue LASER$_STREAMNOTSTART,LASER$_MAXITEMS, LASER$_CREATELOG,LASER$_STARTJOB,LASER$_ERROR, LASER$_STALLED,LASER$_RESUMED,LASER$_NOMEMORY, LASER$_ITEMNOTFOUND,LASER$_TOOMANYTABS, LASER$_USERDATA,LASER$_JOBID,LASER$_TIMEOUT,LASER$_ABORT, LASER$_NOTRESOLVED,LASER$_CONNREFUSED, LASER$_FLUSHED,LASER$_SETUPNOTFOUND,LASER$_INVPARAM; void dassgndev(); void assigndev(); void jobctl_ast(); /* job controller ast routine */ void ltatimeout(); void statetimeout(); struct { int item_code; /* code */ unsigned short item_size; /* size of item */ char *buffer; /* address of item */ } item[MAXITEMS]; struct io$status_block w_iosb = {0, 0, 0}; int stop_task; /* stop task flag */ int stop_reason; /* stop task reason code */ int spooled_file; /* TRUE if spooled file */ int laser_efn; /* laser read event flag */ int startpage; /* task start page */ int endpage; /* task end page */ int jobstart; /* job start page */ int ansi; /* TRUE if ansi specified */ int ascii; /* TRUE if ascii main file */ int hex; /* TRUE if hexified main file */ int tek; /* TRUE if tektronix main file */ int ps; /* TRUE if postscript main file */ int string; /* TRUE if string main file */ int status_idle; /* TRUE if idle status received */ int status_error; /* TRUE if error message received */ int land; /* TRUE if landscape */ int port; /* TRUE if portrait */ int notify_qual; int nup; int olen; int end_sent = FALSE; int cancel_read = TRUE; char queue_name[128]; int iocount,oldiocount; unsigned short laser_iosb[4]; /* laser read iosb */ char laser_buf[1024]; /* laser read buffer */ struct FAB main_fab; /* main file rms stuff */ struct NAM main_nam; struct RAB main_rab; struct FAB log_fab; /* log file rms stuff */ struct RAB log_rab; struct dsc$descriptor_d library_spec = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; struct dsc$descriptor_d buffer_des = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; struct dsc$descriptor_d savelog = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; int userlog = -1; /* user log file */ int notify = FALSE; static char msg[255] = "\007\007\007\r\n"; /* error message to user */ struct dsc$descriptor_s errmsg_dsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; char user_text[20]; /* user name to send error message to */ struct dsc$descriptor_s user_notify = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &user_text}; int ii = 0; /* item index */ int start_task = FALSE; /* start task flag */ int patchneeded = FALSE; /* TRUE if patch module sent */ int io_aborted = FALSE; int stopoutput = FALSE; int shared_device = FALSE; int lta_device = FALSE; int ltaefn = 0,stateefn; int statetime[2]= {-1*1800000000,-1}; /* 3 minutes */ int jobnum = -1,entry_num; short msglen = 0; char message[257]; struct dsc$descriptor_s msgd = {sizeof(message)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, message}; struct { /* operator message to printer */ char type; char target; short fill; long id; char text[257]; } oprmsg = {OPC$_RQ_RQST, OPC$M_NM_PRINT, 0, 0}; struct dsc$descriptor_s oprmsg_dsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &oprmsg}; struct dsc$descriptor_s device = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; struct { unsigned long class; unsigned long read_function; unsigned long write_function; void *terminators; } devinfo; main() { int stat; laserchan = 0; preset(); /* initialize symbiont */ do { while (!start_task) { /* wait for start_task */ stat = sys$hiber(); checkstat(stat,"wait start_task"); } processtask(); /* do a job */ } while (TRUE); } getmsg(errmsg,addpercent) int errmsg,addpercent; { int stat; stat = sys$getmsg(errmsg, &msglen, &msgd, 15, 0); checkstat(stat,"$getmsg"); message[msglen] = 0; if (addpercent) msg[5] = '%'; } sndmsg(type,bells) int type,bells; { int i; /* sys$setrwm(1); */ errmsg_dsc.dsc$w_length = strlen(msg) - 5; errmsg_dsc.dsc$a_pointer = &msg[5]; if (type) { oprmsg_dsc.dsc$w_length = errmsg_dsc.dsc$w_length + 8; strncpy(oprmsg.text,errmsg_dsc.dsc$a_pointer, errmsg_dsc.dsc$w_length); sys$sndopr(&oprmsg_dsc, 0); } errmsg_dsc.dsc$w_length += 5*bells; errmsg_dsc.dsc$a_pointer -= 5*bells; if (type != 2) sys$brkthru(0, &errmsg_dsc, &user_notify, BRK$C_USERNAME,0,32,BRK$M_CLUSTER,0,5,0,0); for (i=5;i 245) laser_buf[245] = 0; strncpy(&msg[5],message,msglen); strncpy(&msg[msglen+5],&laser_buf[17],strlen(laser_buf)-17); jobid(strstr(laser_buf,"Operator") ? 1 : 0); status_error = TRUE; return TRUE; } if (strncmp(laser_buf, "%%[ patch needed ]%%", 20) == 0) { patchneeded = TRUE; return TRUE; } if (strncmp(laser_buf, "stop", 4) == 0) { stopoutput = TRUE; return TRUE; } if (strstr(laser_buf, "not a known parameter")) { stop_reason = LASER$_INVPARAM; return FALSE; } if (strncmp(laser_buf, "%%[ start page #=", 17) == 0 && status_idle) { sscanf(&laser_buf[17], "%d", &startpage); sys$wake(0,0); /* wakeup sync waiting */ return TRUE; } if (strncmp(laser_buf, "%%[ end page #=", 17) == 0 && status_idle) { sscanf(&laser_buf[17], "%d", &endpage); sys$wake(0,0); /* wakeup sync waiting */ return TRUE; } /* Abort the job if we see "%%[ Flushing:" */ /* Don't override an already existing stop_reason condition */ if (strncmp(laser_buf, "%%[ Flushing:", 13) == 0 && startpage && status_idle && !stopoutput) { if (stop_reason == 0) stop_reason = LASER$_FLUSHED; return FALSE; /* write in log */ } if (strncmp(laser_buf,"%%[ Error:", 10) == 0 && ((status_idle && !stopoutput) || strstr(laser_buf,"Operator")) && (userlog == 0 || userlog == -1)) { getmsg(LASER$_ERROR, 0); if (strlen(laser_buf) > 245) laser_buf[245] = 0; strncpy(&msg[5],message,msglen); strncpy(&msg[msglen+5],&laser_buf[10],strlen(laser_buf)-10); jobid(strstr(laser_buf,"Operator") ? 1 : 0); if (userlog == -1) userlog = -2; status_error = TRUE; return FALSE; } if (!stopoutput && startpage && !stop_reason && !stop_task && isalpha(laser_buf[0])) { if (notify_qual) { getmsg(LASER$_USERDATA, 0); if (strlen(laser_buf) > 245) laser_buf[245] = 0; strncpy(&msg[5],message,msglen); strncpy(&msg[msglen+5],laser_buf,strlen(laser_buf)); jobid(0); } return TRUE; } if (stopoutput || !startpage) return TRUE; return FALSE; } /** checkspooled - check for a spooled file. * * If the filename has "[]_" in it, then this is a spooled file * that the user wants to specify the form name for. Further, * if the extension starts with "_", then it contains the * user parameter list. We forge the item list to make things * look right. */ checkspooled() { struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; struct dsc$descriptor_d dynd = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; char *cp, *pp, spoolfile[255]; int len, i, stat; int ourindex; char setup[257]; /* where to put setup name */ long iosb[2]; /* for $getquiw */ short setupl; /* returned length of setup */ struct { /* item list for $getquiw */ short l1; short c1; char *b1; long *r1; short l2; short c2; char *b2; long *r2; long end; } itmlst = {0, QUI$_SEARCH_NAME, 0, 0, sizeof(setup)-1, QUI$_FORM_SETUP_MODULES, setup, &setupl, 0}; spooled_file = FALSE; /* get the file specification */ if (!getitemdescrip(SMBMSG$K_FILE_SPECIFICATION, &temp, FALSE)) return; strncpy(spoolfile, temp.dsc$a_pointer, temp.dsc$w_length); spoolfile[temp.dsc$w_length] = 0; /* check for []_ */ if (!(cp = strchr(spoolfile, '['))) return; if (!(*++cp == ']')) return; spooled_file = TRUE; /* file is spooled */ if (!(*++cp == '_')) return; /* find the extension and terminate the name string */ if (!(pp = strchr(cp, '.'))) return; *pp = 0; cp++; /* translate the form name into setup module names */ /* If it won't translate, then pass on the form name */ itmlst.l1 = strlen(cp); /* point to name */ itmlst.b1 = cp; stat = sys$getquiw(0, QUI$_DISPLAY_FORM, 0, &itmlst, iosb, 0, 0); checkstat(stat, "getquiw"); if ((iosb[0] & 1) != 1) /* if no translation */ strcpy(setup, cp); else setup[setupl] = 0; /* forge the file setup module to have our setup module name */ /* Note that the forge transfers the dynamic string "dynd" to "item" */ ourindex = findandclritem(SMBMSG$K_FILE_SETUP_MODULES); dynd.dsc$w_length = 0; /* get dynamic string */ dynd.dsc$a_pointer = 0; len = strlen(setup); str$copy_r(&dynd, &len, setup); item[ourindex].item_size = dynd.dsc$w_length; /* complete forge */ item[ourindex].buffer = dynd.dsc$a_pointer; /* forge the form name to have our form name */ ourindex = findandclritem(SMBMSG$K_FORM_NAME); dynd.dsc$w_length = 0; /* get dyamic string */ dynd.dsc$a_pointer = 0; len = strlen(cp); /* pointer to form name */ str$copy_r(&dynd, &len, cp); item[ourindex].item_size = dynd.dsc$w_length; /* complete forge */ item[ourindex].buffer = dynd.dsc$a_pointer; /* now check to see if there are parameters */ cp = ++pp; /* set extension address */ if (pp = strchr(cp,';')) *pp = 0; /* terminate at ";" */ for (i = 0; i < 8; i++) { if (*cp != '_') return; /* check next char */ cp++; /* advance over it */ /* if there is another _, point to it, else point to the */ /* end of the string */ if ((pp = strchr(cp,'_')) == 0) pp = cp + strlen(cp); len = pp - cp; /* find length of string */ if (len == 0) continue; /* if null parameter */ /* forge the item */ ourindex = findandclritem(SMBMSG$K_PARAMETER_1+i); dynd.dsc$w_length = 0; /* get dynamic string */ dynd.dsc$a_pointer = 0; str$copy_r(&dynd, &len, cp); item[ourindex].item_size = dynd.dsc$w_length; item[ourindex].buffer = dynd.dsc$a_pointer; cp = pp; } } /** findandclritem - find and clear item. * * Finds an item in the item list. Releases the dynamic string * for that item. If the item doesn't exist in the item list, * create it. * * return: index to item in item list */ findandclritem(whichitem) int whichitem; { int i; struct dsc$descriptor_d temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; for (i = 0; i < ii; i++) { /* search item list */ if (whichitem == item[i].item_code) break; } if (i == ii) { /* if end of list */ if (++ii > MAXITEMS) exit(LASER$_MAXITEMS); /* new item */ item[i].item_code = whichitem; item[i].item_size = 0; item[i].buffer = 0; return i; /* return index */ } temp.dsc$w_length = item[i].item_size; /* release string */ temp.dsc$a_pointer = item[i].buffer; str$free1_dx(&temp); item[i].buffer = 0; return i; } /** checkstat - check value of system service return. */ checkstat(stat, string_dummy) int stat; char *string_dummy; { if (!(stat & 1)) { strcpy(&msg[5], "Printer symbiont crashed due to error in "); strcpy(&msg[strlen(msg)], string_dummy); strcat(msg,"\r\n"); getmsg(stat, 0); strncat(msg,message,msglen); sndmsg(1,1); if (lta_device && jobnum && laserchan) stat = sys$qiow(0, laserchan,IO$_TTY_PORT+IO$M_LT_DISCON, 0, 0, 0,0, 0, 0, 0, 0, 0); if (laserchan) { stat = sys$dassgn(laserchan); laserchan = 0; } exit(stat); } } /** closefile - close main file. */ closefile() { int stat; stat = sys$close(&main_fab, 0, 0); /* ignore error */ notify = FALSE; } /** closeuserlog - close user log file. */ closeuserlog() { int stat; if (userlog < 0) return; /* if no log */ /* If no records written, set for delete on close */ if (userlog == 0) log_fab.fab$l_fop |= FAB$M_DLT; stat = sys$close(&log_fab); checkstat(stat,"close log"); str$free1_dx(&savelog); /* release saved log */ userlog = -1; } /** expand_cc - expand PRN carriage control byte. * * Entry: ccb = fab$v_prn byte * Exit: commands output to printer */ expand_cc(ccb) char ccb; /* carriage control byte */ { int ic, stat; char obuf[40]; if (ccb == 0) { return; } if ((ccb & 0x80) == 0) { /* output (n) LF, 1 CR */ if ((ccb & 0x7f) == 1) { /* 1 LF, output short form */ WRITELASER("XLF XCR\r\n", 9); } else { sprintf(obuf, "%d{XLF}repeat XCR\r\n",(ccb & 0x7f)); WRITELASERBUF(obuf, strlen(obuf)); } } else { if ((ccb & 0xe0) != 0xe0) { /* output single character */ ic = ccb & 0x7f; expand_line(&ic, obuf, 1); } } } /** expand_hex - expand buffer into hex bytes. */ expand_hex(ibuf, obuf, rsz) unsigned char *ibuf; /* pointer to input buffer */ char *obuf; /* pointer to output buffer */ int rsz; /* buffer size */ { int i, c, stat; static char hexnums[] = "0123456789ABCDEF"; for (i = 0; i < rsz; i++) { obuf[i*2] = hexnums[(ibuf[i] & 0xF0) >> 4]; obuf[i*2+1] = hexnums[ibuf[i] & 0xF]; } WRITELASERBUF(obuf,rsz*2) } /** expand_line - expand input buffer and output result to printer. * * The ()pop sequences are an obscure hack to fix an obscure bug * with XON/XOFF. It just works. */ expand_line(ibuf, obuf, rsz) UCHAR *ibuf; /* input buffer */ UCHAR *obuf; int rsz; /* buffer size */ { int i, d, col, stat; static int popcount = 0; /* XON kludge counter */ d = 0; /* preset destination index */ col = 0; /* preset column */ for (i = 0; i < rsz; i++) { if (ibuf[i] == 9) { /* if tab */ if (d == 0) obuf[d++] = '(';/* if first */ do { obuf[d++] = ' '; /* fill spaces */ col++; } while (col & 7); } else if (ibuf[i] == 8 && col > 0) { /* if backspace */ obuf[d++] = 8; /* insert backspace */ col--; } else if (ibuf[i] == '(') { /* ( */ if (d == 0) obuf[d++] = '(';/* if first */ obuf[d++] = '\\'; obuf[d++] = '('; col++; } else if (ibuf[i] == ')') { /* ) */ if (d == 0) obuf[d++] = '(';/* if first */ obuf[d++] = '\\'; obuf[d++] = ')'; col++; } else if (ibuf[i] == '\\') { /* \ */ if (d == 0) obuf[d++] = '(';/* if first */ obuf[d++] = '\\'; obuf[d++] = '\\'; col++; } else if (ibuf[i] == 0x0d) { /* CR */ if (d) { /* if string to terminate */ WRITELASERBUF(obuf,d) if (++popcount == 20) { popcount = 0; WRITELASER(")XSTR()pop\r\n",12) } else { WRITELASER(")XSTR\r\n",7) } d = 0; } WRITELASER("XCR\r\n",5) } else if (ibuf[i] == 0x0a) { /* LF */ if (d) { /* if string to terminate */ WRITELASERBUF(obuf,d) if (++popcount == 20) { popcount = 0; WRITELASER(")XSTR()pop\r\n",12) } else { WRITELASER(")XSTR\r\n",7) } d = 0; } WRITELASER("XLF\r\n",5) } else if (ibuf[i] == 0x0c) { /* FF */ if (d) { /* if string to terminate */ WRITELASERBUF(obuf,d) if (++popcount == 20) { popcount = 0; WRITELASER(")XSTR()pop\r\n",12) } else { WRITELASER(")XSTR\r\n",7) } d = 0; } WRITELASER("XFF\r\n",5) } else if (ibuf[i] < 32) { /* ctrl */ if (d == 0) obuf[d++] = '('; /* if first */ obuf[d++] = '^'; obuf[d++] = ibuf[i] + 'A' - 1; col++; } else { if (d == 0) obuf[d++] = '(';/* if first */ obuf[d++] = ibuf[i]; /* move char */ col++; } } if (d) { obuf[d++] = ')'; obuf[d++] = 'X'; obuf[d++] = 'S'; obuf[d++] = 'T'; obuf[d++] = 'R'; obuf[d++] = '\r'; obuf[d++] = '\n'; } WRITELASERBUF(obuf,d) } /** getitems - get item list from job controller. */ getitems() { int stat; int context; /* read_message_item context */ int item_code; /* item code */ unsigned short item_size; /* item size */ struct dsc$descriptor_d item_buffer = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; context = 0; /* init context */ /* Save each item in a list */ do { item_buffer.dsc$a_pointer = 0; /* force d string allocation */ stat = smb$read_message_item(&buffer_des, &context, &item_code, &item_buffer, &item_size); item[ii].item_code = item_code; item[ii].item_size = item_size; item[ii].buffer = item_buffer.dsc$a_pointer; if (++ii > MAXITEMS) exit(LASER$_MAXITEMS); } while (stat == SS$_NORMAL); } /** getitemdescrip - return item descriptor. * * return: TRUE if item found * FALSE if (item not found) && NOT FATAL * exit if (item not found) && FATAL */ getitemdescrip(code, descrip, fatal) int code; /* item code to search for */ struct dsc$descriptor_s *descrip; /* pointer to descriptor */ int fatal; /* error severity */ { int i; for (i = 0; i < ii; i++) { if (item[i].item_code == code) { /* if found */ descrip->dsc$w_length = item[i].item_size; descrip->dsc$a_pointer = item[i].buffer; return TRUE; } } if (fatal) exit(LASER$_ITEMNOTFOUND); /* item not in list */ else return FALSE; } /** getcopies - send copy count to laserwriter. * * Leave this here for now, but unfortunately, if you specify * /copies=n to the print command, the job contoller sends * the file that many times. Not what we want. */ getcopies() { int stat, n; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; char defcopy[80]; if (!getitemdescrip(SMBMSG$K_FILE_COPIES, &temp, FALSE)) if (!getitemdescrip(SMBMSG$K_JOB_COPIES, &temp, FALSE)) return; /* if no copies */ n = * (long*) temp.dsc$a_pointer; if (n == 1) return; /* if only 1 copy */ sprintf(defcopy, "/#copies %d def\r\n", n); WRITELASER(defcopy,strlen(defcopy)) } /** getnote - get /note= to laserwriter. */ getnote() { int stat; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; if (!getitemdescrip(SMBMSG$K_NOTE, &temp, FALSE)) return; /* none */ /* * KLUDGE ALERT: Multinet LPD puts a /note on its jobs. * Don't send it to the printer. */ if (strncmp(temp.dsc$a_pointer, "Remote LPD request", 18)==0) return; WRITELASER(temp.dsc$a_pointer,temp.dsc$w_length) WRITELASER(&0x0A0D,2) /* cr-lf */ } /** getparams - get user parameters. */ getparams() { int stat; int i, j, k, l, ctl; int first=TRUE,startend=FALSE,border=TRUE; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; char defcmd[255]; struct dsc$descriptor_s defcmd_d = {sizeof(defcmd), DSC$K_DTYPE_T, DSC$K_CLASS_S, defcmd}; char param[255], str[255+15], *eq, start[8],end[8],num[6]; static $DESCRIPTOR(number_up, "NUMBER_UP"); static $DESCRIPTOR(start_end, "STARTEND"); static $DESCRIPTOR(input_tray, "INPUT_TRAY"); static $DESCRIPTOR(sides, "SIDES"); static $DESCRIPTOR(parser,"PARSER"); static $DESCRIPTOR(lnm,"LNM$SYSTEM"); struct ITEM_LST { unsigned short len, code; char *addr; short *retlen; } trnlnm_item = {sizeof(param), LNM$_STRING, ¶m, &temp.dsc$w_length}; strcpy(defcmd,"LPS$"); getitemdescrip (SMBMSG$K_QUEUE, &temp, TRUE); strncat(defcmd,temp.dsc$a_pointer,temp.dsc$w_length); strcat(defcmd,"_PARAMETER"); defcmd_d.dsc$w_length = strlen(defcmd); if (!(sys$trnlnm(0,&lnm,&defcmd_d,0,&trnlnm_item) & 1)) temp.dsc$w_length = 0; else temp.dsc$a_pointer = param; for (i = 0; i < 8; i++) { if (!temp.dsc$w_length && !getitemdescrip(SMBMSG$K_PARAMETER_1+i, &temp, FALSE)) break; /* if no parameter */ if (temp.dsc$w_length == 0) break; /* if null string */ k = 0; l = 0; for (j = temp.dsc$a_pointer ; j < temp.dsc$a_pointer+temp.dsc$w_length; j++) { if (!l && !strncmp(j,",",1) && k == 0) break; else if (!l && !strncmp(j,"(",1)) k++; else if (!l && !strncmp(j,")",1)) k--; else if (!strncmp(j,"\"",1)) l = 1 - l; } strncpy(param, temp.dsc$a_pointer, (int)j-(int)temp.dsc$a_pointer); param[(int)j-(int)temp.dsc$a_pointer] = 0; temp.dsc$w_length = max(0,(int)temp.dsc$w_length - ((int)j-(int)temp.dsc$a_pointer) - 1); temp.dsc$a_pointer = j + 1; if (temp.dsc$w_length) i--; eq = strchr(param, '='); if (eq && !casefree_strncmp(param,"DATA_TYPE",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"TEK4014",strlen(eq))) { tek = TRUE; ascii = FALSE; } else if (!casefree_strncmp(eq,"ANSI",strlen(eq)) || !casefree_strncmp(eq,"ASCII",strlen(eq))) { ansi = TRUE; } else if (!casefree_strncmp(eq,"PS",strlen(eq)) || !casefree_strncmp(eq,"POSTSCRIPT",strlen(eq))) { ps = TRUE; } else { stop_reason = LASER$_INVPARAM; return FALSE; } } else if (eq && !casefree_strncmp(param,"PAGE_ORIENTATION",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"LANDSCAPE",strlen(eq))) { land = TRUE; port = FALSE; } else if (!casefree_strncmp(eq,"PORTRAIT",strlen(eq))) { land = FALSE; port = TRUE; } else { stop_reason = LASER$_INVPARAM; return FALSE; } } else if (eq && !casefree_strncmp(param,"WIDE",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"TRUE",strlen(eq))) { land = TRUE; port = FALSE; } else if (!casefree_strncmp(eq,"FALSE",strlen(eq))) { land = FALSE; port = TRUE; } else { stop_reason = LASER$_INVPARAM; return FALSE; } } else if (eq && !casefree_strncmp(param,"SIDES",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"2",strlen(eq)) || !casefree_strncmp(eq,"TWO",strlen(eq)) || !casefree_strncmp(eq,"TWO_SIDED_DUPLEX",strlen(eq))) { WRITESTRING("false true\r\n") } else if (!casefree_strncmp(eq,"TUMBLE",strlen(eq)) || !casefree_strncmp(eq,"TWO_SIDED_TUMBLE",strlen(eq))) { WRITESTRING("true true\r\n") } else { stop_reason = LASER$_INVPARAM; return FALSE; } if (!writemodule(sides)) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } } else if (eq && !casefree_strncmp(param,"PAGE_LIMIT",(int)eq-(int)param)) { int i = 0; startend = TRUE; *eq++; if (*eq == '(') *eq++; while (i < 5 && isdigit(*eq)) start[i++] = *eq++; if (*eq++ != ',') { strncpy(end,start,i); strncpy(start,"1\r\n\000",4); } else { strncpy(&start[i],"\r\n\000",3); i = 0; while (i < 5 && isdigit(*eq)) end[i++] = *eq++; } if (!i) strncpy(end,"10000\r\n\000",8); else strncpy(&end[i],"\r\n\000",3); } else if (eq && !casefree_strncmp(param,"LW",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; WRITESTRING("/lw ") WRITESTRING(eq) WRITESTRING(" def\r\n") } else if (eq && !casefree_strncmp(param,"NUMBER_UP",(int)eq-(int)param)) { int i = 0; nup = TRUE; *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (*eq == '(') *eq++; while (i < 3 && isdigit(*eq)) num[i++] = *eq++; if (!i) num[i++] = '1'; strncpy(&num[i],"\r\n\000",3); } else if (!casefree_strncmp(param,"BORDER",strlen(param))) { border = TRUE; } else if (eq && !casefree_strncmp(param,"BORDER",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"NONE",strlen(eq))) border = FALSE; else { stop_reason = LASER$_INVPARAM; return FALSE; } } else if (eq && !casefree_strncmp(param,"MESSAGES",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"KEEP",strlen(eq))) openuserlog(); /* open user log file */ else { stop_reason = LASER$_INVPARAM; return FALSE; } } else if (eq && !casefree_strncmp(param,"INPUT_TRAY",(int)eq-(int)param)) { *eq++; if (j=strchr(param,',')) param[(int)j-(int)param] = 0; if (!casefree_strncmp(eq,"LETTER",strlen(eq))) { WRITESTRING("-1\r\n") } else if (!casefree_strncmp(eq,"LEGAL",strlen(eq))) { WRITESTRING("-2\r\n") } else if (!casefree_strncmp(eq,"A4",strlen(eq))) { WRITESTRING("-3\r\n") } else { WRITESTRING(eq) WRITESTRING("\r\n") } if (!writemodule(input_tray)) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } } } if (!(sys$trnlnm(0,&lnm,&defcmd_d,0,&trnlnm_item) & 1)) temp.dsc$w_length = 0; else temp.dsc$a_pointer = param; for (i = 0; i < 8; i++) { if (!temp.dsc$w_length && !getitemdescrip(SMBMSG$K_PARAMETER_1+i, &temp, FALSE)) break; /* if no parameter */ if (temp.dsc$w_length == 0) break; /* if null string */ k = 0; l = 0; for (j = temp.dsc$a_pointer ; j < temp.dsc$a_pointer+temp.dsc$w_length; j++) { if (!l && !strncmp(j,",",1) && k == 0) break; else if (!l && !strncmp(j,"(",1)) k++; else if (!l && !strncmp(j,")",1)) k--; else if (!strncmp(j,"\"",1)) l = 1 - l; } strncpy(param, temp.dsc$a_pointer, (int)j-(int)temp.dsc$a_pointer); param[(int)j-(int)temp.dsc$a_pointer] = 0; temp.dsc$w_length = max(0,(int)temp.dsc$w_length - ((int)j-(int)temp.dsc$a_pointer) - 1); temp.dsc$a_pointer = j + 1; if (temp.dsc$w_length) i--; eq = strchr(param, '='); if (!eq) eq = strchr(param, '\000'); if (!casefree_strncmp(param,"DATA_TYPE",(int)eq-(int)param) || !casefree_strncmp(param,"LW",(int)eq-(int)param) || !casefree_strncmp(param,"SIDES",(int)eq-(int)param) || !casefree_strncmp(param,"INPUT_TRAY",(int)eq-(int)param) || !casefree_strncmp(param,"PAGE_LIMIT",(int)eq-(int)param) || !casefree_strncmp(param,"NUMBER_UP",(int)eq-(int)param) || !casefree_strncmp(param,"BORDER",(int)eq-(int)param) || !casefree_strncmp(param,"MESSAGES",(int)eq-(int)param)) { } else { if (!casefree_strncmp(param,"PAGE_ORIENTATION", (int)eq-(int)param)) if (land) strcpy(param,"WIDE=TRUE"); else strcpy(param,"WIDE=FALSE"); if (first) { /* if first one */ first = FALSE; WRITELASER("%!\r\n",4) WRITELASER("/params [\r\n",11) } for (j= 0; (j < strlen(param)) && (param[j] != '('); j++) { /* lowercase string */ if (isupper(param[j])) param[j] ^= 0x20; } /* if there is an = separator (or - for spooled files), use it */ if ((eq = strchr(param, '=')) || (eq = strchr(param, '-')) || (eq = strchr(param, ':'))) { *eq++ = 0; /* bust string in 2 */ sprintf(str, "(%s) %s\r\n", param, eq); } else sprintf(str, "(param%d) %s\r\n", i+1, param); WRITELASER(str,strlen(str)) } } getitemdescrip(SMBMSG$K_PRINT_CONTROL, &temp, TRUE); ctl = * (long*) temp.dsc$a_pointer; if (ctl & SMBMSG$M_PAGE_HEADER) { if (first) { /* if first one */ first = FALSE; WRITELASER("%!\r\n",4) WRITELASER("/params [\r\n",11) } WRITESTRING("(title) true\r\n") } if (!first) { /* if some params found */ WRITELASER("] def\r\n",7) writemodule(parser); /* write the parser module */ } if (nup) { if (!writemodule(number_up)) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } WRITELASER(num,strlen(num)) WRITELASER("false\r\n",7) /* true to transpose row/col order */ if (port) WRITELASER("false\r\n",7) else WRITELASER("true\r\n",6) WRITELASER("false\r\n",7) /* true for Mac landscape */ WRITELASER("false\r\n",7) /* true to disable clipping */ if (border) WRITELASER("0\r\n",3) else WRITELASER("-1\r\n",4) if (startend) { WRITELASER(start,strlen(start)) WRITELASER(end,strlen(end)) } else { WRITELASER("1\r\n",3) WRITELASER("10000\r\n",7) } WRITELASER("DMM-nup-pre\r\n",13) } else if (startend) { WRITELASER(start,strlen(start)) WRITELASER(end,strlen(end)) if (!writemodule(start_end)) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } } return TRUE; } /** getsetup - get setup module to laserwriter. * * return: TRUE if no problems with setup module. * FALSE if setup module nonexistant */ getsetup() { int stat, len; int library_index; long txtrfa[2]; char inbuf[255]; struct dsc$descriptor_s inbufdes = {sizeof(inbuf), DSC$K_DTYPE_T, DSC$K_CLASS_S, inbuf}; struct dsc$descriptor_s outbufdes; struct dsc$descriptor_s key = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; /* Try for a file setup module first, then a form setup module. For now, we only support one setup module, the first found. We should support lists of setup modules, and all found. */ if (!getitemdescrip(SMBMSG$K_FILE_SETUP_MODULES, &key, FALSE)) if (!getitemdescrip(SMBMSG$K_FORM_SETUP_MODULES, &key, FALSE)) return TRUE; /* if no setup */ if (key.dsc$w_length == 0) return TRUE; /* if no setup */ if (!getparams()) return FALSE; /* get user parameters */ if (ps) return TRUE; /* Get out if no library. Error because the user specified a setup. */ if (library_spec.dsc$a_pointer == 0) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } /* Check to see if the setup module ends in _HEX or _STR */ if (!tek && getitemdescrip(SMBMSG$K_FORM_NAME, &temp, FALSE)) if (strncmp(temp.dsc$a_pointer, "TEK", 3) == 0) tek = TRUE; if (tek && (main_fab.fab$b_rfm == FAB$C_STM || main_fab.fab$b_rfm == FAB$C_STMCR || main_fab.fab$b_rfm == FAB$C_STMLF)) { sys$close(&main_fab, 0, 0); openfile(); } if (!tek && key.dsc$w_length >= 4){ if (strncmp(&key.dsc$a_pointer[key.dsc$w_length-4],"_HEX", 4) == 0){ ascii = FALSE; hex = TRUE; } if (strncmp(&key.dsc$a_pointer[key.dsc$w_length-4],"_STR", 4) == 0){ ascii = FALSE; string = TRUE; } } if (!tek && string) { getitemdescrip(SMBMSG$K_FILE_SPECIFICATION, &temp, TRUE); strcpy(inbuf, "/filename ("); strncat(inbuf, temp.dsc$a_pointer, temp.dsc$w_length); strcat(inbuf, ") def\r\n"); WRITELASER(inbuf,strlen(inbuf)) /* Also send the form name if it exists */ if (getitemdescrip(SMBMSG$K_FORM_NAME, &temp, FALSE)) { strcpy(inbuf, "/formname ("); strncat(inbuf, temp.dsc$a_pointer, temp.dsc$w_length); strcat(inbuf, ") def \r\n"); WRITELASER(inbuf,strlen(inbuf)) } } /* Send the setup module */ if (tek) { strcpy(inbuf,"TEK4014"); key.dsc$a_pointer = &inbuf; key.dsc$w_length = strlen(inbuf); } if (!writemodule(key)) { stop_reason = LASER$_SETUPNOTFOUND; return FALSE; } if (tek && port) WRITELASER("portrait\n",9) if (tek) WRITELASER("NP\n",3) return TRUE; } /** inititems - initialize item list. */ inititems() { int i; for (i = 0; i < MAXITEMS; i++) item[i].buffer = 0; } /** initsymb - initialize printer symbiont. */ initsymb() { int stat; stat = smb$initialize(&SMBMSG$K_STRUCTURE_LEVEL, jobctl_ast, 0); checkstat(stat, "initsymb"); } /** jobctl_ast - ast routine called by the job controller. */ void jobctl_ast() { int stat,stream; int request; /* jobctl request */ struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; stat = smb$read_message(&stream, &buffer_des, &request); if (stat != SS$_NORMAL) exit(stat); /* Process the request */ switch (request) { case SMBMSG$K_START_STREAM: getitems(); startstream(); break; case SMBMSG$K_START_TASK: getitems(); start_task = TRUE; stop_task = 0; stop_reason = 0; break; case SMBMSG$K_RESUME_TASK: getitems(); break; case SMBMSG$K_RESET_STREAM: resetstream(); break; case SMBMSG$K_STOP_STREAM: stopstream(); break; case SMBMSG$K_PAUSE_TASK: break; case SMBMSG$K_STOP_TASK: getitems(); getitemdescrip(SMBMSG$K_STOP_CONDITION, &temp, TRUE); stopoutput = stop_task = * (long*) temp.dsc$a_pointer; break; } sys$wake(0,0); } /** laser_read_ast - laser read ast completion routine. */ static void laser_read_ast () { register unsigned long status; static char buffer[1024]; static int position = 0; static struct io$status_block iosb = {0, 0, 0}; /* * Validate the I/O completion status for the previous I/O. If it is a * cancel or abort, clear out the status and don't issue any more I/O's... */ if (FAILURE (iosb.status) && iosb.status) { switch (iosb.status) { case SS$_ABORT: case SS$_CANCEL: iosb.status = 0; /* reset status to 0 so we re-init */ return; case SS$_DATAOVERUN: break; default: if (!stop_task) stop_task = iosb.status; io_aborted = iosb.status; iosb.status = 0; /* reset status to 0 so we re-init */ iosb.length = 0; sys$wake(0,0); if (!devinfo.terminators) return; }; }; /* * Now press on and buffer up characters. When we hit a control character, * pass the buffer on to the scanner. */ if (iosb.length && !cancel_read) { /* if bytes in buffer */ register int i; for (i = 0; i < iosb.length; i++) { laser_buf[position++] = buffer[i]; if (!devinfo.terminators && iscntrl (buffer[i])) { laser_buf[position] = '\000'; if (!check_operator ()) writeuserlog (); position = 0; }; }; if (devinfo.terminators) { laser_buf[position] = '\000'; if (!check_operator ()) writeuserlog (); position = 0; }; }; /* * Issue a non-blocking read to the port and call ourselves as the I/O * completion routine... this is self perpetuating unless something messes * up badly. */ if (FAILURE (status = sys$qio (laser_efn, laserchan, devinfo.read_function, &iosb, &laser_read_ast, 0, buffer, sizeof (buffer), 0, devinfo.terminators, 0, 0))) { checkstat(status, "qio"); }; } /** openfile - open the main file. * * return: FALSE if open problems. */ openfile() { int stat; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; struct dsc$descriptor_s fid = {28, DSC$K_DTYPE_T, DSC$K_CLASS_S, main_nam.nam$t_dvi}; getitemdescrip(SMBMSG$K_FILE_IDENTIFICATION, &temp, TRUE); main_fab = cc$rms_fab; /* init fab */ main_fab.fab$l_nam = &main_nam; /* use NAM to open by FID */ main_fab.fab$l_fop |= FAB$M_NAM; main_fab.fab$b_fac = 0; if (tek) main_fab.fab$b_fac = FAB$M_BIO|FAB$M_GET; main_nam = cc$rms_nam; /* init nam */ str$copy_dx(&fid, &temp); stat = sys$open(&main_fab); if (!(stat & 1)) { /* if open error */ stop_reason = stat; return FALSE; } main_rab = cc$rms_rab; /* initialize rab */ main_rab.rab$l_fab = &main_fab; stat = sys$connect(&main_rab); if (!(stat & 1)) { /* if connect error */ stop_reason = stat; return FALSE; } return TRUE; } /** openuserlog - open user log file. * * Create a file using the file spec of the file to be printed, * changing the EXT to .LASER_LOG. Try the logical name * LASER$LOG if this does not work (probably a spooled file). * */ openuserlog() { register int status; #if 0 /* This is old code which put message file in same directory as printed file, but was eliminated because there is no code to check if user has access to write into it. */ int i; struct dsc$descriptor_s temp; char filename[256], filespec[255], *cp; log_fab = cc$rms_fab; /* init fab */ /* Build log file name. If a spooled file, prepend the job name and */ /* put the file in LASER$LOG: */ filename[0] = 0; i = 0; if (spooled_file) { getitemdescrip(SMBMSG$K_USER_NAME, &temp, TRUE); strncpy(filename, temp.dsc$a_pointer, temp.dsc$w_length); i = temp.dsc$w_length; /* trim trailing blanks */ do { filename[i] = 0; if (filename[--i] != ' ') break; } while (i > 0); strcat(filename, "-"); } getitemdescrip(SMBMSG$K_FILE_SPECIFICATION, &temp, TRUE); strncpy(filespec, temp.dsc$a_pointer, temp.dsc$w_length); filespec[temp.dsc$w_length] = 0; if (spooled_file) cp = strchr(filespec, ']') + 1; else cp = filespec; strcat(filename, cp); log_fab.fab$l_dna = filename; log_fab.fab$b_dns = strlen(filename); if (spooled_file) { log_fab.fab$l_fna = "LASER$LOG:.laser_log;0"; log_fab.fab$b_fns = 22; } else { log_fab.fab$l_fna = ".laser_log;0"; log_fab.fab$b_fns = 12; } #else struct dsc$descriptor_d username = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; struct dsc$descriptor_s temp; char filetype[64]; static char filespec[255]; userlog = -1; /* flag not opened yet */ /*- * +---------------------------------------------------------------+ * | First of all, find out the username, then determine | * | where his default directory is... this in turn will | * | be where we place the journal. Otherwise, pick the | * | default path provided by laser$log. | * +---------------------------------------------------------------+ */ strcpy (filespec, "LASER$LOG:"); #if LASER_PS strcpy (filetype, ".LOG-PS"); #else strcpy (filetype, ".LASER_LOG"); #endif if (getitemdescrip (SMBMSG$K_USER_NAME, &username, FALSE)) { char default_device[32]; char default_directory[64]; struct ss$item_list getuailist[3]; getuailist[0].code = UAI$_DEFDEV; getuailist[0].length = sizeof (default_device); getuailist[0].address = default_device; getuailist[0].length_address = NULL; getuailist[1].code = UAI$_DEFDIR; getuailist[1].length = sizeof (default_directory); getuailist[1].address = default_directory; getuailist[1].length_address = NULL; getuailist[2].length = 0; getuailist[2].code = 0; getuailist[2].address = NULL; getuailist[2].length_address = NULL; if (SUCCESS (status = SYS$GETUAI (0, 0, &username, getuailist, 0, 0, 0))) { filespec[0] = '\0'; strncat (filespec, &default_device[1], default_device[0]); strncat (filespec, &default_directory[1], default_directory[0]); } else { strcat (filetype, "_"); strcat (filetype, username.dsc$a_pointer, username.dsc$w_length); }; } /*- * +---------------------------------------------------------------+ * | Now that we know where to put it, let's find out | * | it's called and append the filename (if we get it) | * | to as much of the filename as we already have, then | * | tack on the extension ".LOG-PS[_username]" | * +---------------------------------------------------------------+ */ if (getitemdescrip (SMBMSG$K_FILE_SPECIFICATION, &temp, FALSE)) { struct { unsigned short length; unsigned short code; char *address; } fscnitmlst[2]; fscnitmlst[0].code = FSCN$_NAME; fscnitmlst[1].length = 0; fscnitmlst[1].code = 0; fscnitmlst[1].address = NULL; if (SUCCESS (status = SYS$FILESCAN (&temp, fscnitmlst, 0))) if (fscnitmlst[0].length) strncat (filespec, fscnitmlst[0].address, fscnitmlst[0].length); }; strcat (filespec, filetype); /*- * +---------------------------------------------------------------+ * | Create a new version of the file we just generated | * | a name for with CR format variable length records. | * +---------------------------------------------------------------+ */ log_fab = cc$rms_fab; log_fab.fab$l_fna = filespec; log_fab.fab$b_fns = strlen (filespec); #endif log_fab.fab$b_rfm = FAB$C_VAR; log_fab.fab$b_rat = FAB$M_CR; log_fab.fab$w_mrs = 512; if (SUCCESS (status = sys$create (&log_fab))) { log_rab = cc$rms_rab; /* initialize rab */ log_rab.rab$l_fab = &log_fab; status = sys$connect (&log_rab); }; if (SUCCESS (status)) userlog = 0; /* flag open, no records */ } /** preset - preset the symbiont. */ preset() { int stat; stat = lib$get_ef(&laser_efn); /* allocate event flag */ stat = lib$get_ef(&stateefn); setprivs(); /* set process privs */ inititems(); /* init item list */ initsymb(); /* do jobctl init */ } void ltatimeout(param) int param; { dassgndev(); jobnum = 0; } void statetimeout(param) int param; { int stat; if (oldiocount < 0 && iocount != -oldiocount-1) { getmsg(LASER$_RESUMED, 1); sprintf(&msg[6],&message[1],&queue_name); sndmsg(1,0); oldiocount = iocount; } else if (iocount == oldiocount) { getmsg(LASER$_STALLED, 1); sprintf(&msg[6],&message[1],&queue_name); sndmsg(1,1); oldiocount = -oldiocount-1; } else if (oldiocount >= 0) oldiocount = iocount; sys$setimr(stateefn,&statetime,&statetimeout,stateefn,0); } /** processtask - process a file. */ processtask() { int stat, np, request; int svector[2] = {1, SS$_NORMAL}; /* stat vector */ int acctrec[4] = {0,0,0,0}; /* accounting record */ struct dsc$descriptor_s accounting = {sizeof(acctrec), DSC$K_DTYPE_T, DSC$K_CLASS_S, acctrec}; struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; static int assigned = FALSE; int ltatime[2]= {-1*100000000,-1}; int retries = 0; notify_qual = FALSE; ascii = TRUE; /* assume main file is ascii */ hex = FALSE; string = FALSE; port = FALSE; land = FALSE; ps = FALSE; tek = FALSE; ansi = FALSE; stopoutput = FALSE; nup = FALSE; notify = FALSE; userlog = -1; /* flag not opened yet */ #if 0 if (laserchan == 0) exit (LASER$_STREAMNOTSTART); #endif if (shared_device) { getitemdescrip(SMBMSG$K_ENTRY_NUMBER, &temp, TRUE); memcpy(&stat,temp.dsc$a_pointer,4); if (stat == jobnum) sys$cantim(ltaefn,0); /* Cancel ast that deassigns device */ else if (!jobnum) { /* Deassigning ast already run? */ jobnum = stat; /* Yes, so just store new job number */ assigned = FALSE; } else { jobnum = stat; sys$cantim(ltaefn,0); /* Cancel ast that deassigns device */ dassgndev(); /* Deassign to allow other nodes access */ assigned = FALSE; } } getitemdescrip(SMBMSG$K_USER_NAME, &user_notify, TRUE); /* Get username for error messages. */ retries = 0; retry: if (!assigned) { register unsigned long status; struct ss$item_list itmlst[2]; #if TCP || MULTINET /* * Check what kind of device we're after. If the name starts with TCP%, * then assume we are making a TCP/IP type connection... */ if (!casefree_strcmp ("TCP%", device.dsc$a_pointer)) { register char *d; register char *text; register char *hostname; unsigned long address; unsigned long port; struct hostent *host; struct sockaddr_in sin; /* * Break down the device name string as: * * %: */ if (!(text = malloc (strlen (device.dsc$a_pointer) + 1))) exit(LASER$_NOMEMORY); strcpy (text, device.dsc$a_pointer); if (d = strchr (text, '%')) { *d = '\0'; hostname = ++d; } else { d = hostname = text; }; if (strstr (d,"/S") || strstr (d,"/s")) { char *d1 = strchr (d, '/'); *d1 = '\0'; shared_device = TRUE; } if (d = strchr (d, ':')) { *d = '\0'; port = atoi (++d); } else { port = 0; }; /* * Now translate the host address portion into a hostent * structure... If it is not a numeric Internet address, try * calling the resolver. If neither works then punt, we're losing * bad! */ host = ((address = inet_addr (hostname)) == -1) ? gethostbyname (hostname) : gethostbyaddr (&address, sizeof (address), AF_INET); if (!host) { #if MULTINET sprintf (&msg[5], "*** Unable to resolve address for \"%s\" ***\r\n\t%s", hostname, vms_errno_string ()); status = vmserrno; #else sprintf (&msg[5], "*** Unable to resolve address for \"%s\" ***", hostname); status = LASER$_NOTRESOLVED; #endif sndmsg(1,0); exit (status); }; /* * Finally now, assign a socket (channel) to the link and establish * connection to the other side with a call to connect. */ laserchan = socket (host->h_addrtype, SOCK_STREAM, 0); sin.sin_family = host->h_addrtype; bcopy (host->h_addr, &sin.sin_addr, host->h_length); sin.sin_port = htons (port); status = connect (laserchan, &sin, sizeof (sin)); #if MULTINET /* * So long as we get a status of "connection refused" we can assume * that the remote port is busy, so it is safe to retry it. After a * sufficently large of attempts though, we'll want to give up, * 'cause it becomes obvious the other guy just doesn't want to * talk to us... */ while (status == -1) { /* * If we got here, the channel wasn't connected, so get rid of * the channel in question. */ if (socket_close (laserchan) < 0) { sprintf (&msg[5], "*** socket close failed ***\r\n\t%s", vms_errno_string ()); sndmsg(2,0); }; /* * Now wait 15 seconds and try again... every 10 minutes (40 * * 15 sec) we will send an opcom message indicating how * dilligently we tried. */ sleep (15); laserchan = socket (host->h_addrtype, SOCK_STREAM, 0); sin.sin_family = host->h_addrtype; bcopy (host->h_addr, &sin.sin_addr, host->h_length); sin.sin_port = htons (port); status = connect (laserchan, &sin, sizeof (sin)); if (status && (!(++retries % 40))) { /* complain once every * 10 minutes. */ sprintf (&msg[5], "*** %d retries of connect to \"%s\" [%s] port %d have failed ***\r\n\t%s", retries, host->h_name, inet_ntoa (*(unsigned long *) host->h_addr), port, vms_errno_string ()); sndmsg(2,0); }; }; /* * If the connection request returns a non-zero code, it means we * got here without assigning the channel so pass on whatever * information we can and punt on... */ if (status) { sprintf (&msg[5], "*** Connect to \"%s\" [%s] port %d has failed after %d attempts ***\r\n\t%s", host->h_name, inet_ntoa (*(unsigned long *) host->h_addr), port, 1 + retries, vms_errno_string ()); sndmsg(1,0); status = FAILURE (vmserrno) ? vmserrno : LASER$_CONNREFUSED; socket_close (laserchan); shared_device = FALSE; } else status = SS$_NORMAL; #else /* * So long as we get a status of "connection refused" we can assume * that the remote port is busy, so it is safe to retry it. After a * sufficently large of attempts though, we'll want to give up, * 'cause it becomes obvious the other guy just doesn't want to * talk to us... */ while (status == -1) { /* * If we got here, the channel wasn't connected, so get rid of * the channel in question. */ if (close (laserchan) < 0) { sprintf (&msg[5], "*** socket close failed ***\r\n\t%s", vms_errno_string ()); sndmsg(2,0); }; /* * Now wait 15 seconds and try again... every 10 minutes (40 * * 15 sec) we will send an opcom message indicating how * dilligently we tried. */ sleep (15); laserchan = socket (host->h_addrtype, SOCK_STREAM, 0); sin.sin_family = host->h_addrtype; bcopy (host->h_addr, &sin.sin_addr, host->h_length); sin.sin_port = htons (port); status = connect (laserchan, &sin, sizeof (sin)); if (status && (!(++retries % 40))) { /* complain once a * minute... */ sprintf (&msg[5], "*** %d retries of connect to \"%s\" [%s] port %d have failed ***", retries, host->h_name, inet_ntoa (*(unsigned long *) host->h_addr), port); sndmsg(2,0); }; }; /* * If the connection request returns a non-zero code, it means we * got here without assigniong the channel so pass on whatever * information we can and punt on... */ if (status) { sprintf (&msg[5], "*** Connect to \"%s\" [%s] port %d failed after attempt %d ***", host->h_name, inet_ntoa (*(unsigned long *) host->h_addr), port, 1 + retries); sndmsg(1,0); status = LASER$_CONNREFUSED; socket_close (laserchan); shared_device = FALSE; } else status = SS$_NORMAL; #endif if ((status & 1) && ltaefn) laser_read_ast(); } else #endif { if (!laserchan) { /* * Assign the printer. If already allocated, wait for it. Warn the * operator if we have to wait too long. This should probably * exponentially delay longer. We wait since we may be sharing the * printer with other symbionts. */ status = sys$alloc(&device, 0, 0, 0, 0); retries = 0; while (status == SS$_DEVALLOC) { ++retries; if (!(retries % 4 * 10)) { /* if 10 minutes */ sprintf (&msg[5], "*** Unable to assign printer %s after %d attempts ***", device.dsc$a_pointer, retries); sndmsg(2,0); }; sleep (15); status = sys$alloc(&device, 0, 0, 0, 0); }; if (FAILURE (status)) { sprintf (&msg[5], "*** Connect to printer %s failed after attempt %d ***", device.dsc$a_pointer, 1 + retries); sndmsg(1,0); }; status = sys$assign (&device, &laserchan, 0, 0); }; if (lta_device) {assigndev(); status = 1;} }; if ((status & 1) && !ltaefn) { /* * Determine the device class so that we can determine what kind of * device we're talking to... */ itmlst[0].code = DVI$_DEVCLASS|DVI$C_SECONDARY; itmlst[0].length = sizeof (devinfo.class); itmlst[0].address = &devinfo.class; itmlst[0].length_address = NULL; itmlst[1].code = 0; itmlst[1].length = 0; itmlst[1].address = NULL; itmlst[1].length_address = NULL; if (FAILURE (status = SYS$GETDVIW(0, laserchan, 0, itmlst, 0, 0, 0, 0))) checkstat(status, "getdvi"); switch (devinfo.class) { static int terminators[2] = {0, -1}; case DC$_TERM: devinfo.write_function = IO$_WRITEPBLK; devinfo.read_function = (IO$_READPBLK | IO$M_NOECHO); devinfo.terminators = terminators; set_typeahead (laserchan); shared_device = lta_device = strstr(device.dsc$a_pointer,"LTA"); if (lta_device) assigndev(); break; default: devinfo.write_function = IO$_WRITEVBLK; devinfo.read_function = IO$_READVBLK; devinfo.terminators = NULL; }; lib$get_ef(<aefn); if (shared_device) { getitemdescrip(SMBMSG$K_ENTRY_NUMBER, &temp, TRUE); memcpy(&stat,temp.dsc$a_pointer,4); jobnum = stat; } laser_read_ast (); } if (!(status & 1)) stop_reason = status; else assigned = TRUE; } stat = smb$send_to_jobctl(&0, &SMBMSG$K_START_TASK, 0, 0, 0, 0); checkstat(stat, "processtask: send to jobctl"); if (!(stop_reason & 1) && stop_reason) goto skip1; if (!notify_qual && getitemdescrip(SMBMSG$K_PRINT_CONTROL, &temp, TRUE)) { int flags; memcpy(&flags,temp.dsc$a_pointer,4); notify_qual = flags & SMBMSG$M_NOTIFY; if (notify_qual) { char job[255]; if (getitemdescrip(SMBMSG$K_JOB_NAME, &temp, FALSE)) strncpy(job, temp.dsc$a_pointer, temp.dsc$w_length); else temp.dsc$w_length = 0; job[temp.dsc$w_length] = 0; getmsg(LASER$_STARTJOB,1); getitemdescrip(SMBMSG$K_ENTRY_NUMBER, &temp, TRUE); if (strncmp(&entry_num,temp.dsc$a_pointer,4)) { memcpy(&entry_num,temp.dsc$a_pointer,4); sprintf(&msg[6],&message[1],&job,entry_num,&queue_name); sndmsg(0,0); } } else { getitemdescrip(SMBMSG$K_ENTRY_NUMBER, &temp, TRUE); memcpy(&entry_num,temp.dsc$a_pointer,4); } } status_error = FALSE; #if !NOREAD status_idle = FALSE; #endif cancel_read = FALSE; if (!syncprinter() || stop_task) { /* synchronize with printer */ #if TCP || MULTINET if (!devinfo.terminators && io_aborted && io_aborted == stop_task) { stat = sys$cancel(laserchan); dassgndev(); io_aborted = stop_task = assigned = FALSE; retries++; sleep (15); goto retry; } #endif goto skip1; } checkspooled(); /* check for spooled file */ oldiocount = iocount = 0; sys$setimr(stateefn,&statetime,&statetimeout,stateefn,0); trailer(0); /* flag pages */ if (!openfile()) goto skip; /* open main file */ /* getcopies();*/ /* send copy count */ #if !NONOTE getnote(); /* output possible note */ #endif if (!getsetup()) goto skip; /* output setup module */ sendfile(); /* send main file */ skip: closefile(); /* close main file */ trailer(1); /* send trailer */ sys$cantim(stateefn,0); sendendsequence(); /* send job sequence */ if (notify_qual && userlog > 0) { /* if errors logged */ getmsg(LASER$_CREATELOG,0); strncpy(&msg[5],message,msglen); sndmsg(0,0); } closeuserlog(); /* close user log */ skip1: #if TCP || MULTINET if (!devinfo.terminators && io_aborted) { dassgndev(); assigned = FALSE; } #endif io_aborted = FALSE; cancel_read = TRUE; start_task = FALSE; /* clear flag */ np = endpage - startpage; /* compute page count */ if (np >0) acctrec[0] = np; /* if no obvious error */ /* If stop_task, we were stopped by the job controller. */ /* Else, we were stopped by some other error condition */ request = SMBMSG$K_TASK_COMPLETE; if (stop_task) { /* if task aborted */ request = SMBMSG$K_STOP_TASK; svector[1] = stop_task; } else if (stop_reason) { if (stop_reason == LASER$_MAXITEMS || stop_reason == LASER$_ITEMNOTFOUND || stop_reason == LASER$_TOOMANYTABS || stop_reason == LASER$_FLUSHED || stop_reason == LASER$_SETUPNOTFOUND || stop_reason == LASER$_INVPARAM) { getmsg(stop_reason,0); strncpy(&msg[5],message,msglen); jobid(0); } svector[1] = SS$_ABORT; } releaseitems(); /* release item list */ stat = smb$send_to_jobctl(&0, &request, &accounting, 0, 0, svector); checkstat(stat, "processtask: send to jobctl"); if (shared_device) { sys$cantim(ltaefn,0); /* Cancel deassign lta routine */ sys$setimr(ltaefn,<atime,<atimeout,ltaefn,0); /* Requeue timer ast */ } } /** releaseitems - release item list. * * release dynamic strings gotten by read_items. */ releaseitems() { int i; struct dsc$descriptor_d temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}; ii = 0; /* clear item index */ for (i = 0; i < MAXITEMS; i++) { if (item[i].buffer == 0) return; /* if end of list */ temp.dsc$w_length = item[i].item_size; temp.dsc$a_pointer = item[i].buffer; str$free1_dx(&temp); item[i].buffer = 0; } } /** resetstream - reset the stream. */ resetstream() { int stat; if (lta_device && jobnum && laserchan) stat = sys$qiow(0, laserchan,IO$_TTY_PORT+IO$M_LT_DISCON, 0, 0, 0,0, 0, 0, 0, 0, 0); if (laserchan) { stat = sys$dassgn(laserchan); laserchan = 0; } stat = smb$send_to_jobctl(&0, &SMBMSG$K_RESET_STREAM, 0, 0, 0, 0); checkstat(stat, "resetstream: send to jobctl"); exit (SS$_NORMAL); } /** sendendsequence - send end of job sequence. */ sendendsequence() { static char getend[] = {"\004statusdict begin (%%[ end page #=) print \ pagecount pstack pop flush end \r\n\004"}; int stat; int daytim[2]; /* quadword time interval */ int abort_sent = FALSE; static $DESCRIPTOR(timetowait, "0 :1:30"); /* +1:30 min */ endpage = 0; sys$wake(0,0); /* eat pending wakeups */ sys$hiber(); /* (instant return) */ if (!end_sent) { WRITELASER(&0X04,1) /* end of job */ lib$wait(&1.0); /* wait 1 second */ end_sent = FALSE; } #if NOREAD endpage = TRUE; #else WRITELASER(getend,strlen(getend)) /* write end sequence */ #endif do { stat = sys$bintim(&timetowait, daytim); checkstat(stat, "bintim"); stat = sys$schdwk(0, 0, daytim, 0); /* wake up later */ checkstat(stat, "schdwk"); if (endpage || io_aborted) break; /* if sync occured */ stat = sys$hiber(); if (endpage || io_aborted) break; /* if sync occured */ stat = sys$canwak(0,0); /* cancel wakeup requests */ if (!notify && abort_sent) { getmsg(LASER$_STALLED,1); sprintf(&msg[6],&message[1],&queue_name); sndmsg(1,1); notify = TRUE; } if (!abort_sent) { abort_sent = TRUE; /* WRITELASER(&0X03,1) *//* control-c */ /* lib$wait(&1.0); *//* wait 1 second */ /* WRITELASER(&0X04,1) *//* end of job */ /* lib$wait(&1.0); *//* wait 1 second */ cancel_read = TRUE; stat = sys$cancel(laserchan); WRITELASER(getend,strlen(getend)) cancel_read = FALSE; laser_read_ast (); } else abort_sent = FALSE; } while (TRUE); if (notify) { getmsg(LASER$_RESUMED,1); sprintf(&msg[6],&message[1],&queue_name); sndmsg(0,0); notify = FALSE; } } /** sendfile - send the main file to the printer. */ sendfile() { #define IBUFSIZE (32767) #define PREFIX_LEN (1) /* max extra prefix chars */ int stat, end; #if 0 char ibuf[IBUFSIZE]; /* input buffer */ char obuf[IBUFSIZE*2+2]; /* output buffer */ #else char *ibuf; char *obuf; #endif char *cp; int rsz = 0,i; /* record size */ char prn_ctl[2]; /* PRN file control bytes */ int first = TRUE, orsz = 0; ibuf = malloc(IBUFSIZE+PREFIX_LEN); /* extra for prefix chars */ obuf = malloc(IBUFSIZE*2 + 2); main_rab.rab$l_ubf = ibuf+PREFIX_LEN; main_rab.rab$w_usz = IBUFSIZE; /* For PRN type records, set up a pointer to the carriage control byte */ /* pair, or initialize the control byte pair manually. */ if (tek) /* if file is tektronix, init */ tek2ps(cp, obuf, &-1); if (main_fab.fab$b_rat & FAB$M_PRN) { if (main_fab.fab$b_fsz == 2) { main_rab.rab$l_rhb = &prn_ctl; /* ptr to PRN ctrl */ } else { prn_ctl[0] = 0x01; /* LF CR before */ prn_ctl[1] = 0x8d; /* CR after */ } } do { /* send the file */ if (main_fab.fab$b_fac & FAB$M_BIO) stat = sys$read(&main_rab, 0, 0); /* get a record */ else stat = sys$get(&main_rab, 0, 0); /* get a record */ if (!first || stat != RMS$_RTB) { if ((stat == RMS$_EOF) || (stop_task | stop_reason)) break; if (!(stat & 1)) { /* if error */ stop_reason = stat; break; } } if (stopoutput) break; rsz = main_rab.rab$w_rsz; cp = ibuf+PREFIX_LEN; /* Leave room for prefix chs */ if (first && !tek && !ps && !ansi) { /* File is postscript if starts with % */ /* or ctrl-d followed by % */ if (stat != RMS$_RTB && rsz && string && (((main_fab.fab$b_rat & FAB$M_FTN) && (cp[1]=='%' || cp[1]==4 && cp[2]=='%')) || (!(main_fab.fab$b_rat & FAB$M_FTN) && (cp[0]=='%' || (cp[0]==4 && cp[1]=='%') || (rsz > 1 && cp[0]==10 && cp[1]=='%') || (rsz > 1 && cp[0]==10 && cp[1]==4 && cp[2]=='%'))))) { ascii = TRUE; string = FALSE; ps = TRUE; } if (!ps) { tek = (stat == RMS$_RTB); if (!tek && rsz) { for (i=0; i blank line */ cp[rsz++] = ' '; } switch(*cp) { case 0: /* (null) - No CC */ cp++; /* ignore column 1 */ rsz--; break; case '0': /* 0 - Double Space */ *cp = '\n'; /* 2 LF in front, CR at end */ *--cp = '\n'; rsz++; cp[rsz++] = '\r'; break; case '1': /* 1 - Page Eject */ *cp = '\n'; *--cp = '\f'; rsz++; cp[rsz++] = '\r'; break; case '+': /* + - overprint */ cp++; /* ignore column 1 */ cp[rsz-1] = '\r'; break; case '$': /* $ - no trailing CC */ *cp = '\r'; /* LF, CR before record */ *--cp = '\n'; rsz++; break; default : /* space, etc. */ *cp = '\n'; cp[rsz++] = '\r'; } } /* if implied carriage control */ if (main_fab.fab$b_rat & FAB$M_CR || (!string && main_fab.fab$b_rat & FAB$M_PRN)) { *--cp = '\n'; /* prefix LF, suffix CR */ rsz++; cp[rsz++] = '\r'; } /* print carriage control. Expand and output */ /* leading carriage control, then expand trailing */ /* control to output after the text. */ else if (main_fab.fab$b_rat & FAB$M_PRN) { expand_cc(prn_ctl[0]); } if (string) expand_line(cp, obuf, rsz); else { if (orsz + rsz > IBUFSIZE) { WRITELASERBUF(obuf,orsz) orsz = 0; } memcpy(&obuf[orsz],cp,rsz); orsz = orsz + rsz; if (ps) for (i=orsz-rsz;i 0) { /* if log file */ str$append(&savelog, &zero); for (cp=savelog.dsc$a_pointer; *cp; cp+=strlen(cp)+1) { sprintf(buf, "(%s) h-logline\n", cp); WRITELASER(buf,strlen(buf)) } } sprintf(buf, " showpage \004"); WRITELASER(buf,strlen(buf)) } /** writemodule - write module from library. * * return: TRUE if module written, else FALSE. */ writemodule(key) struct dsc$descriptor_s key; { int stat, len; int library_index; long txtrfa[2]; char inbuf[255]; struct dsc$descriptor_s inbufdes = {sizeof(inbuf), DSC$K_DTYPE_T, DSC$K_CLASS_S, inbuf}; struct dsc$descriptor_s outbufdes; if (library_spec.dsc$a_pointer == 0) return FALSE; stat = lbr$ini_control(&library_index, &LBR$C_READ, &LBR$C_TYP_TXT, 0); checkstat(stat, "ini_control"); stat = lbr$open(&library_index, &library_spec, 0, 0, 0, 0, 0); checkstat(stat, "open"); stat = lbr$lookup_key(&library_index, &key, txtrfa); if ((stat & 1) != 1) { /* if bad key */ stat = lbr$close(&library_index); checkstat(stat, "close library"); return FALSE; } do { stat = lbr$get_record(&library_index, &inbufdes, &outbufdes); if (stat == RMS$_EOF) break; len = outbufdes.dsc$w_length; inbuf[len++] = '\r'; inbuf[len++] = '\n'; WRITELASER(inbuf,len) } while (1); stat = lbr$close(&library_index); checkstat(stat, "close"); } /** writeuserlog - write line to user log file. */ writeuserlog() { int stat; static struct dsc$descriptor_s temp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; if (userlog < 0) return; /* if no log file */ sys$setast(0); userlog++; /* bump flag */ log_rab.rab$l_rbf = laser_buf; log_rab.rab$w_rsz = strlen(laser_buf); stat = sys$put(&log_rab, 0, 0); if (userlog <= 5) { /* save first 5 lines */ temp.dsc$w_length = strlen(laser_buf) + 1; /* incl 0 */ temp.dsc$a_pointer = laser_buf; str$append(&savelog, &temp); } sys$setast(1); checkstat(stat, "write log"); } /** casefree_strcmp - compare source string against a target * independent of case sensitivities * (for length of source string only) */ static int casefree_strcmp (source, destination) char *source; char *destination; { register int result; for (; *source; source++, destination++) if (result = tolower (*source) - tolower (*destination)) return (result); return (0); } /** casefree_strcmp - compare source string against a target * independent of case sensitivities * (for length of source string only) */ static int casefree_strncmp (source, destination, length) char *source; char *destination; { register int result, i; for (i=0; i < length; i++) if (result = tolower (source[i]) - tolower (destination[i])) return (result); return (0); } #M#O#E#SOFT $ copy sys$input: LASER.HLP $DECK/DOLLARS="#M#O#E#SOFT" 1 Postscript This help describes how to print to postscript printers. This only applies to queues not running DEC's software. The two have similarities, but the non-DEC software is faster, particularly when printing tektronix files. Tektronix plots also are printed with a smaller line width, which can be changed to any value, if so desired. The software also attempts to determine if the file is postscript or tektronix rather than requiring the user to specify that information on the PRINT command. You can determine what software your printer queue is running by using the SHOW QUEUE/FULL command. If it shows PROCESSOR=CPS$SMB, then it is DEC, and you should refer to the main help topic PRINT_Parameters. The parameters subtopic describes parameters that are similar to DEC's parameters and are mainly not dependent on the file type, such as PAGE_LIMIT and NUMBER_UP. The forms subtopic describes file dependent parameters such as margins for text files. For parameters which are general to all printer queues, see the main help topic PRINT. 2 Parameters The PRINT command accepts the /PARAMETERS qualifier to specify functions which emulates the DECprint Printing Services software for printers. Format: $ PRINT/PARAMETERS=(parameter[,...]) file-spec If you specify only one parameter, you can omit the parentheses. If you specify two or more parameters, separate them with commas and enclose the set in parentheses. 3 DATA_TYPE DATA_TYPE=data-type-name Specifies the file type. Data-type-name can be ANSI, ASCII (same as ANSI), TEK4014, PS or POSTSCRIPT (same as PS). If you do not specify DATA_TYPE, it tries to determine if the file is TEK4014 or POSTSCRIPT. Otherwise, it defaults to the data type associated with the print queue. If there is no data type associated with the print queue, the data type defaults to ANSI. ANSI is used for printing text. It does not emulate an LN03. 3 INPUT_TRAY INPUT_TRAY=value Specifies what tray to use. Values vary between printer. Top and bottom trays can either be 0 and 1 or 1 and 2. The following values can be specified if you have a printer that can determine tray type: LEGAL, LETTER, or A4. 3 MESSAGES MESSAGES=KEEP Specifies what happens to job-generated event messages. Messages are printed on the job log page. MESSAGES=KEEP specifies that messages are recorded in a file named SYS$LOGIN:.LASER_LOG. 3 PAGE_LIMIT PAGE_LIMIT=([lower-limit,][upper-limit]) Specifies the numbers of the first and last pages to print. Header, trailer, and burst pages are not included in the count. If you omit the lower limit, printing starts at the first page of the job. If you omit the upper limit, printing continues to the end of the job. You can omit the parentheses if you specify only the upper limit. The maximum value for upper-limit is 10000. The default is to print the entire job. 3 PAGE_ORIENTATION PAGE_ORIENTATION=logical-orientation Specifies the orientation of printed output on the logical page. Logical-orientation can be PORTRAIT or LANDSCAPE. The default is PORTRAIT. If the DATA_TYPE is POSTSCRIPT this parameter is ignored. If the DATA_TYPE is TEK4014, the default is LANDSCAPE. 3 NUMBER_UP NUMBER_UP=n NUMBER_UP specifies the maximum number of pages you can print per sheet. This is the number of pages per sheet that will actually print. (A sheet is a physical piece of paper. A page is an image, which you would generally print on a single sheet.) A border is printed around each page. You can disable this by adding the parameter BORDER=NONE. The value n can be from 1 to 16. The default is NUMBER_UP=1. When NUMBER_UP is specified, PAGE_ORIENTATION can not be specified with postscript files. 3 SIDES SIDES=sides-layout-value Specifies whether your job will print on two sides of a sheet, and whether it will print in tumble mode. Sides-layout-value can be: 2, TWO, or Your job is printed on both sides of a sheet. TWO_SIDED_DUPLEX TUMBLE or Your job is printed on both sides of the sheet, TWO_SIDED_TUMBLE and alternating pages are rotated 180°. 2 Forms The following forms are defined for use with postscript printers. Some forms have special parameters associated only with that form, and are listed following the form name. They are passed as follows on the print command: /param=(parameter=value,...) Use the SHOW QUEUE/FULL command to see the default form for your queue. Form Parameters HEADERS Print file with filename and page number headers. ncopies: Number of copies. (default: 1) Note: This produces uncollated copies vs. collated copies produced by the /COPY qualifier. fsize: Font size in points. (default: 10) wide: If true set landscape mode. (default: false) title: If false suppress the page headers. (default: true) ncolumns: Number of columns. (default: 1) linelimit: Max number of lines per page. (default: 77) font: Font type. (default: Courier) Must be specified as follows: font="(fontname)". left: Left margin. (default: 20 mm) right: Right margin. (default: 10 mm) (has affect only when used with ncolumns or alternate.) top: Top margin. (default: 20 mm) bottom: Bottom margin. (default: 20 mm, 7 for landscape) alternate: If true, alternate left and right margins at end of page for printing double sided output. (default: false) wrap: Causes lines to wrap rather than be truncated. (default: false) lpp: Specifies the number of lines that are to be printed between top and bottom margins. Line spacing is adjusted to fill the region. header: if you want a header different from filename: header="(This is my private document)" LETTER Same as HEADERS except default title to false. LANDSCAPE Same as LETTER except default wide to true. 2UP Same as LANDSCAPE except default ncolumns to 2. POST Send a PostScript file to the printer for execution. TEK4014 Print a tektronix file. lw: Line width. (default: 1.5 points) BANNER Prints file in landscape with very large letters, 1 line to a page, with wrapping. PAINT Print a MacPaint image. ncopies: Number of copies. (default: 1) scale: Scale factor. (default: 4, recommended: 1-4) BITIMAGE Print an uncompressed image. ncopies: Number of copies. (default: 1) scale: Scale factor. (default: 1) xsize: Number of pixels in a row. (default: 512) ysize: Number of pixel columns. (default: 512) pxlwid: Number of bits in a pixel, default 1, values: 1,2,4,8 ZETA Print a zeta plot file. ncopies: Number of copies. (default: 1) scale: Scale factor. (default: 1) zFont: false - selects Helvetica font for internal character true - (default) uses Zeta characters penscale: Scaling factor for pen point (default: 1) usepens: false - (default) ignore alternate pen select Example: $ PRINT/QUEUE=ALW/FORM=HEADERS/PARAM=(LINELIMIT=66,FSIZE=14) STUFF.TXT Prints STUFF.TXT with a font size of 14 and a limit of 66 lines per page. 2 Spooling Spooled file names have the following syntax: _FormName._ParameterList where ParameterList is a list of parameters separated by "_". Keywords are separated from their values with "-". Example: $ copy thing.mpt alw:_paint._scale-4_ncopies-5 #M#O#E#SOFT $ copy sys$input: PRINT_SYMBOLS_DEFINE.COM $DECK/DOLLARS="#M#O#E#SOFT" $! print_symbols_define.com define symbols for printing 26-AUG-94 HM $! ------------------------ on DEClaser / HPlaser $! $! Arguments $! P1 DEC define for QUEUE = DEClaser default $! HP define for QUEUE = HPlaser $! assumes: $! Queue DEClaser / HPlaser were setup with $! DECLASER_STARTUP.COM / HPLASER_STARTUP.COM $! $ q = "/QUEUE=DECLASER" $ if p1 .eqs. "HP" then q = "/QUEUE=HPLASER" $ pr :== print'q' $ prh :== print'q'/form=headers $ prh60 :== print'q'/form=headers/params=(LPP=60,FS=10) $ prh72 :== print'q'/form=headers/params=(LPP=72) $ prl72 :== print'q'/form=headers/params=(LPP=72,wide=true) $ pr2 :== print'q'/form=headers/params=(LPP=72,wide=true,ncolumns=2,fs=6) $ pr2up :== print'q'/form=headers/params=(number_up=2) $ pr2up80 :== print'q'/form=headers/params=(number_up=2,fs=10,lpp=72) #M#O#E#SOFT $ copy sys$input: PRISO.FOR $DECK/DOLLARS="#M#O#E#SOFT" program priso implicit none byte b(255) character*255 c /' '/ equivalence (b,c) integer*4 i byte ib equivalence (i,ib) 1001 format(I4,': ',A) DO i=32,255 IF(i.ge. 127 .and. i.le. 143)GOTO10002 IF(i.eq. 153 .or. i.eq. 156)GOTO10002 b(i) = ib 10002 CONTINUE ENDDO DO i=32,255,8 write(6,1001) i,c(i:i+7) ENDDO END #M#O#E#SOFT $ copy sys$input: PRISO.FPP $DECK/DOLLARS="#M#O#E#SOFT" program priso ! print ISOLatin1 Encoding implicit none byte b(255) character*255 c /' '/ equivalence (b,c) integer*4 i byte ib equivalence (i,ib) 1001 format(I4,': ',A) @do i=32,255 @next (i.ge. 127 .and. i.le. 143) @next (i.eq. 153 .or. i.eq. 156) b(i) = ib @enddo @do i=32,255,8 write(6,1001) i,c(i:i+7) @enddo @end #M#O#E#SOFT $ copy sys$input: README.1ST $DECK/DOLLARS="#M#O#E#SOFT" readme.1st Minor Modifications on [LASER] H. Moerchen ---------- 31-AUG-94 Source was DECUS Essential Tools Collection CDROM : VS0174 The following modifications were done: LASER.C support 8-bit characters, i.e. >= 128 HEADERS_STR.PS support A4 paper specify margins in mm instead of inches use default Courier-ISO, Helvetica-Bold-ISO LASER.HLP document changes of (default) margins new files: PRISO.FPP, .FOR Print ISOLatin1 Encoding PRINT_SYMBOLS_DEFINE.COM some examples for print commands #M#O#E#SOFT