home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 613b.lha / PF_v2.12 / Source / pf1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-26  |  17.3 KB  |  624 lines

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