Remove building with NOCRYPTO option
[minix.git] / minix / commands / cawf / cawf.c
blob1528652d4c4320cf0468fabed56d186a12ba932a
1 /*
2 * cawf - a C version of Henry Spencer's awf(1), the Amazingly
3 * Workable (text) Formatter
5 * V. Abell, Purdue University Computing Center
6 */
8 /*
9 * Copyright (c) 1991 Purdue University Research Foundation,
10 * West Lafayette, Indiana 47907. All rights reserved.
12 * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
13 * University Computing Center. Not derived from licensed software;
14 * derived from awf(1) by Henry Spencer of the University of Toronto.
16 * Permission is granted to anyone to use this software for any
17 * purpose on any computer system, and to alter it and redistribute
18 * it freely, subject to the following restrictions:
20 * 1. The author is not responsible for any consequences of use of
21 * this software, even if they arise from flaws in it.
23 * 2. The origin of this software must not be misrepresented, either
24 * by explicit claim or by omission. Credits must appear in the
25 * documentation.
27 * 3. Altered versions must be plainly marked as such, and must not
28 * be misrepresented as being the original software. Credits must
29 * appear in the documentation.
31 * 4. This notice may not be removed or altered.
34 static char Version[] = "4.0";
36 #include "cawf.h"
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #ifndef UNIX
41 #include <io.h>
42 #include <process.h>
43 #include <string.h>
44 #include <sys\types.h>
45 #include <sys\stat.h>
46 #endif
49 int main(int argc, char *argv[]) {
50 char *ep; /* environment pointer */
51 int fff = 0; /* final form feed status */
52 char **files; /* file names */
53 int help = 0; /* help status */
54 int i; /* temporary index */
55 size_t l; /* length */
56 char *lib = CAWFLIB; /* library path */
57 int libl; /* library path length */
58 int mac = 0; /* macro specification status */
59 int nf = 0; /* number of files */
60 char *np; /* name pointer */
61 int pc; /* prolog count */
62 struct stat sbuf; /* stat buffer */
64 * Save program name.
66 if ((Pname = strrchr(argv[0], '\\')) != NULL)
67 Pname++;
68 else if ((Pname = strrchr(argv[0], '/')) != NULL)
69 Pname++;
70 else
71 Pname = argv[0];
73 * Set error file stream pointer.
75 Efs = stderr;
77 * Get library name.
79 if ((np = getenv("CAWFLIB")) != NULL)
80 lib = np;
81 libl = strlen(lib);
83 * Get device file name.
85 for (ep = getenv("TERM");; ep = NULL) {
86 if (ep == NULL || *ep == '\0')
87 ep = "dumb";
88 l = libl + 1 + strlen(ep) + strlen(".dev") + 1;
89 if ((np = malloc(l)) == NULL)
90 Error(FATAL, NOLINE,
91 " no string space for device file: ", ep);
92 (void) sprintf(np, "%s/%s.dev", lib, ep);
93 if (stat(np, &sbuf) == 0)
94 break;
95 if (strcmp(ep, "dumb") == 0)
96 Error(FATAL, NOLINE, " no dumb.dev file in ", lib);
97 (void) free(np);
99 if ((files = malloc((argc + 2) * sizeof(files[0]))) == NULL)
100 Error(FATAL, NOLINE, " no space for file list",
101 NULL);
102 files[nf++] = np;
104 * Get common text file name.
106 l = libl + 1 + strlen("common") + 1;
107 if ((np = malloc(l)) == NULL)
108 Error(FATAL, NOLINE, " no string space for common file name",
109 NULL);
110 (void) sprintf(np, "%s/common", lib);
111 files[nf++] = np;
113 * Process options.
115 while ((i = getopt(argc, argv, "c:d:ef:hm:")) != EOF) {
116 switch (i) {
118 * -c<device_configuration_file_path>>
120 case 'c':
121 Devconf = optarg;
122 break;
124 * -d<output_device_name> -- define output device name
126 * The default output device name is NORMAL -- i.e., a device that
127 * does bold face with backspace and overprinting and italic face with
128 * underscore. NORMAL is usually a terminal device.
130 * There is a built-in device, named ANSI, that does bold face with
131 * the ANSI shadow mode and italic face with the ANSI underscore mode.
132 * ANSI is normally a terminal device that supports the ANSI shadow
133 * and underscore modes.
135 * There is a built-in output device, named NONE, that does nothing
136 * at all for the bold or italic faces. This is usually a terminal
137 * device.
139 * All other device names must match a stanza in the device
140 * configuration file.
142 case 'd':
143 Device = optarg;
144 break;
146 * -e -- eject: issue final form feed
148 case 'e':
149 fff = 1;
150 break;
152 * -f<output_device_font_name> -- define font name for the output
153 * device (from device configuration
154 * file)
156 case 'f':
157 Devfont = optarg;
158 break;
160 * -h -- display help (usage)
162 case 'h':
163 help = 1;
164 break;
166 * -m<macro_file_name>
168 * Special support is provided for -man, -me and -ms.
170 case 'm':
171 if (mac) {
172 Error(WARN, NOLINE,
173 "multiple macro file declaration",
174 NULL);
175 break;
177 l = libl + 2 + strlen(optarg) + strlen(".mac") + 1;
178 if ((np = malloc(l)) == NULL)
179 Error(FATAL, NOLINE, " no string space for ",
180 argv[1]);
181 (void) sprintf(np, "%s/m%s.mac", lib, optarg);
182 files[nf++] = np;
183 if (strcmp(optarg, "an") == 0)
184 Marg = MANMACROS;
185 else if (strcmp(optarg, "s") == 0
186 || strcmp(optarg, "e") == 0)
187 Marg = MSMACROS;
188 mac++;
189 break;
191 * Option not recognized by getopt().
193 case '?':
194 Err = 1;
197 if (Defdev())
198 Err++;
199 if (help || Err) {
200 (void) fprintf(stderr,
201 "%s %s usage: [-c<c>] [-d<d>] [-e] [-f<f>] [-h] [-m<m>] file...\n",
202 Pname, Version);
203 (void) fprintf(stderr,
204 "\t-c<c> <c> is the device configuration file path\n");
205 (void) fprintf(stderr,
206 "\t-d<d> <d> is the output device name\n");
207 (void) fprintf(stderr,
208 "\t (default = NORMAL, using \\b for bold and italic)\n");
209 (void) fprintf(stderr,
210 "\t (built-ins = ANSI, NONE and NORMAL)\n");
211 (void) fprintf(stderr,
212 "\t-e issue eject after last page\n");
213 (void) fprintf(stderr,
214 "\t-f<f> <f> is the output device font name\n");
215 (void) fprintf(stderr,
216 "\t-h display help (this output)\n");
217 (void) fprintf(stderr,
218 "\t-m<m> m<m> is the macro file name\n");
219 (void) fprintf(stderr,
220 "\tfile ... source file names\n");
221 exit(Err);
223 if (mac == 0) {
226 * No macroes - enable Bold, Italic, Roman and Courier fonts.
228 for (i = 0; Fcode[i].nm; i++) {
229 switch (Fcode[i].nm) {
230 case 'B':
231 case 'I':
232 case 'R':
233 case 'C':
234 Fcode[i].status = '1';
239 * Add user-supplied file names.
241 pc = nf;
242 if (optind >= argc) {
243 files[nf++] = NULL; /* STDIN */
244 } else {
245 while (optind < argc)
246 files[nf++] = argv[optind++];
249 * Make sure all input files are accessible.
251 for (i = 0; i < nf; i++) {
252 if (files[i] != NULL) {
253 if (stat(files[i], &sbuf) != 0)
254 Error(WARN, NOLINE, " can't find ", files[i]);
257 if (Err)
258 exit(1);
260 * Miscellaneous initialization.
263 for (i = 0; ; i++) {
264 if (Pat[i].re == NULL)
265 break;
266 if ((Pat[i].pat = regcomp(Pat[i].re)) == NULL)
267 Error(WARN, NOLINE, Pat[i].re, " regcomp failure");
269 if ((i = Findscale((int)'n', 0.0, 0)) < 0)
270 Error(WARN, NOLINE, " can't find Scale['n']", NULL);
271 Scalen = Scale[i].val;
272 if ((i = Findscale((int)'u', 0.0, 0)) < 0)
273 Error(WARN, NOLINE, " can't find Scale['u']", NULL);
274 Scaleu = Scale[i].val;
275 if ((i = Findscale((int)'v', 0.0, 0)) < 0)
276 Error(WARN, NOLINE, " can't find Scale['v']", NULL);
277 Scalev = Scale[i].val;
278 (void) Findstr((unsigned char *)"CH", (unsigned char *)"= % -", 1);
279 Cont = Newstr((unsigned char *)" ");
280 Contlen = 1;
281 if ((Trtbl = (unsigned char *)malloc(256)) == NULL)
282 Error(WARN, NOLINE, " can't allocate translate table space",
283 NULL);
284 else {
285 *Trtbl = ' ';
286 for (i = 1; i < 256; i++)
287 Trtbl[i] = (unsigned char) i;
289 if (Err)
290 exit(1);
292 * Here begins pass1 of awf - reading input lines and expanding macros.
296 * Output prolog.
298 if (Fstr.i) {
299 for (i = 0; i < Fstr.il; i++) {
300 Charput((int)Fstr.i[i]);
303 Macro((unsigned char *)".^x");
304 Macro((unsigned char *)".^b");
305 Macro((unsigned char *)".^# 1 <prolog>");
307 * Read input files.
309 for (i = 0; i < nf; i++) {
310 Dowarn = (i >= pc);
311 if (files[i] == NULL) {
312 np = "stdin";
313 Ifs = stdin;
314 } else {
315 #ifdef UNIX
316 if ((Ifs = fopen(files[i], "r")) == NULL)
317 #else
318 if ((Ifs = fopen(files[i], "rt")) == NULL)
319 #endif
320 Error(FATAL, NOLINE, " can't open ", files[i]);
321 np = files[i];
323 if (i >= pc) {
324 (void) sprintf((char *)Line, ".^# 1 %s", np);
325 Macro(Line);
326 NR = 0;
328 Fsp = 0;
329 do {
330 while (fgets((char *)Line, MAXLINE, Ifs) != NULL) {
331 NR++;
332 if ((np = strrchr((char *)Line, '\n')) != NULL)
333 *np = '\0';
334 else
335 Line[MAXLINE-1] = '\0';
336 Macro(Line);
338 if (i >= pc)
339 Macro((unsigned char *)".^e");
340 if (Ifs != stdin)
341 (void) fclose(Ifs);
342 if (Fsp > 0) {
343 Free(&Inname);
344 Inname = Inn_stk[Fsp-1];
345 NR = NR_stk[Fsp-1];
346 Ifs = Ifs_stk[Fsp-1];
348 } while (Fsp-- > 0);
350 Macro(NULL);
351 if (fff)
352 Charput((int)'\f');
353 exit(Err);
358 * Macro(inp) - process a possible macro statement
359 * pass non-macros and macros alike to pass 2
362 void Macro(unsigned char *inp) { /* possible macro statement pointer */
363 unsigned char c[2]; /* characters */
364 int endm; /* end of macro status */
365 FILE *fs; /* temporary file stream */
366 int i, j, k; /* temporary indexes */
367 int mx; /* Macrotab[] index */
368 int req; /* request character status */
369 unsigned char *s1, *s2; /* temporary string pointers */
371 if (inp == NULL) {
372 Pass2(NULL);
373 return;
375 req = (*inp == '.' || *inp == '\'') ? 1 : 0;
377 * Check for file name designator.
379 if (req && inp[1] == '^' && inp[2] == '#') {
380 Free(&Inname);
381 Inname = Field(3, inp, 1);
382 F = NULL;
383 Pass2(inp);
384 return;
387 * Check for source command - "^[.']so".
389 if (req && inp[1] == 's' && inp[2] == 'o') {
390 if ((s1 = Field(2, inp, 1)) == NULL) {
391 Error(WARN, LINE, " no file specified", NULL);
392 return;
394 if ((fs = fopen((char *)s1, "r")) == NULL) {
395 Error(WARN, LINE, " can't open", NULL);
396 return;
398 if (Fsp >= MAXFSTK) {
399 (void) fclose(fs);
400 Error(WARN, LINE, " nesting too deep", NULL);
401 return;
403 Ifs_stk[Fsp] = Ifs;
404 Ifs = fs;
405 Inn_stk[Fsp] = Inname;
406 Inname = F;
407 F = NULL;
408 NR_stk[Fsp++] = NR;
409 NR = 0;
410 return;
413 * Check for ignore.
415 if (req && inp[1] == 'i' && inp[2] == 'g') {
416 while (fgets((char *)inp, MAXLINE, Ifs) != NULL) {
417 NR++;
418 if (inp[0] == '.' && inp[1] == '.') break;
420 return;
423 * Check for start of macro definition.
425 if (req && inp[1] == 'd' && inp[2] == 'e') {
426 if (inp[3] != ' ' || inp[4] == '\0') {
427 Error(WARN, LINE, " illegal macro definition", NULL);
428 return;
430 c[0] = inp[4];
431 c[1] = inp[5];
432 Curmx = Findmacro(c, 1);
433 return;
436 * Check for macro text. Remove double backslashes.
438 if (req && (inp[1] == '\0' || (inp[2] == '\0' && inp[0] == inp[1])))
439 endm = 1;
440 else
441 endm = 0;
442 if (Curmx >= 0 && !endm) {
443 if (Mtx >= MAXMTXT)
444 Error(FATAL, LINE, " out of macro text space", NULL);
445 if ((s1 = (unsigned char *)strchr((char *)inp, '\\')) == NULL)
446 Macrotxt[Mtx] = Newstr(inp);
447 else {
448 for (s1 = Pass1ln, s2 = inp;; s1++) {
449 if ((*s1 = *s2++) == '\0')
450 break;
451 if (*s1 == '\\' && *s2 == '\\')
452 s2++;
454 Macrotxt[Mtx] = Newstr(Pass1ln);
456 if (Macrotab[Curmx].bx == -1)
457 Macrotab[Curmx].bx = Mtx;
458 Mtx++;
459 Macrotab[Curmx].ct++;
460 return;
463 * Check for end of macro.
465 if (Curmx >= 0 && endm) {
466 Curmx = -1;
467 (void) sprintf((char *)Pass1ln, ".^# %d %s", NR, Inname);
468 Pass2(Pass1ln);
469 return;
472 * Check for conditionals and macro expansions.
474 if (req
475 && (((mx = Findmacro(inp+1, 0)) != -1) || regexec(Pat[0].pat, inp))) {
476 Expand(inp);
477 return;
480 * None of the above: forward the line.
482 Pass2(inp);