From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  1-SEP-1989 13:44
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Apple LaserWriter Symbiont (3 of 12)

Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Fri,  1 SEP 89 07:17:59 PDT
Received: from ecsgate.uncecs.edu by KL.SRI.COM with TCP; Fri, 1 Sep 89 07:02:56 PDT
Received: by ecsgate.uncecs.edu (5.59/UNCECS/8-30-88)
	id AA22609; Fri, 1 Sep 89 10:02:55 EDT
Message-Id: <8909011402.AA22609@ecsgate.uncecs.edu>
Date: Fri, 1 Sep 89 10:00 EDT
From: "Bill Bailey, 'The VAXman'" <BAILEYB@ATSUVAX1.BITNET>
Subject: Apple LaserWriter Symbiont (3 of 12)
To: INFO-VAX@KL.SRI.COM
X-Vms-To: INFOVAX

-+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+
X*`0094. The file to be printed itself.  If the setup module name ends in
X*`009   "_HEX" the file is hex-ified to the printer instead.
X*
X*`009where: <notestring> is the string from $PRINT /NOTE=<notestring>
X*`009       <paramstring> is the string from $PRINT /PARAM=("<string>"...)
X*`009       <filename> is the file specification for the file to print.
X*
X*`009Limitations, bugs, etc:
X*
X*`0091. No checkpointing is done.
X*`0092. $PRINT/COPIES=n sends the job to the LaserWriter n times. This
X*`009   is not optimal, but is how the job controller handles things.
X*`009   It makes sense for most printers.  Multiple copy handling is
X*`009   better handled in most of the postscript setup files.  Also
X*`009   /note="/#copies n def" will usually work.
X*`0093. $PRINT/SPACE=n is not implemented.
X*`0094. BURST pages are not implemented but FLAG and TRAILER are.
X*`0095. Does not handle lists of setup modules.
X*
X*`009Recommended device setup:
X*
X*`009$ define/system/exec/trans=(concealed,terminal) alw <term>: ! laser
X*`009$ set term /perm /speed=9600 /nomodem /notype /nohang alw
X*`009$ set term /perm /hostsync /pasthru /ttsync /eightbit /nobroad alw
X*`009$ set term /perm /noauto alw
X*`009$ set prot=o:rwlp /dev alw
X*`009$ set device /spooled=(ALW,sys$sysdevice:) alw
X*
X*`009Recommended queue initialize:
X*
X*`009$ initialize/queue/start -
X*`009/default=(noburst,nofeed,noflag,notrailer,form=headers) -
X*`009/separate=(noburst,noflag,trailer) -`032
X*`009/library=laser /base_prio=8 /form=headers -
X*`009/processor=laser /on=alw: alw
X*
X* NOTE: change /separate=(...trailer) to (...flag) if your laser printer
X*       stacks right side up.
X*
X*`009Modification History:
X*`00912-Feb-1987 R. Watson`009Created.
X*`00915-Apr-1987 R. Watson   Added some record format processing (cr,
X*`009`009`009`009fortran).
X*`00916-Apr-1987 R. Watson`009Allow ':' as a parameter separator.
X*`00921-Apr-1987 R. Watson`009Some mods to trailer page. Send PATCH module
X*`009`009`009`009if v 23.0 printer.
X*`00924-Apr-1987 R. Watson`009This version submitted to Spring '87 Decus.
X*`00924-Aug-1987 R. Watson`009Handle implied vs not carriage control better.
X*`00915-Sep-1987 R. Watson`009Add support for "_STR" setup module types to
X*`009`009`009`009allow RUNOFF style underlining.
X*`009`009`009`009Fixup timing problems with TI 2115.
X*`00901-Oct-1987 R. Watson`009Treat PRN carriage control like implied.`032
X*`009`009`009`009Still need to rewrite carriage control to
X*`009`009`009`009really handle Fortran and Print carriage
X*`009`009`009`009control.
X*`00921-Mar-1988 R. Watson`009Get big buffer for I/O.  Reduce frequency of
X*`009`009`009`009offline messages.
X*`00913-May-1988 S. Roseman  Added support for PRN and FTN carriage control.
X*`00915-Jun-1988 R. Watson`009Fixup page model for new carriage control supp
Vort.
X*`009`009`009`009Add FLAG pages, also fix for DEF=FLAG=`091ONE`124ALL`093,
X*`009`009`009`009etc.  No BURST (redundant).
X*`009`009`009`009This is version LASER_V2_01.
X*/
X
X#include <stdio.h>
X#include <ssdef.h>
X#include <descrip.h>
X#include <prvdef.h>
X#include <rms.h>
X#include <iodef.h>
X#include <opcdef.h>
X#include <ttdef.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include "smbdef.h"
X#include "lbrdef.h"
X#include "quidef.h"
X
X#define TRUE`0091
X#define FALSE`0090
X
X#define MAXITEMS 60`009`009`009/* max expected items from jobctl */
X
X#define WRITELASER(p1,p2) stat = sys$qiow(0,laserchan, IO$_WRITEPBLK, 0, 0,
V 0,\
Xp1, p2, 0, 0, 0, 0); checkstat(stat,"writelaser");
X
Xvoid jobctl_ast();`009`009`009/* job controller ast routine */
Xvoid laser_read_ast();`009`009`009/* laser read completion ast routine */
X
Xstruct `123
X`009int`009item_code;`009`009/* code */
X`009unsigned short `009item_size;`009/* size of item */
X`009char`009*buffer;`009`009/* address of item */
X`125 item`091MAXITEMS`093;
X
Xglobalvalue LASER$_MAXITEMS;`009`009/* exit statuses found in laser_err */
Xglobalvalue LASER$_ITEMNOTFOUND;
Xglobalvalue LASER$_STREAMNOTSTART;
Xglobalvalue LASER$_TOOMANYTABS;
Xglobalvalue LASER$_FLUSHED;
Xglobalvalue LASER$_SETUPNOTFOUND;
X
Xint`009ii = 0;`009`009`009`009/* item index */
Xint`009start_task = FALSE;`009`009/* start task flag */
Xint`009stop_task;`009`009`009/* stop task flag */
Xint`009stop_reason;`009`009`009/* stop task reason code */
Xint`009spooled_file;`009`009`009/* TRUE if spooled file */
Xint`009laser_efn;`009`009`009/* laser read event flag */
Xint`009startpage;`009`009`009/* task start page */
Xint`009endpage;`009`009`009/* task end page */
Xint`009jobstart;`009`009`009/* job start page */
Xint`009ascii;`009`009`009`009/* TRUE if ascii main file */
Xint`009hex;`009`009`009`009/* TRUE if hexified main file */
Xint`009string;`009`009`009`009/* TRUE if string main file */
Xint`009status_idle;`009`009`009/* TRUE if idle status received */
Xint`009patchneeded = FALSE;`009`009/* TRUE if patch module sent */
Xshort`009laserchan = 0;`009`009`009/* laserwriter channel */
Xunsigned short laser_iosb`0914`093;`009`009/* laser read iosb */
Xchar`009laser_buf`0911024`093;`009`009/* laser read buffer */
Xstruct`009FAB main_fab;`009`009`009/* main file rms stuff */
Xstruct`009NAM main_nam;
Xstruct`009RAB main_rab;
Xstruct`009FAB log_fab;`009`009`009/* log file rms stuff */
Xstruct`009RAB log_rab;
Xstruct  dsc$descriptor_d library_spec = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_D,
V 0`125;
Xstruct`009dsc$descriptor_d buffer_des = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_D,
V 0`125;
Xstruct`009dsc$descriptor_d savelog = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`
V125;
Xint`009userlog = -1;`009`009`009/* user log file */
X
Xstruct `123`009`009`009`009/* operator message to printer */
X`009char type;
X`009char target;
X`009short fill;
X`009long id;
X`009char text`091255`093;
X`125 msg = `123OPC$_RQ_RQST, OPC$M_NM_PRINT, 0, 0`125;
X
Xstruct dsc$descriptor_s oprmsg_dsc =`032
X`009`1230, DSC$K_DTYPE_T, DSC$K_CLASS_S, &msg`125;
X
X
Xmain()
X`123
X`009int stat;
X`009
X`009preset();`009`009`009`009/* initialize symbiont */
X`009
X`009do `123
X
X`009`009while (!start_task) `123`009`009/* wait for start_task */
X`009`009`009stat = sys$hiber();
X`009`009`009checkstat(stat,"wait start_task");
X`009`009`125
X
X`009`009processtask();`009`009`009/* do a job */
X`009`125 while (TRUE);
X`125
X
X
X/**`009check_operator - checks for a laserwriter message that should
X*`009`009`009 go to the operator.
X*`009returns TRUE if message sent to operator.
X*/
Xcheck_operator()
X`123
X`009int i;
X
X`009if (strncmp(laser_buf,"%%`091 PrinterError:", 17) == 0) `123
X
X`009`009if (strlen(laser_buf) > 255) return FALSE;`009/* check max */
X
X`009`009for (i = 0;i<strlen(laser_buf);i++) msg.text`091i`093 = laser_buf`09
V1i`093;
X
X`009`009oprmsg_dsc.dsc$w_length = strlen(laser_buf) + 8;
X
X`009`009sys$sndopr(&oprmsg_dsc, 0);
X`009`009return TRUE;
X`009`125
X`009
X`009if (strncmp(laser_buf, "%%`091 status: ", 12) == 0) `123
X`009`009if (strncmp(laser_buf, "%%`091 status: idle `093%%", 20) == 0) `123
X`009`009`009status_idle = TRUE;
X`009`009`009sys$wake(0,0);
X`009`009`125
X`009`009return TRUE;
X`009`125
X
X`009if (strncmp(laser_buf, "%%`091 patch needed `093%%", 20) == 0) `123
X`009`009patchneeded = TRUE;
X`009`009return TRUE;
X`009`125
X
X`009if (strncmp(laser_buf, "%%`091 start page #=", 17) == 0) `123
X`009`009sscanf(&laser_buf`09117`093, "%d", &startpage);
X`009`009sys$wake(0,0);`009`009`009/* wakeup sync waiting */
X`009`009return TRUE;
X`009`125
X`009
X`009if (strncmp(laser_buf, "%%`091 end page   #=", 17) == 0) `123
X`009`009sscanf(&laser_buf`09117`093, "%d", &endpage);
X`009`009sys$wake(0,0);`009`009`009/* wakeup sync waiting */
X`009`009return TRUE;
X`009`125
X
X/*  Abort the job if we see "%%`091 Flushing:"`009`009     */
X/*  Don't override an already existing stop_reason condition */
X
X`009if (strncmp(laser_buf, "%%`091 Flushing:", 13) == 0) `123
X`009`009if (stop_reason == 0) stop_reason = LASER$_FLUSHED;
X`009`009return FALSE;`009`009`009/* write in log */
X`009`125
X`009
X`009return FALSE;
X`125
X
X
X/**`009checkspooled - check for a spooled file.
X*
X*`009If the filename has "`091`093_" in it, then this is a spooled file
X*`009that the user wants to specify the form name for. Further,
X*`009if the extension starts with "_", then it contains the
X*`009user parameter list.  We forge the item list to make things
X*`009look right.
X*/
Xcheckspooled()
X`123
X`009struct dsc$descriptor_s temp = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`12
V5;
X`009struct dsc$descriptor_d dynd = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`12
V5;
X`009char *cp, *pp, spoolfile`091255`093;
X`009int len, i, stat;
X`009int ourindex;
X`009char setup`091257`093;`009`009`009/* where to put setup name */
X`009long iosb`0912`093;`009`009`009`009/* for $getquiw */
X`009short setupl;`009`009`009`009/* returned length of setup */
X`009struct `123`009`009`009`009/* item list for $getquiw */
X`009`009short`009l1;
X`009`009short`009c1;
X`009`009char`009*b1;
X`009`009long`009*r1;
X`009`009short`009l2;
X`009`009short`009c2;
X`009`009char`009*b2;
X`009`009long`009*r2;
X`009`009long`009end;
X`009`125 itmlst = `1230,  QUI$_SEARCH_NAME, 0, 0,
X`009`009sizeof(setup)-1, QUI$_FORM_SETUP_MODULES, setup, &setupl,
X`009`0090`125;
X
X`009spooled_file = FALSE;
X`009
X/*  get the file specification */
X
X`009if (!getitemdescrip(SMBMSG$K_FILE_SPECIFICATION, &temp, FALSE)) return;
X`009
X`009strncpy(spoolfile, temp.dsc$a_pointer, temp.dsc$w_length);
X`009spoolfile`091temp.dsc$w_length`093 = 0;
X`009`009
X/*  check for `091`093_ */
X`009
X`009if (!(cp = strchr(spoolfile, '`091'))) return;
X`009if (!(*++cp == '`093')) return;
X`009spooled_file = TRUE;`009`009`009/* file is spooled */
X`009if (!(*++cp == '_')) return;
X`009
X/*  find the extension and terminate the name string */`009
X`009
X`009if (!(pp = strchr(cp, '.'))) return;
X`009*pp = 0;
X`009cp++;
X
X/*  translate the form name into setup module names */
X/*  If it won't translate, then pass on the form name */
X
X`009itmlst.l1 = strlen(cp);`009`009`009/* point to name */
X`009itmlst.b1 = cp;
X`009stat = sys$getquiw(0, QUI$_DISPLAY_FORM, 0, &itmlst, iosb, 0, 0);
X`009checkstat(stat, "getquiw");
X`009if ((iosb`0910`093 & 1) != 1) `009`009/* if no translation */
X`009`009strcpy(setup, cp);
X`009else
X`009`009setup`091setupl`093 = 0;
X
X/*  forge the file setup module to have our setup module name */
X/*  Note that the forge transfers the dynamic string "dynd" to "item" */
X
X`009ourindex = findandclritem(SMBMSG$K_FILE_SETUP_MODULES);
X`009dynd.dsc$w_length = 0;`009`009/* get dynamic string */
X`009dynd.dsc$a_pointer = 0;
X`009len = strlen(setup);
X`009str$copy_r(&dynd, &len, setup);
X`009item`091ourindex`093.item_size = dynd.dsc$w_length;`009/* complete forge
V */
X`009item`091ourindex`093.buffer = dynd.dsc$a_pointer;
X
X/*  forge the form name to have our form name */
X`009
X`009ourindex = findandclritem(SMBMSG$K_FORM_NAME);
X`009dynd.dsc$w_length = 0;`009`009/* get dyamic string */
X`009dynd.dsc$a_pointer = 0;
X`009len = strlen(cp);`009`009`009/* pointer to form name */
X`009str$copy_r(&dynd, &len, cp);
X`009item`091ourindex`093.item_size = dynd.dsc$w_length;`009/* complete forge
V */
X`009item`091ourindex`093.buffer = dynd.dsc$a_pointer;
X`009
X/*  now check to see if there are parameters */
X
X`009cp = ++pp;`009`009`009`009/* set extension address */
X`009if (pp = strchr(cp,';')) *pp = 0;`009/* terminate at ";" */
X`009
X`009for (i = 0; i < 8; i++) `123
X`009`009if (*cp != '_') return;`009`009/* check next char */
X`009`009cp++;`009`009`009`009/* advance over it */
X
X`009`009/* if there is another _, point to it, else point to the */
X`009`009/* end of the string `009`009`009`009`009 */
X`009`009if ((pp = strchr(cp,'_')) == 0) pp = cp + strlen(cp);
X
X`009`009len = pp - cp;`009`009`009/* find length of string */
X`009`009if (len == 0) continue;`009`009/* if null parameter */
X
X`009`009/*  forge the item */
X`009`009ourindex = findandclritem(SMBMSG$K_PARAMETER_1+i);
X`009`009dynd.dsc$w_length = 0;`009`009/* get dynamic string */
X`009`009dynd.dsc$a_pointer = 0;
X`009`009str$copy_r(&dynd, &len, cp);
X`009`009item`091ourindex`093.item_size = dynd.dsc$w_length;
X`009`009item`091ourindex`093.buffer = dynd.dsc$a_pointer;
X`009`009
X`009`009cp = pp;
X`009`125
X`125
X`009`009
X`009
X/**`009findandclritem - find and clear item.
X*
X*`009Finds an item in the item list. Releases the dynamic string
X*`009for that item. If the item doesn't exist in the item list,
X*`009create it.
X*
X*`009return:`009index to item in item list
X*/
Xfindandclritem(whichitem)
Xint whichitem;
X`123
X`009int i;
X`009struct dsc$descriptor_d temp = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`12
V5;
X
X`009for (i = 0; i < ii; i++) `123`009`009/* search item list */
X`009`009if (whichitem == item`091i`093.item_code) break;
X`009`125
X`009
X`009if (i == ii) `123`009`009`009`009/* if end of list */
X`009`009if (++ii > MAXITEMS) exit(LASER$_MAXITEMS);`009/* new item */
X`009`009item`091i`093.item_code = whichitem;
X`009`009item`091i`093.item_size = 0;
X`009`009item`091i`093.buffer = 0;
X`009`009return i;`009`009`009/* return index */
X`009`125
X
X`009temp.dsc$w_length = item`091i`093.item_size;`009/* release string */
X`009temp.dsc$a_pointer = item`091i`093.buffer;
X`009str$free1_dx(&temp);
X`009item`091i`093.buffer = 0;
X`009return i;
X`125
X
X
X/**`009checkstat - check value of system service return.
X*/
Xcheckstat(stat, string)
Xint stat;
Xchar *string;
X`123`009
X`009if (!(stat & 1)) exit(stat);
X`125
X
X
X/**`009closefile - close main file.
X*/
Xclosefile()
X`123
X`009int stat;
X
X`009stat = sys$close(&main_fab, 0, 0);
X`009/*  ignore error */
X`125
X
X
X/**`009closeuserlog - close user log file.
X*/
Xcloseuserlog()
X`123
X`009int stat;
X
X`009if (userlog == -1) return;`009`009/* if no log */
X
X/*  If no records written, set for delete on close */
X`009
X`009if (userlog == 0) log_fab.fab$l_fop `124= FAB$M_DLT;
X
X`009stat = sys$close(&log_fab);
X`009checkstat(stat,"close log");
X`009
X`009str$free1_dx(&savelog);`009`009`009/* release saved log */
X
X`009userlog = -1;
X`125
X`009
X
X/**`009expand_cc - expand PRN carriage control byte.
X*
X*`009Entry:`009ccb = fab$v_prn byte
X*`009Exit:`009commands output to printer
X*/
Xexpand_cc(ccb)
Xchar ccb;`009`009`009`009/* carriage control byte */
X`123
X`009int ic, stat;
+-+-+-+-+-+-+-+-  END  OF PART 3 +-+-+-+-+-+-+-+-

