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