home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / commands / pf.lzh / PF / Source / print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-31  |  16.2 KB  |  679 lines

  1. /*---------------------------------------------------------*
  2.  | Author:  Maurizio Loreti, aka MLO or I3NOO.             |
  3.  | Address: University of Padova - Department of Physics   |
  4.  |          Via F. Marzolo, 8 - 35131 PADOVA - Italy       |
  5.  | Phone:   (39)(49) 844-313         FAX: (39)(49) 844-245 |
  6.  | E-Mail:  LORETI at IPDINFN (BITNET); or VAXFPD::LORETI  |
  7.  |         (DECnet) - VAXFPD is node 38.257 i.e. 39169; or |
  8.  |          LORETI@PADOVA.INFN.IT (INTERNET).              |
  9.  | Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
  10.  *---------------------------------------------------------*/
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdarg.h>
  15. #include <stdlib.h>
  16. #include <ctype.h>
  17. #include <exec/types.h>
  18. #include <intuition/intuition.h>
  19. #include <graphics/gfxbase.h>
  20. #include <libraries/dos.h>
  21. #include <libraries/reqbase.h>
  22. #include <devices/printer.h>
  23. #include "mlo.h"
  24. #include "pf2.h"
  25. #include "ext.h"
  26.  
  27. /**
  28.  | Intuition prototypes
  29. **/
  30.  
  31. long int SetSignal();
  32. PrintIO *CreatePort();
  33. int OpenDevice();
  34. int DoIO();
  35. PrintIO *CreateExtIO();
  36.  
  37. /**
  38.  | Routines (sorted in alphabetical order)
  39. **/
  40.  
  41. Boolean CheckBreak(void)
  42. {
  43.  
  44. /**
  45.  | Check for CTRL-C
  46. **/
  47.  
  48.   if (SetSignal(0L, 0x1000L)  &  0x1000L) {
  49.     return True;
  50.   }
  51.   return False;
  52. }
  53.  
  54. void CheckDefaults(void)
  55. {
  56.  
  57. /**
  58.  | As the name says, this procedure checks for incompatible options
  59.  | selected: e.g. the only Landscape fonts are Courier, so to give
  60.  | the command PF2 -TL ... is an error. I suppose that the internal
  61.  | fonts only are present; otherwise this procedure should be modified.
  62.  | Checks:
  63.  | -> Letter-Gothic: 12 or 24 cpi; portrait only.
  64.  | -> Times: proportional; portrait only.
  65.  | -> Courier: 10 or 20 cpi; plus 16.67 cpi for Courier Roman (not
  66.  |    allowed for Courier Italic).
  67.  | -> Landscape/Italic not allowed.
  68.  | -> The number of extra spaces inserted before every line must be
  69.  |    not negative.
  70. **/
  71.  
  72.   switch (Font) {
  73.     case GOTHIC:
  74.       Orientation = PORTRAIT;
  75.       if (Pitch == P10CPI) {
  76.         Pitch = P12CPI;
  77.       } else {
  78.         Pitch = P24CPI;
  79.       }
  80.       break;
  81.     case TIMES:
  82.       Orientation = PORTRAIT;
  83.       Pitch = PROPORTIONAL;
  84.       break;
  85.     case COURIER:
  86.       if (Pitch == P16_67CPI   &&   Style == ITALIC) {
  87.         Pitch = P20CPI;
  88.       }
  89.       break;
  90.   }
  91.  
  92.   if (Orientation == LANDSCAPE) {
  93.     Style = ROMAN;
  94.   }
  95.  
  96.   if (nBlanks < 0) {
  97.     nBlanks = 0;
  98.   } else {
  99.     if (nBlanks) {
  100.       Buffer = inBuffer + nBlanks;
  101.       memset(inBuffer, BLANK, nBlanks);
  102.     }
  103.   }
  104. }
  105.  
  106. void Cleanup(
  107.   int code
  108. ){
  109.  
  110. /**
  111.  | Releases all system resources (closes opened files
  112.  | and frees heap memory - if any). "code" is the
  113.  | status to be returned to the operating system.
  114. **/
  115.  
  116.   windowOff();
  117.  
  118.   if (fp  != NULL)        fclose(fp);
  119.  
  120.   if (pPB != NULL) {
  121.     if (pPB->line[0] != NULL)     free(pPB->line[0]);
  122.     free(pPB);
  123.   }
  124.  
  125.   if (PrinterOpened)      CloseDevice(IOrequest);
  126.   if (IOrequest != NULL)  DeleteExtIO(IOrequest, sizeof(PrintIO));
  127.   if (printPort != NULL)  DeletePort(printPort);
  128.  
  129.   if (ReqBase != NULL) {
  130.     PurgeFiles(&fr);
  131.     CloseLibrary(ReqBase);
  132.   }
  133.   if (GfxBase != NULL)        CloseLibrary(GfxBase);
  134.   if (IntuitionBase != NULL)  CloseLibrary(IntuitionBase);
  135.  
  136.   exit(code);
  137. }
  138.  
  139. void ClearPageBuffer(void)
  140. {
  141.  
  142. /**
  143.  | This routine resets the content of the page buffer
  144.  | used in the 2-pages-on-a-sheet mode to all-blank
  145.  | lines, and the pointer to the next line to be filled
  146.  | to the first line in the buffer.
  147. **/
  148.  
  149.   memset(pPB->line[0], BLANK, BUFFER_SIZE);
  150.   ThisLine = 0;
  151. }
  152.  
  153. void ClearThisPage(void)
  154. {
  155.  
  156. /**
  157.  | Called every end of file: in the normal mode, ejects a page;
  158.  | in the 2-pages mode, switches from the left to the right page
  159.  | (if there is at least a line on this page), and leaving the
  160.  | remainder of the lines on the current page all blank.
  161. **/
  162.  
  163.   switch (PageMode) {
  164.     case SINGLE_PAGE:
  165.       EjectPage();
  166.       break;
  167.     case LEFT_PAGE:
  168.       if (ThisLine) {
  169.         Header(UP);
  170.         PageMode = RIGHT_PAGE;
  171.         ThisLine = 0;
  172.       }
  173.       break;
  174.     case RIGHT_PAGE:
  175.       if (ThisLine) {
  176.         FlushBuffers();
  177.         PageMode = LEFT_PAGE;
  178.         ClearPageBuffer();
  179.       }
  180.       break;
  181.   }
  182. }
  183.  
  184. void Detab(
  185.   char *buffer,
  186.   int length
  187. ){
  188.  
  189. /**
  190.  | Translates TAB stops to blanks: TAB stops are assumed at columns
  191.  | (1 + N * nTabs), with N = 1, 2, ... ; the default value of nTabs
  192.  | is 8, and can be changed using the command switches. In the same
  193.  | time non-printable characters are deleted from the input string:
  194.  | for non-printable I mean characters from 00 to 037 and 0177, assuming
  195.  | that characters over 0177 have special meaning different for every
  196.  | computer and that nothing can be said about them.
  197.  | The buffer can hold "length" characters only.
  198. **/
  199.  
  200.   char temp[LINE_LENGTH];                 /* Internal buffer */
  201.   char *pC1, *pC2;                        /* Temporary pointers */
  202.   char *pEnd;                             /* Pointer to the buffer end */
  203.  
  204.   strcpy(temp, buffer);
  205.   pEnd = (buffer + length - 1);
  206.   for (pC1 = temp, pC2 = buffer; *pC1 && pC2 < pEnd; pC1++) {
  207.     if (*pC1 == TAB) {
  208.       do {
  209.         *pC2++ = BLANK;
  210.       } while (((pC2 - buffer) % nTabs) && (pC2 < pEnd));
  211.     } else {
  212.       if (isspace(*pC1)  ||  !iscntrl(*pC1)) {
  213.         *pC2++ = *pC1;
  214.       }
  215.     }
  216.   }
  217.   *pC2 = NIHIL;
  218. }
  219.  
  220. void DoOutput(
  221.   char *FileName
  222. ){
  223.  
  224. /**
  225.  | Sends to the printer the given file.
  226. **/
  227.  
  228.   if ((fp = fopen(FileName, "r")) == NULL) {
  229.     ErrMes("Can't open input file %s ...", FileName);
  230.     return;
  231.   }
  232.   if (FromCLI)    printf("Printing file %s ... ", FileName);
  233.  
  234.   while (fgets(Buffer, bufferLength, fp) != NULL) {
  235.     if (FromCLI  &&  CheckBreak()) {
  236.       printf("*** BREAK ***\n");
  237.       EjectPage();
  238.       ExitProgram();
  239.     }
  240.     Detab(Buffer, bufferLength);
  241.     OutLine();
  242.   }
  243.  
  244.   if (FromCLI)    printf("done.\n");
  245.   fclose(fp);
  246.   fp = NULL;
  247.   ClearThisPage();
  248. }
  249.  
  250. void DoubleLine(
  251.   char *left,
  252.   char *right
  253. ){
  254.  
  255. /**
  256.  | Prints a line in the 2-pages mode, the two parameters being
  257.  | pointers to the left-page line and the right-page line; a
  258.  | blank line is printed if the corresponding pointer is NULL.
  259. **/
  260.  
  261.   if (left == NULL) {
  262.     SendToPrinter("%c%*c%c%*c",
  263.         V_LINE, TOTAL_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
  264.   } else {
  265.     SendToPrinter("%c%*c%.*s%*c%c%*c",
  266.         V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, left,
  267.         SIDE_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
  268.   }
  269.  
  270.   if (right == NULL) {
  271.     SendToPrinter("%c%*c%c\r",
  272.         V_LINE, TOTAL_LENGTH, BLANK, V_LINE);
  273.   } else {
  274.     SendToPrinter("%c%*c%.*s%*c%c\r",
  275.         V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, right,
  276.         SIDE_LENGTH, BLANK, V_LINE);
  277.   }
  278. }
  279.  
  280. void EjectPage(void)
  281. {
  282.   SendToPrinter("%c", FORM_FEED);
  283. }
  284.  
  285. void ExitProgram(void)
  286. {
  287.   ResetPrinter();
  288.   if (FromCLI) printf("Good Bye!\n");
  289.   Cleanup(SYS_NORMAL_CODE);
  290. }
  291.  
  292. void FlushBuffers(void)
  293. {
  294.  
  295. /**
  296.  | In the 2-pages mode, prints the current page as
  297.  | it is (non filled lines will be left blank).
  298. **/
  299.  
  300.   int i;
  301.  
  302.   switch (PageMode) {
  303.     case LEFT_PAGE:
  304.       if (!ThisLine) return;
  305.       for (i=0; i<ThisLine; i++) {
  306.         DoubleLine(pPB->line[i], NULL);
  307.         InterLine();
  308.       }
  309.       for (i=ThisLine; i<PAGE_LENGTH; i++) {
  310.         DoubleLine(NULL, NULL);
  311.         InterLine();
  312.       }
  313.       Header(DOWN);
  314.       break;
  315.     case RIGHT_PAGE:
  316.       for (i=ThisLine; i<PAGE_LENGTH; i++) {
  317.         DoubleLine(pPB->line[i], NULL);
  318.         InterLine();
  319.       }
  320.       Header(DOWN);
  321.       break;
  322.   }
  323. }
  324.  
  325. void Header(
  326.   int type
  327. ){
  328.  
  329. /**
  330.  | Prints the top or the down header in the 2-pages mode:
  331.  | a solid line separated from the text by a blank line.
  332. **/
  333.  
  334.   memset(Buffer, H_LINE, TOTAL_LENGTH);
  335.  
  336.   if (type == UP) {
  337.     SendToPrinter("%c%.*s%c%*c%c%.*s%c\r",
  338.          NW, TOTAL_LENGTH, Buffer, NE, SEP_LENGTH,
  339.          BLANK, NW, TOTAL_LENGTH, Buffer, NE);
  340.     InterLine();
  341.   }
  342.   DoubleLine(NULL, NULL);
  343.   InterLine();
  344.   if (type == DOWN) {
  345.     SendToPrinter("%c%.*s%c%*c%c%.*s%c\r",
  346.          SW, TOTAL_LENGTH, Buffer, SE, SEP_LENGTH,
  347.          BLANK, SW, TOTAL_LENGTH, Buffer, SE);
  348.     EjectPage();
  349.   }
  350. }
  351.  
  352. void InitPrinter(void)
  353. {
  354.  
  355.   char *PitchID[] = {"10", "12", "16.67", "20", "24"};
  356.   UBYTE status[2] = {0, 0};
  357.   int dummy;
  358.  
  359. /**
  360.  | Connect properly to printer device
  361. **/
  362.  
  363.   printPort = CreatePort(PORT_NAME, 0);
  364.   IOrequest = CreateExtIO(printPort, sizeof(PrintIO));
  365.   if (!(PrinterOpened =
  366.        (OpenDevice("printer.device", 0, IOrequest, 0) == 0))) {
  367.     Cleanup(SYS_ABORT_CODE);
  368.   }
  369.  
  370. /**
  371.  | Check if the printer is there... Actually, if the printer is connected
  372.  | to the serial port, I don't know what to do: in this case I continue,
  373.  | knowing that a System requester will come after a while. If the printer
  374.  | is connected to the parallel port, printer selected (bit 0), paper out
  375.  | (bit 1) and printer offline (bit 2) are checked.
  376. **/
  377.  
  378.   FOREVER {
  379.     IOrequest->ios.io_Command = PRD_QUERY;
  380.     IOrequest->ios.io_Data    = (APTR) status;
  381.     IOrequest->ios.io_Flags   = 0;
  382.     if (DoIO(IOrequest)) {
  383.       Cleanup(SYS_ABORT_CODE);
  384.     }
  385.     if (IOrequest->ios.io_Actual == 2)  break;
  386.     if ((status[0] & 0x7) == 0x4)       break;
  387.  
  388.     ErrMes("Please, check if your printer is ready!");
  389.     if (FromCLI) {
  390.       printf("When done, enter <CR> ... ");
  391.       while (((dummy = getc(stdin)) != NEWLINE) && (dummy != EOF) ) {}
  392.       puts("");
  393.     }
  394.   }
  395.  
  396. /**
  397.  | Printer initialisation: see the HP DeskJet 500
  398.  | user's manual for explanation...
  399. **/
  400.  
  401.   SendToPrinter("%c&l%do%dD%c(10U%c(s0u", ESC, Orientation, Lpi, ESC, ESC);
  402.   if (Pitch == PROPORTIONAL) {
  403.     SendToPrinter("1p");
  404.   } else {
  405.     SendToPrinter("0p%sh", PitchID[Pitch]);
  406.   }
  407.   SendToPrinter("%dv%ds0b%dt%dQ", Height, Style, Font, Quality);
  408. }
  409.  
  410. void InterLine(void)
  411. {
  412.  
  413. /**
  414.  | Writing at 8 lines per inch and 6 points high characters,
  415.  | the double page border is not continuous. This procedure
  416.  | skips half line, draws the border, then skips another half
  417.  | line down to the correct placement for next printing.
  418. **/
  419.  
  420.   SendToPrinter("%c=", ESC);
  421.   DoubleLine(NULL, NULL);
  422.   SendToPrinter("%c=", ESC);
  423. }
  424.  
  425. void OutLine(void)
  426. {
  427.  
  428. /**
  429.  | Outputs a line to the printer.
  430.  | In the normal mode, the line is sent to the port after storing a
  431.  | carriage return and a line feed after the text, and leaving to the
  432.  | printer to deal with form feeds and long lines.
  433.  | In the 2-pages mode, the line is truncated to a fixed length: if
  434.  | we are in the left page, the line is stored in the internal buffer;
  435.  | otherwise, it is printed together with the corresponding left line.
  436. **/
  437.  
  438.   int length, n;
  439.   static char *EndOfLine = "\r\n";
  440.  
  441.   length = strlen(inBuffer) - 1;
  442.  
  443.   switch (PageMode) {
  444.     case SINGLE_PAGE:
  445.       memcpy(inBuffer+length, EndOfLine, 3);
  446.       SendBuffer(inBuffer);
  447.       break;
  448.     case LEFT_PAGE:
  449.       if (length > OUTPUT_LENGTH) {
  450.         length = OUTPUT_LENGTH;
  451.       }
  452.       memcpy(pPB->line[ThisLine], Buffer, length);
  453.       if (++ThisLine >= PAGE_LENGTH) {
  454.         Header(UP);
  455.         PageMode = RIGHT_PAGE;
  456.         ThisLine = 0;
  457.       }
  458.       break;
  459.     case RIGHT_PAGE:
  460.       if ((n = OUTPUT_LENGTH - length) > 0) {
  461.         memset(Buffer+length, BLANK, n);
  462.       }
  463.       DoubleLine(pPB->line[ThisLine], Buffer);
  464.       InterLine();
  465.       if (++ThisLine >= PAGE_LENGTH) {
  466.         Header(DOWN);
  467.         PageMode = LEFT_PAGE;
  468.         ClearPageBuffer();
  469.       }
  470.       break;
  471.   }
  472. }
  473.  
  474. void ResetPrinter(void)
  475. {
  476.  
  477. /**
  478.  | Resets the printer to the default.
  479. **/
  480.  
  481.   SendToPrinter("%cE", ESC);
  482. }
  483.  
  484. void SendBuffer(
  485.   char *buffer
  486. ){
  487.   IOrequest->ios.io_Command = PRD_RAWWRITE;
  488.   IOrequest->ios.io_Data    = (APTR) buffer;
  489.   IOrequest->ios.io_Length  = strlen(buffer);
  490.   IOrequest->ios.io_Flags   = 0;
  491.   if (DoIO(IOrequest)) {
  492.     Cleanup(SYS_ABORT_CODE);
  493.   }
  494. }
  495.  
  496. void SendToPrinter(
  497.   char *fmt,
  498.   ...
  499. ){
  500.   static char slate[LINE_LENGTH];
  501.   va_list vl;
  502.  
  503.   va_start(vl, fmt);
  504.   vsprintf(slate, fmt, vl);
  505.   va_end(vl);
  506.   SendBuffer(slate);
  507. }
  508.  
  509. void SetSpecialMode(void)
  510. {
  511.  
  512. /**
  513.  | Sets the internal constants for the "two pages on a sheet"
  514.  | special mode.
  515. **/
  516.  
  517.   int i;
  518.  
  519.   if ((pPB = malloc(sizeof(PageBuffer))) == NULL) {
  520.     ErrMes("Can't allocate the Page Buffer ...");
  521.     Cleanup(SYS_ABORT_CODE);
  522.   }
  523.   if ((pPB->line[0] = malloc(BUFFER_SIZE)) == NULL) {
  524.     ErrMes("Can't allocate the Line Buffer ...");
  525.     Cleanup(SYS_ABORT_CODE);
  526.   }
  527.   for (i=1; i<PAGE_LENGTH; i++) {
  528.     pPB->line[i] = pPB->line[0] + (i * OUTPUT_LENGTH);
  529.   }
  530.  
  531.   Orientation = LANDSCAPE;
  532.   Font = COURIER;
  533.   Style = ROMAN;
  534.   Pitch = P16_67CPI;
  535.   Height = 6;
  536.   Lpi = 8;
  537.   nBlanks = 0;
  538.   ClearPageBuffer();
  539. }
  540.  
  541. char **Setup(
  542.   int *pArgc,
  543.   char **argv
  544. ){
  545.  
  546. /**
  547.  | We look into the command line for switches; the function value is
  548.  | argv when pointing to the first non-switch argument (i.e. the first
  549.  | file name) - if any. If the 2-page mode was requested, the procedure
  550.  | allocates from the heap memory the internal buffer for the left-page
  551.  | lines, and a service buffer filled with the pointers to the first
  552.  | character of every line in the left page; this calling malloc(),
  553.  | to make this program more portable.
  554. **/
  555.  
  556.   int i;
  557.   char c;
  558.  
  559.   printf("\n\t\"PF2\" - v%.2f - MLO %ld\n\n", VERSION, LAST_CHANGE);
  560.  
  561. /**
  562.  | Error if called from the Workbench, or if called
  563.  | from the CLI but without any argument.
  564. **/
  565.  
  566.   if (*pArgc < 2) Syntax();
  567.  
  568.   while (--(*pArgc)) {
  569.     if ((*++argv)[0] == '-') {
  570.  
  571. /**
  572.  | A switch ...
  573. **/
  574.  
  575.       for (i=1; (c = (*argv)[i]); i++) {
  576.         switch (c) {
  577.           case 'l': case 'L':
  578.             Orientation = LANDSCAPE;
  579.             break;
  580.           case 'i': case 'I':
  581.             Style = ITALIC;
  582.             break;
  583.           case 'b': case 'B':
  584.             nBlanks = atoi(*argv + ++i);
  585.             goto NextSwitch;
  586.           case 'a': case 'A':
  587.             nTabs = atoi(*argv + ++i);
  588.             goto NextSwitch;
  589.           case 'g': case 'G':
  590.             Font = GOTHIC;
  591.             break;
  592.           case 't': case 'T':
  593.             Font = TIMES;
  594.             break;
  595.           case 's': case 'S':
  596.             Pitch = P16_67CPI;
  597.             break;
  598.           case 'x': case 'X':
  599.             Pitch = P20CPI;
  600.             break;
  601.           case '6':
  602.             Height = 6;
  603.             break;
  604.           case '8':
  605.             Lpi = 8;
  606.             break;
  607.           case 'd': case 'D':
  608.             Quality = DRAFT_Q;
  609.             break;
  610.           case '2':
  611.             PageMode = LEFT_PAGE;
  612.             break;
  613.           default:
  614.             Syntax();
  615.         }
  616.       }
  617.     } else {
  618.  
  619. /**
  620.  | The first file name; perform some
  621.  | intialisations, then return to the caller.
  622. **/
  623.  
  624.       if (PageMode != SINGLE_PAGE) {
  625.         SetSpecialMode();
  626.       } else {
  627.         CheckDefaults();
  628.       }
  629.       return argv;
  630.     }
  631.  
  632. NextSwitch: ;
  633.   }
  634.  
  635. /**
  636.  | Here if no file name given; initialise
  637.  | the printer, then exit without reset.
  638. **/
  639.  
  640.   CheckDefaults();
  641.   InitPrinter();
  642.   puts("Printer initialised ... Good bye!");
  643.   Cleanup(SYS_NORMAL_CODE);
  644. }
  645.  
  646. void Syntax(void)
  647. {
  648.  
  649. /**
  650.  | A syntax error has been detected in the command
  651.  | line; a short help is output to the screen.
  652. **/
  653.  
  654.   puts("Usage:   PF2   [switches]   [file [file [file ... ] ] ]");
  655.   puts("Switches: -l : Landscape (default is Portrait);");
  656.   puts("          -i : Italic (default is Roman);");
  657.   puts("         -bN : insert N Blanks before every output line;");
  658.   puts("         -aN : tAb stops every N characters (default: 8);");
  659.   puts("          -g : Letter-Gothic font (default is Courier);");
  660.   puts("          -t : Times font (default is Courier);");
  661.   puts("          -s : Small pitch (Courier: 16.67 cpi; "
  662.        "Letter-Gothic: 24 cpi);");
  663.   puts("          -x : eXtra-small pitch (20 cpi - for Courier only);");
  664.   puts("          -8 : 8 lines per inch (default: 6 lpi);");
  665.   puts("          -6 : 6 points high font (default: 12 points);");
  666.   puts("          -d : Draft quality (default is Letter quality);");
  667.   puts("          -2 : special mode (2 pages on every sheet of paper).\n");
  668.   puts("The s/x/l switches are ignored when incompatible with selected font.");
  669.   puts("The default pitch is 10 cpi for Courier and 12 cpi for Letter-Gothic");
  670.   puts("(Times is a proportional font);   all switches different from -d and");
  671.   puts("-a will be ignored,  if -2 is selected.  The switches on the command");
  672.   puts("line can be grouped: e.g. -c -8 -s is the same as -c8s; only -bN and");
  673.   puts("-aN, if present, must be specified alone or the last in a group. The");
  674.   puts("printer is reset to its default,  at the completion  -  UNLESS if no");
  675.   puts("file names are given. This program can be interrupted with CTRL-C.\n");
  676.  
  677.   Cleanup(SYS_NORMAL_CODE);
  678. }
  679.