home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
-
- File: epr.c
- Function: Permits listing of files on Epson printer with control
- over format of listing and printer attributes.
- Version: 1.10-A
- Author: Robert Sjoberg (SJOBRG@MIT-OZ)
- Implementation notes:
- Originally written to be compiled using Computer Innovations C86
- compiler running under IBM PC-DOS. Requires external functions
- in "timestmp.c"; should run under CP/M without modification,
- provided compiler and C library has support for stdin, stdout, and
- stderr output (Aztec C certainly does).
- Code written applies to Epson FX-80 printer.
- Revision History:
- V1.00 (09/24/83) - original program.
- V1.01 - put in h= option.
- V1.02 - added new dash options, fixed the way initialization done.
- V1.03 - added -p option to allow change of sheet-fed paper.
- V1.04 - added code to turn off autoskip on paper perforation;
- modified to use timestmp external function.
- V1.05 (11/28/83) - fixed bug in optfile routine and added o= option.
- V1.06 (01/08/84) - Fixed line overflow problem, introduced b= option.
- V1.07 (01/27/84) - Added -1 option, changed -t option to -h and so
- that it only suppresses the header, not top margin.
- V1.08 (05/23/84) - Modified for Unix V7.
- V1.09 (06/27/84) - Added -d switch, modified -s to simply suppress
- printer control codes. Added "UPMODE" hack. Sigh.
- V1.10 (07/16/84) - Removed -d switch (it is redundant with o=),
- added c= keyword to select character set.
-
- 11 Dec 85 Craig Milo Rogers at USC/ISI (Rogers@USC-ISIB.ARPA)
- Added another debugging line.
-
- Converting to Lattice C (ver. 2.12).
-
- Changed "c" and "firstc" from "char" to "int" in getline() --
- EOF tests weren't working! Same for "term" in main() and
- "c" in optfile().
-
- Tabs weren't working when international characters were
- enabled, uparrow mode didn't work -- I recoded the whole
- section.
-
- I added code to allow Epson escape sequences to be specified
- in the user's header. Should be redone more cleanly, though.
-
- The table of printer widths didn't specify the full 137 chars
- possible in condensed (ie, compressed) mode. It didn't tell
- about enlarged compressed pitch, either. I rewrote it.
-
- The program didn't allow specification of the full set of Epson
- FX-80 print modes. I rewrote the code involved.
-
- I added code to allow the header print modes to be assigned the
- same way as the modes for the body. However, I didn't give
- the header a seperate columns-per-line value.
-
- I changed the default left margin to be 0 (this isn't completely
- arbitrary, my measurements of the margin didn't agree with
- what the program claimed it was doing.
-
- NOTICE This program is furnished to the public domain. It may
- ------ not be sold or otherwise commercially distributed for
- profit, in its original form or in any derivational form.
- It may be copied and distributed freely, without charge
- to recipients. If you see fit to improve this program,
- you are welcome to do so PROVIDED you clearly indicate
- the changes in the Revision History above, you include
- your name and handle (network or U.S. Mail address is
- sufficient), and you provide an original copy of this
- program to anyone who receives the modified copy.
-
- ************************************************************************/
-
- /* Select host operating system by defining appropriate symbol.
- * The default is PCDOS for PC-DOS or MS-DOS or CP/M. The alternative
- * is UNIX for UNIX V7 (also works for newer UNIX).
- */
-
- #ifndef UNIX
- #ifndef PCDOS
- #define PCDOS
- #endif
- #endif
-
- /* Format of include file names may be changed at different sites */
- #include <stdio.h>
- #include "timestmp.h"
-
- #ifdef UNIX
- #include <ctype.h>
- #endif
-
- #ifndef EOS
- #define EOS '\0' /* end of string character */
- #endif
-
- /* Define the name of the device attached to printer */
-
- #ifdef UNIX
- #define Epson "/dev/tty01" /* name of printer device */
- #define UPMODE 2 /* Unix will not output certain control
- * codes unless in RAW mode, but then it
- * doesn't like XON/XOFF protocol. This
- * gets around some (temporary) problems
- * the author is having. It should not
- * affect use of epr. */
- #endif
-
- #ifdef PCDOS
- #define Epson "PRN:" /* name of printer device */
- #define UPMODE 0
- #endif
-
- /* CP/M converts its command line to upper case, so use the following
- * to convert critical characters to lower case, for both CP/M and
- * PC-DOS/MS-DOS implementations.
- */
- #define casecvt(x) if (isupper(x)) x = tolower(x)
-
- /* Debugging information (lots of it) is available by defining the
- * symbol "Dbug". All diagnostic output is written to stderr.
- */
- /*
- #define Dbug 1
- */
-
- #ifdef Dbug
- #define DBG(form) form
- FILE *dfp = stderr;
- #else
- #define DBG(form)
- #endif
-
- /* Convenience definitions */
- #define BS '\b' /* Ascii 010 */
- #define HT '\t' /* Ascii 011 */
- #define LF '\n' /* Ascii 012 */
- #define FF '\f' /* Ascii 014 */
- #define CR '\r' /* Ascii 015 */
- #define ESC '\033'
- #define SP ' '
- #define DEL '\177'
- #define LL 0276 /* used to indicate long line on input */
- #define EOH 0277 /* marks end of page header sequence */
-
- /* Dash Option Variables */
- char altset = 0; /* -a, 1 if use alternate character set */
- char cchar = 0; /* -c, 1 if print control chars as ^X */
- char ffeed = 0; /* -f, 1 if use form feed to end page */
- char nohead = 0; /* -h, 1 if header should be suppressed */
- char intl = 0; /* -i, 1 if allow international chars */
- char trunc = 0; /* -o, 1 if truncate long lines */
- char pagpaus = 0; /* -p, 1 if special start-of-page pause */
- char nopcc = 0; /* -s, 1 if suppress printer control codes */
- char nopage1 = 0; /* -1, 1 if suppress heading on page 1 */
- char space8 = 0; /* -8, 1 if use 8 lines/inch */
-
- /* Output Control and Printer Modes (currently only Epson) */
- FILE *ofp; /* output file pointer */
- char outfile[50]=Epson; /* name of output file (o= option) */
- short pmode = 0; /* mode byte for p= option */
- short qmode = 0; /* mode byte for q= option */
-
- #define F_t 010000 /* top (ie, superscript) */
- #define F_s 04000 /* subscript */
- #define F_p 02000 /* proportional */
- #define F_u 01000 /* underlined */
- #define F_i 0400 /* italic */
- #define F_e 040 /* expanded */
- #define F_d 020 /* double strike */
- #define F_b 010 /* bold (ie, emphasized) */
- #define F_c 04 /* compressed */
- #define F_l 01 /* elite */
-
- short cmode = 0; /* intl character set (defaults to U.S.A.) */
- char *cntries[] = { /* table of country mnemonics */
- "us","fr","ge","uk","de","sw","it","sp","ja",NULL
- };
-
- /* Input control */
- char **nextf = NULL; /* list of input file names */
- short nfiles; /* number of files to process */
-
- /* Page formatting */
- short topmar = -1; /* top margin, in lines */
- short leftmar = -1; /* left margin, in chars */
- short cpl = -1; /* chars per line */
- short lpp = -1; /* number of lines per page before FF */
- short phycpl; /* number of physical chars per line */
- short phylpp; /* number of physical lines per page */
- short tabspaces = 8; /* tabs expand into this many spaces */
- short headpf = 0; /* flags order of pagen, filename */
- short hlines; /* number of lines in header */
- char header[80] = /* holds header string */
- "%d %t %f Page %p\\n\\n"; /* default header */
- char hformat[130]; /* actual header format string */
- char textline[256]; /* holds input text line */
- struct timedata timeinfo; /* holds time and date info */
-
-
- Abort (msg, param)
- char *msg;
- int param;
- /*
- * Prints out an error message with optional parameter, then exits
- * with non-zero exit code.
- */
- {
- fprintf(stderr,"epr: ");
- fprintf(stderr,msg,param);
- fprintf("\n");
- exit (1);
- }
-
-
- /* The main sequence following handles input file specs and reading
- * in characters. Makes line-by-line output.
- * If no file names are specified in the command, then input is
- * from standard input.
- */
-
- main (argc,argv)
- int argc;
- char **argv;
- {
- FILE *ifp; /* fp for input file */
- char *filename; /* input filename */
- int pagen; /* page number */
- int lines; /* lines processed per page */
- int c, l, n, endfile;
- int term; /* line terminator */
- char *tl;
-
- DBG(fprintf(dfp,"About to parse command line.\n");)
- pcl (argc, argv); /* parse command line options */
-
- DBG(fprintf(dfp,"About to initialize.\n");)
- initialize ();
-
- /* For debugging */
- #ifdef Dbug
- fprintf (dfp,"Output is to %s\n",
- (outfile[0] ? outfile : "stdout"));
- fprintf (dfp,"altset %d, cchar %d, pagpaus %d, ffeed %d\n",
- altset,cchar,pagpaus,ffeed);
- fprintf (dfp,"intl %d, trunc %d, nohead %d, space8 %d\n",
- intl,trunc,nohead,space8);
- fprintf (dfp,"pmode %04o, qmode %04o, headpf %d, nopcc %d, nopage1 %d\n",
- pmode,qmode,headpf,nopcc,nopage1);
- fprintf (dfp,"topmar %d, leftmar %d, cpl %d, lpp %d\n",
- topmar,leftmar,cpl,lpp);
- fprintf (dfp,"header [%s]\n",header);
- fprintf (dfp,"hlines %d, hformat [%s]\n",hlines,hformat);
- fprintf (dfp,"nfiles %d",nfiles);
- for (n = 0; n < nfiles; n++) fprintf (dfp,", %s",nextf[n]);
- fprintf (dfp,"\n");
- #endif
-
- if (nfiles == 0) { /* input from stdin */
- ifp = stdin;
- }
- do { /* repeat for each file */
- if (ifp != stdin) {
- filename = *nextf++;
- nfiles--;
- DBG( fprintf (dfp,"Opening %s ...\n",filename); )
- ifp = fopen (filename, "r");
- if (ifp == NULL) {
- fprintf (stderr,"Couldn't open %s -- skipping\n",filename);
- continue;
- }
- }
- else {
- filename = "stdin";
- /* DBG( fprintf (dfp,"Using stdin ...\n"); ) */
- }
- endfile = 0;
- term = 0;
- for (pagen = 1; ; pagen++) { /* repeat for each page */
- /* Pause at start of each page, if requested */
- if (pagpaus) {
- printf ("Set up printer and type CR...");
- while (getchar() != LF);
- }
- /* Output any top margin and header */
- lines = 0;
- if (n = topmar) { /* write top margin */
- sendpcc(pmode); /* Send body printer modes. */
- lines += n;
- while (n--) putc (LF,ofp);
- }
- if (!(nohead || (pagen == 1 && nopage1))) {
- sendpcc(qmode); /* Send header printer modes. */
- lines += outhead (pagen, filename);
- }
- sendpcc(pmode); /* Send body printer modes. */
-
- while (lines < lpp) {
- if (term != LL && term != CR) {
- /* Not continuation of long line or overprint */
- if ((term = getline (ifp, textline)) == EOF) {
- endfile++; break;
- }
- if (term == FF) break; /* end of page */
- /*
- * Routine putline writes a full line of text to
- * output and returns the line-terminating char.
- * A CR means the line is being overprinted; a LF
- * means true end-of-line; a FF means a lone FF seen;
- * and LL means long line (wrapped).
- */
- tl = textline;
- /* DBG(showtl(tl);) */
- }
- term = putline (&tl, 0);
- if (term == CR) putc(term,ofp); /* overprint */
- else {
- putc(LF,ofp); /* end of line */
- lines++;
- }
- }
- /* Write any trailing blank lines */
- if (ffeed) putc(FF,ofp);
- else while (lines++ < phylpp) putc(LF,ofp);
-
- if (endfile) break;
- }
- if (ifp != stdin) fclose (ifp);
- } while (nfiles > 0);
-
- DBG(fprintf(dfp,"Closing output file\n");)
- fflush (ofp);
- if (ofp != stdout) fclose (ofp); /* close output file */
- }
-
- char htext[120]; /* holds formatted header text */
-
- outhead (pagen, filename)
- int pagen;
- char *filename;
- /*
- * Print the header using the given page number and filename.
- */
- {
- int c, lines;
- char *tl;
-
- /* There are two forms for the header format string. In one, the
- * page number comes before the file name (or just the page number
- * is used), and in the other the file name comes before the page
- * number (or just the file name is used).
- */
- if (headpf) sprintf (htext, hformat, pagen, filename);
- else sprintf (htext, hformat, filename, pagen);
- tl = htext;
- lines = 0;
- do {
- c = putline (&tl, 1);
- /* DBG(fprintf(dfp,"Got %03o\n",c&0377);) */
- if (c == LF) { putc(c,ofp); lines++; }
- } while (c != EOH);
- return (lines);
- }
-
- #ifdef Dbug
-
- showtl (s)
- register char *s;
- /*
- * Display the text line to be output for debugging.
- */
- {
- fprintf(dfp,"showtl[");
- while (*s) {
- if (*s < SP || *s == DEL) fprintf(dfp,"^%c",*s ^ 0100);
- else if (*s < DEL) fprintf(dfp,"%c",*s);
- else fprintf(dfp,"\\%03o ",*s & 0377);
- s++;
- }
- fprintf(dfp,"]\n");
- }
- #endif
-
-
- initialize ()
-
- /*
- * Obtains current date and time information and places it in a global
- * structure. Establishes default values for formatting options, validates
- * them, and if output is to printer, outputs appropriate format information.
- * These defaults may be changed to suit individual preferences.
- */
- {
- timestmp (&timeinfo); /* gets date and time */
-
- /* The Epson FX-80 has three basic pitches: pica (the default),
- * elite, and compressed. They are mutually exclusive (but may
- * be enabled by seperate commands, in which case elite has
- * priority over compressed, which is over pica). All three
- * basic pitches may be "expanded", for a total of six pitches.
- *
- * In addition to the six pitches there are other modes (italic,
- * double-strike, emphasized, proportional, and underlined) which
- * may be combined with each other and the six pitches in various
- * patterns (but not arbitrarily).
- *
- * Since the FX-80 has a printing width of 8.0 inches, the following
- * table gives the number of characters per line in each of the
- * six pitches (it doesn't apply when proportional mode is turned on,
- * of course):
- *
- * Basic Pitch Expanded? Chars/Line
- * ----------- --------- ----------
- * pica no 80
- * elite no 96
- * compressed no 137
- * pica yes 40
- * elite yes 48
- * compressed yes 68
- */
-
- DBG(fprintf(dfp,"Before respmode, pmode = %o, qmode = %o\n",pmode,qmode);)
- pmode = respmode(pmode); /* Resolve Epson FX-80 conflicts. */
- qmode = respmode(qmode);
- DBG(fprintf(dfp,"Resolved pmode = %o, qmode = %o\n",pmode,qmode);)
-
- if (pmode & F_l) {
- phycpl = 96;
- } else if (pmode & F_c) {
- phycpl = 137;
- } else {
- phycpl = 80;
- }
- if (pmode & F_e) phycpl = phycpl / 2;
- DBG(fprintf(dfp,"Physical characters per line = %d\n",phycpl);)
-
- if (leftmar < 0) leftmar = 0;
- if (cpl <= 0) cpl = phycpl - leftmar;
-
- if (nohead) hlines = 0; /* inhibit header */
- else formatheader (); /* build actual header string */
-
- phylpp = (space8 ? 88 : 66); /* number lines per 11 inch page */
- if (topmar < 0) topmar = 0;
- /*
- * lpp counts number of actual text lines, top margin, and number of
- * lines in header (i.e., everything but bottom margin).
- */
- if (lpp <= 0) lpp = phylpp - 5; /* subtract bottom margin */
- else lpp += hlines + topmar;
-
- /* Open printer or output file. Unless printer codes have been
- * suppressed, output them to condition the printer.
- */
- if (outfile[0] == EOS) ofp = stdout; /* use stdout */
- else {
- ofp = fopen (outfile,"w");
- if (ofp == NULL) abort ("Can't open %s for output!",outfile);
- }
-
- if (!nopcc) { /* control codes, unless inhibited */
- putc(ESC,ofp); putc('O',ofp); /* turn off auto-skip over
- * perforation */
- /* Page pause also means deselecting out-of-paper detector */
- putc(ESC,ofp);
- if (pagpaus) putc('8',ofp);
- else putc('9',ofp);
- }
- }
-
- sendpcc(mode)
- int mode; /* The mode to use. */
- /*
- * This routine sends the printer control codes that are set before
- * and after each page header (allowing the page header to set different
- * values).
- */
- {
- if (!nopcc) { /* control codes, unless inhibited */
- putc(ESC,ofp); /* line spacing, 6 or 8 per inch */
- if (space8) putc('0',ofp);
- else putc('2',ofp);
-
- putc(ESC,ofp); /* alternate character set */
- if (altset) putc('4',ofp);
- else putc('5',ofp);
-
-
- putc(ESC,ofp); /* "master print mode" */
- putc('!',ofp);
- putc((mode|UPMODE) &0377,ofp);
-
- putc(ESC,ofp); /* underline mode */
- putc('-',ofp);
- if (mode & F_u) putc('1',ofp);
- else putc('0',ofp);
-
- putc(ESC,ofp); /* italic mode */
- if (mode & F_i) putc('4',ofp);
- else putc('5',ofp);
-
- putc(ESC,ofp); /* Super/sub-script mode */
- if (mode & F_t) { /* Superscript mode. */
- putc('S',ofp);
- putc('0',ofp);
- } else if (mode & F_s) { /* Subscript mode. */
- putc('S',ofp);
- putc('1',ofp);
- } else putc('T',ofp); /* Neither. */
-
- putc(ESC,ofp); /* proportional mode */
- putc('p',ofp);
- if (mode & F_p) putc('1',ofp);
- else putc('0',ofp);
-
- /* Select international character set */
- putc(ESC,ofp);
- putc('R',ofp);
- putc(cmode,ofp);
- }
- }
-
-
- formatheader ()
-
- /*
- * Creates the header format string from the source string in array header.
- */
- {
- char *s, *h, c;
- int v; /* Builds an ASCII character value. */
-
- s = header; /* source string */
- h = hformat; /* final format string */
- hlines = 0; /* number of newlines in header */
-
- while (c = *s++) { /* Repeat for each character in header. */
- switch (c) { /* Dispatch on this character. */
-
- case '%': /* Percent lead-in. */
- h += percent (h, *s++);
- break;
-
- case '\\': /* Backslash-quoted char. */
- c = *s++; /* Get the next char. */
- casecvt(c); /* Lower its case. */
- switch (c) { /* Dispatch it. */
- case '\\': *h++ = '\\'; break;
- case 'n': *h++ = '\n'; hlines++; break;
- case 't': *h++ = '\t'; break;
- case 'r': *h++ = '\r'; break;
- case 'b': *h++ = '\b'; break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- v = c - '0'; /* Ugh! ASCII-specific. */
- c = *s;
- if (isdigit(c)) {
- s++;
- v = (v * 8) + (c - '0');
- c = *s;
- if (isdigit(c)) {
- s++;
- v = (v * 8) + (c - '0');
- }
- }
- *h++ = v;
- break;
-
- default: /* Unknown backslashed char. */
- *h++ = '\\';
- *h++ = c;
- }
- break;
-
- default: /* Neither backslash nor percent. */
- *h++ = c;
- }
- }
- *h++ = '\n'; hlines++;
- *h++ = EOH;
- *h++ = EOS;
- headpf &= 1; /* save only order flag */
- }
-
- /*
- * Need to keep track of whether %p and %f appear in header, and if
- * both do, in which order, so we can pick the right sprintf when
- * printing the header.
- */
- #define hp_f 02 /* %f seen */
- #define hp_p 04 /* %p seen */
-
- percent (h, c)
- char c, *h;
- /*
- * Process one of the special %x options in the header source, where
- * c gives the option (char following the %). Returns number of
- * chars inserted in h.
- */
- {
- casecvt(c);
- DBG(fprintf(dfp,"percent(%c)\n",c);)
- switch (c) {
- case ' ': *h = ' '; return (1);
- case '%': *h = '%'; return (1);
- case 'd': return (getdate (h));
- case 't': return (gettime (h));
- case 'f':
- if (headpf & hp_f) Abort ("%%f given twice in header string");
- headpf |= hp_f;
- if (headpf & hp_p) headpf |= 1;
- *h++ = '%'; *h++ = 's'; return (2);
- case 'p':
- if (headpf & hp_p) Abort ("%%p given twice in header string");
- headpf |= hp_p;
- if (!(headpf & hp_f)) headpf |= 1;
- *h++ = '%'; *h++ = 'd'; return (2);
- default: return (0);
- }
- }
-
- gettime (s)
- char *s;
- /*
- * Gets current time in the form "hh:mm" and places it in string s.
- * Returns number of chars inserted.
- */
- {
- sprintf (s,"%2d:%02d",timeinfo.tim_hr,timeinfo.tim_min);
- return (5);
- }
-
- getdate (s)
- char *s;
- /*
- * Gets date in the form "dd mon yyyy" and puts it into string s.
- * Returns the length of the string inserted.
- */
- {
- sprintf (s,"%2d %s %4d",timeinfo.tim_dat,
- timemon[timeinfo.tim_mon],timeinfo.tim_yr);
- return (11);
- }
-
- getline (ifp, s)
- FILE *ifp;
- register char *s;
- /*
- * Fills array s with chars from stream ifp. Stops when it reads
- * LF, FF, or EOF. Returns the terminator (one of these three)
- * but inserts a LF as the last character in s (plus a EOS).
- * Does special processing:
- * CR LF, CR FF, CR EOF all ignore the CR;
- * FF at end of line with no preceding text gets turned into LF FF;
- * EOF at end of line with no preceding text gets turned into LF EOF.
- * Returns of FF and EOF happen only when they are read at the
- * beginning of the line.
- */
- {
- register int c;
- static int firstc = 0;
- int n;
-
- if (firstc) { c = firstc; firstc = 0; }
- else c = getc(ifp);
-
- /* Skip initial CR's */
- while (c == CR) c = getc(ifp);
-
- if (c == EOF || c == FF) return (c);
-
- n = 0; /* use as flag if any text chars seen */
- while (c != LF) {
- /* DBG(fprintf(dfp,"GET %3o ",c);) */
- if (c == CR) {
- c = getc(ifp);
- /* CR followed by terminator is ignored */
- if (c != LF && c != FF && c != EOF) *s++ = CR;
- }
- if (c == FF || c == EOF) {
- /*
- * If no text chars have been processed yet, then return c.
- * Otherwise, simulate LF and save c for next call.
- */
- if (n == 0) return (c);
- firstc = c;
- c = LF;
- }
- if (c != LF) { /* Normal text char or LF */
- *s++ = c;
- n++;
- c = getc(ifp); /*next char */
- }
- }
- *s++ = LF;
- *s++ = EOS; /* for safety's sake */
- return (LF);
- }
-
-
- putline (sp, sflg)
- char **sp;
- int sflg; /* !=0 ==> pass specials through. */
- /*
- * Process one line's worth of input, from the string pointed to by sp,
- * after printing blanks for the left margin. Stops when termination
- * condition met:
- * (1) when LF is seen, returns LF;
- * (2) when CR is seen, returns CR;
- * (3) when EOH is seen (only when printing header), returns EOH;
- * (4) when cpl chars have been printed, returns LF.
- * Updates sp to point to the next char to be read. Expands tabs into
- * appropriate number of spaces (determined by tabspaces variables).
- */
- {
- register char *s;
- int c, chrs, num;
- int lmflg = 0; /* TRUE ==> printed left margin. */
- int pmode; /* Printing mode. */
- #define PRINTMODE 0 /* Normal printing character. */
- #define TABMODE 1 /* Expand tabs. */
- #define UPARROWMODE 2 /* Uparrow prefix. */
-
- s = *sp; /* Local copy of pointer. */
- chrs = 0; /* Carriage position (no margin). */
- /* DBG(fprintf(dfp,"putline (%o)\n",s);) */
-
- while (1) {
- /* Dispatch on next character */
- c = *s++ & 0377; /* Pick up a character. */
- if (c == EOH) { /* Check for end-of-header. */
- *sp = s; /* Update the string pointer. */
- return (c); /* Return the terminator. */
- }
- if (c < SP || c == DEL) {
- /* DBG(fprintf(dfp,"Ctrl %03o at %d\n",c,s - *sp);) */
- switch (c) {
- case CR: /* Terminators. */
- case LF:
- *sp = s; /* Update the string pointer. */
- return (c); /* Return the terminator. */
-
- case BS: /* Backspace -- backup if we can. */
- if (chrs) {
- putc(c, ofp);
- chrs--;
- }
- continue; /* Proceed with the next char. */
-
- case HT: /* Horizontal tab -- expand it. */
- num = tabspaces - (chrs % tabspaces);
- pmode = TABMODE;
- break;
-
- default: /* Other control characters. */
- if (intl && validintl(c)) {
- num = 1; /* Int'l mode -- printing char. */
- pmode = PRINTMODE;
- } else if (sflg) { /* Special header -- print it. */
- num = 0; /* Part of an escape sequence? */
- pmode = PRINTMODE;
- } else if (cchar) {
- num = 2; /* Uparrow mode -- prefix it. */
- pmode = UPARROWMODE;
- } else continue; /* Unwanted char -- ignore it. */
- }
- } else { /* Regular printing char. */
- num = 1;
- pmode = PRINTMODE;
- }
-
- /*
- * If we get here we know we intend to print something.
- * So, first we gotta print a left margin (if needed). Next,
- * we check whether we're about to cross the right margin.
- * If all's OK we print whatever we're trying to print.
- */
-
- if (!lmflg) { /* Output blanks for left margin */
- register int n = leftmar;
- while (n--) putc(SP,ofp);
- lmflg = 1;
- }
-
- chrs += num; /* update count */
- if (chrs > cpl) { /* handle overflow line */
- /* DBG(fprintf(dfp,"Line overflow. *sp %o, s %o, diff %d\n",
- *sp,s,s - *sp);) */
- if (!trunc) { /* fold line */
- if (c != HT) s--; /* back up a char */
- *sp = s; /* Return updated pointer. */
- return (LL); /* Indicate long line. */
- }
- }
-
- switch (pmode) { /* Dispatch on special print mode. */
- case PRINTMODE: /* Normal printing char. */
- putc(c, ofp);
- break;
-
- case TABMODE: /* Expand tabs. */
- while (num--) putc(SP, ofp);
- break;
-
- case UPARROWMODE: /* Uparrow-prefix. */
- putc('^', ofp);
- if (c == DEL) {
- putc('?', ofp);
- } else {
- putc(c + '@', ofp);
- }
- }
- }
- }
-
- validintl (c)
- char c;
- /*
- * Returns 1 if char c is one of the international characters for
- * the Epson printer, 0 otherwise. (An international character is
- * one that is assigned an Ascii code in the range 0 to 31 decimal,
- * but that can be printed if in a special mode--Epson calls this
- * mode "control code selection".)
- */
- {
- if (c < 6 || c == 16 || c == 17 || c >= 21 && c <= 31 && c != 27)
- return (1);
- else return (0);
- }
-
-
- pcl (argc, argv)
- int argc; char **argv;
- /*
- * Parse command line and set option variables
- */
- {
- int n;
-
- argc--;
- argv++;
- n = getopts (argc, argv);
- DBG(fprintf(dfp,"getopts => %d, argc %d\n",n,argc);)
- argc -= n;
- argv += n;
- if (nfiles = argc) nextf = argv;
- }
-
- getopts (argc, argv)
- int argc; char **argv;
- /*
- * Set option variables according to the command line given in argc/argv.
- * Return number of arguments processed.
- */
- {
- int cnt;
- char *p;
-
- cnt = argc;
- while (argc) {
- DBG(fprintf(dfp,"Processing %d %s\n",argc,*argv);)
- p = *argv++; argc--;
- if (*p == '-') { /* found a switch */
- p++;
- while (*p) dodash (*p++);
- } else if (p[1] == '=') {
- casecvt(p[0]);
- if (p[0] == 'h') { /* collect header string */
- char delim, *h, c;
- p += 2;
- delim = *p++;
- h = header;
- while ((c = *p++) != delim) {
- if (c == EOS) {
- if (argc == 0)
- Abort ("No terminating quote in h=");
- p = *argv++; argc--;
- *h++ = SP; /* end of a substring in the
- * command line before end of
- * the end of the header is
- * turned into a blank.
- */
- }
- else *h++ = c;
- }
- *h++ = EOS;
- }
- else doequal (p); /* found a keyword */
- } else {
- argc++; argv--;
- break; /* file names follow */
- }
- }
- return (cnt - argc);
- }
-
-
- dodash (c)
- char c;
- /*
- * Process dash option given by c
- */
- {
- casecvt(c);
- DBG(fprintf(dfp,"dodash(%c)\n",c);)
- switch (c) {
- case 'a': altset++; break;
- case 'c': cchar++; break;
- case 'f': ffeed++; break;
- case 'h': nohead++; break;
- case 'i': intl++; break;
- case 'o': trunc++; break;
- case 'p': pagpaus++; break;
- case 's': nopcc++; break;
- case '1': nopage1++; break;
- case '8': space8++; break;
- default:
- Abort ("unrecognized switch option -%c",c);
- }
- }
-
-
- doequal (s)
- char *s;
- /*
- * Process a keyword=value option given by string s. Notice that there
- * is no checking on the bounds of the values accepted by the
- * parameters, although there certainly ought to be.
- */
- {
- char c;
-
- c = *s;
- casecvt(c);
- s += 2;
- switch (c) {
- case 'b': tabspaces = atoi(s); break;
- case 'c': cmode = country(s); break;
- case 'f': optfile (s); break;
- case 'l': lpp = atoi(s); break;
- case 'm': leftmar = atoi(s); break;
- case 'o': strcpy(outfile,s); break;
- case 'p': pmode = getpmode (s); break;
- case 'q': qmode = getpmode (s); break;
- case 't': topmar = atoi(s); break;
- case 'w': cpl = atoi(s); break;
- default:
- Abort ("unrecognized keyword %c=",c);
- }
- }
-
- country (s)
- char *s;
- /*
- * Matches string s against the list of country mnemonics and, if a
- * match is found, returns the corresponding country code. Otherwise,
- * returns 0 (default for USA). Only the first two characters of s
- * are significant.
- */
- {
- int n;
- char **p;
-
- casecvt(s[0]); casecvt(s[1]); /* make lower case */
- for (n = 0, p = cntries; *p; n++, p++) {
- if (s[0] == (*p)[0] && s[1] == (*p)[1]) break;
- }
- if (*p == NULL) n = 0;
- return (n);
- }
-
-
- getpmode (s)
- char *s;
- /*
- * Constructs the printer mode from the string s and returns it.
- */
- {
- int n;
- char c;
-
- n = 0;
- while (*s) {
- c = *s;
- casecvt(c);
- switch (c) {
- case 'b': n |= F_b; break; /* bold (ie, emphasized) */
- case 'c': n |= F_c; break; /* condensed */
- case 'd': n |= F_d; break; /* double strike */
- case 'e': n |= F_e; break; /* enlarged */
- case 'i': n |= F_i; break; /* italic */
- case 'l': n |= F_l; break; /* elite */
- case 'p': n |= F_p; break; /* proportional */
- case 's': n |= F_s; break; /* subscript */
- case 't': n |= F_t; break; /* top (superscript) */
- case 'u': n |= F_u; break; /* underlined */
- default:
- Abort ("invalid printer mode specifier %c", *s);
- }
- s++;
- }
- return (n);
- }
-
- respmode(n)
- int n; /* The user's mode spec. */
- /*
- * Resolve a printer mode spec by applying the Epson FX-80
- * priority rules. In the descriptions below, "->" means overrides.
- */
- {
- /* Elite -> Proportional -> Emphasized -> Compressed */
- if (n & F_l) n &= ~(F_p|F_b|F_c);
- if (n & F_p) n &= ~(F_b|F_c);
- if (n & F_b) n &= ~(F_c);
-
- /* Proportional -> (Superscript, Subscript, Double Strike) */
- if (n & F_p) n &= ~(F_t|F_s|F_d);
-
- /*
- * Superscript and Subscript are exclusive. This program (not
- * the Epson FX-80) will give Subscript priority.
- */
- if (n & F_s) n &= ~(F_t);
-
- /* Superscript and Subscript imply Double Strike */
- if (n & (F_t|F_s)) n |= F_d;
-
- return (n); /* Return the resolved mode. */
- }
-
- optfile (filnam)
- char *filnam;
- /*
- * Found f=filnam option. Take options from given file, make them
- * appear like command line (build an argc and argv vector), and call
- * getopts on the result.
- */
- {
- FILE *fp;
- char buf[160], *p, *argv[16];
- int c;
- int argc;
-
- fp = fopen (filnam, "r");
- if (fp == NULL) {
- fprintf (stderr, "File %s not found. ",filnam);
- Abort ("Cannot process f= option.");
- }
- DBG(fprintf(dfp,"Indirect file %s\n",filnam);)
- for (p = buf, argc = 0, c = 0; c != EOF; ) {
- do c = getc (fp); while (isspace(c)); /* skip blanks */
- if (c == EOF) break;
- argv[argc++] = p; /* next argument */
- do { /* save argument */
- *p++ = c;
- c = getc(fp);
- } while (!isspace(c) && c != EOF);
- *p++ = EOS;
- DBG(fprintf(dfp,"Arg %d is '%s'\n",argc,argv[argc-1]);)
- if (c == EOF) break;
- }
- DBG(fprintf(dfp,"EOF on optfile\n");)
- fclose (fp);
- getopts (argc, argv);
- }
-