/* * cawf - a C version of Henry Spencer's awf(1), the Amazingly * Workable (text) Formatter * * V. Abell, Purdue University Computing Center * Version 1.0, February, 1991 */ /* * Copyright (c) 1991 Purdue University Research Foundation, * West Lafayette, Indiana 47907. All rights reserved. * * Written by Victor A. Abell , Purdue * University Computing Center. Not derived from licensed software; * derived from awf(1) by Henry Spencer of the University of Toronto. * * Permission is granted to anyone to use this software for any * purpose on any computer system, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The author is not responsible for any consequences of use of * this software, even if they arise from flaws in it. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. Credits must appear in the * documentation. * * 3. Altered versions must be plainly marked as such, and must not * be misrepresented as being the original software. Credits must * appear in the documentation. * * 4. This notice may not be removed or altered. */ #include "cawf.h" #ifdef UNIX #ifdef USG #include #else #include #endif #include #else #include #include #include #include #include #endif main(argc, argv) int argc; char *argv[]; { char buf[MAXLINE]; /* character buffer */ char *ep; /* environment pointer */ int f = 0; /* -f option count */ char *files[MAXFILES]; /* file names */ int i; /* temporary index */ size_t l; /* length */ char *lib = CAWFLIB; /* library path */ int libl; /* library path length */ int mac = 0; /* macro specification status */ int nf = 0; /* number of files */ char *np; /* name pointer */ int pc; /* prolog count */ struct stat sbuf; /* stat buffer */ /* * Save program name. */ if ((Pname = strrchr(argv[0], '\\')) != NULL) Pname++; else if ((Pname = strrchr(argv[0], '/')) != NULL) Pname++; else Pname = argv[0]; /* * Set error file stream pointer. */ Efs = stderr; /* * Get library name. */ if ((np = getenv("CAWFLIB")) != NULL) lib = np; libl = strlen(lib); /* * Get device file name. */ if ((ep = getenv("TERM")) == NULL || *ep == '\0') ep = "dumb"; l = libl + 1 + strlen(ep) + strlen(".dev") + 1; if ((np = malloc(l)) == NULL) Error(FATAL, NOLINE, " no string space for device file name", NULL); (void) sprintf(np, "%s/%s.dev", lib, ep); files[nf++] = np; /* * Get common text file name. */ l = libl + 1 + strlen("common") + 1; if ((np = malloc(l)) == NULL) Error(FATAL, NOLINE, " no string space for common file name", NULL); (void) sprintf(np, "%s/common", lib); files[nf++] = np; /* * Process options. */ while ((i = getopt(argc, argv, "f:m:")) != EOF) { switch (i) { /* * -f: n = none * b = use backspaces and underlines (default) * e = use ESC */ case 'f': switch(*optarg) { case 'n': case 'b': case 'e': Fontout = *optarg; f++; break; default: Error(WARN, NOLINE, "illegal -f option: ", optarg); } break; /* * -m */ case 'm': if (mac) { Error(WARN, NOLINE, "multiple macro file declaration", NULL); break; } l = libl + 2 + strlen(optarg) + strlen(".mac") + 1; if ((np = malloc(l)) == NULL) Error(FATAL, NOLINE, " no string space for ", argv[1]); (void) sprintf(np, "%s/m%s.mac", lib, optarg); files[nf++] = np; if (strcmp(optarg, "an") == 0) Marg = MANMACROS; else if (strcmp(optarg, "s") == 0) Marg = MSMACROS; mac++; break; case '?': Err = 1; } } if (f > 1) Error(WARN, NOLINE, " conflicting font (-f) specifications"); if (Err) { (void) fprintf(stderr, "%s usage: -f[n|b|e] -m[macro_file] file . . .\n", Pname); exit(1); } if (mac == 0) { /* * No macroes - enable Bold, Italic and Roman fonts. */ for (i = 0; Fcode[i].nm; i++) { switch (Fcode[i].nm) { case 'B': case 'I': case 'R': Fcode[i].status = '1'; } } } /* * Add user-supplied file names. */ pc = nf; if (optind >= argc) { files[nf++] = NULL; /* STDIN */ } else { while (optind < argc) { if (nf >= MAXFILES) Error(WARN, NOLINE, " too many files at ", argv[optind]); files[nf++] = argv[optind++]; } } /* * Make sure all input files are accessible. */ for (i = 0; i < nf; i++) { if (files[i] != NULL) { if (stat(files[i], &sbuf) != 0) Error(WARN, NOLINE, " can't find ", files[i]); } } if (Err) exit(1); /* * Miscellaneous initialization. */ for (i = 0; ; i++) { if (Pat[i].re == NULL) break; if ((Pat[i].pat = regcomp(Pat[i].re, 0)) == NULL) Error(WARN, NOLINE, Pat[i].re, " regcomp failure"); } if ((i = Findscale('n', 0.0, 0)) < 0) Error(WARN, NOLINE, " can't find Scale['n']", NULL); Scalen = Scale[i].val; if ((i = Findscale('u', 0.0, 0)) < 0) Error(WARN, NOLINE, " can't find Scale['u']", NULL); Scaleu = Scale[i].val; if ((i = Findscale('v', 0.0, 0)) < 0) Error(WARN, NOLINE, " can't find Scale['v']", NULL); Scalev = Scale[i].val; (void) Findstr("CH", "= % -", 1); Cont = Newstr(" "); Contlen = 1; if ((Trtbl = (char *)malloc(256)) == NULL) Error(WARN, NOLINE, " can't allocate translate table space", NULL); else { *Trtbl = ' '; for (i = 1; i < 256; i++) Trtbl[i] = (char) i; } if (Err) exit(1); /* * Here begins pass1 of awf - reading input lines and expanding macros. */ /* * Output prolog. */ Macro(".^x"); Macro(".^b"); Macro(".^# 1 "); /* * Read input files. */ for (i = 0; i < nf; i++) { if (files[i] == NULL) { np = "stdin"; Ifs = stdin; } else { #ifdef UNIX if ((Ifs = fopen(files[i], "r")) == NULL) #else if ((Ifs = fopen(files[i], "rt")) == NULL) #endif Error(FATAL, NOLINE, " can't open ", files[i]); np = files[i]; } if (i >= pc) { (void) sprintf(Line, ".^# 1 %s", np); Macro(Line); NR = 0; } Fsp = 0; do { while (fgets(Line, MAXLINE, Ifs) != NULL) { NR++; if ((np = strrchr(Line, '\n')) != NULL) *np = '\0'; else Line[MAXLINE-1] = '\0'; Macro(Line); } if (i >= pc) Macro(".^e"); if (Ifs != stdin) (void) fclose(Ifs); if (Fsp > 0) { Free(&Inname); Inname = Inn_stk[Fsp-1]; NR = NR_stk[Fsp-1]; Ifs = Ifs_stk[Fsp-1]; } } while (Fsp-- > 0); } Macro(NULL); exit(Err); } /* * Macro(inp) - process a possible macro statement * pass non-macros and macros alike to pass 2 */ void Macro(inp) char *inp; /* possible macro statement pointer */ { char c[2]; /* characters */ FILE *fs; /* temporary file stream */ int i, j, k; /* temporary indexes */ int mx; /* Macrotab[] index */ char *s1, *s2; /* temporary string pointers */ if (inp == NULL) { Pass2(NULL); return; } /* * Check for file name designator. */ if (strncmp(inp, ".^#", 3) == 0) { Free(&Inname); Inname = Field(3, inp, 1); F = NULL; Pass2(inp); return; } /* * Check for source command - "^\.so". */ if (strncmp(inp, ".so", 3) == 0) { if ((s1 = Field(2, inp, 1)) == NULL) { Error(WARN, LINE, " no file specified", NULL); return; } if ((fs = fopen(s1, "r")) == NULL) { Error(WARN, LINE, " can't open", NULL); return; } if (Fsp >= MAXFSTK) { (void) fclose(fs); Error(WARN, LINE, " nesting too deep", NULL); return; } Ifs_stk[Fsp] = Ifs; Ifs = fs; Inn_stk[Fsp] = Inname; Inname = F; F = NULL; NR_stk[Fsp++] = NR; NR = 0; return; } /* * Check for start of macro definition. */ if (strncmp(inp, ".de", 3) == 0) { if (inp[3] != ' ' || inp[4] == '\0') { Error(WARN, LINE, " illegal macro definition", NULL); return; } c[0] = inp[4]; c[1] = inp[5]; Curmx = Findmacro(c, 1); return; } /* * Check for macro text. Remove double backslashes. */ if (Curmx >= 0 && strcmp(inp, "..") != 0) { if (Mtx >= MAXMTXT) Error(FATAL, LINE, " out of macro text space", NULL); if ((s1 = strchr(inp, '\\')) == NULL) Macrotxt[Mtx] = Newstr(inp); else { for (s1 = Pass1ln, s2 = inp;; s1++) { if ((*s1 = *s2++) == '\0') break; if (*s1 == '\\' && *s2 == '\\') s2++; } Macrotxt[Mtx] = Newstr(Pass1ln); } if (Macrotab[Curmx].bx == -1) Macrotab[Curmx].bx = Mtx; Mtx++; Macrotab[Curmx].ct++; return; } /* * Check for end of macro. */ if (Curmx >= 0 && strcmp(inp, "..") == 0) { Curmx = -1; (void) sprintf(Pass1ln, ".^# %d %s", NR, Inname); Pass2(Pass1ln); return; } /* * Check for conditionals and macro expansions. */ if (*inp == '.' && (((mx = Findmacro(inp+1, 0)) != -1) || regexec(Pat[0].pat, inp))) { Expand(inp); return; } /* * None of the above: forward the line. */ Pass2(inp); }