home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / nroffgraphics / part02 / dotmatrix.c next >
C/C++ Source or Header  |  1988-06-06  |  15KB  |  539 lines

  1. /*
  2.  * dotmatrix.c -- make driver & postprocessor tables for dot-matrix printers
  3.  *
  4.  * This code brought to you as a public service by Eric S. Raymond, Feb 1988
  5.  * and is copyrighted (c)1988 by the author. Use, distribute, and mangle
  6.  * freely, but don't try to make money selling it unless you're going to send
  7.  * me a cut. Send bug reports, love letters and death threats to eric@snark
  8.  * aka ...!rutgers!vu-vlsi!snark!eric.
  9.  */
  10. /*LINTLIBRARY*/        /* this suppresses some bogus messages about _iob */
  11. #include <stdio.h>
  12. #include <ctype.h>
  13.  
  14. extern char *strcpy(), *strchr();
  15.  
  16. #define TRUE    1
  17. #define FALSE    0
  18.  
  19. /*
  20.  * General equates.  Note that this code has insidious ASCII dependencies all
  21.  * through it (in particular, it counts on being able to step through all the
  22.  * normal printables by starting at <sp>). EBCDIC sites can eat flaming death
  23.  * for all I care. Have a nice day.
  24.  */
  25. #define MAXGLEN    64    /* maximum width of a graphic in bits */
  26. #define CDEPTH    24    /* MX80 graphics are 8 bits deep */
  27. #define NAMSIZE    10    /* maximum size of character names */
  28. #define STAR    '*'    /* bit-on character for picture files */
  29. #define SI    0x17    /* ASCII SI starts a graphics escape */
  30. #define SO    0x16    /* ASCII SO ends a graphics escape */
  31. #define FNS    15    /* maximum size of a local filename + 1 */
  32. #define MAXLINE    80    /* maximum size of an input line */
  33. #define MAXMODE    10    /* maximum number of print modes supported */
  34.  
  35. typedef struct
  36. {
  37.     char name[NAMSIZE];    /* the mode name */
  38.     int width;        /* dot-matrix elements per character width */
  39.     int height;        /* height of chars in this mode */
  40.     char fmt[NAMSIZE];    /* format string for graphics emission */
  41. }
  42. mode_t;
  43.  
  44. static mode_t    modes[MAXMODE];            /* printer mode table */
  45. static mode_t    *maxmode = &modes[0];        /* next free mode slot */
  46.  
  47. static char    dtabfile[FNS]  = "tab.mx80";    /* driver table source */
  48. static FILE    *dtabfp;            /* dtabfile open for output */
  49.  
  50. static char    postproto[FNS] = "post.proto";    /* postprocessor template */
  51. static FILE    *protofp;            /* postproto open for input */
  52.  
  53. static char    postcode[FNS]  = "mx80.c";    /* result postprocessor */
  54. static FILE    *postfp;            /* postcode open for output */
  55.  
  56. static char    testfile[FNS]  = "mx80.test";    /* result test file */
  57. static FILE    *testfp;            /* testfile open for output */
  58.  
  59. /* miscellaneous globals */
  60. static char    line[MAXLINE];        /* buffer for line processing */
  61. static char    comment[MAXLINE];   /* description of the type */
  62. static char    *ptype = "mx80";    /* device type we're customizing for */
  63. static int    trigger = ' ';        /* trigger character for postprocessor */
  64. static int    verbose = FALSE;    /* debugging flag */
  65. static int    quiet = FALSE;        /* if true, suppress stdout msgs */
  66. static int    testflag = TRUE;    /* test file creation flag */
  67. static int    postflag = TRUE;    /* postprocessor creation flag */
  68. static int    dtabflag = TRUE;    /* driver table creation flag */
  69. static int    forcepost = FALSE;  /* set true to suppress optimization */
  70. static int    errline = 0;        /* count of input lines processed */
  71.  
  72. main(argc, argv)
  73. int    argc;
  74. char    *argv[];
  75. {
  76.     void    transpix(), exit();
  77.     int        c;
  78.     extern int    optind;
  79.  
  80.     while ((c = getopt(argc, argv, "nvtpdq")) != EOF)
  81.     {
  82.     switch(c)
  83.     {
  84.     case 'n':    /* don't try to emit printer controls from the table */
  85.         forcepost = TRUE;
  86.         break;
  87.  
  88.     case 'v':    /* be verbose when parsing the picture file */
  89.         verbose = TRUE;
  90.         break;
  91.  
  92.     case 'q':    /* suppress normal messages to stdout */
  93.         quiet = TRUE;
  94.         break;
  95.  
  96.     case 't':    /* suppress test file creation */
  97.         testflag = FALSE;
  98.         break;
  99.  
  100.     case 'p':    /* suppress postprocessor file creation */
  101.         postflag = FALSE;
  102.         break;
  103.  
  104.     case 'd':    /* suppress driver table creation */
  105.         dtabflag = FALSE;
  106.         break;
  107.     }
  108.     }
  109.  
  110.     /* if the user gave a name, rename all files */
  111.     if (optind < argc)
  112.     {
  113.     ptype = argv[optind];
  114.     (void) sprintf(dtabfile, "tab%s.c", ptype);
  115.     (void) sprintf(postcode, "%s.c", ptype);
  116.     (void) sprintf(testfile, "%s.test", ptype);
  117.     }
  118.  
  119.     /* open the postprocessor prototype if we're to create one */
  120.     if (postflag && (protofp = fopen(postproto, "r")) == NULL)
  121.     {
  122.     (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postproto);
  123.     exit(2);
  124.     }
  125.  
  126.     /* open the postprocessor output if we're to generate one */
  127.     if (postflag && (postfp = fopen(postcode, "w")) == NULL)
  128.     {
  129.     (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postcode);
  130.     exit(2);
  131.     }
  132.  
  133.     /* open the postprocessor output if we're to generate one */
  134.     if (postflag && (postfp = fopen(postcode, "w")) == NULL)
  135.     {
  136.     (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postcode);
  137.     exit(2);
  138.     }
  139.  
  140.     /* open the driver file output if we're to create one */
  141.     if (dtabflag && (dtabfp = fopen(dtabfile, "w")) == NULL)
  142.     {
  143.     (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", dtabfile);
  144.     exit(2);
  145.     }
  146.  
  147.     /* open the test file output if we're to create one */
  148.     if (testflag && (testfp = fopen(testfile, "w")) == NULL)
  149.     {
  150.     (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", testfile);
  151.     exit(2);
  152.     }
  153.     else if (testflag)
  154.     (void) fprintf(testfp,
  155.                ".\\\" %s -- special character test file\n", testfile);
  156.  
  157.     /* here's where we parse the picture file */
  158.     if (postflag || dtabflag || testflag)
  159.     {
  160.     if (postflag)
  161.         (void) fprintf(postfp,
  162.         "/* %s -- postprocessor for %s */\n",
  163.         postcode, dtabfile);
  164.  
  165.     while (fgets(line, sizeof(line), protofp) != NULL)
  166.         if (strncmp(line, "$A", 2) == 0)
  167.         {
  168.         transpix();
  169.         if (postflag)
  170.             (void) fprintf(postfp, "#define MAXSPCH\t0%03o\n",trigger);
  171.         }
  172.         else
  173.         (void) fputs(line, postfp);
  174.  
  175.     if (postflag)
  176.         (void) fprintf(postfp, "/* %s ends here */\n", postcode);
  177.     }
  178.  
  179.     /* if we are generating a test file, add a completeness indication */
  180.     if (testflag)
  181.     {
  182.     (void) fprintf(testfp,".\\\" %s ends here\n", testfile);
  183.     (void) fclose(testfp);
  184.     }
  185.     return(0);
  186. }
  187.  
  188. static void transpix()
  189. /* read and translate a picture file from stdin */
  190. {
  191.     void    readpic(), enter(), makemode(), makeover();
  192.     char    tgon[MAXGLEN], tgoff[MAXGLEN], *sp;
  193.     char    name[NAMSIZE];
  194.     int        pass = 1;
  195.  
  196.     for (;;)
  197.     {
  198.     /* read in a line to parse */
  199.     if (gets(line) == NULL)
  200.         return;
  201.     else
  202.         errline++;
  203.  
  204.     if (verbose)
  205.         (void) fprintf(stdout, "%s\n", line);
  206.  
  207.     comment[0] = 0;
  208.  
  209.     /* copy out the comment if there is one */
  210.     if ((sp = strchr(line, '#')) != NULL)
  211.     {
  212.         (void) strcpy(comment, sp + 1);
  213.         while (isspace(*sp) || *sp == '#')
  214.         sp--;
  215.         *++sp = 0;
  216.     }
  217.  
  218.     /* here's where we check for the end of the passthrough section */
  219.     if (pass)
  220.     {
  221.         if (strcmp(line, "charset") == 0)
  222.         pass = 0;
  223.         (void) fprintf(dtabfp, "%s\n", line);
  224.         continue;
  225.     }
  226.  
  227.     /* after charset, if the line is blank ignore it */
  228.     else if (strspn(line, "\t ") == strlen(line))
  229.         continue;
  230.  
  231.     /* interpret 'comment' directives */
  232.     if (strncmp("comment ", line, 8) == 0)
  233.     {
  234.         if (postflag)
  235.         (void) fprintf(postfp, "/* %s */\n", line + 8);
  236.         continue;
  237.     }
  238.  
  239.     /* interpret 'mode' directives */
  240.     if (strncmp("mode ", line, 5) == 0)
  241.     {
  242.         makemode(line);
  243.         continue;
  244.     }
  245.  
  246.     /* interpret 'toggle' directives */
  247.     if (sscanf(line, "toggle %s \"%[^\"]\" \"%[^\"]\"", name, tgon, tgoff))
  248.     {
  249.         /* interpret escape sequences including \000 */
  250.         int tgonl = escape(tgon, tgon);
  251.         int tgoffl = escape(tgoff, tgoff);
  252.         
  253.         /*   Name    Width    Tstate    Size    Data */
  254.         enter(name,    0,    0,    tgonl,    tgon);
  255.         enter(name, 0,    1,    tgoffl,    tgoff);
  256.  
  257.         /* now we may need to generate a test file line */
  258.         if (testflag)
  259.         (void) fprintf(testfp,
  260.             "This is a test of the %s\\%s%s toggle\n.br\n",
  261.             name, name, name);
  262.  
  263.         continue;
  264.     }
  265.  
  266.     /* interpret 'picture' sections */
  267.     if (strncmp("picture ", line, 8) == 0)
  268.     {
  269.         readpic();
  270.         continue;
  271.     }
  272.  
  273.     /* interpret 'test' directives */
  274.     if (strncmp("test ", line, 5) == 0 && testflag)
  275.     {
  276.         (void) fprintf(testfp, "%s\n.br\n", line + 5);
  277.         continue;
  278.     }
  279.  
  280.     /* interpret 'overstrike ' directives */
  281.     if (strncmp("overstrike ", line, 11) == 0)
  282.     {
  283.         makeover(line);
  284.         continue;
  285.     }
  286.  
  287.     /* else there's garbage on the line */
  288.     (void) fprintf(stderr,
  289.                "dotmatrix: unknown command, line %d\n", errline);
  290.     exit(1);
  291.     }
  292. }
  293.  
  294. static void makemode(mline)
  295. /* process a printer mode declaration */
  296. char *mline;
  297. {
  298.     if (maxmode >= modes + MAXMODE - 1)
  299.     {
  300.     (void) fprintf(stderr, "dotmatrix: too many print modes\n");
  301.     exit(1);
  302.     }
  303.  
  304.     if (sscanf(mline, "mode %s %d %d \"%[^\"]\"",
  305.         maxmode->name, &maxmode->width, &maxmode->height, maxmode->fmt)
  306.         != 4)
  307.     (void) fprintf(stderr, "dotmatrix: invalid mode line ignored\n");
  308.     else if (maxmode->height > CDEPTH)
  309.     (void) fprintf(stderr, "dotmatrix: height must be < %d\n", CDEPTH);
  310.     else
  311.     {
  312.     (void) escape(maxmode->fmt, maxmode->fmt);
  313.     maxmode++;
  314.     }
  315. }
  316.  
  317. static void makeover(oline)
  318. /* interpret an overstrike directive */
  319. char *oline;
  320. {
  321.     char    name[NAMSIZE], value[MAXGLEN];
  322.     int fc;
  323.  
  324.     if ((fc = sscanf(oline, "overstrike %s %s", name, value)) != 2)
  325.     {
  326.     (void) fprintf(stderr,
  327.         "dotmatrix: overstrike directive invalid, %d arguments found\n",
  328.         fc);
  329.     exit(1);
  330.     }
  331.     else
  332.     {
  333.     (void) escape(value, value);
  334.     enter(name, 0, 2, 1, value);
  335.  
  336.     /* now we may need to generate a test file line */
  337.     if (testflag)
  338.         (void) fprintf(testfp,
  339.                "%sThis is a test%s of the \\%s overstrike\n.br\n",
  340.                name, name, name);
  341.     }
  342. }
  343.  
  344. static void readpic()
  345. /* process a single picture file entry */
  346. {
  347.     char    name[NAMSIZE];        /* nroff name of the graphic */
  348.     int        width = 1;            /* the graphic width */
  349.     char    type[NAMSIZE];        /* type of the graphic (optional) */
  350.     char    value[MAXGLEN + NAMSIZE];    /* what we'll send */
  351.     char    graphic[MAXGLEN][CDEPTH];   /* where we'll read in the pattern */
  352.     int        lrow[CDEPTH];        /* the row lengths */
  353.     int        row, i, cwidth;        /* scratch variables */
  354.     char    *sp, *tp;            /* scratch variables */
  355.     mode_t  *mode;            /* print mode selector */
  356.  
  357.     /* scan the header line */
  358.     if (sscanf(line, "picture %s %d %s", name, &width, type) != 3)
  359.     {
  360.     (void) fprintf(stderr,
  361.                "dotmatrix: invalid picture directive: %s\n", line);
  362.     exit(1);
  363.     }
  364.  
  365.     /* identify the print mode */
  366.     for (mode = modes; mode <= maxmode; mode++)
  367.     if (strcmp(type, mode->name) == 0)
  368.         break;
  369.     if (mode == maxmode)
  370.     {
  371.     (void) fprintf(stderr,
  372.         "dotmatrix: %s is not a declared print mode, picture ignored\n",
  373.         type);
  374.     return;
  375.     }
  376.  
  377.     /* next read in the pattern bits */
  378.     for (row = 0; row < mode->height; row++)
  379.     {
  380.     if (fgets(graphic[row], MAXGLEN, stdin) == NULL)
  381.     {
  382.         (void) fprintf(stderr,
  383.         "dotmatrix: ran out of graphic lines in %s\n",
  384.         name);
  385.         exit(1);
  386.     }
  387.     else if (verbose)
  388.         (void) fprintf(stderr, "row %d: %s", row, graphic[row]);
  389.     }
  390.  
  391.     /* emit the pattern strings if we're generating a postprocessor */
  392.     if (postflag)
  393.     {
  394.     /* now interpret special escape */
  395.     tp = value;
  396.     cwidth = 0;
  397.     for (sp = mode->fmt; *sp; sp++)
  398.     {
  399.         if (*sp != '%')
  400.         {
  401.         *tp++ = *sp;
  402.         cwidth++;
  403.         }
  404.         else switch (*++sp)
  405.         {
  406.         case '%':
  407.         *tp++ = '%';
  408.         cwidth++;
  409.         break;
  410.         case 'h':
  411.         *tp++ = ((width * mode->width) / 256);
  412.         cwidth++;
  413.         break;
  414.         case 'l':
  415.         *tp++ = (width * mode->width) % 256;
  416.         cwidth++;
  417.         break;
  418.         case 'c':
  419.         /* compute the row lengths */
  420.         for (i = 0; i < mode->height; i++)
  421.             lrow[i] = strlen(graphic[i]);
  422.  
  423.         /* now compute and emit Epson-flavored graphics bits */
  424.         for (i = 0; i < width * mode->width; i++)
  425.         {
  426.             *tp++
  427.             = (lrow[7] > i && graphic[7][i] == STAR) * 1
  428.             + (lrow[6] > i && graphic[6][i] == STAR) * 2
  429.             + (lrow[5] > i && graphic[5][i] == STAR) * 4
  430.             + (lrow[4] > i && graphic[4][i] == STAR) * 8
  431.             + (lrow[3] > i && graphic[3][i] == STAR) * 16
  432.             + (lrow[2] > i && graphic[2][i] == STAR) * 32
  433.             + (lrow[1] > i && graphic[1][i] == STAR) * 64
  434.             + (lrow[0] > i && graphic[0][i] == STAR) * 128;
  435.         }
  436.         cwidth += width * mode->width;
  437.         break;
  438.         default:
  439.         (void) fprintf(stderr,
  440.                "dotmatrix: invalid escape in mode declaration\n");
  441.         exit(1);
  442.         break;
  443.         }
  444.     }
  445.     enter(name, width, -1, cwidth, value);
  446.     }
  447.  
  448.     /* now we may need to generate a test file line */
  449.     if (testflag)
  450.     (void) fprintf(testfp, "\\%s  |%s|  %s\n.br\n", name, name, comment);
  451. }
  452.  
  453. static void enter(name, width, tstate, len, bytes)
  454. /* generate a postprocessor table entry */
  455. char    *name;    /* name of the entry */
  456. int    width;  /* its nroff width */
  457. int    tstate;    /* the toggle state entry */
  458. int    len;    /* number of data bytes in entry */
  459. char    *bytes;    /* data bytes to emit */
  460. {
  461.     register int    i;
  462.     int            funnycount = 0;
  463.     char        bbuf[MAXGLEN * 5 + 1];
  464.  
  465.     if (tstate != -1)    /* force toggles to be done in the postprocessor */
  466.     funnycount = 1;
  467.     else
  468.     /* test to see if the data contains nulls or plot-mode triggers */
  469.     for (i = 0; i < len; i++)
  470.         if (bytes[i] == 0 || (bytes[i] & 0200))
  471.         funnycount++;
  472.  
  473.     /* if there are none, embed the sequence in the driver table */
  474.     if (funnycount == 0 && !forcepost)
  475.     {
  476.     if (dtabflag)
  477.     {
  478.         char *np = name;
  479.  
  480.         if (np[0] == '\\' && np[1] == '(')
  481.         np += 2;
  482.  
  483.         (void) expand(bytes, bbuf);
  484.         (void) fprintf(dtabfp, "%s %d %s\n", np, width, bbuf);
  485.         if (!quiet || verbose)
  486.         (void) fprintf(stdout,
  487.                "%s will be handled by the driver table\n", name);
  488.     }
  489.     return;
  490.     }
  491.  
  492.     /* if we're generating a postprocessor, write the entry */
  493.     if (postflag)
  494.     {
  495.     char    *ttype = "";
  496.  
  497.     if (tstate == 0)
  498.         ttype = " on ";
  499.     else if (tstate == 1)
  500.         ttype = " off";
  501.  
  502.     (void) fprintf(postfp,
  503.                "/* %s%s */ {%d, %d, ", name, ttype, tstate, len);
  504.  
  505.     for (i = 0; i < len; i++)
  506.         (void) fprintf(postfp, "0x%02x,", bytes[i] & 0xff);
  507.  
  508.     (void) fprintf(postfp, "},\n");
  509.     }
  510.  
  511.     /* update the special character count and generate a driver change */
  512.     if (tstate == 1)    /* a toggle end string doesn't get its own entry, */
  513.     trigger++;    /*  but must skip a postprocessor table slot      */
  514.     else        /* a graphic or the start string of a toggle */
  515.     {
  516.     if (!forcepost && (!quiet || verbose))
  517.         (void) fprintf(stdout,
  518.         "%s will require postprocessor assistance\n",
  519.         name);
  520.  
  521.     if (dtabflag)
  522.     {
  523.         char *np = name;
  524.  
  525.         if (np[0] == '\\' && np[1] == '(')
  526.         np += 2;
  527.  
  528.         if (isprint(trigger) && trigger != '\\' && trigger != ' ')
  529.         (void) fprintf(dtabfp, "%s %d \\%03.3o%c\\%03.3o\n",
  530.               np, width, SI, trigger++, SO);
  531.         else
  532.         (void) fprintf(dtabfp, "%s %d \\%03.3o\\%03.3o\\%03.3o\n",
  533.               np, width, SI, trigger++, SO);
  534.     }
  535.     }
  536. }
  537.  
  538. /* dotmatrix.c ends here */
  539.