earleh@dartvax.UUCP (Earle R. Horton) (10/05/87)
[Serial Printing desk accessory source] This is the source for a desk accessory I wrote to get letter-quality printing from my Mac without buying a LaserWriter. I wrote it to be as general as possible. I wanted to have: User-selectable strings for initializing the printer, etc. Variable left margins and page length. Support of either sheet feed or continuous feed. A bunch of communications port options. Compatible with 64k ROMs (God knows why). Expands tabs, or not, as required. Prints text only files with carriage return at end of each line. Most important: work on as many different printer types as possible. I have posted the binhex'd DA to comp.binaries.mac. These are the sources. The DA worked with my Tandy DMP-110 and with my Silver-Reed Penman Deluxe with the I/F40 Serial Interface. I tried a bunch of baud rates, and both CTS and ^S^Q flow control. I regret that I didn't support ^S^Q flow control for 64k ROMs, but you never can tell whether the RAM serial driver is going to be present... It seemed to work with all the printer settings I threw at it, so I posted the binhex, and here are the sources. The comments are kinda skimpy, but I believe I have used enough meaningful variable names to compensate. Even if you see no need for the desk accessory since your boss just got a LaserWriter or whatever, you might be able to glean some programming tips from this code. How to send junk out the serial port, how to push radio buttons, how to manipulate STR# resources in memory, how to highlite the "OK" button when using ModalDialog() instead of Alert(). You might even see some huge bugs, and then be able to flame me in next week's comp.sys.mac (or whatever they want to call it next week). If you want, you can flame me for not writing a Chooser-compatible printer driver instead of this. (Make my day.) The system I used was LSC and RMaker. Code may differ for other systems. -- ********************************************************************* *Earle R. Horton, H.B. 8000, Dartmouth College, Hanover, NH 03755 * ********************************************************************* --- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # SerialPrint.c # SerialPrint.rsrc sed 's/^X//' << 'SHAR_EOF' > SerialPrint.c X/* X * SerialPrint.c. A generic serial printer driver in desk accessory X * form for the Macintosh. X * Earle R. Horton. August 17, 1987 X * LightspeedC source. X * To use, build a project with this file and MacTraps in it. X * Set the project type to Desk Accessory. Build the desk accessory. X * Run RMaker to put the owned resources in the suitcase file. X * Do not attempt to "Run" from within LightspeedC. The use of owned X * resources presents problems here. X */ X#include <DeviceMgr.h> X#include <WindowMgr.h> /* includes QuickDraw.h, MacTypes.h */ X#include <EventMgr.h> X#include <MenuMgr.h> X#include <FileMgr.h> X#include <DialogMgr.h> X#include <SerialDvr.h> X#include <StdFilePkg.h> X#include <ControlMgr.h> X X# define nil 0L X X/* global variables and macros to use them */ Xtypedef struct{ X int dummy[9]; X} pconfig,*Pcfg,**Pfg; XPfg settings = nil; X/* Be a real Mac cowboy, access data by the handle. */ X#define pport ((*settings)->dummy[0]) X#define pbaud ((*settings)->dummy[1]) X#define sheetfeed ((*settings)->dummy[2]) X#define tabstops ((*settings)->dummy[3]) X#define width ((*settings)->dummy[4]) X#define margin ((*settings)->dummy[5]) X#define pagelength ((*settings)->dummy[6]) X#define XonXoff ((*settings)->dummy[7]) X#define SDClose ((*settings)->dummy[8]) X/* Yeeeeee-Hah !! I won't even lock it! */ Xtypedef struct bauds{ X int rate; X char label[10]; X}BAUDS; XBAUDS mybauds[] = { /* Baud rate constant table. */ X { baud300, "\p300"}, /* Should use a string list. */ X { baud600, "\p600"}, /* But these are numbers, so I */ X { baud1200, "\p1200"}, /* Think it's OK. */ X { baud1800, "\p1800"}, X { baud2400, "\p2400"}, X { baud3600, "\p3600"}, X { baud4800, "\p4800"}, X { baud7200, "\p7200"}, X { baud9600, "\p9600"}, X { baud19200, "\p19200"} X}; Xtypedef struct { /* Structure description of STR# */ X int numstrings; /* resource. */ X unsigned char thestrings[]; X}stringlist,**StrList; XStrList mystrings = nil; XPoint where = {80,80}; XSFTypeList mytypelist = {'TEXT'}; XParamBlockRec iopb; XParamBlockRec filepb; Xchar _iobuf[522]; Xint ResID; Xstatic int phone = FALSE; Xstatic int printer = FALSE; Xstatic MenuHandle MHandl; Xstatic CHANGE1 = FALSE; Xstatic CHANGE2 = FALSE; Xstatic int rom,machine; X X/* Useful constants */ X#define OWNED_BASE -16384 X#define BAUDLABEL 8 /* Item numbers of configuration box. */ X#define BAUDBUTTON 9 X#define DONEITEM 1 X#define STOPITEM 2 X#define MODEM 5 X#define PRINTER 6 X X/* Menu item numbers */ X#define ABOUTITEM 1 X#define SETITEM 2 X#define PAGEITEM 3 X#define FLOWITEM 4 X#define PRINTITEM 5 X#define SAVEITEM 6 X#define QUITITEM 7 X/* Printer setup editText Item numbers */ X X#define TABSITEM 5 X#define WIDTHITEM 6 X#define MARGINITEM 7 X#define LINESITEM 8 X X#define EOLITEM 11 X#define INITITEM 12 X#define TOPITEM 13 X#define EOPITEM 14 X#define EOFITEM 15 X#define SHEETITEM 19 X#define CONTINUOUSITEM 20 X#define NUMSTRINGS 5 X#define RESPAD 24 X X#define SERRESET 8 /* csCodes for PBControl */ X#define SERSHAKE 10 X X#define FLOWBOX (ResID + 4) /* Should have done all like this */ X /* forgot... */ X#define XONCR ((char)17) X#define XOFFCR ((char)19) X X Xmain(p, d, n) XcntrlParam *p; /* ==> parameter block */ XDCtlPtr d; /* ==> device control entry */ Xint n; /* entry point selector */ X X{ X X /* check to make sure our data area was allocated */ X X if (d->dCtlStorage == 0) X { X if (n == 0) /* open */ X CloseDriver(d->dCtlRefNum); X } X else switch (n) /* dispatch */ X { X case 0: /* open */ X ResID = (~d->dCtlRefNum)<<5 | OWNED_BASE; X d->dCtlMenu = ResID; X MHandl = GetMenu(ResID); X if(MHandl == nil){ X CloseDriver(d->dCtlRefNum); X return(0); X } X InsertMenu(MHandl,0); X DrawMenuBar(); X if ((settings = (Pfg)(GetResource('Stng',ResID))) == nil || X (mystrings = (StrList)(GetResource('STR#',ResID))) == nil){ X CloseDriver(d->dCtlRefNum); X return(0); X } X LoadResource(settings); X HNoPurge(settings); X LoadResource(mystrings); X HNoPurge(mystrings); X HLock(mystrings); X Environs(&rom,&machine); X if(rom < 117){ /* If < 512KE, no XOn/XOff */ X SDClose = FALSE; X XonXoff = FALSE; X } X break; X X case 2: /* control */ X switch (p->csCode){ X case accMenu: X switch (p->csParam[1]){ X case ABOUTITEM: X DoAbout(); X break; X case SETITEM: X if(!prsetup()) X CloseDriver(d->dCtlRefNum); X break; X case PAGEITEM: X if(!pagesetup()) X CloseDriver(d->dCtlRefNum); X break; X case FLOWITEM: X moresettings(); X break; X case PRINTITEM: X ffprint(); X break; X case SAVEITEM: X if(CHANGE1){ X ChangedResource(settings); X } X if(CHANGE2){ X ChangedResource(mystrings); X } X if(CHANGE1 || CHANGE2) X UpdateResFile(HomeResFile(settings)); X break; X case QUITITEM: X CloseDriver(d->dCtlRefNum); X break; X } X break; X } X break; X case 4: /* close */ X quit(); X break; X } X X /* done */ X X return(0); X} Xquit() X{ X if(MHandl != nil){ X DeleteMenu(ResID); X ReleaseResource(MHandl); X DrawMenuBar(); X MHandl = nil; X } X if(SDClose){ X if(printer)RAMSDClose(sPortA); X if(phone)RAMSDClose(sPortB); X } X if (settings != nil) { /* We don't want to leave our junk laying */ X HPurge(settings); /* around... */ X ReleaseResource(settings); X settings = nil; X } X if (mystrings != nil) { X ReleaseResource(mystrings); X mystrings = nil; X } X} Xpushradiobutton(thedialog,itemhit,first,last) /* push a radio Button */ XDialogPtr thedialog; /* set itemhit, unset */ Xint itemhit,first,last; /* all others in range */ X{ X int itemtype,i; X Handle itemhandle; /* Does check boxes, too. */ X Rect itemrect; X ControlHandle itemcntlhand; X if(first ==0) return; X for(i=first-1;last-i++;){ X GetDItem(thedialog,i,&itemtype,&itemhandle,&itemrect); X itemcntlhand = (ControlHandle)itemhandle; X if(i == itemhit) SetCtlValue(itemcntlhand,1); X else SetCtlValue(itemcntlhand,0); X } X} Xpagesetup() /* Derive left margin, tab stops, page length */ X{ /* and number columns. */ XDialogPtr pagedialog; XWindowPtr tempport; Xint itemhit,i,numtype,donetype; XHandle numitem,doneitem; XRect numbox,donebox; XStr255 numtext; Xlong temp; X if((pagedialog = GetNewDialog(ResID+1, 0L,(WindowPtr) -1)) == nil) X return FALSE; X GetDItem(pagedialog,DONEITEM,&donetype,&doneitem,&donebox); X for(i = TABSITEM - 1;LINESITEM - i++;){ X GetDItem(pagedialog,i,&numtype,&numitem,&numbox); X NumToString((long)((*settings)->dummy[i-2]),numtext); X SetIText(numitem,numtext); X } X GetPort(&tempport); X SetPort(pagedialog); X PenSize(3,3); X InsetRect(&donebox,-4,-4); X FrameRoundRect(&donebox,16,16); X itemhit = 0; X while(itemhit != DONEITEM){ X ModalDialog(0L,&itemhit); X switch(itemhit){ X default: X break; X } X } X for(i = TABSITEM - 1;LINESITEM - i++;){ X GetDItem(pagedialog,i,&numtype,&numitem,&numbox); X GetIText(numitem,numtext); X StringToNum(numtext,&temp); X (*settings)->dummy[i-2] = (int)temp; X } X DisposDialog(pagedialog); X SetPort(tempport); X CHANGE1 = TRUE; X return(TRUE); X} X#define XONXOFF 2 X#define CTS 3 X#define SDCLOSE 4 Xmoresettings() /* If 64k ROM or XL, show dialog, do nothing. */ X{ XDialogPtr flowdialog; XWindowPtr tempport; Xint itemhit,donetype; XHandle doneitem; XRect donebox; X if((flowdialog = GetNewDialog(FLOWBOX,0L,(WindowPtr) -1)) == nil) X return FALSE; X GetDItem(flowdialog,DONEITEM,&donetype,&doneitem,&donebox); X GetPort(&tempport); X SetPort(flowdialog); X PenSize(3,3); X InsetRect(&donebox,-4,-4); X FrameRoundRect(&donebox,16,16); X if (SDClose) X pushradiobutton(flowdialog, SDCLOSE,SDCLOSE,SDCLOSE); X else X pushradiobutton(flowdialog,0,SDCLOSE,SDCLOSE); X if (XonXoff) X pushradiobutton(flowdialog,XONXOFF,XONXOFF,CTS); X else X pushradiobutton(flowdialog,CTS,XONXOFF,CTS); X itemhit = 0; X while(itemhit != DONEITEM){ X ModalDialog(0L,&itemhit); X if( rom >= 117){ /* If ROM version < 117, forget this. */ X switch(itemhit){ X case XONXOFF: X XonXoff = TRUE; X pushradiobutton(flowdialog, itemhit,XONXOFF,CTS); X break; X case CTS: X XonXoff = FALSE; X pushradiobutton(flowdialog, itemhit,XONXOFF,CTS); X break; X case SDCLOSE: X SDClose = !SDClose; X if (SDClose) X pushradiobutton(flowdialog, X SDCLOSE,SDCLOSE,SDCLOSE); X else X pushradiobutton(flowdialog,0,SDCLOSE,SDCLOSE); X break; X } X } X } X CHANGE1 = TRUE; X DisposDialog(flowdialog); X SetPort(tempport); X return TRUE; X} X X /* This one enquires for and sets the printer variables. X * Radio buttons (cute) are used. X */ Xprsetup() X{ XDialogPtr printdialog; XWindowPtr tempport; Xint itemhit,i,baudtype,edittype,donetype; XHandle bauditem,doneitem,edititem; XRect baudbox,donebox,editbox; XStr255 thestring; Xunsigned char *strptr; Xlong length; X if (pbaud<0 || pbaud>9) pbaud = 0; X if((printdialog = GetNewDialog(ResID, 0L,(WindowPtr) -1)) == nil) X return FALSE; X GetDItem(printdialog,BAUDLABEL,&baudtype,&bauditem,&baudbox); X GetDItem(printdialog,DONEITEM,&donetype,&doneitem,&donebox); X SetIText(bauditem,mybauds[pbaud].label); X/* This gets the editText items in the dialog box to contain X * the strings from one of our string lists. X */ X strptr = &((*mystrings)->thestrings[0]); X for(i = EOLITEM-1;EOFITEM - i++;){ X GetDItem(printdialog,i,&edittype,&edititem,&editbox); X SetIText(edititem,strptr); X strptr += (*strptr) + 1; X } X GetPort(&tempport); X SetPort(printdialog); X PenSize(3,3); X InsetRect(&donebox,-4,-4); X FrameRoundRect(&donebox,16,16); X pushradiobutton(printdialog, pport+5,5,6); X pushradiobutton(printdialog,SHEETITEM + sheetfeed,SHEETITEM, X CONTINUOUSITEM); X itemhit = 0; X while(itemhit != DONEITEM){ X ModalDialog(0L,&itemhit); X switch(itemhit){ X case MODEM: /* port change. */ X case PRINTER: X pport = itemhit - MODEM; X pushradiobutton(printdialog,itemhit, X MODEM,PRINTER); X break; X case BAUDBUTTON: /* next baud rate change */ X /* Ten radio buttons would be just too much. */ X if(++pbaud == 10) pbaud = 0; X SetIText(bauditem,mybauds[pbaud].label); X break; X case SHEETITEM: /* feed options */ X case CONTINUOUSITEM: X sheetfeed = itemhit - SHEETITEM; X pushradiobutton(printdialog, X itemhit,SHEETITEM,CONTINUOUSITEM); X break; X } X } X /* The user has set the baud rate and the port, and also possibly X * edited the printer control strings. Since we used ModalDialog() X * with no filterproc we don't know whether any of the strings have X * been changed. Therefore we just rebuild the whole string list. X * First, determine the length. X */ X length = (long) (sizeof(int)+RESPAD); X /* Try doing this with RESPAD = 0! */ X for(i = EOLITEM-1;EOFITEM - i++;){ X GetDItem(printdialog,i,&edittype,&edititem,&editbox); X GetIText(edititem,thestring); X length += (long) thestring[0]; X } X /* Size might have changed, so we unlock the handle and attempt to X * resize it. Should work, unless no RAM left. */ X HUnlock(mystrings); X SetHandleSize(mystrings,length); X if (GetHandleSize(mystrings)!=length){ /* Abort on error. */ X DisposDialog(printdialog); X SetPort(tempport); X return(FALSE); X } X HNoPurge(mystrings); X HLock(mystrings); X /* Rebuild the STR# from the item list. */ X strptr = &((*mystrings)->thestrings[0]); X for(i = EOLITEM-1;EOFITEM - i++;){ X GetDItem(printdialog,i,&edittype,&edititem,&editbox); X GetIText(edititem,strptr); X strptr += (*strptr) + 1; X } X DisposDialog(printdialog); X SetPort(tempport); X CHANGE2 = CHANGE1 = TRUE; X return(TRUE); X} Xwaitnextpage() /* For sheet feeders. */ X{ XDialogPtr sheetdialog; XWindowPtr tempport; Xint itemhit,donetype; XHandle doneitem; XRect donebox; X if((sheetdialog = GetNewDialog(ResID+3, 0L,(WindowPtr) -1)) == nil) X return FALSE; X GetDItem(sheetdialog,DONEITEM,&donetype,&doneitem,&donebox); X GetPort(&tempport); X SetPort(sheetdialog); X PenSize(3,3); X InsetRect(&donebox,-4,-4); X FrameRoundRect(&donebox,16,16); X ModalDialog(0L,&itemhit); X DisposDialog(sheetdialog); X SetPort(tempport); X if(itemhit == STOPITEM) return FALSE; X return TRUE; X} X Xchar outbuf[200]; /* Or whatever size you think appropriate. */ Xchar inbuf[200]; Xffprint() X{ Xregister int nline,nchars,i,tab; Xregister ParmBlkPtr pb; Xchar c; Xint serconfig,drivernum,length,filefinished; XEventRecord myevent; Xlong count1; Xunsigned char *eolstr,*initstr,*topstr,*eopstr,*eofstr; X X pb = &iopb; X /* Get strings from string list. (Pascal strings) */ X eolstr = eofstr = &((*mystrings)->thestrings[0]); X initstr = (eofstr += (*eofstr) + 1); X topstr = (eofstr += (*eofstr) + 1); X eopstr = (eofstr += (*eofstr) + 1); X eofstr += (*eofstr) + 1; X X tab = tabstops - 1; X switch (pport){ /* get the correct port */ X case 0: /* modem port */ X if(!phone) { X prinit("\p.AOut"); X phone = TRUE; X if(rom >= 117)RAMSDOpen(sPortA); X } X drivernum = AoutRefNum; X break; X case 1: /* printer port */ X if(!printer) { X prinit("\p.BOut"); X printer = TRUE; X if(rom >= 117)RAMSDOpen(sPortB); X } X drivernum = BoutRefNum; X break; X } X /* set up the io parameter block for writing to the serial driver. */ X /* a control call resets the baud rate */ X pb->ioParam.ioRefNum = drivernum; X pb->ioParam.ioCompletion = nil; X ((cntrlParam *)pb)->csCode = SERRESET; X serconfig = data8 + noParity + stop20; X serconfig += mybauds[pbaud].rate; X ((cntrlParam*)pb)->csParam[0] = serconfig; X PBControl(pb,FALSE); X#define shake ((SerShk*)&((cntrlParam*)pb)->csParam[0]) X if(rom >= 117){ /* If ROM version < 117, forget this. */ X shake->errs = FALSE; X shake->evts = FALSE; X shake->fDTR = FALSE; X shake->fInX = FALSE; X if(XonXoff){ X shake->fXOn = TRUE; X shake->fCTS = FALSE; X shake->xOn = XONCR; X shake->xOff = XOFFCR; X } X else { X shake->fXOn = FALSE; X shake->fCTS = TRUE; X } X ((cntrlParam *)pb)->csCode = SERSHAKE; X PBControl(pb,FALSE); X } X#undef shake X pb->ioParam.ioPosMode = 0; X pb->ioParam.ioPosOffset = 0; X X for(nchars=0;margin-nchars;nchars++){ /* pad the sucker on the */ X outbuf[nchars] = ' '; /* left with margin spaces */ X } X X while(ffopen()){ X printstring(initstr); X filefinished = FALSE; X nline = 0; X while (!filefinished){ X if(nline == 0){ /* top of a page */ X printstring(topstr); X nline++; X } X else if (nline == pagelength + 2){ /* bottom */ X printstring(eopstr); X nline = 0; X if(sheetfeed == 0) { X if (waitnextpage() == FALSE) { X PBClose(&filepb,FALSE); X return; X } X } X } X else { /* body */ X if(!getline(inbuf,width,&length)) X filefinished = TRUE; X nchars = 0; X i = 0; X while( i <= width && nchars <= length){ X switch(c = inbuf[nchars++]){ X case 9: /* a tab */ X if (tab){ X do{ X outbuf[margin + i++] = ' '; X }while((i % tab)!=0); X } X else X outbuf[margin + i++]= c; X break; X default: X outbuf[margin + i++]= c; X break; X } X } X count1 = (long) (i + margin - 1); X nline++; /* count lines */ X /* check after every line for user abort */ X /* Admitted, less effective at high baud rates. */ X if (GetNextEvent(everyEvent, &myevent)) { X switch (myevent.what) { X case keyDown: X c = LoWord(myevent.message & charCodeMask); X if (myevent.modifiers & cmdKey) { X if( c == '.'){ X PBClose(&filepb,FALSE); X return; X } /* quit now */ X } X break; X default: X break; X } X } X /* write out the expanded line */ X /* to the proper device driver. */ X if(!filefinished){ X pb->ioParam.ioBuffer = outbuf; X pb->ioParam.ioReqCount = count1; X PBWrite(pb,FALSE); X printstring(eolstr); X } X } X } X PBClose(&filepb,FALSE); X printstring(eofstr); X } X} Xchar stringbuf[256]; X/* X * Used for interpreting the printer control codes. Not very efficient, X * since they are interpreted every time sent. X */ Xprintstring(string) Xunsigned char string[]; X{ X register unsigned int i; X long count; X count = 0L; X i = string[0]; X for(i=0;string[0]-i++;){ X switch (string[i]){ X case '^': X stringbuf[count] = 31 & string[++i]; X break; X default: X stringbuf[count] = string[i]; X break; X } X count++; X } X iopb.ioParam.ioBuffer = stringbuf; X iopb.ioParam.ioReqCount = count; X PBWrite(&iopb,FALSE); X} Xprinit(name) /* Open a driver by name. */ X /* ROM serial driver? RAM serial driver? Who cares? */ X /* Seriously, if ROM is 128k or newer, we do the RAM */ X /* serial driver open later. */ Xchar *name; X{ X iopb.ioParam.ioNamePtr = (StringPtr)name; X iopb.ioParam.ioCompletion = nil; X iopb.ioParam.ioPermssn = 0; X PBOpen(&iopb,FALSE); X} Xffopen () X{ Xstatic SFReply frommac; Xregister ParmBlkPtr pb; X Xpb = &filepb; X X SFGetFile (where, 0L, 0L, 1, mytypelist, 0L, &frommac); X if (frommac.good) { X pb->ioParam.ioNamePtr = frommac.fName; X pb->ioParam.ioCompletion = nil; X pb->ioParam.ioVersNum = 0; X pb->ioParam.ioMisc = _iobuf; X pb->ioParam.ioVRefNum = frommac.vRefNum; X pb->ioParam.ioPermssn = fsRdPerm; X pb->ioParam.ioPosMode = 3456; X PBOpen(pb,FALSE); X if(pb->ioParam.ioResult){ X return (FALSE); X } X else return (TRUE); X } X else return (FALSE); X} X/* X * Read a line from a file, and store the bytes in the supplied buffer. The X * "nbuf" is the length of the buffer. Return FALSE if no bytes read. X * filepb.ioParam.ioPosMode determines that we stop at the newline X * character, which is <cr>. Should possibly stop on error, but I X * think error implies no bytes read (?). X */ Xgetline(buf,nbuf,nbytes) Xregister char buf[]; Xint nbuf; Xint *nbytes; X{ Xregister int i; Xregister ParmBlkPtr pb; X Xpb = &filepb; X X pb->ioParam.ioPosMode = 3456; X /* This means reads stop at '\r', see IM for details. */ X pb->ioParam.ioBuffer = buf; X pb->ioParam.ioReqCount = (long)nbuf; X PBRead(pb,FALSE); X if ((i = (int)pb->ioParam.ioActCount) == 0){ X *nbytes = 0; X return (FALSE); X } X if(buf[i-1] == '\r') i--; /* strip CR */ X *nbytes = i; X return (TRUE); X} X/* X * DoAbout: X * X * Dialog box handler for extended about box. Put up a dialog X * box with help information. Cycle through a string list X * (STR# ID HLIST) to change the contents of a statText item. X * Help information is updated by changing the contents of the X * STR#, making things easier to localize. X */ X#define HDLOG ResID+2 X#define HLIST ResID+1 X#define HITEM 5 X#define MORE 1 X#define BACK 2 X#define ENOUGH 3 X#define int16 short XDoAbout() X{ Xint16 res,i,helptype,nlimit; XDialogPtr helpdialog; XWindowPtr tempport; XStr255 helpstring; XHandle helpitem,moreitem; XRect helpbox,morebox; Xint16 **stringlist; Xint16 moretype; X /* Prepare to use dialog box. */ X helpdialog = GetNewDialog(HDLOG,(long)0,(WindowPtr) -1); X GetDItem(helpdialog,HITEM,&helptype,&helpitem,&helpbox); X GetDItem(helpdialog,MORE,&moretype,&moreitem,&morebox); X GetPort(&tempport); X SetPort(helpdialog); X PenSize(3,3); X InsetRect(&morebox,-4,-4); X FrameRoundRect(&morebox,16,16); X /* How many strings? */ X stringlist = (int16 **)GetResource('STR#',HLIST); X if(stringlist == nil) return FALSE; X LoadResource(stringlist); X nlimit = (int16) **stringlist; X i = 0; X res = 1; X while(res != ENOUGH){ /* Done when quit button selected. */ X if (res == BACK) i--; /* Cycle back. */ X else i++; /* Cycle forwards. */ X if (i<1) i=nlimit; /* Choose < 1, use last string. */ X GetIndString(helpstring,HLIST,i); /* Get the string. */ X if(helpstring[0] == '\0'){ /* Out of range, last string. */ X i=1; /* Cycle back to first one. */ X GetIndString(helpstring,HLIST,i); /* Get it. */ X } X SetIText(helpitem,helpstring); /* Use it. */ X ModalDialog(0L,&res); /* ModalDialog handles events. */ X } X DisposDialog(helpdialog); /* Done, clean up. */ X SetPort(tempport); X ReleaseResource(stringlist); X return TRUE; X} X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > SerialPrint.rsrc X*Resource definition file for Device Dependent Printing Desk Accessory X X!LSC:SerialPrint:Serial XDFILDMOV X XType DITL XPrinter Dialog Template,-16000 X20 X X* 1 XBtnItem Enabled X224 143 240 213 XDone X X* 2 XStatText Enabled X149 7 165 120 XBottom of page X X* 3 XStatText Disabled X6 91 23 219 XPrinter Port Setup X X* 4 XStatText Disabled X30 6 46 51 XPort: X X* 5 XRadioItem Enabled X30 57 46 157 XModem Port X X* 6 XRadioItem Enabled X30 165 46 265 XPrinter Port X X* 7 XStatText Disabled X57 6 73 81 XBaud Rate: X X* 8 XStatText Enabled X57 98 73 143 Xruntime X X* 9 XBtnItem Enabled X58 153 74 218 XmoreI X X* 10 XStatText Disabled X83 5 99 122 XLine Terminator X X* 11 XEditText Enabled X83 128 99 320 Xruntime X X* 12 XEditText Enabled X105 128 121 320 Xruntime X X* 13 XEditText Enabled X127 128 143 320 Xruntime X X* 14 XEditText Enabled X149 128 165 320 Xruntime X X* 15 XEditText Enabled X171 128 187 320 Xruntime X X* 16 XStatText Disabled X105 6 121 123 XInitialize X X* 17 XStatText Disabled X127 7 143 124 XTop of page X X* 18 XStatText Enabled X171 8 187 121 XEnd of file X X* 19 XRadioItem Enabled X197 8 213 121 XSheet feed X X* 20 XRadioItem Enabled X197 165 213 265 XContinuous X XType DLOG XPrinter Config Box,-16000 XSerial Port Configuration X40 80 296 424 XVisible NoGoAway X1 ;; procID X0 ;; refCon X-16000 X XType DLOG XPage Setup Box,-15999 XPage Setup X48 51 165 449 XVisible NoGoAway X1 ;; procID X0 ;; refCon X-15999 X XType DLOG XNext Page Box,-15997 XNext Page X48 51 100 300 XVisible NoGoAway X1 ;; procID X0 ;; refCon X-15997 X XType DITL XNext Page Template,-15997 X3 X X* 1 XBtnItem Enabled X30 60 46 140 XDone X X* 2 XBtnItem Enabled X30 160 46 240 XStop X X* 3 XStatText X8 8 24 292 XSerialPrint: Insert Next Sheet X X XType DITL XPage Setup Template,-15999 X10 X X* 1 XBtnItem X96 165 112 235 XDone X X* 2 XStatText X64 201 82 316 XLines per page X X* 3 XStatText X7 166 24 243 XPage Setup X X* 4 XStatText X34 5 50 50 XTabs X X* 5 XEditText X34 135 52 167 Xruntime X X* 6 XEditText X32 328 49 369 Xruntime X X* 7 XEditText X64 136 80 177 Xruntime X X* 8 XEditText X66 331 82 376 Xruntime X X* 9 XStatText X64 5 80 122 XLeft Margin X X* 10 XStatText X34 202 50 277 XWidth X XType Stng = GNRL XPrinter Settings,-16000 X.H ;; Printer port, 1200 baud,no sheet feed, tabstops 8, width = 90, X0001 0002 0000 0008 005A 0008 0037 0000 0000 ;;left margin 8, 55 lines/page X XType MENU ;; Set procID of this menu to 0 with ResEdit XSerialPrint menu,-16000 ;; for operation without la bombe XSerialPrint XAbout SerialPrintI XPrinter SettingsI XPage SetupI XFlow ControlI XPrintI XSave Settings XQuit X XType STR# ;; String list for EOL, EOP, BOP strings XPrinter control strings,-16000 X5 X^M ;; End of line X^[^W ;; Initialize printer X^M^M^M^M^M ;; beginning of page X^L ;; end of page X^L ;; end of document X XType STR# ;; About this DA help strings XHelp Strings,-15999 X12 XSerialPrint, Edit of August 17, 1987\0DEarle R. Horton\0DPortions Copyright THINK Technologies\0DCompiled with the LightspeedC compiler and RMaker. XSerialPrint is an adaptable printing program meant to be used in draft mode with printers for which no Macintosh printer driver is available. XIt prints text-only files which have a carriage return at the end of every line.\0DThis revision does not wrap long lines at word boundaries. XThe Printer SettingsI menu allows you to change the port, baud rate, and five printer control strings. Your printer manual should have the appropriate settings to use. XNon-printing characters are set using control character notation. For example, carriage return is "^M", line feed is "^J".\0DSome printers require ^M at the end of a line, some require ^M^J. XTo set the top margin, put the appropriate number of your printer's linefeed character combinations in the box marked "Top of page". XIf your printer does not recognize the formfeed character (^L), just put some newlines in the box marked "Bottom of page". XThe Page SetupI menu allows setting of tabstops, left margin, #columns in page, and page length. Page length is the number of printed rows on the page, and does not include top and bottom margins. XThe flow control menu has no effect with 64k ROM or Mac XL systems, where CTS flow control only is used.\0DFor newer systems, this menu allows selection of either XOn/XOff or CTS. XThe flow control menu also allows you to specify whether the printer driver used is closed when you quit SerialPrint.\0D(Not done with 64k ROMs.) XThe most difficult part of using SerialPrint may be obtaining the proper printer cable. Obtain pinout diagrams of your Macintosh and printer; take them to a responsible electronics technician. XSettings are not saved unless the menu item is chosen. This edit of SerialPrint saves its settings in the system file. X XType DLOG XExtended AboutI Box,-15998 XAbout SerialPrint X60 86 242 412 XVisible NoGoAway X1 ;; procID X0 ;; refCon X-15998 ;; itemsID X XType DITL XExtended AboutI Box Template,-15998 X5 X XBtnItem X152 44 171 109 XMore X XBtnItem X152 129 171 190 XLess X XBtnItem X152 210 171 285 XEnough X XStatText Disabled X18 111 25 229 XSerialPrint X XStatText X46 8 142 310 XString list <OWNER> + 2. X X* This resource owned by: DRVR 12: local id 4 XType DLOG Xmore settings,-15996 XNew Dialog X59 134 209 336 XVisible GoAway X1 ;; procID X0 ;; refCon X-15996 X X* This resource owned by: DRVR 12: local id 4 XType DITL Xflow control template,-15996 X4 X XBtnItem X109 67 129 127 Xdone X XRadioItem X10 19 30 193 XXOn/XOff Flow control X XRadioItem X40 19 60 193 XCTS Flow Control X XChkItem X70 19 90 193 XClose Driver on Quit X SHAR_EOF exit ---