home *** CD-ROM | disk | FTP | other *** search
- /*
- * dotmatrix.c -- make driver & postprocessor tables for dot-matrix printers
- *
- * This code brought to you as a public service by Eric S. Raymond, Feb 1988
- * and is copyrighted (c)1988 by the author. Use, distribute, and mangle
- * freely, but don't try to make money selling it unless you're going to send
- * me a cut. Send bug reports, love letters and death threats to eric@snark
- * aka ...!rutgers!vu-vlsi!snark!eric.
- */
- /*LINTLIBRARY*/ /* this suppresses some bogus messages about _iob */
- #include <stdio.h>
- #include <ctype.h>
-
- extern char *strcpy(), *strchr();
-
- #define TRUE 1
- #define FALSE 0
-
- /*
- * General equates. Note that this code has insidious ASCII dependencies all
- * through it (in particular, it counts on being able to step through all the
- * normal printables by starting at <sp>). EBCDIC sites can eat flaming death
- * for all I care. Have a nice day.
- */
- #define MAXGLEN 64 /* maximum width of a graphic in bits */
- #define CDEPTH 24 /* MX80 graphics are 8 bits deep */
- #define NAMSIZE 10 /* maximum size of character names */
- #define STAR '*' /* bit-on character for picture files */
- #define SI 0x17 /* ASCII SI starts a graphics escape */
- #define SO 0x16 /* ASCII SO ends a graphics escape */
- #define FNS 15 /* maximum size of a local filename + 1 */
- #define MAXLINE 80 /* maximum size of an input line */
- #define MAXMODE 10 /* maximum number of print modes supported */
-
- typedef struct
- {
- char name[NAMSIZE]; /* the mode name */
- int width; /* dot-matrix elements per character width */
- int height; /* height of chars in this mode */
- char fmt[NAMSIZE]; /* format string for graphics emission */
- }
- mode_t;
-
- static mode_t modes[MAXMODE]; /* printer mode table */
- static mode_t *maxmode = &modes[0]; /* next free mode slot */
-
- static char dtabfile[FNS] = "tab.mx80"; /* driver table source */
- static FILE *dtabfp; /* dtabfile open for output */
-
- static char postproto[FNS] = "post.proto"; /* postprocessor template */
- static FILE *protofp; /* postproto open for input */
-
- static char postcode[FNS] = "mx80.c"; /* result postprocessor */
- static FILE *postfp; /* postcode open for output */
-
- static char testfile[FNS] = "mx80.test"; /* result test file */
- static FILE *testfp; /* testfile open for output */
-
- /* miscellaneous globals */
- static char line[MAXLINE]; /* buffer for line processing */
- static char comment[MAXLINE]; /* description of the type */
- static char *ptype = "mx80"; /* device type we're customizing for */
- static int trigger = ' '; /* trigger character for postprocessor */
- static int verbose = FALSE; /* debugging flag */
- static int quiet = FALSE; /* if true, suppress stdout msgs */
- static int testflag = TRUE; /* test file creation flag */
- static int postflag = TRUE; /* postprocessor creation flag */
- static int dtabflag = TRUE; /* driver table creation flag */
- static int forcepost = FALSE; /* set true to suppress optimization */
- static int errline = 0; /* count of input lines processed */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- void transpix(), exit();
- int c;
- extern int optind;
-
- while ((c = getopt(argc, argv, "nvtpdq")) != EOF)
- {
- switch(c)
- {
- case 'n': /* don't try to emit printer controls from the table */
- forcepost = TRUE;
- break;
-
- case 'v': /* be verbose when parsing the picture file */
- verbose = TRUE;
- break;
-
- case 'q': /* suppress normal messages to stdout */
- quiet = TRUE;
- break;
-
- case 't': /* suppress test file creation */
- testflag = FALSE;
- break;
-
- case 'p': /* suppress postprocessor file creation */
- postflag = FALSE;
- break;
-
- case 'd': /* suppress driver table creation */
- dtabflag = FALSE;
- break;
- }
- }
-
- /* if the user gave a name, rename all files */
- if (optind < argc)
- {
- ptype = argv[optind];
- (void) sprintf(dtabfile, "tab%s.c", ptype);
- (void) sprintf(postcode, "%s.c", ptype);
- (void) sprintf(testfile, "%s.test", ptype);
- }
-
- /* open the postprocessor prototype if we're to create one */
- if (postflag && (protofp = fopen(postproto, "r")) == NULL)
- {
- (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postproto);
- exit(2);
- }
-
- /* open the postprocessor output if we're to generate one */
- if (postflag && (postfp = fopen(postcode, "w")) == NULL)
- {
- (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postcode);
- exit(2);
- }
-
- /* open the postprocessor output if we're to generate one */
- if (postflag && (postfp = fopen(postcode, "w")) == NULL)
- {
- (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", postcode);
- exit(2);
- }
-
- /* open the driver file output if we're to create one */
- if (dtabflag && (dtabfp = fopen(dtabfile, "w")) == NULL)
- {
- (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", dtabfile);
- exit(2);
- }
-
- /* open the test file output if we're to create one */
- if (testflag && (testfp = fopen(testfile, "w")) == NULL)
- {
- (void) fprintf(stderr, "dotmatrix: can't open %s file!\n", testfile);
- exit(2);
- }
- else if (testflag)
- (void) fprintf(testfp,
- ".\\\" %s -- special character test file\n", testfile);
-
- /* here's where we parse the picture file */
- if (postflag || dtabflag || testflag)
- {
- if (postflag)
- (void) fprintf(postfp,
- "/* %s -- postprocessor for %s */\n",
- postcode, dtabfile);
-
- while (fgets(line, sizeof(line), protofp) != NULL)
- if (strncmp(line, "$A", 2) == 0)
- {
- transpix();
- if (postflag)
- (void) fprintf(postfp, "#define MAXSPCH\t0%03o\n",trigger);
- }
- else
- (void) fputs(line, postfp);
-
- if (postflag)
- (void) fprintf(postfp, "/* %s ends here */\n", postcode);
- }
-
- /* if we are generating a test file, add a completeness indication */
- if (testflag)
- {
- (void) fprintf(testfp,".\\\" %s ends here\n", testfile);
- (void) fclose(testfp);
- }
- return(0);
- }
-
- static void transpix()
- /* read and translate a picture file from stdin */
- {
- void readpic(), enter(), makemode(), makeover();
- char tgon[MAXGLEN], tgoff[MAXGLEN], *sp;
- char name[NAMSIZE];
- int pass = 1;
-
- for (;;)
- {
- /* read in a line to parse */
- if (gets(line) == NULL)
- return;
- else
- errline++;
-
- if (verbose)
- (void) fprintf(stdout, "%s\n", line);
-
- comment[0] = 0;
-
- /* copy out the comment if there is one */
- if ((sp = strchr(line, '#')) != NULL)
- {
- (void) strcpy(comment, sp + 1);
- while (isspace(*sp) || *sp == '#')
- sp--;
- *++sp = 0;
- }
-
- /* here's where we check for the end of the passthrough section */
- if (pass)
- {
- if (strcmp(line, "charset") == 0)
- pass = 0;
- (void) fprintf(dtabfp, "%s\n", line);
- continue;
- }
-
- /* after charset, if the line is blank ignore it */
- else if (strspn(line, "\t ") == strlen(line))
- continue;
-
- /* interpret 'comment' directives */
- if (strncmp("comment ", line, 8) == 0)
- {
- if (postflag)
- (void) fprintf(postfp, "/* %s */\n", line + 8);
- continue;
- }
-
- /* interpret 'mode' directives */
- if (strncmp("mode ", line, 5) == 0)
- {
- makemode(line);
- continue;
- }
-
- /* interpret 'toggle' directives */
- if (sscanf(line, "toggle %s \"%[^\"]\" \"%[^\"]\"", name, tgon, tgoff))
- {
- /* interpret escape sequences including \000 */
- int tgonl = escape(tgon, tgon);
- int tgoffl = escape(tgoff, tgoff);
-
- /* Name Width Tstate Size Data */
- enter(name, 0, 0, tgonl, tgon);
- enter(name, 0, 1, tgoffl, tgoff);
-
- /* now we may need to generate a test file line */
- if (testflag)
- (void) fprintf(testfp,
- "This is a test of the %s\\%s%s toggle\n.br\n",
- name, name, name);
-
- continue;
- }
-
- /* interpret 'picture' sections */
- if (strncmp("picture ", line, 8) == 0)
- {
- readpic();
- continue;
- }
-
- /* interpret 'test' directives */
- if (strncmp("test ", line, 5) == 0 && testflag)
- {
- (void) fprintf(testfp, "%s\n.br\n", line + 5);
- continue;
- }
-
- /* interpret 'overstrike ' directives */
- if (strncmp("overstrike ", line, 11) == 0)
- {
- makeover(line);
- continue;
- }
-
- /* else there's garbage on the line */
- (void) fprintf(stderr,
- "dotmatrix: unknown command, line %d\n", errline);
- exit(1);
- }
- }
-
- static void makemode(mline)
- /* process a printer mode declaration */
- char *mline;
- {
- if (maxmode >= modes + MAXMODE - 1)
- {
- (void) fprintf(stderr, "dotmatrix: too many print modes\n");
- exit(1);
- }
-
- if (sscanf(mline, "mode %s %d %d \"%[^\"]\"",
- maxmode->name, &maxmode->width, &maxmode->height, maxmode->fmt)
- != 4)
- (void) fprintf(stderr, "dotmatrix: invalid mode line ignored\n");
- else if (maxmode->height > CDEPTH)
- (void) fprintf(stderr, "dotmatrix: height must be < %d\n", CDEPTH);
- else
- {
- (void) escape(maxmode->fmt, maxmode->fmt);
- maxmode++;
- }
- }
-
- static void makeover(oline)
- /* interpret an overstrike directive */
- char *oline;
- {
- char name[NAMSIZE], value[MAXGLEN];
- int fc;
-
- if ((fc = sscanf(oline, "overstrike %s %s", name, value)) != 2)
- {
- (void) fprintf(stderr,
- "dotmatrix: overstrike directive invalid, %d arguments found\n",
- fc);
- exit(1);
- }
- else
- {
- (void) escape(value, value);
- enter(name, 0, 2, 1, value);
-
- /* now we may need to generate a test file line */
- if (testflag)
- (void) fprintf(testfp,
- "%sThis is a test%s of the \\%s overstrike\n.br\n",
- name, name, name);
- }
- }
-
- static void readpic()
- /* process a single picture file entry */
- {
- char name[NAMSIZE]; /* nroff name of the graphic */
- int width = 1; /* the graphic width */
- char type[NAMSIZE]; /* type of the graphic (optional) */
- char value[MAXGLEN + NAMSIZE]; /* what we'll send */
- char graphic[MAXGLEN][CDEPTH]; /* where we'll read in the pattern */
- int lrow[CDEPTH]; /* the row lengths */
- int row, i, cwidth; /* scratch variables */
- char *sp, *tp; /* scratch variables */
- mode_t *mode; /* print mode selector */
-
- /* scan the header line */
- if (sscanf(line, "picture %s %d %s", name, &width, type) != 3)
- {
- (void) fprintf(stderr,
- "dotmatrix: invalid picture directive: %s\n", line);
- exit(1);
- }
-
- /* identify the print mode */
- for (mode = modes; mode <= maxmode; mode++)
- if (strcmp(type, mode->name) == 0)
- break;
- if (mode == maxmode)
- {
- (void) fprintf(stderr,
- "dotmatrix: %s is not a declared print mode, picture ignored\n",
- type);
- return;
- }
-
- /* next read in the pattern bits */
- for (row = 0; row < mode->height; row++)
- {
- if (fgets(graphic[row], MAXGLEN, stdin) == NULL)
- {
- (void) fprintf(stderr,
- "dotmatrix: ran out of graphic lines in %s\n",
- name);
- exit(1);
- }
- else if (verbose)
- (void) fprintf(stderr, "row %d: %s", row, graphic[row]);
- }
-
- /* emit the pattern strings if we're generating a postprocessor */
- if (postflag)
- {
- /* now interpret special escape */
- tp = value;
- cwidth = 0;
- for (sp = mode->fmt; *sp; sp++)
- {
- if (*sp != '%')
- {
- *tp++ = *sp;
- cwidth++;
- }
- else switch (*++sp)
- {
- case '%':
- *tp++ = '%';
- cwidth++;
- break;
- case 'h':
- *tp++ = ((width * mode->width) / 256);
- cwidth++;
- break;
- case 'l':
- *tp++ = (width * mode->width) % 256;
- cwidth++;
- break;
- case 'c':
- /* compute the row lengths */
- for (i = 0; i < mode->height; i++)
- lrow[i] = strlen(graphic[i]);
-
- /* now compute and emit Epson-flavored graphics bits */
- for (i = 0; i < width * mode->width; i++)
- {
- *tp++
- = (lrow[7] > i && graphic[7][i] == STAR) * 1
- + (lrow[6] > i && graphic[6][i] == STAR) * 2
- + (lrow[5] > i && graphic[5][i] == STAR) * 4
- + (lrow[4] > i && graphic[4][i] == STAR) * 8
- + (lrow[3] > i && graphic[3][i] == STAR) * 16
- + (lrow[2] > i && graphic[2][i] == STAR) * 32
- + (lrow[1] > i && graphic[1][i] == STAR) * 64
- + (lrow[0] > i && graphic[0][i] == STAR) * 128;
- }
- cwidth += width * mode->width;
- break;
- default:
- (void) fprintf(stderr,
- "dotmatrix: invalid escape in mode declaration\n");
- exit(1);
- break;
- }
- }
- enter(name, width, -1, cwidth, value);
- }
-
- /* now we may need to generate a test file line */
- if (testflag)
- (void) fprintf(testfp, "\\%s |%s| %s\n.br\n", name, name, comment);
- }
-
- static void enter(name, width, tstate, len, bytes)
- /* generate a postprocessor table entry */
- char *name; /* name of the entry */
- int width; /* its nroff width */
- int tstate; /* the toggle state entry */
- int len; /* number of data bytes in entry */
- char *bytes; /* data bytes to emit */
- {
- register int i;
- int funnycount = 0;
- char bbuf[MAXGLEN * 5 + 1];
-
- if (tstate != -1) /* force toggles to be done in the postprocessor */
- funnycount = 1;
- else
- /* test to see if the data contains nulls or plot-mode triggers */
- for (i = 0; i < len; i++)
- if (bytes[i] == 0 || (bytes[i] & 0200))
- funnycount++;
-
- /* if there are none, embed the sequence in the driver table */
- if (funnycount == 0 && !forcepost)
- {
- if (dtabflag)
- {
- char *np = name;
-
- if (np[0] == '\\' && np[1] == '(')
- np += 2;
-
- (void) expand(bytes, bbuf);
- (void) fprintf(dtabfp, "%s %d %s\n", np, width, bbuf);
- if (!quiet || verbose)
- (void) fprintf(stdout,
- "%s will be handled by the driver table\n", name);
- }
- return;
- }
-
- /* if we're generating a postprocessor, write the entry */
- if (postflag)
- {
- char *ttype = "";
-
- if (tstate == 0)
- ttype = " on ";
- else if (tstate == 1)
- ttype = " off";
-
- (void) fprintf(postfp,
- "/* %s%s */ {%d, %d, ", name, ttype, tstate, len);
-
- for (i = 0; i < len; i++)
- (void) fprintf(postfp, "0x%02x,", bytes[i] & 0xff);
-
- (void) fprintf(postfp, "},\n");
- }
-
- /* update the special character count and generate a driver change */
- if (tstate == 1) /* a toggle end string doesn't get its own entry, */
- trigger++; /* but must skip a postprocessor table slot */
- else /* a graphic or the start string of a toggle */
- {
- if (!forcepost && (!quiet || verbose))
- (void) fprintf(stdout,
- "%s will require postprocessor assistance\n",
- name);
-
- if (dtabflag)
- {
- char *np = name;
-
- if (np[0] == '\\' && np[1] == '(')
- np += 2;
-
- if (isprint(trigger) && trigger != '\\' && trigger != ' ')
- (void) fprintf(dtabfp, "%s %d \\%03.3o%c\\%03.3o\n",
- np, width, SI, trigger++, SO);
- else
- (void) fprintf(dtabfp, "%s %d \\%03.3o\\%03.3o\\%03.3o\n",
- np, width, SI, trigger++, SO);
- }
- }
- }
-
- /* dotmatrix.c ends here */
-