From: MRL@PFC.MIT.EDU (MARK LONDON)
Newsgroups: comp.os.vms
Subject: LASER New (different) LASER symbiont. 2/7
Date: 22 Aug 92 16:22:00 GMT
Distribution: world
Organization: The Internet

-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
X*`09/processor=laser /on=alw: alw
X*
X* NOTE: change /separate=(...trailer) to (...flag) if your laser printer
X*       stacks right side up.
X*
X*/
X
X#include iodef
X#include stdio
X#include ssdef
X#include descrip
X#include rms
X#include ctype
X#include stdlib
X#include brkdef
X#include "smbdef.h"
X#include quidef
X#include prvdef
X#include "lbrdef.h"
X#include ttdef
X#include opcdef
X
X#define TRUE`091
X#define FALSE`090
X
X#define MAXITEMS 60`09`09`09/* max expected items from jobctl */
X#define min(a,b) ( ((a)<(b)) ? (a) : (b) )
X#define max(a,b) ( ((a)>(b)) ? (a) : (b) )`20
X#define WRITELASER(p1,p2) `7Bstat = sys$qiow(0,laserchan, IO$_WRITEPBLK, 0,
V 0, 0,\
Xp1, p2, 0, 0, 0, 0); checkstat(stat,"writelaser"); iocount++;`7D
X#define WRITELASERBUF(p1,p2) `7B\
Xolen = p2;while (olen > 0)\
X`7Bstat = sys$qiow(0,laserchan, IO$_WRITEPBLK, 0, 0, 0,\
Xp1+p2-olen, min(1536,olen), 0, 0, 0, 0); checkstat(stat,"writelaser");\
Xolen -= min(1536,olen); iocount++;`7D`7D
X#define WRITESTRING(p1) WRITELASER(p1,strlen(p1))
Xextern short laserchan;`09`09`09/* laserwriter channel */
X`09
Xglobalvalue LASER$_STREAMNOTSTART,LASER$_MAXITEMS,
X`09    LASER$_CREATELOG,LASER$_STARTJOB,LASER$_ERROR,
X`09    LASER$_STALLED,LASER$_RESUMED,
X`09    LASER$_ITEMNOTFOUND,LASER$_TOOMANYTABS,
X`09    LASER$_USERDATA,LASER$_JOBID,LASER$_TIMEOUT,LASER$_ABORT,
X`09    LASER$_FLUSHED,LASER$_SETUPNOTFOUND,LASER$_INVPARAM;
X
Xvoid jobctl_ast();`09`09`09/* job controller ast routine */
Xvoid laser_read_ast();`09`09`09/* laser read completion ast routine */
Xvoid ltatimeout();
Xvoid statetimeout();
X
Xstruct `7B
X`09int`09item_code;`09`09/* code */
X`09unsigned short `09item_size;`09/* size of item */
X`09char`09*buffer;`09`09/* address of item */
X`7D item`5BMAXITEMS`5D;
X
Xint stop_task;`09`09`09/* stop task flag */
Xint stop_reason;`09`09/* stop task reason code */
Xint spooled_file;`09`09/* TRUE if spooled file */
Xint laser_efn;`09`09`09/* laser read event flag */
Xint startpage;`09`09`09/* task start page */
Xint endpage;`09`09`09/* task end page */
Xint jobstart;`09`09`09/* job start page */
Xint ansi;`09`09`09/* TRUE if ansi specified */
Xint ascii;`09`09`09/* TRUE if ascii main file */
Xint hex;`09`09`09/* TRUE if hexified main file */
Xint tek;`09`09`09/* TRUE if tektronix main file */
Xint ps;`09`09`09`09/* TRUE if postscript main file */
Xint string;`09`09`09/* TRUE if string main file */
Xint status_idle;`09`09/* TRUE if idle status received */
Xint status_error;`09`09/* TRUE if error message received */
Xint land;                       /* TRUE if landscape */
Xint port;                       /* TRUE if portrait */
Xint notify_qual;
Xint nup;
Xint olen;
Xchar queue_name`5B128`5D;
Xshort queue_name_l;
Xint iocount,oldiocount;
Xunsigned short laser_iosb`5B4`5D;`09/* laser read iosb */
Xchar laser_buf`5B1024`5D;`09`09/* laser read buffer */
Xstruct FAB main_fab;`09`09/* main file rms stuff */
Xstruct NAM main_nam;
Xstruct RAB main_rab;
Xstruct FAB log_fab;`09`09/* log file rms stuff */
Xstruct RAB log_rab;
X
Xstruct dsc$descriptor_d library_spec = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0
V`7D;
Xstruct dsc$descriptor_d buffer_des = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`7
VD;
Xstruct dsc$descriptor_d savelog = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`7D;
Xint userlog = -1;`09`09`09/* user log file */
Xint notify = FALSE;
X
Xchar msg`5B255`5D = "\007\007\007\r\n";`09/* error message to user */
Xstruct dsc$descriptor_s errmsg_dsc = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7
VD;
X
Xchar user_text`5B20`5D;`09`09/* user name to send error message to */
Xstruct dsc$descriptor_s user_notify = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &u
Vser_text`7D;
X
Xint ii = 0;`09`09`09`09/* item index */
Xint start_task = FALSE;`09`09`09/* start task flag */
Xint patchneeded = FALSE;`09`09/* TRUE if patch module sent */
Xint stopoutput = FALSE;
Xint lta_device = FALSE;
Xint ltaefn,stateefn;
Xint statetime`5B2`5D= `7B-1*900000000,-1`7D;
Xint jobnum = -1,entry_num;
Xshort msglen = 0;
Xchar message`5B257`5D;
Xstruct dsc$descriptor_s msgd =
X`09`09`7Bsizeof(message)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, message`7D;
Xstruct `7B`09`09`09`09/* operator message to printer */
X    char type;
X    char target;
X    short fill;
X    long id;
X    char text`5B257`5D;
X`7D oprmsg = `7BOPC$_RQ_RQST, OPC$M_NM_PRINT, 0, 0`7D;
X
Xstruct dsc$descriptor_s oprmsg_dsc =`20
X`09`7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &oprmsg`7D;
X
Xmain()
X`7B
X`09int stat;
X`09laserchan = 0;
X`09
X`09preset();`09`09`09`09/* initialize symbiont */
X`09
X`09do `7B
X
X`09`09while (!start_task) `7B`09`09/* wait for start_task */
X`09`09`09stat = sys$hiber();
X`09`09`09checkstat(stat,"wait start_task");
X`09`09`7D
X
X`09`09processtask();`09`09`09/* do a job */
X`09`7D while (TRUE);
X`7D
X
Xsndmsg(type)
Xint type;
X`7B
X`09sys$setrwm(0);
X`09if (type) `7B
X`09`09oprmsg_dsc.dsc$w_length = errmsg_dsc.dsc$w_length + 8;
X`09`09strncpy(oprmsg.text,errmsg_dsc.dsc$a_pointer,
X`09`09`09errmsg_dsc.dsc$w_length);
X`09`09sys$sndopr(&oprmsg_dsc, 0);
X`09`7D`20
X `09sys$brkthru(0, &errmsg_dsc, &user_notify,
X `09`09`09BRK$C_USERNAME,0,32,BRK$M_CLUSTER,0,5,0,0);
X`09sys$setrwm(1);
X`7D
X
Xjobid(type)
Xint type;
X`7B
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09static char job`5B255`5D;
X`09int stat, i;
X        if (getitemdescrip(SMBMSG$K_JOB_NAME, &temp, FALSE))
X                strncpy(job, temp.dsc$a_pointer, temp.dsc$w_length);
X        else
X                temp.dsc$w_length = 0;
X`09job`5Btemp.dsc$w_length`5D = 0;
X`09stat = sys$getmsg(LASER$_JOBID, &msglen, &msgd, 15, 0);
X`09checkstat(stat,"$getmsg");
X`09message`5Bmsglen`5D = 0;
X`09queue_name`5Bqueue_name_l`5D = 0;
X`09i = errmsg_dsc.dsc$w_length;
X`09strcpy(errmsg_dsc.dsc$a_pointer+i,"\r\n%");
X`09sprintf(errmsg_dsc.dsc$a_pointer+i+3,&message`5B1`5D,&job,entry_num,&queu
Ve_name);
X`09errmsg_dsc.dsc$w_length = strlen(errmsg_dsc.dsc$a_pointer);
X`09sndmsg(type);
X`7D
X
X/**`09check_operator - checks for a laserwriter message that should
X*`09`09`09 go to the operator.
X*`09returns TRUE if message sent to operator.
X*/
Xcheck_operator()
X`7B
X`09int i,stat;
X
X`09if (strncmp(laser_buf, "%%`5B status: ", 12) == 0) `7B
X`09`09if (strncmp(laser_buf, "%%`5B status: idle", 16) == 0) `7B
X`09`09`09status_idle = TRUE;
X`09`09`09sys$wake(0,0);
X`09`09`09return TRUE;
X`09`09`7D else if (status_error)
X`09`09`09return TRUE;`09
X`09`09else if (strncmp(laser_buf, "%%`5B status: offline", 19) == 0) `7B
X`09`09`09strcpy(&laser_buf`5B18`5D,&laser_buf`5B12`5D);`20
X`09`09`09strcpy(&laser_buf`5B4`5D,"PrinterError");
X`09`09`7D else
X`09`09`09strcpy(&laser_buf`5B4`5D,&laser_buf`5B12`5D);
X`09`7D
X
X`09if (strncmp(laser_buf,"%%`5B PrinterError:", 17) == 0) `7B
X`09`09stat = sys$getmsg(LASER$_ERROR, &msglen, &msgd, 15, 0);
X`09`09checkstat(stat,"$getmsg");
X`09`09if (strlen(laser_buf) > 245) laser_buf`5B245`5D = 0;
X`09`09strncpy(&msg`5B5`5D,message,msglen);
X`09`09strncpy(&msg`5Bmsglen+5`5D,&laser_buf`5B17`5D,strlen(laser_buf)-17);
X`09`09errmsg_dsc.dsc$w_length =
X`09`09`09strlen(laser_buf) - 17 + msglen;
X`09`09errmsg_dsc.dsc$a_pointer = &msg`5B5`5D;
X`09`09jobid(1);
X`09`09status_error = TRUE;
X`09`09return TRUE;
X`09`7D
X
X`09if (strncmp(laser_buf, "%%`5B patch needed `5D%%", 20) == 0) `7B
X`09`09patchneeded = TRUE;
X`09`09return TRUE;
X`09`7D
X
X`09if (strncmp(laser_buf, "stop", 4) == 0) `7B
X`09`09stopoutput = TRUE;
X`09`09return TRUE;
X`09`7D
X
X`09if (strstr(laser_buf, "not a known parameter")) `7B
X                stop_reason = LASER$_INVPARAM;
X`09`09return FALSE;
X`09`7D
X
X`09if (strncmp(laser_buf, "%%`5B start page #=", 17) == 0 && status_idle) `7
VB
X`09`09sscanf(&laser_buf`5B17`5D, "%d", &startpage);
X`09`09sys$wake(0,0);`09`09`09/* wakeup sync waiting */
X`09`09return TRUE;
X`09`7D
X`09
X`09if (strncmp(laser_buf, "%%`5B end page   #=", 17) == 0 && status_idle) `7
VB
X`09`09sscanf(&laser_buf`5B17`5D, "%d", &endpage);
X`09`09sys$wake(0,0);`09`09`09/* wakeup sync waiting */
X`09`09return TRUE;
X`09`7D
X
X/*  Abort the job if we see "%%`5B Flushing:"`09`09     */
X/*  Don't override an already existing stop_reason condition */
X
X`09if (strncmp(laser_buf, "%%`5B Flushing:", 13) == 0
X`09    && startpage && status_idle && !stopoutput) `7B
X`09`09if (stop_reason == 0) stop_reason = LASER$_FLUSHED;
X`09`09return FALSE;`09`09`09/* write in log */
X`09`7D
X
X`09if (strncmp(laser_buf,"%%`5B Error:", 10) == 0 &&
X`09`09(userlog == 0 `7C`7C userlog == -1) && !stopoutput) `7B
X`09`09stat = sys$getmsg(LASER$_ERROR, &msglen, &msgd, 15, 0);
X`09`09checkstat(stat,"$getmsg");
X`09`09if (strlen(laser_buf) > 245) laser_buf`5B245`5D = 0;
X`09`09strncpy(&msg`5B5`5D,message,msglen);
X`09`09strncpy(&msg`5Bmsglen+5`5D,&laser_buf`5B10`5D,strlen(laser_buf)-10);
X`09`09errmsg_dsc.dsc$w_length =
X`09`09`09strlen(laser_buf) - 10 + msglen - 4;
X`09`09errmsg_dsc.dsc$a_pointer = &msg`5B5`5D;
X`09`09jobid(1);
X`09`09if (userlog == -1) userlog = -2;
X`09`09status_error = TRUE;
X`09`09return FALSE;
X`09`7D
X
X`09if (!stopoutput && startpage && !stop_reason && !stop_task &&`20
X`09`09isalpha(laser_buf`5B0`5D)) `7B
X`09`09if (notify_qual) `7B
X`09`09`09stat = sys$getmsg(LASER$_USERDATA, &msglen, &msgd, 15, 0);
X`09`09`09checkstat(stat,"$getmsg");
X`09`09`09if (strlen(laser_buf) > 245) laser_buf`5B245`5D = 0;
X`09`09`09strncpy(&msg`5B5`5D,message,msglen);
X`09`09`09strncpy(&msg`5Bmsglen+5`5D,laser_buf,strlen(laser_buf));
X`09`09`09errmsg_dsc.dsc$w_length =
X`09`09`09`09strlen(laser_buf) + msglen;
X`09`09`09errmsg_dsc.dsc$a_pointer = &msg`5B5`5D;
X`09`09`09jobid(0);
X`09`09`7D
X`09`09return TRUE;
X`09`7D
X`09
X`09if (stopoutput `7C`7C !startpage) return TRUE;
X`09return FALSE;
X`7D
X
X
X/**`09checkspooled - check for a spooled file.
X*
X*`09If the filename has "`5B`5D_" in it, then this is a spooled file
X*`09that the user wants to specify the form name for. Further,
X*`09if the extension starts with "_", then it contains the
X*`09user parameter list.  We forge the item list to make things
X*`09look right.
X*/
Xcheckspooled()
X`7B
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09struct dsc$descriptor_d dynd = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`7D;
X`09char *cp, *pp, spoolfile`5B255`5D;
X`09int len, i, stat;
X`09int ourindex;
X`09char setup`5B257`5D;`09`09`09/* where to put setup name */
X`09long iosb`5B2`5D;`09`09`09`09/* for $getquiw */
X`09short setupl;`09`09`09`09/* returned length of setup */
X`09struct `7B`09`09`09`09/* item list for $getquiw */
X`09`09short`09l1;
X`09`09short`09c1;
X`09`09char`09*b1;
X`09`09long`09*r1;
X`09`09short`09l2;
X`09`09short`09c2;
X`09`09char`09*b2;
X`09`09long`09*r2;
X`09`09long`09end;
X`09`7D itmlst = `7B0,  QUI$_SEARCH_NAME, 0, 0,
X`09`09sizeof(setup)-1, QUI$_FORM_SETUP_MODULES, setup, &setupl,
X`09`090`7D;
X
X`09spooled_file = FALSE;
X`09
X/*  get the file specification */
X
X`09if (!getitemdescrip(SMBMSG$K_FILE_SPECIFICATION, &temp, FALSE)) return;
X`09
X`09strncpy(spoolfile, temp.dsc$a_pointer, temp.dsc$w_length);
X`09spoolfile`5Btemp.dsc$w_length`5D = 0;
X`09`09
X/*  check for `5B`5D_ */
X`09
X`09if (!(cp = strchr(spoolfile, '`5B'))) return;
X`09if (!(*++cp == '`5D')) return;
X`09spooled_file = TRUE;`09`09`09/* file is spooled */
X`09if (!(*++cp == '_')) return;
X`09
X/*  find the extension and terminate the name string */`09
X`09
X`09if (!(pp = strchr(cp, '.'))) return;
X`09*pp = 0;
X`09cp++;
X
X/*  translate the form name into setup module names */
X/*  If it won't translate, then pass on the form name */
X
X`09itmlst.l1 = strlen(cp);`09`09`09/* point to name */
X`09itmlst.b1 = cp;
X`09stat = sys$getquiw(0, QUI$_DISPLAY_FORM, 0, &itmlst, iosb, 0, 0);
X`09checkstat(stat, "getquiw");
X`09if ((iosb`5B0`5D & 1) != 1) `09`09/* if no translation */
X`09`09strcpy(setup, cp);
X`09else
X`09`09setup`5Bsetupl`5D = 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`09ourindex = findandclritem(SMBMSG$K_FILE_SETUP_MODULES);
X`09dynd.dsc$w_length = 0;`09`09/* get dynamic string */
X`09dynd.dsc$a_pointer = 0;
X`09len = strlen(setup);
X`09str$copy_r(&dynd, &len, setup);
X`09item`5Bourindex`5D.item_size = dynd.dsc$w_length;`09/* complete forge */
X`09item`5Bourindex`5D.buffer = dynd.dsc$a_pointer;
X
X/*  forge the form name to have our form name */
X`09
X`09ourindex = findandclritem(SMBMSG$K_FORM_NAME);
X`09dynd.dsc$w_length = 0;`09`09/* get dyamic string */
X`09dynd.dsc$a_pointer = 0;
X`09len = strlen(cp);`09`09`09/* pointer to form name */
X`09str$copy_r(&dynd, &len, cp);
X`09item`5Bourindex`5D.item_size = dynd.dsc$w_length;`09/* complete forge */
X`09item`5Bourindex`5D.buffer = dynd.dsc$a_pointer;
X`09
X/*  now check to see if there are parameters */
X
X`09cp = ++pp;`09`09`09`09/* set extension address */
X`09if (pp = strchr(cp,';')) *pp = 0;`09/* terminate at ";" */
X`09
X`09for (i = 0; i < 8; i++) `7B
X`09`09if (*cp != '_') return;`09`09/* check next char */
X`09`09cp++;`09`09`09`09/* advance over it */
X
X`09`09/* if there is another _, point to it, else point to the */
X`09`09/* end of the string `09`09`09`09`09 */
X`09`09if ((pp = strchr(cp,'_')) == 0) pp = cp + strlen(cp);
X
X`09`09len = pp - cp;`09`09`09/* find length of string */
X`09`09if (len == 0) continue;`09`09/* if null parameter */
X
X`09`09/*  forge the item */
X`09`09ourindex = findandclritem(SMBMSG$K_PARAMETER_1+i);
X`09`09dynd.dsc$w_length = 0;`09`09/* get dynamic string */
X`09`09dynd.dsc$a_pointer = 0;
X`09`09str$copy_r(&dynd, &len, cp);
X`09`09item`5Bourindex`5D.item_size = dynd.dsc$w_length;
X`09`09item`5Bourindex`5D.buffer = dynd.dsc$a_pointer;
X`09`09
X`09`09cp = pp;
X`09`7D
X`7D
X`09`09
X`09
X/**`09findandclritem - find and clear item.
X*
X*`09Finds an item in the item list. Releases the dynamic string
X*`09for that item. If the item doesn't exist in the item list,
X*`09create it.
X*
X*`09return:`09index to item in item list
X*/
Xfindandclritem(whichitem)
Xint whichitem;
X`7B
X`09int i;
X`09struct dsc$descriptor_d temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`7D;
X
X`09for (i = 0; i < ii; i++) `7B`09`09/* search item list */
X`09`09if (whichitem == item`5Bi`5D.item_code) break;
X`09`7D
X`09
X`09if (i == ii) `7B`09`09`09`09/* if end of list */
X`09`09if (++ii > MAXITEMS) exit(LASER$_MAXITEMS);`09/* new item */
X`09`09item`5Bi`5D.item_code = whichitem;
X`09`09item`5Bi`5D.item_size = 0;
X`09`09item`5Bi`5D.buffer = 0;
X`09`09return i;`09`09`09/* return index */
X`09`7D
X
X`09temp.dsc$w_length = item`5Bi`5D.item_size;`09/* release string */
X`09temp.dsc$a_pointer = item`5Bi`5D.buffer;
X`09str$free1_dx(&temp);
X`09item`5Bi`5D.buffer = 0;
X`09return i;
X`7D
X
X
X/**`09checkstat - check value of system service return.
X*/
Xcheckstat(stat, string_dummy)
Xint stat;
Xchar *string_dummy;
X`7B`09
X`09if (!(stat & 1)) `7B
X`09`09strcpy(&msg`5B5`5D, "Printer symbiont crashed due to error in ");
X`09`09strcpy(&msg`5Bstrlen(msg)`5D, string_dummy);
X`09`09errmsg_dsc.dsc$w_length = strlen(msg) ;
X`09`09errmsg_dsc.dsc$a_pointer = &msg`5B0`5D;
X`09`09msg`5Berrmsg_dsc.dsc$w_length-2`5D = '\r';
X`09`09msg`5Berrmsg_dsc.dsc$w_length-1`5D = '\n';
X`09`09sys$getmsg(stat, &msglen, &msgd, 15, 0);
X`09`09strncpy(&msg`5Berrmsg_dsc.dsc$w_length`5D,message,msglen);
X`09`09errmsg_dsc.dsc$w_length += msglen;
X`09`09sndmsg(1);
X`09`09if (lta_device && jobnum)
X`09`09`09sys$qio(0, laserchan,IO$_TTY_PORT+IO$M_LT_DISCON, 0, 0, 0,
X`09`09`090, 0, 0, 0, 0, 0);
X`09  `09exit(stat);
X        `7D
X`7D
X
X
X/**`09closefile - close main file.
X*/
Xclosefile()
X`7B
X`09int stat;
X
X`09stat = sys$close(&main_fab, 0, 0);
X`09/*  ignore error */
X
X`09notify = FALSE;
X`7D
X
X
X/**`09closeuserlog - close user log file.
X*/
Xcloseuserlog()
X`7B
X`09int stat;
X`09static int privs`5B2`5D = `7BPRV$M_BYPASS,0`7D;
X
X`09if (userlog < 0) return;`09`09/* if no log */
X
X/*  If no records written, set for delete on close */
X`09
X`09if (userlog == 0) log_fab.fab$l_fop `7C= FAB$M_DLT;
X
X`09stat = sys$close(&log_fab);
X
X`09stat = sys$setprv(1, privs, 0, 0);
X`09checkstat(stat,"close log");
X`09stat = sys$setprv(0, privs, 0, 0);
X`09
X`09str$free1_dx(&savelog);`09`09`09/* release saved log */
X
X`09userlog = -1;
X`7D
X`09
X
X/**`09expand_cc - expand PRN carriage control byte.
X*
X*`09Entry:`09ccb = fab$v_prn byte
X*`09Exit:`09commands output to printer
X*/
Xexpand_cc(ccb)
Xchar ccb;`09`09`09`09/* carriage control byte */
X`7B
X`09int ic, stat;
X`09char obuf`5B40`5D;
X
X`09if (ccb == 0) `7B
X`09`09return;
X`09`7D
X
X`09if ((ccb & 0x80) == 0) `7B`09`09/* output (n) LF, 1 CR */
X`09`09if ((ccb & 0x7f) == 1) `7B`09/* 1 LF, output short form */
X`09`09`09WRITELASER("XLF XCR\r\n", 9);
X`09`09`7D
X`09`09else `7B
X`09`09`09sprintf(obuf, "%d`7BXLF`7Drepeat XCR\r\n",(ccb & 0x7f));
X`09`09`09WRITELASERBUF(obuf, strlen(obuf));
X`09`09`7D
X`09`7D
X`09else `7B
X`09`09if ((ccb & 0xe0) != 0xe0) `7B`09/* output single character */
X`09`09`09ic = ccb & 0x7f;
X`09`09`09expand_line(&ic, obuf, 1);
X`09`09`7D
X`09`7D
X`7D
X
X
X/**`09expand_hex - expand buffer into hex bytes.
X*/
Xexpand_hex(ibuf, obuf, rsz)
Xunsigned char *ibuf;`09`09`09/* pointer to input buffer */
Xchar *obuf;`09`09`09`09/* pointer to output buffer */
Xint rsz;`09`09`09`09/* buffer size */
X`7B
X`09int i, c, stat;
X`09static char hexnums`5B`5D = "0123456789ABCDEF";
X`09
X`09for (i = 0; i < rsz; i++) `7B
X`09`09obuf`5Bi*2`5D = hexnums`5B(ibuf`5Bi`5D & 0xF0) >> 4`5D;
X`09`09obuf`5Bi*2+1`5D = hexnums`5Bibuf`5Bi`5D & 0xF`5D;
X`09`7D
X`09WRITELASERBUF(obuf,rsz*2)
X`7D
X
X`09
X/**`09expand_line - expand input buffer and output result to printer.
X*
X*`09The ()pop sequences are an obscure hack to fix an obscure bug
X*`09with XON/XOFF.  It just works.
X*/
Xexpand_line(ibuf, obuf, rsz)
Xchar *ibuf;`09`09`09`09`09/* input buffer */
Xchar *obuf;
Xint rsz;`09`09`09`09`09/* buffer size */
X`7B
X`09int i, d, col, stat;
X`09static int popcount = 0;`09`09/* XON kludge counter */
X`09
X`09d = 0;`09`09`09`09`09/* preset destination index */
X`09col = 0;`09`09`09`09/* preset column */
X
X`09for (i = 0; i < rsz; i++) `7B
X`09`09if (ibuf`5Bi`5D == 9) `09`09`7B`09/* if tab */
X`09`09`09if (d == 0) obuf`5Bd++`5D = '(';/* if first */
X`09`09`09do `7B
X`09`09`09`09obuf`5Bd++`5D = ' ';`09/* fill spaces */
X`09`09`09`09col++;
X`09`09`09`7D while (col & 7);
X`09`09`7D
X`09`09else if (ibuf`5Bi`5D == 8 && col > 0) `7B`09/* if backspace */
X`09`09`09obuf`5Bd++`5D = 8;`09/* insert backspace */
X`09`09`09col--;
X`09`09`7D
X`09`09else if (ibuf`5Bi`5D == '(') `7B`09/* ( */
X`09`09`09if (d == 0) obuf`5Bd++`5D = '(';/* if first */
X`09`09`09obuf`5Bd++`5D = '\\';
X`09`09`09obuf`5Bd++`5D = '(';
X`09`09`09col++;
X`09`09`7D
X`09`09else if (ibuf`5Bi`5D == ')') `7B`09/* ) */
X`09`09`09if (d == 0) obuf`5Bd++`5D = '(';/* if first */
X`09`09`09obuf`5Bd++`5D = '\\';
X`09`09`09obuf`5Bd++`5D = ')';
X`09`09`09col++;
X`09`09`7D
X`09`09else if (ibuf`5Bi`5D == '\\') `7B`09/* \ */
X`09`09`09if (d == 0) obuf`5Bd++`5D = '(';/* if first */
X`09`09`09obuf`5Bd++`5D = '\\';
X`09`09`09obuf`5Bd++`5D = '\\';
X`09`09`09col++;
X`09`09`7D
X`09`09else if (ibuf`5Bi`5D == 0x0d) `7B /* CR */
X`09`09`09if (d) `7B`09`09/* if string to terminate */
X`09`09`09`09WRITELASERBUF(obuf,d)
X`09`09`09`09if (++popcount == 20) `7B
X`09`09`09`09`09popcount = 0;
X`09`09`09`09`09WRITELASER(")XSTR()pop\r\n",12)
X`09`09`09`09`7D
X`09`09`09`09else `7B
X`09`09`09`09`09WRITELASER(")XSTR\r\n",7)
X`09`09`09`09`7D
X`09`09`09`09d = 0;
X`09`09`09`7D
X`09`09`09WRITELASER("XCR\r\n",5)
X`09`09`7D
X `09`09else if (ibuf`5Bi`5D == 0x0a) `7B /* LF */
X`09`09`09if (d) `7B`09`09/* if string to terminate */
X`09`09`09`09WRITELASERBUF(obuf,d)
X`09`09`09`09if (++popcount == 20) `7B
X`09`09`09`09`09popcount = 0;
X`09`09`09`09`09WRITELASER(")XSTR()pop\r\n",12)
X`09`09`09`09`7D
X`09`09`09`09else `7B
X`09`09`09`09`09WRITELASER(")XSTR\r\n",7)
X`09`09`09`09`7D
X`09`09`09`09d = 0;
X`09`09`09`7D
X`09`09`09WRITELASER("XLF\r\n",5)
X`09`09`7D
X `09`09else if (ibuf`5Bi`5D == 0x0c) `7B /* FF */
X`09`09`09if (d) `7B`09`09/* if string to terminate */
X`09`09`09`09WRITELASERBUF(obuf,d)
X`09`09`09`09if (++popcount == 20) `7B
X`09`09`09`09`09popcount = 0;
X`09`09`09`09`09WRITELASER(")XSTR()pop\r\n",12)
X`09`09`09`09`7D
X`09`09`09`09else `7B
X`09`09`09`09`09WRITELASER(")XSTR\r\n",7)
X`09`09`09`09`7D
X`09`09`09`09d = 0;
X`09`09`09`7D
X`09`09`09WRITELASER("XFF\r\n",5)
X`09`09`7D
X`09`09else `7B
X`09`09`09if (d == 0) obuf`5Bd++`5D = '(';/* if first */
X`09`09`09obuf`5Bd++`5D = ibuf`5Bi`5D;`09/* move char */
X`09`09`09col++;
X`09`09`7D
X`09`7D
X`09if (d) `7B
X`09`09obuf`5Bd++`5D = ')';
X`09`09obuf`5Bd++`5D = 'X';
X`09`09obuf`5Bd++`5D = 'S';
X`09`09obuf`5Bd++`5D = 'T';
X`09`09obuf`5Bd++`5D = 'R';
X`09`09obuf`5Bd++`5D = '\r';
X`09`09obuf`5Bd++`5D = '\n';
X`09`7D
X`09WRITELASERBUF(obuf,d)
X`7D
X
X
X/**`09getitems - get item list from job controller.
X*/
Xgetitems()
X`7B
X`09int stat;
X`09int`09context;`09`09`09/* read_message_item context */
X`09int`09item_code;`09`09`09/* item code */
X`09unsigned short item_size;`09`09/* item size */
X`09struct dsc$descriptor_d item_buffer =
X`09`09`09`09`7B0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`7D;
X
X`09context = 0;`09`09`09`09/* init context */
X
X/*  Save each item in a list */
X`09
X`09do `7B
X`09`09item_buffer.dsc$a_pointer = 0;`09/* force d string allocation */
X
X`09`09stat = smb$read_message_item(&buffer_des, &context,
X`09`09&item_code, &item_buffer, &item_size);
X
X`09`09item`5Bii`5D.item_code = item_code;
X`09`09item`5Bii`5D.item_size = item_size;
X`09`09item`5Bii`5D.buffer = item_buffer.dsc$a_pointer;
X`09`09if (++ii > MAXITEMS) exit(LASER$_MAXITEMS);
X`09`7D while (stat == SS$_NORMAL);
X`7D
X
X
X/**`09getitemdescrip - return item descriptor.
X*
X*`09return:`09TRUE if item found
X*`09`09FALSE if (item not found) && NOT FATAL
X*`09`09exit if (item not found) && FATAL
X*/
Xgetitemdescrip(code, descrip, fatal)
Xint code;`09`09`09`09`09/* item code to search for */
Xstruct dsc$descriptor_s *descrip;`09`09/* pointer to descriptor */
Xint fatal;`09`09`09`09`09/* error severity */
X`7B
X`09int`09i;
X
X`09for (i = 0; i < ii; i++) `7B
X`09`09if (item`5Bi`5D.item_code == code) `7B`09/* if found */
X`09`09`09descrip->dsc$w_length = item`5Bi`5D.item_size;
X`09`09`09descrip->dsc$a_pointer = item`5Bi`5D.buffer;
X`09`09`09return TRUE;
X`09`09`7D
X`09`7D
X`09if (fatal) exit(LASER$_ITEMNOTFOUND);`09/* item not in list */
X`09else return FALSE;
X`7D
X
X
X/**`09getcopies - send copy count to laserwriter.
X*
X*`09Leave this here for now, but unfortunately, if you specify
X*`09/copies=n to the print command, the job contoller sends
X*`09the file that many times.  Not what we want.
X*/
Xgetcopies()
X`7B
X`09int stat, n;
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09char defcopy`5B80`5D;
X
X`09if (!getitemdescrip(SMBMSG$K_FILE_COPIES, &temp, FALSE))
X`09`09if (!getitemdescrip(SMBMSG$K_JOB_COPIES, &temp, FALSE))
X`09`09`09return;`09`09`09/* if no copies */
X
X`09n = * (long*) temp.dsc$a_pointer;
X`09if (n == 1) return;`09`09`09/* if only 1 copy */
X`09sprintf(defcopy, "/#copies %d def\r\n", n);
X
X`09WRITELASER(defcopy,strlen(defcopy))
X`7D
X
X
X/**`09getnote - get /note=<Text> to laserwriter.
X*/
Xgetnote()
X`7B
X`09int stat;
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09
X`09if (!getitemdescrip(SMBMSG$K_NOTE, &temp, FALSE)) return; /* none */
X   `20
X/*
X* KLUDGE ALERT: Multinet LPD puts a /note on its jobs.
X*               Don't send it to the printer.
X*/
X`09if (strncmp(temp.dsc$a_pointer, "Remote LPD request", 18)==0)
X`09`09return;
X`09
X`09WRITELASER(temp.dsc$a_pointer,temp.dsc$w_length)
X`09WRITELASER(&0x0A0D,2)`09`09`09/* cr-lf */
X`7D
X
X
X/**`09getparams - get user parameters.
X*/
Xgetparams()
X`7B
X`09int stat;
X`09int i, j, ctl;
X`09int first=TRUE,startend=FALSE,border=TRUE;
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09char param`5B255`5D, str`5B255+15`5D, *eq, start`5B8`5D,end`5B8`5D,num`5B
V6`5D;
X`09static $DESCRIPTOR(number_up, "NUMBER_UP");
X`09static $DESCRIPTOR(start_end, "STARTEND");
X`09static $DESCRIPTOR(sides, "SIDES");
X`09static $DESCRIPTOR(parser,"PARSER");
X
X`09for (i = 0; i < 8; i++) `7B`09`09/* loop for 8  parameters */
X`09`09if (!getitemdescrip(SMBMSG$K_PARAMETER_1+i, &temp, FALSE))
X`09`09`09continue;`09`09/* if no parameter */
X
X`09`09if (temp.dsc$w_length == 0) continue;`09/* if null string */
X
X`09`09strncpy(param, temp.dsc$a_pointer, temp.dsc$w_length);
X`09`09param`5Btemp.dsc$w_length`5D = 0;
X`09`09
X                eq = strchr(param, '=');
X                if (eq && !strncmp(param,"DATA_TYPE",(int)eq-(int)param)) `7
VB
X                        *eq++;
X                        if (!strncmp(eq,"TEK4014",strlen(eq))) `7B
X                        `09tek = TRUE;
X                                ascii = FALSE;
X                        `7D else if (!strncmp(eq,"ANSI",strlen(eq)) `7C`7C`2
V0
X`09`09`09`09 !strncmp(eq,"ASCII",strlen(eq))) `7B
X                                ansi = TRUE;
X                        `7D else if (!strncmp(eq,"PS",strlen(eq)) `7C`7C`20
X`09`09`09`09 !strncmp(eq,"POSTSCRIPT",strlen(eq))) `7B
X                                ps = TRUE;
X                        `7D else `7B
X`09`09`09`09stop_reason = LASER$_INVPARAM;
X`09`09`09`09return FALSE;
X`09`09`09`7D
X                `7D else if (eq &&
X`09`09`09!strncmp(param,"PAGE_ORIENTATION",(int)eq-(int)param)) `7B
X                        *eq++;
X                        if (!strncmp(eq,"LANDSCAPE",strlen(eq))) `7B
X                                land = TRUE;
X                                port = FALSE;
X                        `7D else if (!strncmp(eq,"PORTRAIT",strlen(eq))) `7B
X                                land = FALSE;
X                                port = TRUE;
X                        `7D else `7B
X`09`09`09`09stop_reason = LASER$_INVPARAM;
X`09`09`09`09return FALSE;
X`09`09`09`7D
X                `7D else if (eq &&
X`09`09`09!strncmp(param,"SIDES",(int)eq-(int)param)) `7B
X                        *eq++;
X                        if (!strncmp(eq,"2",strlen(eq)) `7C`7C`20
X`09`09`09    !strncmp(eq,"TWO",strlen(eq)) `7C`7C`20
X`09`09`09    !strncmp(eq,"TWO_SIDED_DUPLEX",strlen(eq))) `7B
X                                WRITESTRING("false true\r\n")
X                        `7D else if (!strncmp(eq,"TUMBLE",strlen(eq)) `7C`7C
V`20
X`09`09`09   `09   !strncmp(eq,"TWO_SIDED_TUMBLE",strlen(eq))) `7B
X                                WRITESTRING("true true\r\n")
X                        `7D else `7B
X`09`09`09`09stop_reason = LASER$_INVPARAM;
X`09`09`09`09return FALSE;
X`09`09`09`7D
X `09`09`09if (!writemodule(sides)) `7B
X`09`09`09`09stop_reason = LASER$_SETUPNOTFOUND;
X`09`09`09`09return FALSE;
X`09`09`09`7D
X`09`09`7D else if (eq &&
X`09`09`09!strncmp(param,"PAGE_LIMIT",(int)eq-(int)param)) `7B
X`09`09`09int i = 0;
X`09`09`09startend = TRUE;
X                        *eq++;
X`09`09`09if (*eq == '(') *eq++;
X`09`09`09while (i < 5 && isdigit(*eq)) start`5Bi++`5D = *eq++;
X`09`09`09if (*eq++ != ',') `7B
X`09`09`09`09strncpy(end,start,i);
X`09`09`09`09strncpy(start,"1\r\n\000",4);
X`09`09`09`7D else `7B
X`09`09`09`09strncpy(&start`5Bi`5D,"\r\n\000",3);
X`09`09`09`09i = 0;
X`09`09`09`09while (i < 5 && isdigit(*eq)) end`5Bi++`5D = *eq++;
X`09`09`09`7D
X`09`09`09if (!i)`20
X`09`09`09`09strncpy(end,"10000\r\n\000",8);
X`09`09`09else
X                                strncpy(&end`5Bi`5D,"\r\n\000",3);`20
X`09`09`7D else if (eq &&
X`09`09`09!strncmp(param,"LW",(int)eq-(int)param)) `7B
X                        *eq++;
X`09`09`09WRITESTRING("/lw ")
X`09`09`09WRITESTRING(eq)
X`09`09`09WRITESTRING(" def\r\n")
X                `7D else if (eq &&
X`09`09`09!strncmp(param,"NUMBER_UP",(int)eq-(int)param)) `7B
X`09`09`09int i = 0;
X`09`09`09nup = TRUE;
X                        *eq++;
X`09`09`09if (*eq == '(') *eq++;
X`09`09`09while (i < 3 && isdigit(*eq)) num`5Bi++`5D = *eq++;
X`09`09`09if (!i) num`5Bi++`5D = '1';
X                        strncpy(&num`5Bi`5D,"\r\n\000",3);`20
X                `7D else if (!strncmp(param,"BORDER",strlen(param))) `7B
X`09`09`09border = TRUE;
X                `7D else if (eq &&
X`09`09`09!strncmp(param,"BORDER",(int)eq-(int)param)) `7B
X                        *eq++;
X`09`09`09if (!strncmp(eq,"NONE",strlen(eq)))
X`09`09`09`09border = FALSE;
X                        else `7B
X                                stop_reason = LASER$_INVPARAM;
X                                return FALSE;
X                        `7D
X                `7D else if (eq &&
X`09`09`09!strncmp(param,"MESSAGES",(int)eq-(int)param)) `7B
X                        *eq++;
X                        if (!strncmp(eq,"KEEP",strlen(eq)))`20
X`09`09`09`09openuserlog();`09`09/* open user log file */
X                        else `7B
X                                stop_reason = LASER$_INVPARAM;
X                                return FALSE;
X                        `7D
X`09`09`7D
X`09`7D
X
X`09for (i = 0; i < 8; i++) `7B`09`09/* loop for 8  parameters */
X`09`09if (!getitemdescrip(SMBMSG$K_PARAMETER_1+i, &temp, FALSE))
X`09`09`09continue;`09`09/* if no parameter */
X
X`09`09if (temp.dsc$w_length == 0) continue;`09/* if null string */
X
X`09`09strncpy(param, temp.dsc$a_pointer, temp.dsc$w_length);
X`09`09param`5Btemp.dsc$w_length`5D = 0;
X`09`09
X`09`09eq = strchr(param, '=');
X`09`09if (!eq) eq = strchr(param, '\000');
X                if (!strncmp(param,"DATA_TYPE",(int)eq-(int)param)
X `09`09 `7C`7C !strncmp(param,"LW",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"PAGE_ORIENTATION",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"SIDES",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"PAGE_LIMIT",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"NUMBER_UP",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"BORDER",(int)eq-(int)param)
X`09`09 `7C`7C !strncmp(param,"MESSAGES",(int)eq-(int)param)) `7B
X`09`09`7D else `7B
X`09`09`09if (first) `7B`09`09`09/* if first one */
X`09`09`09`09first = FALSE;
X`09`09`09`09WRITELASER("/params `5B\r\n",11)
X`09`09`09`7D
X
X`09`09`09for (j= 0; (j < strlen(param)) && (param`5Bj`5D != '(');
X`09`09`09`09 j++) `7B`09/* lowercase string */
X`09`09`09`09if (isupper(param`5Bj`5D)) param`5Bj`5D `5E= 0x20;
X`09`09`09`7D      `20
X`09`09
X/*  if there is an = separator (or - for spooled files), use it */
X`09`09
X`09`09`09if ((eq = strchr(param, '='))
X`09`09`09`09`7C`7C (eq = strchr(param, '-'))
X`09`09`09`09`7C`7C (eq = strchr(param, ':'))) `7B
X`09`09`09`09*eq++ = 0;`09`09/* bust string in 2 */
X`09`09`09`09sprintf(str, "(%s) %s\r\n", param, eq);
X`09`09`09`7D
X`09`09`09else sprintf(str, "(param%d) %s\r\n", i+1, param);
X
X`09`09`09WRITELASER(str,strlen(str))
X`09`09`7D
X`09`7D
X       `20
X        getitemdescrip(SMBMSG$K_PRINT_CONTROL, &temp, TRUE);
X        ctl = * (long*) temp.dsc$a_pointer;
X
X`09if (ctl & SMBMSG$M_PAGE_HEADER) `7B
X`09`09if (first) `7B`09`09`09`09/* if first one */
X`09`09`09first = FALSE;
X`09`09`09WRITELASER("/params `5B\r\n",11)
X`09`09`7D
X
X`09`09WRITESTRING("(title) true\r\n")
X`09`7D
X`09
X`09if (!first) `7B`09`09`09`09/* if some params found */
X`09`09WRITELASER("`5D def\r\n",7)
X`09`09writemodule(parser);`09`09/* write the parser module */
X`09`7D
X
X`09if (nup) `7B
X`09`09if (!writemodule(number_up)) `7B
X`09`09`09stop_reason = LASER$_SETUPNOTFOUND;
X`09`09`09return FALSE;
X`09`09`7D
X`09`09WRITELASER(num,strlen(num))
X`09`09WRITELASER("false\r\n",7)  /* true to transpose row/col order */
X`09`09if (port)
X`09       `09`09WRITELASER("false\r\n",7)
X`09`09else
X`09       `09`09WRITELASER("true\r\n",6)
X`09       `09WRITELASER("false\r\n",7)  /* true for Mac landscape */
X`09       `09WRITELASER("false\r\n",7)  /* true to disable clipping */
X`09`09if (border)`20
X`09       `09`09WRITELASER("0\r\n",3)
X`09`09else
X`09       `09`09WRITELASER("-1\r\n",4)
X`09`09if (startend) `7B
X`09`09       `09WRITELASER(start,strlen(start))
X`09`09       `09WRITELASER(end,strlen(end))
X`09`09`7D else `7B
X`09`09`09WRITELASER("1\r\n",3)
X`09`09`09WRITELASER("10000\r\n",7)
X`09`09`7D
X`09`09WRITELASER("DMM-nup-pre\r\n",13)
X        `7D else if (startend) `7B
X`09`09WRITELASER(start,strlen(start))
X`09`09WRITELASER(end,strlen(end))
X`09`09if (!writemodule(start_end)) `7B
X`09`09`09stop_reason = LASER$_SETUPNOTFOUND;
X`09`09`09return FALSE;
X`09`09`7D
X`09`7D
X
X`09return TRUE;
X`7D
X
X
X/**`09getsetup - get setup module to laserwriter.
X*
X*`09return:`09TRUE if no problems with setup module.
X*`09        FALSE if setup module nonexistant
X*/
Xgetsetup()
X`7B
X`09int stat, len;
X`09int library_index;
X`09long txtrfa`5B2`5D;
X`09char inbuf`5B255`5D;
X`09struct dsc$descriptor_s inbufdes = `7Bsizeof(inbuf), DSC$K_DTYPE_T, DSC$K
V_CLASS_S, inbuf`7D;
X`09struct dsc$descriptor_s outbufdes;
X`09struct dsc$descriptor_s key = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X`09struct dsc$descriptor_s temp = `7B0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`7D;
X
X/*  Try for a file setup module first, then a form setup module.  For now,
X    we only support one setup module, the first found. We should support
X    lists of setup modules, and all found. */
X`09
X`09if (!getitemdescrip(SMBMSG$K_FILE_SETUP_MODULES, &key, FALSE))
X`09`09if (!getitemdescrip(SMBMSG$K_FORM_SETUP_MODULES, &key, FALSE))
X`09`09`09return TRUE;`09`09/* if no setup */
X
X`09if (key.dsc$w_length == 0) return TRUE;`09/* if no setup */
X`09
X`09if (!getparams()) return FALSE;`09`09/* get user parameters */
X
X`09if (ps) return TRUE;
X
X/*  Get out if no library. Error because the user specified a setup. */
X
X`09if (library_spec.dsc$a_pointer == 0) `7B
+-+-+-+-+-+-+-+-  END  OF PART 2 +-+-+-+-+-+-+-+-