home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / cshar_sr.sit < prev    next >
Encoding:
Text File  |  1988-06-20  |  28.7 KB  |  1,178 lines

  1. 18-Jun-88 14:41:49-MDT,30525;000000000000
  2. Return-Path: <u-lchoqu%sunset@cs.utah.edu>
  3. Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:41:03 MDT
  4. Received: by cs.utah.edu (5.54/utah-2.0-cs)
  5.     id AA22579; Sat, 18 Jun 88 14:40:58 MDT
  6. Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
  7.     id AA24751; Sat, 18 Jun 88 14:40:53 MDT
  8. Date: Sat, 18 Jun 88 14:40:53 MDT
  9. From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
  10. Message-Id: <8806182040.AA24751@sunset.utah.edu>
  11. To: rthum@simtel20.arpa
  12. Subject: SerialPrint.c.shar
  13.  
  14. #! /bin/sh
  15. #
  16. # This is a shell archive.  Save this into a file, edit it
  17. # and delete all lines above this comment.  Then give this
  18. # file to sh by executing the command "sh file".  The files
  19. # will be extracted into the current directory owned by
  20. # you with default permissions.
  21. #
  22. # The files contained herein are:
  23. #
  24. #    3 README
  25. #   20 SerialPrint.c
  26. #    6 SerialPrint.rsrc
  27. #
  28. echo 'Extracting README'
  29. if test -f README; then echo 'shar: will not overwrite README'; else
  30. cat << '________This_Is_The_END________' > README
  31. This is the source for a desk accessory I wrote to get letter-quality
  32. printing from my Mac without buying a LaserWriter.  I wrote it to be
  33. as general as possible.  I wanted to have:
  34.  
  35.      User-selectable strings for initializing the printer, etc.
  36.      Variable left margins and page length.
  37.      Support of either sheet feed or continuous feed.
  38.      A bunch of communications port options.
  39.      Compatible with 64k ROMs (God knows why).
  40.      Expands tabs, or not, as required.
  41.      Prints text only files with carriage return at end of each line.
  42.      Most important: work on as many different printer types as possible.
  43.  
  44. I have posted the binhex'd DA to comp.binaries.mac.  These are the sources.
  45. The DA worked with my Tandy DMP-110 and with my Silver-Reed Penman Deluxe
  46. with the I/F40 Serial Interface.  I tried a bunch of baud rates, and 
  47. both CTS and ^S^Q flow control.  I regret that I didn't support ^S^Q
  48. flow control for 64k ROMs, but you never can tell whether the RAM serial
  49. driver is going to be present...
  50.  
  51. It seemed to work with all the printer settings I threw at it, so I posted
  52. the binhex, and here are the sources.  The comments are kinda skimpy, but
  53. I believe I have used enough meaningful variable names to compensate.
  54. Even if you see no need for the desk accessory since your boss just got
  55. a LaserWriter or whatever, you might be able to glean some programming
  56. tips from this code.  How to send junk out the serial port, how to push
  57. radio buttons, how to manipulate STR# resources in memory, how to 
  58. highlite the "OK" button when using ModalDialog() instead of Alert().
  59.  
  60. You might even see some huge bugs, and then be able to flame me in
  61. next week's comp.sys.mac (or whatever they want to call it next week).
  62. If you want, you can flame me for not writing a Chooser-compatible
  63. printer driver instead of this.  (Make my day.)
  64.  
  65. The system I used was LSC and RMaker.  Code may differ for other systems.
  66. -- 
  67. *********************************************************************
  68. *Earle R. Horton, H.B. 8000, Dartmouth College, Hanover, NH 03755   *
  69. *********************************************************************
  70. ________This_Is_The_END________
  71. if test `wc -l < README` -ne 39; then
  72.     echo 'shar: README was damaged during transit'
  73.   echo '      (should have been 39 bytes)'
  74. fi
  75. fi        ; : end of overwriting check
  76. echo 'Extracting SerialPrint.c'
  77. if test -f SerialPrint.c; then echo 'shar: will not overwrite SerialPrint.c'; else
  78. cat << '________This_Is_The_END________' > SerialPrint.c
  79. /*
  80.  * SerialPrint.c.  A generic serial printer driver in desk accessory
  81.  * form for the Macintosh.
  82.  * Earle R. Horton.  August 17, 1987
  83.  * LightspeedC source.
  84.  * To use, build a project with this file and MacTraps in it.
  85.  * Set the project type to Desk Accessory.  Build the desk accessory.
  86.  * Run RMaker to put the owned resources in the suitcase file.
  87.  * Do not attempt to "Run" from within LightspeedC.  The use of owned
  88.  * resources presents problems here.
  89.  */
  90. #include <DeviceMgr.h>
  91. #include <WindowMgr.h>    /* includes QuickDraw.h, MacTypes.h */
  92. #include <EventMgr.h>
  93. #include <MenuMgr.h>
  94. #include <FileMgr.h>
  95. #include <DialogMgr.h>
  96. #include <SerialDvr.h>    
  97. #include <StdFilePkg.h>
  98. #include <ControlMgr.h>
  99.  
  100. # define    nil            0L
  101.  
  102. /*  global variables and macros to use them */
  103. typedef struct{
  104.     int    dummy[9];
  105. } pconfig,*Pcfg,**Pfg;
  106. Pfg    settings = nil;
  107. /* Be a real Mac cowboy, access data by the handle. */
  108. #define pport         ((*settings)->dummy[0])
  109. #define pbaud         ((*settings)->dummy[1])
  110. #define sheetfeed    ((*settings)->dummy[2])
  111. #define tabstops     ((*settings)->dummy[3])
  112. #define width         ((*settings)->dummy[4])
  113. #define margin         ((*settings)->dummy[5])
  114. #define pagelength     ((*settings)->dummy[6])
  115. #define XonXoff        ((*settings)->dummy[7])
  116. #define SDClose        ((*settings)->dummy[8])
  117. /* Yeeeeee-Hah !! I won't even lock it! */
  118. typedef struct bauds{
  119.     int    rate;
  120.     char label[10];
  121. }BAUDS;
  122. BAUDS    mybauds[] = {            /* Baud rate constant table. */
  123.     { baud300,    "\p300"},    /* Should use a string list. */
  124.     { baud600,    "\p600"},    /* But these are numbers, so I */
  125.     { baud1200,    "\p1200"},    /* Think it's OK. */
  126.     { baud1800,    "\p1800"},
  127.     { baud2400,    "\p2400"},
  128.     { baud3600,    "\p3600"},
  129.     { baud4800,    "\p4800"},
  130.     { baud7200,    "\p7200"},
  131.     { baud9600,    "\p9600"},
  132.     { baud19200,    "\p19200"}
  133. };
  134. typedef struct {            /* Structure description of STR# */
  135.     int    numstrings;        /* resource. */
  136.     unsigned char    thestrings[];
  137. }stringlist,**StrList;
  138. StrList    mystrings = nil;
  139. Point where = {80,80};
  140. SFTypeList    mytypelist = {'TEXT'};
  141. ParamBlockRec     iopb;
  142. ParamBlockRec     filepb;
  143. char _iobuf[522];
  144. int ResID;
  145. static int phone   =       FALSE;
  146. static int printer =     FALSE;
  147. static MenuHandle    MHandl;
  148. static CHANGE1       =     FALSE;
  149. static CHANGE2     =     FALSE;
  150. static    int        rom,machine;
  151.  
  152. /* Useful constants */
  153. #define OWNED_BASE -16384
  154. #define BAUDLABEL 8        /* Item numbers of configuration box. */
  155. #define BAUDBUTTON 9
  156. #define DONEITEM 1
  157. #define STOPITEM 2
  158. #define MODEM    5
  159. #define PRINTER 6
  160.  
  161. /* Menu item numbers */
  162. #define ABOUTITEM    1
  163. #define SETITEM     2
  164. #define PAGEITEM     3
  165. #define FLOWITEM    4
  166. #define PRINTITEM     5
  167. #define SAVEITEM    6
  168. #define QUITITEM     7
  169. /* Printer setup editText Item numbers */
  170.  
  171. #define    TABSITEM    5
  172. #define    WIDTHITEM    6
  173. #define    MARGINITEM    7
  174. #define    LINESITEM    8
  175.  
  176. #define EOLITEM        11
  177. #define    INITITEM    12
  178. #define    TOPITEM        13
  179. #define    EOPITEM        14
  180. #define    EOFITEM        15
  181. #define SHEETITEM    19
  182. #define CONTINUOUSITEM    20
  183. #define NUMSTRINGS    5
  184. #define RESPAD        24
  185.  
  186. #define    SERRESET    8    /* csCodes for PBControl */
  187. #define    SERSHAKE    10
  188.  
  189. #define FLOWBOX        (ResID + 4)  /* Should have done all like this */
  190.                     /* forgot... */
  191. #define XONCR    ((char)17)
  192. #define XOFFCR    ((char)19)
  193.  
  194.  
  195. main(p, d, n)
  196. cntrlParam *p;        /*  ==> parameter block  */
  197. DCtlPtr d;        /*  ==> device control entry  */
  198. int n;            /*  entry point selector  */
  199.  
  200. {
  201.  
  202.     /*  check to make sure our data area was allocated  */
  203.         
  204.     if (d->dCtlStorage == 0)
  205.     {
  206.         if (n == 0)    /*  open  */
  207.             CloseDriver(d->dCtlRefNum);
  208.     }
  209.     else switch (n)        /*  dispatch  */
  210.     {
  211.         case 0:        /*  open  */
  212.         ResID = (~d->dCtlRefNum)<<5 | OWNED_BASE; 
  213.         d->dCtlMenu = ResID;
  214.         MHandl = GetMenu(ResID);
  215.         if(MHandl == nil){
  216.             CloseDriver(d->dCtlRefNum);
  217.             return(0);
  218.         }            
  219.         InsertMenu(MHandl,0);
  220.         DrawMenuBar();
  221.         if ((settings = (Pfg)(GetResource('Stng',ResID))) == nil ||
  222.             (mystrings = (StrList)(GetResource('STR#',ResID))) == nil){
  223.             CloseDriver(d->dCtlRefNum);
  224.             return(0);
  225.         }
  226.         LoadResource(settings);
  227.         HNoPurge(settings);
  228.         LoadResource(mystrings);
  229.         HNoPurge(mystrings);
  230.         HLock(mystrings);
  231.         Environs(&rom,&machine);
  232.         if(rom < 117){            /* If < 512KE, no XOn/XOff */
  233.             SDClose = FALSE;
  234.             XonXoff = FALSE;
  235.         }
  236.         break;
  237.  
  238.         case 2:        /*  control  */
  239.         switch (p->csCode){
  240.             case accMenu:
  241.             switch (p->csParam[1]){
  242.                 case ABOUTITEM:
  243.                 DoAbout();
  244.                 break;
  245.                 case SETITEM:
  246.                 if(!prsetup())
  247.                     CloseDriver(d->dCtlRefNum);
  248.                 break;
  249.                 case PAGEITEM:
  250.                 if(!pagesetup())
  251.                     CloseDriver(d->dCtlRefNum);
  252.                 break;
  253.                 case FLOWITEM:
  254.                 moresettings();
  255.                 break;
  256.                 case PRINTITEM:
  257.                 ffprint();
  258.                 break;
  259.                 case SAVEITEM:
  260.                 if(CHANGE1){
  261.                     ChangedResource(settings);
  262.                 }
  263.                 if(CHANGE2){
  264.                     ChangedResource(mystrings);
  265.                 }
  266.                 if(CHANGE1 || CHANGE2)
  267.                     UpdateResFile(HomeResFile(settings));
  268.                 break;
  269.                 case QUITITEM:
  270.                 CloseDriver(d->dCtlRefNum);
  271.                 break;
  272.             }
  273.             break; 
  274.         }
  275.         break;
  276.         case 4:        /*  close  */
  277.             quit();
  278.             break;
  279.     }
  280.     
  281.     /*  done  */
  282.     
  283.     return(0);
  284. }
  285. quit()
  286. {
  287.     if(MHandl != nil){
  288.         DeleteMenu(ResID);
  289.         ReleaseResource(MHandl);
  290.         DrawMenuBar();
  291.         MHandl = nil;
  292.     }
  293.     if(SDClose){
  294.         if(printer)RAMSDClose(sPortA);
  295.         if(phone)RAMSDClose(sPortB);
  296.     }
  297.     if (settings != nil) {    /* We don't want to leave our junk laying */
  298.         HPurge(settings);        /* around... */
  299.         ReleaseResource(settings);
  300.         settings = nil;
  301.     }
  302.     if (mystrings != nil) {
  303.         ReleaseResource(mystrings);
  304.         mystrings = nil;
  305.     }
  306. }
  307. pushradiobutton(thedialog,itemhit,first,last)    /* push a radio Button */
  308. DialogPtr thedialog;                /* set itemhit, unset  */
  309. int itemhit,first,last;                /* all others in range */
  310. {
  311.     int itemtype,i;
  312.     Handle itemhandle;            /* Does check boxes, too. */
  313.     Rect itemrect;
  314.     ControlHandle itemcntlhand;
  315.     if(first ==0) return;
  316.     for(i=first-1;last-i++;){
  317.         GetDItem(thedialog,i,&itemtype,&itemhandle,&itemrect);
  318.         itemcntlhand = (ControlHandle)itemhandle;
  319.         if(i == itemhit) SetCtlValue(itemcntlhand,1);
  320.         else SetCtlValue(itemcntlhand,0);
  321.     }
  322. }
  323. pagesetup()        /* Derive left margin, tab stops, page length */
  324. {            /* and number columns.                  */
  325. DialogPtr pagedialog;
  326. WindowPtr tempport;
  327. int     itemhit,i,numtype,donetype;
  328. Handle    numitem,doneitem;
  329. Rect    numbox,donebox;
  330. Str255    numtext;
  331. long    temp;
  332.     if((pagedialog = GetNewDialog(ResID+1, 0L,(WindowPtr) -1)) == nil)
  333.         return FALSE;
  334.     GetDItem(pagedialog,DONEITEM,&donetype,&doneitem,&donebox);
  335.     for(i = TABSITEM - 1;LINESITEM - i++;){
  336.         GetDItem(pagedialog,i,&numtype,&numitem,&numbox);
  337.         NumToString((long)((*settings)->dummy[i-2]),numtext);
  338.         SetIText(numitem,numtext);
  339.     }
  340.     GetPort(&tempport);
  341.     SetPort(pagedialog);
  342.     PenSize(3,3);
  343.     InsetRect(&donebox,-4,-4);
  344.     FrameRoundRect(&donebox,16,16);
  345.     itemhit = 0;
  346.     while(itemhit != DONEITEM){
  347.           ModalDialog(0L,&itemhit);
  348.           switch(itemhit){
  349.           default:
  350.               break;
  351.           }
  352.     }
  353.     for(i = TABSITEM - 1;LINESITEM - i++;){
  354.         GetDItem(pagedialog,i,&numtype,&numitem,&numbox);
  355.         GetIText(numitem,numtext);
  356.         StringToNum(numtext,&temp);
  357.         (*settings)->dummy[i-2] = (int)temp;
  358.     }
  359.     DisposDialog(pagedialog);
  360.     SetPort(tempport);                          
  361.     CHANGE1 = TRUE;
  362.     return(TRUE);
  363. }
  364. #define XONXOFF    2
  365. #define CTS    3
  366. #define SDCLOSE    4
  367. moresettings()        /* If 64k ROM or XL, show dialog, do nothing. */
  368. {
  369. DialogPtr flowdialog;
  370. WindowPtr tempport;
  371. int    itemhit,donetype;
  372. Handle    doneitem;
  373. Rect    donebox;
  374.     if((flowdialog = GetNewDialog(FLOWBOX,0L,(WindowPtr) -1)) == nil)
  375.         return FALSE;
  376.     GetDItem(flowdialog,DONEITEM,&donetype,&doneitem,&donebox);
  377.     GetPort(&tempport);
  378.     SetPort(flowdialog);
  379.     PenSize(3,3);
  380.     InsetRect(&donebox,-4,-4);
  381.     FrameRoundRect(&donebox,16,16);
  382.     if (SDClose)
  383.         pushradiobutton(flowdialog, SDCLOSE,SDCLOSE,SDCLOSE);
  384.     else 
  385.         pushradiobutton(flowdialog,0,SDCLOSE,SDCLOSE);
  386.     if (XonXoff) 
  387.         pushradiobutton(flowdialog,XONXOFF,XONXOFF,CTS);
  388.     else 
  389.         pushradiobutton(flowdialog,CTS,XONXOFF,CTS);
  390.     itemhit = 0;
  391.     while(itemhit != DONEITEM){
  392.         ModalDialog(0L,&itemhit);
  393.         if( rom >= 117){  /* If ROM version < 117, forget this. */
  394.             switch(itemhit){
  395.             case XONXOFF:
  396.                 XonXoff = TRUE;
  397.                 pushradiobutton(flowdialog, itemhit,XONXOFF,CTS);
  398.                 break;
  399.             case CTS:
  400.                 XonXoff = FALSE;
  401.                 pushradiobutton(flowdialog, itemhit,XONXOFF,CTS);
  402.                 break;
  403.             case SDCLOSE:
  404.                 SDClose = !SDClose;
  405.                 if (SDClose)
  406.                 pushradiobutton(flowdialog,
  407.                     SDCLOSE,SDCLOSE,SDCLOSE);
  408.                 else 
  409.                 pushradiobutton(flowdialog,0,SDCLOSE,SDCLOSE);
  410.                 break;
  411.             }
  412.         }
  413.     }
  414.     CHANGE1 = TRUE;
  415.     DisposDialog(flowdialog);
  416.     SetPort(tempport);
  417.     return TRUE;
  418. }
  419.  
  420.  /* This one enquires for and sets the printer variables.
  421.  * Radio buttons (cute) are used.
  422.  */
  423. prsetup()
  424. {
  425. DialogPtr printdialog;
  426. WindowPtr tempport;
  427. int     itemhit,i,baudtype,edittype,donetype;
  428. Handle    bauditem,doneitem,edititem;
  429. Rect    baudbox,donebox,editbox;
  430. Str255    thestring;
  431. unsigned char    *strptr;
  432. long    length;
  433.     if (pbaud<0 || pbaud>9) pbaud = 0;
  434.     if((printdialog = GetNewDialog(ResID, 0L,(WindowPtr) -1)) == nil)
  435.         return FALSE;
  436.     GetDItem(printdialog,BAUDLABEL,&baudtype,&bauditem,&baudbox);
  437.     GetDItem(printdialog,DONEITEM,&donetype,&doneitem,&donebox);
  438.     SetIText(bauditem,mybauds[pbaud].label);
  439. /* This gets the editText items in the dialog box to contain
  440.  * the strings from one of our string lists.
  441.  */
  442.     strptr = &((*mystrings)->thestrings[0]);
  443.     for(i = EOLITEM-1;EOFITEM - i++;){
  444.         GetDItem(printdialog,i,&edittype,&edititem,&editbox);
  445.         SetIText(edititem,strptr);
  446.         strptr += (*strptr) + 1;
  447.     }
  448.     GetPort(&tempport);
  449.     SetPort(printdialog);
  450.     PenSize(3,3);
  451.     InsetRect(&donebox,-4,-4);
  452.     FrameRoundRect(&donebox,16,16);
  453.     pushradiobutton(printdialog, pport+5,5,6);
  454.     pushradiobutton(printdialog,SHEETITEM + sheetfeed,SHEETITEM,
  455.         CONTINUOUSITEM);
  456.     itemhit = 0;
  457.     while(itemhit != DONEITEM){
  458.           ModalDialog(0L,&itemhit);
  459.           switch(itemhit){
  460.             case MODEM:        /* port change. */
  461.             case PRINTER:
  462.                 pport = itemhit - MODEM;
  463.                 pushradiobutton(printdialog,itemhit,
  464.                    MODEM,PRINTER);
  465.                 break;
  466.             case BAUDBUTTON:    /* next baud rate change */
  467.                 /* Ten radio buttons would be just too much. */
  468.                 if(++pbaud == 10) pbaud = 0;
  469.                 SetIText(bauditem,mybauds[pbaud].label);
  470.                 break;
  471.             case SHEETITEM:          /* feed options */
  472.             case CONTINUOUSITEM:
  473.                 sheetfeed = itemhit - SHEETITEM;
  474.                 pushradiobutton(printdialog,
  475.                     itemhit,SHEETITEM,CONTINUOUSITEM);
  476.                 break;
  477.         }
  478.     }
  479.     /* The user has set the baud rate and the port, and also possibly
  480.      * edited the printer control strings.  Since we used ModalDialog()
  481.      * with no filterproc we don't know whether any of the strings have
  482.      * been changed.  Therefore we just rebuild the whole string list.
  483.      * First, determine the length.
  484.      */
  485.     length = (long) (sizeof(int)+RESPAD);
  486.     /* Try doing this with RESPAD = 0! */
  487.     for(i = EOLITEM-1;EOFITEM - i++;){
  488.         GetDItem(printdialog,i,&edittype,&edititem,&editbox);
  489.         GetIText(edititem,thestring);
  490.         length += (long) thestring[0];
  491.     }
  492.     /* Size might have changed, so we unlock the handle and attempt to
  493.      * resize it.  Should work, unless no RAM left. */
  494.     HUnlock(mystrings);
  495.     SetHandleSize(mystrings,length);
  496.     if (GetHandleSize(mystrings)!=length){    /* Abort on error. */
  497.         DisposDialog(printdialog);
  498.         SetPort(tempport);                          
  499.         return(FALSE);
  500.     }
  501.     HNoPurge(mystrings);
  502.     HLock(mystrings);
  503.     /* Rebuild the STR# from the item list. */
  504.     strptr = &((*mystrings)->thestrings[0]);
  505.     for(i = EOLITEM-1;EOFITEM - i++;){
  506.         GetDItem(printdialog,i,&edittype,&edititem,&editbox);
  507.         GetIText(edititem,strptr);
  508.         strptr += (*strptr) + 1;
  509.     }
  510.     DisposDialog(printdialog);
  511.     SetPort(tempport);                          
  512.     CHANGE2 = CHANGE1 = TRUE;
  513.     return(TRUE);
  514. }
  515. waitnextpage()        /* For sheet feeders. */
  516. {
  517. DialogPtr sheetdialog;
  518. WindowPtr tempport;
  519. int    itemhit,donetype;
  520. Handle    doneitem;
  521. Rect    donebox;
  522.     if((sheetdialog = GetNewDialog(ResID+3, 0L,(WindowPtr) -1)) == nil)
  523.         return FALSE;
  524.     GetDItem(sheetdialog,DONEITEM,&donetype,&doneitem,&donebox);
  525.     GetPort(&tempport);
  526.     SetPort(sheetdialog);
  527.     PenSize(3,3);
  528.     InsetRect(&donebox,-4,-4);
  529.     FrameRoundRect(&donebox,16,16);
  530.     ModalDialog(0L,&itemhit);
  531.     DisposDialog(sheetdialog);
  532.     SetPort(tempport);
  533.     if(itemhit == STOPITEM) return FALSE;
  534.     return TRUE;
  535. }
  536.  
  537. char outbuf[200];    /* Or whatever size you think appropriate. */
  538. char inbuf[200];
  539. ffprint()
  540. {
  541. register int    nline,nchars,i,tab;
  542. register     ParmBlkPtr pb;
  543. char         c;
  544. int        serconfig,drivernum,length,filefinished;
  545. EventRecord    myevent;
  546. long         count1;
  547. unsigned char    *eolstr,*initstr,*topstr,*eopstr,*eofstr;
  548.  
  549.     pb = &iopb;
  550.     /* Get strings from string list.  (Pascal strings) */
  551.     eolstr = eofstr = &((*mystrings)->thestrings[0]);
  552.     initstr = (eofstr += (*eofstr) + 1);
  553.     topstr = (eofstr += (*eofstr) + 1);
  554.     eopstr = (eofstr += (*eofstr) + 1);
  555.     eofstr += (*eofstr) + 1;
  556.  
  557.     tab = tabstops - 1;
  558.     switch (pport){        /* get the correct port */
  559.         case 0:        /* modem port */
  560.             if(!phone) {
  561.                 prinit("\p.AOut");
  562.                 phone = TRUE;
  563.                 if(rom >= 117)RAMSDOpen(sPortA);
  564.             }
  565.             drivernum = AoutRefNum;
  566.             break;
  567.         case 1:        /* printer port */
  568.             if(!printer) {
  569.                 prinit("\p.BOut");
  570.                 printer = TRUE;
  571.                 if(rom >= 117)RAMSDOpen(sPortB);
  572.             }
  573.             drivernum = BoutRefNum;
  574.             break;
  575.         }
  576.     /* set up the io parameter block for writing to the serial driver. */
  577.     /* a control call resets the baud rate */
  578.     pb->ioParam.ioRefNum = drivernum;
  579.     pb->ioParam.ioCompletion = nil;
  580.     ((cntrlParam *)pb)->csCode = SERRESET;
  581.     serconfig = data8 + noParity + stop20;
  582.     serconfig += mybauds[pbaud].rate;
  583.     ((cntrlParam*)pb)->csParam[0] = serconfig;
  584.     PBControl(pb,FALSE);
  585. #define shake     ((SerShk*)&((cntrlParam*)pb)->csParam[0])
  586.     if(rom >= 117){        /* If ROM version < 117, forget this. */
  587.         shake->errs = FALSE;
  588.         shake->evts = FALSE;
  589.         shake->fDTR = FALSE;
  590.         shake->fInX = FALSE;
  591.         if(XonXoff){
  592.         shake->fXOn = TRUE;
  593.         shake->fCTS = FALSE;
  594.         shake->xOn = XONCR;
  595.         shake->xOff = XOFFCR;
  596.         }
  597.         else {
  598.         shake->fXOn = FALSE;
  599.         shake->fCTS = TRUE;
  600.         }
  601.         ((cntrlParam *)pb)->csCode = SERSHAKE;
  602.         PBControl(pb,FALSE);
  603.     }
  604. #undef shake
  605.     pb->ioParam.ioPosMode = 0;
  606.     pb->ioParam.ioPosOffset = 0;
  607.     
  608.     for(nchars=0;margin-nchars;nchars++){ /* pad the sucker on the  */
  609.         outbuf[nchars] = ' ';         /* left with margin spaces */
  610.     }
  611.  
  612.     while(ffopen()){
  613.         printstring(initstr);
  614.         filefinished = FALSE;
  615.         nline = 0;
  616.         while (!filefinished){
  617.         if(nline == 0){            /* top of a page */
  618.             printstring(topstr);
  619.             nline++;
  620.         }
  621.         else if (nline == pagelength + 2){        /* bottom */
  622.             printstring(eopstr);
  623.             nline = 0;
  624.             if(sheetfeed == 0) {
  625.                 if (waitnextpage() == FALSE) {
  626.                 PBClose(&filepb,FALSE);
  627.                 return;
  628.                 }
  629.             }
  630.         }
  631.         else {                        /* body */
  632.             if(!getline(inbuf,width,&length)) 
  633.                 filefinished = TRUE;
  634.             nchars = 0;
  635.             i = 0;
  636.             while( i <= width && nchars <= length){
  637.             switch(c = inbuf[nchars++]){
  638.                 case 9: /* a tab */
  639.                 if (tab){
  640.                     do{
  641.                     outbuf[margin + i++] = ' ';
  642.                     }while((i % tab)!=0);
  643.                 }
  644.                 else
  645.                     outbuf[margin + i++]= c;
  646.                 break;
  647.                 default:
  648.                 outbuf[margin + i++]= c;
  649.                 break;
  650.             }
  651.             }
  652.             count1 = (long) (i + margin - 1);
  653.             nline++;       /* count lines */
  654.         /* check after every line for user abort */
  655.         /* Admitted, less effective at high baud rates. */
  656.         if (GetNextEvent(everyEvent, &myevent))  {
  657.             switch (myevent.what) {
  658.             case keyDown:
  659.                 c = LoWord(myevent.message & charCodeMask);
  660.                 if (myevent.modifiers & cmdKey) {
  661.                 if( c == '.'){
  662.                      PBClose(&filepb,FALSE);
  663.                     return;
  664.                 }    /* quit now */
  665.                 }
  666.                 break;
  667.             default:
  668.                 break;
  669.             }
  670.         }
  671.             /* write out the expanded line */
  672.             /* to the proper device driver. */
  673.         if(!filefinished){
  674.             pb->ioParam.ioBuffer = outbuf;
  675.             pb->ioParam.ioReqCount = count1;
  676.             PBWrite(pb,FALSE);
  677.             printstring(eolstr);
  678.         }
  679.         }
  680.         }
  681.     PBClose(&filepb,FALSE);
  682.     printstring(eofstr);
  683.     }
  684. }
  685. char stringbuf[256];
  686. /*
  687.  * Used for interpreting the printer control codes. Not very efficient,
  688.  * since they are interpreted every time sent.
  689.  */
  690. printstring(string)
  691. unsigned char    string[];        
  692. {
  693.     register unsigned int    i;
  694.     long    count;
  695.     count = 0L;
  696.     i = string[0];
  697.     for(i=0;string[0]-i++;){
  698.         switch (string[i]){
  699.         case '^':
  700.             stringbuf[count] = 31 & string[++i];
  701.             break;
  702.         default:
  703.             stringbuf[count] = string[i];
  704.             break;
  705.         }
  706.         count++;
  707.     }
  708.     iopb.ioParam.ioBuffer = stringbuf;
  709.     iopb.ioParam.ioReqCount = count;
  710.     PBWrite(&iopb,FALSE);
  711. }
  712. prinit(name)                    /* Open a driver by name. */
  713.         /* ROM serial driver?  RAM serial driver?  Who cares? */
  714.         /* Seriously, if ROM is 128k or newer, we do the RAM  */
  715.         /* serial driver open later. */
  716. char *name;
  717. {
  718.     iopb.ioParam.ioNamePtr = (StringPtr)name;
  719.     iopb.ioParam.ioCompletion = nil;
  720.     iopb.ioParam.ioPermssn = 0;
  721.     PBOpen(&iopb,FALSE);
  722. }
  723. ffopen ()
  724. {
  725. static    SFReply frommac;
  726. register ParmBlkPtr pb;
  727.  
  728. pb = &filepb;
  729.     
  730.     SFGetFile (where, 0L, 0L, 1, mytypelist, 0L, &frommac);
  731.     if (frommac.good) {
  732.         pb->ioParam.ioNamePtr = frommac.fName;
  733.         pb->ioParam.ioCompletion = nil;
  734.         pb->ioParam.ioVersNum = 0;
  735.         pb->ioParam.ioMisc = _iobuf;
  736.         pb->ioParam.ioVRefNum = frommac.vRefNum;
  737.         pb->ioParam.ioPermssn = fsRdPerm;
  738.         pb->ioParam.ioPosMode = 3456;
  739.         PBOpen(pb,FALSE);
  740.         if(pb->ioParam.ioResult){
  741.             return (FALSE);
  742.         }
  743.         else return (TRUE);
  744.     }
  745.     else return (FALSE);
  746. }
  747. /*
  748.  * Read a line from a file, and store the bytes in the supplied buffer. The
  749.  * "nbuf" is the length of the buffer.     Return FALSE if no bytes read.
  750.  * filepb.ioParam.ioPosMode determines that we stop at the newline
  751.  * character, which is <cr>.  Should possibly stop on error, but I 
  752.  * think error implies no bytes read (?).
  753.  */
  754. getline(buf,nbuf,nbytes)
  755. register char   buf[];
  756. int nbuf;
  757. int *nbytes;
  758. {
  759. register int    i;
  760. register ParmBlkPtr pb;
  761.  
  762. pb = &filepb;
  763.  
  764.     pb->ioParam.ioPosMode = 3456;
  765.     /* This means reads stop at '\r', see IM for details. */
  766.     pb->ioParam.ioBuffer = buf;
  767.     pb->ioParam.ioReqCount = (long)nbuf;
  768.     PBRead(pb,FALSE);
  769.     if ((i = (int)pb->ioParam.ioActCount) == 0){
  770.          *nbytes = 0;
  771.          return (FALSE);
  772.     }
  773.     if(buf[i-1] == '\r') i--;    /* strip CR */
  774.     *nbytes = i;    
  775.     return (TRUE);
  776. }
  777. /*
  778.  * DoAbout:
  779.  *
  780.  *    Dialog box handler for extended about box.  Put up a dialog
  781.  *    box with help information.  Cycle through a string list
  782.  *    (STR# ID HLIST) to change the contents of a statText item.
  783.  *    Help information is updated by changing the contents of the
  784.  *    STR#, making things easier to localize.
  785.  */
  786. #define HDLOG ResID+2
  787. #define HLIST ResID+1
  788. #define HITEM 5
  789. #define MORE 1
  790. #define BACK 2
  791. #define ENOUGH 3
  792. #define    int16    short
  793. DoAbout()
  794. {
  795. int16         res,i,helptype,nlimit;
  796. DialogPtr    helpdialog;
  797. WindowPtr    tempport;
  798. Str255        helpstring;
  799. Handle        helpitem,moreitem;
  800. Rect        helpbox,morebox;
  801. int16        **stringlist;
  802. int16        moretype;
  803.     /* Prepare to use dialog box. */
  804.     helpdialog = GetNewDialog(HDLOG,(long)0,(WindowPtr) -1);
  805.     GetDItem(helpdialog,HITEM,&helptype,&helpitem,&helpbox);
  806.     GetDItem(helpdialog,MORE,&moretype,&moreitem,&morebox);
  807.     GetPort(&tempport);
  808.     SetPort(helpdialog);
  809.     PenSize(3,3);
  810.     InsetRect(&morebox,-4,-4);
  811.     FrameRoundRect(&morebox,16,16);
  812.     /* How many strings? */
  813.     stringlist = (int16 **)GetResource('STR#',HLIST);
  814.     if(stringlist == nil) return FALSE;
  815.     LoadResource(stringlist);
  816.     nlimit = (int16) **stringlist;
  817.     i = 0;
  818.     res = 1;
  819.     while(res != ENOUGH){        /* Done when quit button selected. */
  820.         if (res == BACK) i--;                /* Cycle back. */
  821.         else i++;                /* Cycle forwards. */
  822.         if (i<1) i=nlimit;       /* Choose < 1, use last string. */
  823.         GetIndString(helpstring,HLIST,i);    /* Get the string. */
  824.         if(helpstring[0] == '\0'){   /* Out of range, last string. */
  825.             i=1;               /* Cycle back to first one. */
  826.             GetIndString(helpstring,HLIST,i);    /* Get it. */
  827.         }
  828.         SetIText(helpitem,helpstring);            /* Use it. */
  829.         ModalDialog(0L,&res);        /* ModalDialog handles events. */
  830.     }
  831.     DisposDialog(helpdialog);            /* Done, clean up. */
  832.     SetPort(tempport);
  833.     ReleaseResource(stringlist);
  834.     return TRUE;
  835. }
  836.  
  837. ________This_Is_The_END________
  838. if test `wc -l < SerialPrint.c` -ne 758; then
  839.     echo 'shar: SerialPrint.c was damaged during transit'
  840.   echo '      (should have been 758 bytes)'
  841. fi
  842. fi        ; : end of overwriting check
  843. echo 'Extracting SerialPrint.rsrc'
  844. if test -f SerialPrint.rsrc; then echo 'shar: will not overwrite SerialPrint.rsrc'; else
  845. cat << '________This_Is_The_END________' > SerialPrint.rsrc
  846. *Resource definition file for Device Dependent Printing Desk Accessory
  847.  
  848. !LSC:SerialPrint:Serial
  849. DFILDMOV
  850.  
  851. Type DITL
  852. Printer Dialog Template,-16000
  853. 20
  854.  
  855. *   1
  856. BtnItem Enabled
  857. 224 143 240 213
  858. Done
  859.  
  860. *   2
  861. StatText Enabled
  862. 149 7 165 120
  863. Bottom of page
  864.  
  865. *   3
  866. StatText Disabled
  867. 6 91 23 219
  868. Printer Port Setup
  869.  
  870. *   4
  871. StatText Disabled
  872. 30 6 46 51
  873. Port:
  874.  
  875. *   5
  876. RadioItem Enabled
  877. 30 57 46 157
  878. Modem Port
  879.  
  880. *   6
  881. RadioItem Enabled
  882. 30 165 46 265
  883. Printer Port
  884.  
  885. *   7
  886. StatText Disabled
  887. 57 6 73 81
  888. Baud Rate:
  889.  
  890. *   8
  891. StatText Enabled
  892. 57 98 73 143
  893. runtime
  894.  
  895. *   9
  896. BtnItem Enabled
  897. 58 153 74 218
  898. moreI
  899.  
  900. *   10
  901. StatText Disabled
  902. 83 5 99 122
  903. Line Terminator
  904.  
  905. *   11
  906. EditText Enabled
  907. 83 128 99 320
  908. runtime
  909.  
  910. *   12
  911. EditText Enabled
  912. 105 128 121 320
  913. runtime
  914.  
  915. *   13
  916. EditText Enabled
  917. 127 128 143 320
  918. runtime
  919.  
  920. *   14
  921. EditText Enabled
  922. 149 128 165 320
  923. runtime
  924.  
  925. *   15
  926. EditText Enabled
  927. 171 128 187 320
  928. runtime
  929.  
  930. *   16
  931. StatText Disabled
  932. 105 6 121 123
  933. Initialize
  934.  
  935. *   17
  936. StatText Disabled
  937. 127 7 143 124
  938. Top of page
  939.  
  940. *   18
  941. StatText Enabled
  942. 171 8 187 121
  943. End of file
  944.  
  945. *    19
  946. RadioItem Enabled 
  947. 197 8 213 121
  948. Sheet feed
  949.  
  950. *   20
  951. RadioItem Enabled
  952. 197 165 213 265
  953. Continuous
  954.  
  955. Type DLOG
  956. Printer Config Box,-16000
  957. Serial Port Configuration
  958. 40 80 296 424
  959. Visible NoGoAway
  960. 1 ;; procID
  961. 0 ;; refCon
  962. -16000
  963.  
  964. Type DLOG
  965. Page Setup Box,-15999
  966. Page Setup
  967. 48 51 165 449
  968. Visible NoGoAway
  969. 1 ;; procID
  970. 0 ;; refCon
  971. -15999
  972.  
  973. Type DLOG
  974. Next Page Box,-15997
  975. Next Page
  976. 48 51 100 300
  977. Visible NoGoAway
  978. 1 ;; procID
  979. 0 ;; refCon
  980. -15997
  981.  
  982. Type DITL
  983. Next Page Template,-15997
  984. 3
  985.  
  986. *   1
  987. BtnItem Enabled
  988. 30 60 46 140
  989. Done
  990.  
  991. *   2
  992. BtnItem Enabled
  993. 30 160 46 240
  994. Stop
  995.  
  996. *   3
  997. StatText
  998. 8 8 24 292
  999. SerialPrint: Insert Next Sheet
  1000.  
  1001.  
  1002. Type DITL
  1003. Page Setup Template,-15999
  1004. 10
  1005.  
  1006. *   1
  1007. BtnItem
  1008. 96 165 112 235
  1009. Done
  1010.  
  1011. *   2
  1012. StatText
  1013. 64 201 82 316
  1014. Lines per page
  1015.  
  1016. *   3
  1017. StatText
  1018. 7 166 24 243
  1019. Page Setup
  1020.  
  1021. *   4
  1022. StatText
  1023. 34 5 50 50
  1024. Tabs
  1025.  
  1026. *   5
  1027. EditText
  1028. 34 135 52 167
  1029. runtime
  1030.  
  1031. *   6
  1032. EditText
  1033. 32 328 49 369
  1034. runtime
  1035.  
  1036. *   7
  1037. EditText
  1038. 64 136 80 177
  1039. runtime
  1040.  
  1041. *   8
  1042. EditText
  1043. 66 331 82 376
  1044. runtime
  1045.  
  1046. *   9
  1047. StatText
  1048. 64 5 80 122
  1049. Left Margin
  1050.  
  1051. *   10
  1052. StatText
  1053. 34 202 50 277
  1054. Width
  1055.  
  1056. Type Stng = GNRL
  1057. Printer Settings,-16000
  1058.  .H    ;; Printer port, 1200 baud,no sheet feed, tabstops 8, width = 90,
  1059. 0001 0002 0000 0008 005A 0008 0037 0000 0000    ;;left margin 8, 55 lines/page
  1060.  
  1061. Type MENU        ;; Set procID of this menu to 0 with ResEdit
  1062. SerialPrint menu,-16000    ;; for operation without la bombe
  1063. SerialPrint
  1064. About SerialPrintI
  1065. Printer SettingsI
  1066. Page SetupI
  1067. Flow ControlI
  1068. PrintI
  1069. Save Settings
  1070. Quit
  1071.  
  1072. Type STR#        ;; String list for EOL, EOP, BOP strings
  1073. Printer control strings,-16000
  1074. 5
  1075. ^M            ;; End of line
  1076. ^[^W            ;; Initialize printer
  1077. ^M^M^M^M^M        ;; beginning of page
  1078. ^L            ;; end of page
  1079. ^L            ;; end of document
  1080.  
  1081. Type STR#        ;; About this DA help strings
  1082. Help Strings,-15999
  1083. 12
  1084. SerialPrint, Edit of August 17, 1987\0DEarle R. Horton\0DPortions Copyright THINK Technologies\0DCompiled with the Lightspeed
  1085. C compiler and RMaker.
  1086. SerialPrint is an adaptable printing program meant to be used in draft mode with printers for which no Macintosh printer driv
  1087. er is available.
  1088. It prints text-only files which have a carriage return at the end of every line.\0DThis revision does not wrap long lines at 
  1089. word boundaries.
  1090. The Printer SettingsI menu allows you to change the port, baud rate, and five printer control strings.  Your printer manual s
  1091. hould have the appropriate settings to use.
  1092. Non-printing characters are set using control character notation.  For example, carriage return is "^M", line feed is "^J".\0
  1093. DSome printers require ^M at the end of a line, some require ^M^J.
  1094. To set the top margin, put the appropriate number of your printer's linefeed character combinations in the box marked "Top of
  1095.  page".
  1096. If your printer does not recognize the formfeed character (^L), just put some newlines in the box marked "Bottom of page".
  1097. The Page SetupI menu allows setting of tabstops, left margin, #columns in page, and page length.  Page length is the number o
  1098. f printed rows on the page, and does not include top and bottom margins.
  1099. The flow control menu has no effect with 64k ROM or Mac XL systems, where CTS flow control only is used.\0DFor newer systems,
  1100.  this menu allows selection of either XOn/XOff or CTS.
  1101. The flow control menu also allows you to specify whether the printer driver used is closed when you quit SerialPrint.\0D(Not 
  1102. done with 64k ROMs.)
  1103. The most difficult part of using SerialPrint may be obtaining the proper printer cable.  Obtain pinout diagrams of your Macin
  1104. tosh and printer; take them to a responsible electronics technician.
  1105. Settings are not saved unless the menu item is chosen.  This edit of SerialPrint saves its settings in the system file.
  1106.  
  1107. Type DLOG
  1108. Extended AboutI Box,-15998
  1109. About SerialPrint
  1110. 60 86 242 412
  1111. Visible NoGoAway
  1112. 1 ;; procID
  1113. 0 ;; refCon
  1114. -15998 ;; itemsID
  1115.  
  1116. Type DITL
  1117. Extended AboutI Box Template,-15998
  1118. 5
  1119.  
  1120. BtnItem
  1121. 152 44 171 109
  1122. More
  1123.  
  1124. BtnItem
  1125. 152 129 171 190
  1126. Less
  1127.  
  1128. BtnItem
  1129. 152 210 171 285
  1130. Enough
  1131.  
  1132. StatText Disabled
  1133. 18 111 25 229
  1134. SerialPrint
  1135.  
  1136. StatText
  1137. 46 8 142 310
  1138. String list <OWNER> + 2.
  1139.  
  1140. * This resource owned by: DRVR 12: local id 4
  1141. Type DLOG
  1142. more settings,-15996
  1143. New Dialog
  1144. 59 134 209 336
  1145. Visible GoAway
  1146. 1 ;; procID
  1147. 0 ;; refCon
  1148. -15996
  1149.  
  1150. * This resource owned by: DRVR 12: local id 4
  1151. Type DITL
  1152. flow control template,-15996
  1153. 4
  1154.  
  1155. BtnItem
  1156. 109 67 129 127
  1157. done
  1158.  
  1159. RadioItem
  1160. 10 19 30 193
  1161. XOn/XOff Flow control
  1162.  
  1163. RadioItem
  1164. 40 19 60 193
  1165. CTS Flow Control
  1166.  
  1167. ChkItem
  1168. 70 19 90 193
  1169. Close Driver on Quit
  1170.  
  1171. ________This_Is_The_END________
  1172. if test `wc -l < SerialPrint.rsrc` -ne 325; then
  1173.     echo 'shar: SerialPrint.rsrc was damaged during transit'
  1174.   echo '      (should have been 325 bytes)'
  1175. fi
  1176. fi        ; : end of overwriting check
  1177. exit 0
  1178.