source: trunk/minix/commands/cawf/cawf.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.5 KB
RevLine 
[9]1/*
2 * cawf - a C version of Henry Spencer's awf(1), the Amazingly
3 * Workable (text) Formatter
4 *
5 * V. Abell, Purdue University Computing Center
6 */
7
8/*
9 * Copyright (c) 1991 Purdue University Research Foundation,
10 * West Lafayette, Indiana 47907. All rights reserved.
11 *
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.
15 *
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:
19 *
20 * 1. The author is not responsible for any consequences of use of
21 * this software, even if they arise from flaws in it.
22 *
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.
26 *
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.
30 *
31 * 4. This notice may not be removed or altered.
32 */
33
34static char Version[] = "4.0";
35
36#include "cawf.h"
37
38#include <sys/stat.h>
39#ifndef UNIX
40#include <io.h>
41#include <process.h>
42#include <string.h>
43#include <sys\types.h>
44#include <sys\stat.h>
45#endif
46
47
48main(argc, argv)
49 int argc;
50 char *argv[];
51{
52 char *ep; /* environment pointer */
53 int fff = 0; /* final form feed status */
54 char **files; /* file names */
55 int help = 0; /* help status */
56 int i; /* temporary index */
57 size_t l; /* length */
58 char *lib = CAWFLIB; /* library path */
59 int libl; /* library path length */
60 int mac = 0; /* macro specification status */
61 int nf = 0; /* number of files */
62 char *np; /* name pointer */
63 int pc; /* prolog count */
64 struct stat sbuf; /* stat buffer */
65/*
66 * Save program name.
67 */
68 if ((Pname = strrchr(argv[0], '\\')) != NULL)
69 Pname++;
70 else if ((Pname = strrchr(argv[0], '/')) != NULL)
71 Pname++;
72 else
73 Pname = argv[0];
74/*
75 * Set error file stream pointer.
76 */
77 Efs = stderr;
78/*
79 * Get library name.
80 */
81 if ((np = getenv("CAWFLIB")) != NULL)
82 lib = np;
83 libl = strlen(lib);
84/*
85 * Get device file name.
86 */
87 for (ep = getenv("TERM");; ep = NULL) {
88 if (ep == NULL || *ep == '\0')
89 ep = "dumb";
90 l = libl + 1 + strlen(ep) + strlen(".dev") + 1;
91 if ((np = malloc(l)) == NULL)
92 Error(FATAL, NOLINE,
93 " no string space for device file: ", ep);
94 (void) sprintf(np, "%s/%s.dev", lib, ep);
95 if (stat(np, &sbuf) == 0)
96 break;
97 if (strcmp(ep, "dumb") == 0)
98 Error(FATAL, NOLINE, " no dumb.dev file in ", lib);
99 (void) free(np);
100 }
101 if ((files = malloc((argc + 2) * sizeof(files[0]))) == NULL)
102 Error(FATAL, NOLINE, " no space for file list",
103 NULL);
104 files[nf++] = np;
105/*
106 * Get common text file name.
107 */
108 l = libl + 1 + strlen("common") + 1;
109 if ((np = malloc(l)) == NULL)
110 Error(FATAL, NOLINE, " no string space for common file name",
111 NULL);
112 (void) sprintf(np, "%s/common", lib);
113 files[nf++] = np;
114/*
115 * Process options.
116 */
117 while ((i = getopt(argc, argv, "c:d:ef:hm:")) != EOF) {
118 switch (i) {
119 /*
120 * -c<device_configuration_file_path>>
121 */
122 case 'c':
123 Devconf = optarg;
124 break;
125 /*
126 * -d<output_device_name> -- define output device name
127 *
128 * The default output device name is NORMAL -- i.e., a device that
129 * does bold face with backspace and overprinting and italic face with
130 * underscore. NORMAL is usually a terminal device.
131 *
132 * There is a built-in device, named ANSI, that does bold face with
133 * the ANSI shadow mode and italic face with the ANSI underscore mode.
134 * ANSI is normally a terminal device that supports the ANSI shadow
135 * and underscore modes.
136 *
137 * There is a built-in output device, named NONE, that does nothing
138 * at all for the bold or italic faces. This is usually a terminal
139 * device.
140 *
141 * All other device names must match a stanza in the device
142 * configuration file.
143 */
144 case 'd':
145 Device = optarg;
146 break;
147 /*
148 * -e -- eject: issue final form feed
149 */
150 case 'e':
151 fff = 1;
152 break;
153 /*
154 * -f<output_device_font_name> -- define font name for the output
155 * device (from device configuration
156 * file)
157 */
158 case 'f':
159 Devfont = optarg;
160 break;
161 /*
162 * -h -- display help (usage)
163 */
164 case 'h':
165 help = 1;
166 break;
167 /*
168 * -m<macro_file_name>
169 *
170 * Special support is provided for -man, -me and -ms.
171 */
172 case 'm':
173 if (mac) {
174 Error(WARN, NOLINE,
175 "multiple macro file declaration",
176 NULL);
177 break;
178 }
179 l = libl + 2 + strlen(optarg) + strlen(".mac") + 1;
180 if ((np = malloc(l)) == NULL)
181 Error(FATAL, NOLINE, " no string space for ",
182 argv[1]);
183 (void) sprintf(np, "%s/m%s.mac", lib, optarg);
184 files[nf++] = np;
185 if (strcmp(optarg, "an") == 0)
186 Marg = MANMACROS;
187 else if (strcmp(optarg, "s") == 0
188 || strcmp(optarg, "e") == 0)
189 Marg = MSMACROS;
190 mac++;
191 break;
192 /*
193 * Option not recognized by getopt().
194 */
195 case '?':
196 Err = 1;
197 }
198 }
199 if (Defdev())
200 Err++;
201 if (help || Err) {
202 (void) fprintf(stderr,
203 "%s %s usage: [-c<c>] [-d<d>] [-e] [-f<f>] [-h] [-m<m>] file...\n",
204 Pname, Version);
205 (void) fprintf(stderr,
206 "\t-c<c> <c> is the device configuration file path\n");
207 (void) fprintf(stderr,
208 "\t-d<d> <d> is the output device name\n");
209 (void) fprintf(stderr,
210 "\t (default = NORMAL, using \\b for bold and italic)\n");
211 (void) fprintf(stderr,
212 "\t (built-ins = ANSI, NONE and NORMAL)\n");
213 (void) fprintf(stderr,
214 "\t-e issue eject after last page\n");
215 (void) fprintf(stderr,
216 "\t-f<f> <f> is the output device font name\n");
217 (void) fprintf(stderr,
218 "\t-h display help (this output)\n");
219 (void) fprintf(stderr,
220 "\t-m<m> m<m> is the macro file name\n");
221 (void) fprintf(stderr,
222 "\tfile ... source file names\n");
223 exit(Err);
224 }
225 if (mac == 0) {
226
227 /*
228 * No macroes - enable Bold, Italic, Roman and Courier fonts.
229 */
230 for (i = 0; Fcode[i].nm; i++) {
231 switch (Fcode[i].nm) {
232 case 'B':
233 case 'I':
234 case 'R':
235 case 'C':
236 Fcode[i].status = '1';
237 }
238 }
239 }
240/*
241 * Add user-supplied file names.
242 */
243 pc = nf;
244 if (optind >= argc) {
245 files[nf++] = NULL; /* STDIN */
246 } else {
247 while (optind < argc)
248 files[nf++] = argv[optind++];
249 }
250/*
251 * Make sure all input files are accessible.
252 */
253 for (i = 0; i < nf; i++) {
254 if (files[i] != NULL) {
255 if (stat(files[i], &sbuf) != 0)
256 Error(WARN, NOLINE, " can't find ", files[i]);
257 }
258 }
259 if (Err)
260 exit(1);
261/*
262 * Miscellaneous initialization.
263 */
264
265 for (i = 0; ; i++) {
266 if (Pat[i].re == NULL)
267 break;
268 if ((Pat[i].pat = regcomp(Pat[i].re)) == NULL)
269 Error(WARN, NOLINE, Pat[i].re, " regcomp failure");
270 }
271 if ((i = Findscale((int)'n', 0.0, 0)) < 0)
272 Error(WARN, NOLINE, " can't find Scale['n']", NULL);
273 Scalen = Scale[i].val;
274 if ((i = Findscale((int)'u', 0.0, 0)) < 0)
275 Error(WARN, NOLINE, " can't find Scale['u']", NULL);
276 Scaleu = Scale[i].val;
277 if ((i = Findscale((int)'v', 0.0, 0)) < 0)
278 Error(WARN, NOLINE, " can't find Scale['v']", NULL);
279 Scalev = Scale[i].val;
280 (void) Findstr((unsigned char *)"CH", (unsigned char *)"= % -", 1);
281 Cont = Newstr((unsigned char *)" ");
282 Contlen = 1;
283 if ((Trtbl = (unsigned char *)malloc(256)) == NULL)
284 Error(WARN, NOLINE, " can't allocate translate table space",
285 NULL);
286 else {
287 *Trtbl = ' ';
288 for (i = 1; i < 256; i++)
289 Trtbl[i] = (unsigned char) i;
290 }
291 if (Err)
292 exit(1);
293/*
294 * Here begins pass1 of awf - reading input lines and expanding macros.
295 */
296
297/*
298 * Output prolog.
299 */
300 if (Fstr.i) {
301 for (i = 0; i < Fstr.il; i++) {
302 Charput((int)Fstr.i[i]);
303 }
304 }
305 Macro((unsigned char *)".^x");
306 Macro((unsigned char *)".^b");
307 Macro((unsigned char *)".^# 1 <prolog>");
308/*
309 * Read input files.
310 */
311 for (i = 0; i < nf; i++) {
312 Dowarn = (i >= pc);
313 if (files[i] == NULL) {
314 np = "stdin";
315 Ifs = stdin;
316 } else {
317#ifdef UNIX
318 if ((Ifs = fopen(files[i], "r")) == NULL)
319#else
320 if ((Ifs = fopen(files[i], "rt")) == NULL)
321#endif
322 Error(FATAL, NOLINE, " can't open ", files[i]);
323 np = files[i];
324 }
325 if (i >= pc) {
326 (void) sprintf((char *)Line, ".^# 1 %s", np);
327 Macro(Line);
328 NR = 0;
329 }
330 Fsp = 0;
331 do {
332 while (fgets((char *)Line, MAXLINE, Ifs) != NULL) {
333 NR++;
334 if ((np = strrchr((char *)Line, '\n')) != NULL)
335 *np = '\0';
336 else
337 Line[MAXLINE-1] = '\0';
338 Macro(Line);
339 }
340 if (i >= pc)
341 Macro((unsigned char *)".^e");
342 if (Ifs != stdin)
343 (void) fclose(Ifs);
344 if (Fsp > 0) {
345 Free(&Inname);
346 Inname = Inn_stk[Fsp-1];
347 NR = NR_stk[Fsp-1];
348 Ifs = Ifs_stk[Fsp-1];
349 }
350 } while (Fsp-- > 0);
351 }
352 Macro(NULL);
353 if (fff)
354 Charput((int)'\f');
355 exit(Err);
356}
357
358
359/*
360 * Macro(inp) - process a possible macro statement
361 * pass non-macros and macros alike to pass 2
362 */
363
364void
365Macro(inp)
366 unsigned char *inp; /* possible macro statement pointer */
367{
368 unsigned char c[2]; /* characters */
369 int endm; /* end of macro status */
370 FILE *fs; /* temporary file stream */
371 int i, j, k; /* temporary indexes */
372 int mx; /* Macrotab[] index */
373 int req; /* request character status */
374 unsigned char *s1, *s2; /* temporary string pointers */
375
376 if (inp == NULL) {
377 Pass2(NULL);
378 return;
379 }
380 req = (*inp == '.' || *inp == '\'') ? 1 : 0;
381/*
382 * Check for file name designator.
383 */
384 if (req && inp[1] == '^' && inp[2] == '#') {
385 Free(&Inname);
386 Inname = Field(3, inp, 1);
387 F = NULL;
388 Pass2(inp);
389 return;
390 }
391/*
392 * Check for source command - "^[.']so".
393 */
394 if (req && inp[1] == 's' && inp[2] == 'o') {
395 if ((s1 = Field(2, inp, 1)) == NULL) {
396 Error(WARN, LINE, " no file specified", NULL);
397 return;
398 }
399 if ((fs = fopen((char *)s1, "r")) == NULL) {
400 Error(WARN, LINE, " can't open", NULL);
401 return;
402 }
403 if (Fsp >= MAXFSTK) {
404 (void) fclose(fs);
405 Error(WARN, LINE, " nesting too deep", NULL);
406 return;
407 }
408 Ifs_stk[Fsp] = Ifs;
409 Ifs = fs;
410 Inn_stk[Fsp] = Inname;
411 Inname = F;
412 F = NULL;
413 NR_stk[Fsp++] = NR;
414 NR = 0;
415 return;
416 }
417 /*
418 * Check for ignore.
419 */
420 if (req && inp[1] == 'i' && inp[2] == 'g') {
421 while (fgets((char *)inp, MAXLINE, Ifs) != NULL) {
422 NR++;
423 if (inp[0] == '.' && inp[1] == '.') break;
424 }
425 return;
426 }
427 /*
428 * Check for start of macro definition.
429 */
430 if (req && inp[1] == 'd' && inp[2] == 'e') {
431 if (inp[3] != ' ' || inp[4] == '\0') {
432 Error(WARN, LINE, " illegal macro definition", NULL);
433 return;
434 }
435 c[0] = inp[4];
436 c[1] = inp[5];
437 Curmx = Findmacro(c, 1);
438 return;
439 }
440/*
441 * Check for macro text. Remove double backslashes.
442 */
443 if (req && (inp[1] == '\0' || (inp[2] == '\0' && inp[0] == inp[1])))
444 endm = 1;
445 else
446 endm = 0;
447 if (Curmx >= 0 && !endm) {
448 if (Mtx >= MAXMTXT)
449 Error(FATAL, LINE, " out of macro text space", NULL);
450 if ((s1 = (unsigned char *)strchr((char *)inp, '\\')) == NULL)
451 Macrotxt[Mtx] = Newstr(inp);
452 else {
453 for (s1 = Pass1ln, s2 = inp;; s1++) {
454 if ((*s1 = *s2++) == '\0')
455 break;
456 if (*s1 == '\\' && *s2 == '\\')
457 s2++;
458 }
459 Macrotxt[Mtx] = Newstr(Pass1ln);
460 }
461 if (Macrotab[Curmx].bx == -1)
462 Macrotab[Curmx].bx = Mtx;
463 Mtx++;
464 Macrotab[Curmx].ct++;
465 return;
466 }
467/*
468 * Check for end of macro.
469 */
470 if (Curmx >= 0 && endm) {
471 Curmx = -1;
472 (void) sprintf((char *)Pass1ln, ".^# %d %s", NR, Inname);
473 Pass2(Pass1ln);
474 return;
475 }
476 /*
477 * Check for conditionals and macro expansions.
478 */
479 if (req
480 && (((mx = Findmacro(inp+1, 0)) != -1) || regexec(Pat[0].pat, inp))) {
481 Expand(inp);
482 return;
483 }
484/*
485 * None of the above: forward the line.
486 */
487 Pass2(inp);
488}
Note: See TracBrowser for help on using the repository browser.