|
|
1.1 root 1: /*
2: * main.c
3: * Nroff/Troff.
4: * Main program and initialization.
5: */
6:
7: #include <ctype.h>
8: #if MSDOS
9: #include <types.h>
10: #include <stat.h>
11: #else
12: #include <sys/types.h>
13: #include <sys/stat.h>
14: #endif
15: #include <time.h>
16: #include <path.h>
17: #include "roff.h"
18:
19: extern char *getenv();
20: extern char *path();
21: extern time_t time();
22: #ifdef GEMDOS
23: extern char *tempnam();
24: #else
25: extern char *mktemp();
26: #endif
27:
28: #ifdef GEMDOS
29: unsigned long _stksize = 0x8000L;
30: #endif
31:
32: static int kflag; /* keep tmp file for debug purposes */
33: static char template[sizeof(TMPLATE)+1] = TMPLATE;
34: static char *tempname; /* temp file name */
35:
36: main(argc, argv) int argc; char *argv[];
37: {
38: register int i, fileflag, iflag;
39: register char *libpath, *cp;
40: register REG *rp;
41: char c, name[2];
42:
43: argv0 = (ntroff == NROFF) ? "nroff" : "troff";
44: cp = getenv((ntroff == NROFF) ? "NROFF" : "TROFF");
45: if (cp != NULL && *cp != '\0')
46: addargs(cp, &argc, &argv);
47: initialize(argc, argv);
48:
49: /*
50: * Process specified input files.
51: * initialize() already handled most options.
52: */
53: fileflag = iflag = 0;
54: for (i = 1; i < argc; i++) {
55: cp = argv[i];
56: if (*cp != '-') {
57: /* Process non-option argument. */
58: fileflag = 1;
59: if (adsfile(cp) != 0)
60: process();
61: continue;
62: }
63:
64: /* Process '-'-option argument. */
65: c = *++cp; /* argv[i][1] */
66: cp++; /* &argv[i][2] */
67: if (c == 'i')
68: iflag = 1; /* process stdin when done */
69: else if (c == 'f')
70: ++i; /* ignore tempfile arg */
71: else if (c == 'm') {
72: /* Process "-m" macro package argument. */
73: sprintf(miscbuf, TMACFMT, cp);
74: libpath = DEFLIBPATH;
75: if ((libpath = path(libpath, miscbuf, R_OK)) != NULL)
76: strcpy(miscbuf, libpath);
77: #if (DDEBUG & DBGFILE)
78: printd(DBGFILE, "tmac file = %s\n", miscbuf);
79: #endif
80: adsfile(miscbuf);
81: process();
82: } else if (c == 'n') {
83: /* Reset page number. */
84: pno = atoi(cp);
85: npn = pno + 1;
86: } else if (c == 'r' && *cp != '\0') {
87: /* Reset register value. */
88: name[0] = *cp++;
89: if (isdigit(*cp))
90: name[1] = '\0';
91: else
92: name[1] = *cp++;
93: rp = getnreg(name);
94: rp->n_reg.r_nval = atoi(cp);
95: if (rp == nrpnreg) /* Page # register */
96: npn = pno + 1; /* Set next page # */
97: }
98: }
99: if (fileflag == 0 || iflag != 0) {
100: /* Process standard input. */
101: adsunit(stdin);
102: process();
103: }
104: if (iestackx != -1)
105: printe(".ie without matching .el");
106: leave(0);
107: }
108:
109: /*
110: * Open temp file, set up registers and general initialization.
111: */
112: initialize(argc, argv) int argc; char *argv[];
113: {
114: register REG *rp;
115: register REQ *qp;
116: register int i;
117: int Dflag, tmparg;
118: char *s;
119:
120: A_reg = ntroff==NROFF;
121:
122: /*
123: * Pass over args, process those dealing with global initialization.
124: * main() makes another pass over the arg list to process input files.
125: */
126: Dflag = tmparg = 0;
127: for (i = 1; i < argc; i++) {
128: if (argv[i][0] != '-')
129: continue;
130: switch (argv[i][1]) {
131: case 'a':
132: A_reg = 1;
133: continue;
134: case 'd':
135: #if DDEBUG
136: if (argv[i][2] != '\0') {
137: dbglvl = atoi(&argv[i][2]);
138: dbginit();
139: } else
140: #endif
141: dflag++;
142: continue;
143: case 'D':
144: Dflag = 1;
145: continue;
146: case 'f':
147: if (i < (argc-1))
148: tmparg = ++i;
149: else
150: panic("-f option requires file argument");
151: continue;
152: case 'i':
153: continue; /* handled in main() */
154: case 'K':
155: case 'k':
156: kflag++;
157: continue;
158: case 'l':
159: lflag = 1;
160: continue;
161: case 'm':
162: continue; /* handled in main() */
163: case 'n':
164: continue; /* handled in main() */
165: case 'p':
166: pflag = 1;
167: continue;
168: case 'r':
169: continue; /* handled in main() */
170: #ifndef GEMDOS
171: case 'T':
172: if (ntroff == NROFF)
173: T_reg = 1;
174: continue;
175: #endif
176: case 'x':
177: xflag++;
178: continue;
179: case 'V':
180: case 'v':
181: fprintf(stderr, "%s: V%s\n", argv0, VERSION);
182: continue;
183: #if ZKLUDGE
184: case 'Z':
185: if (argv[i][2] != '\0')
186: Zflag = atoi(&argv[i][2]);
187: else
188: Zflag = ZPAGES;
189: continue;
190: #endif
191: default:
192: fprintf(stderr, "%s: illegal option: %s\n", argv0, argv[i]);
193: /* fall through... */
194: case '?':
195: usage();
196: }
197: }
198:
199: /* Initialize tempfile. */
200: #ifdef GEMDOS
201: tempname = (tmparg) ? argv[tmparg] : tempnam(0L, "nroff");
202: #else
203: tempname = (tmparg) ? argv[tmparg] : mktemp(template);
204: #endif
205: dprint2(DBGFILE, "temp file name = %s\n", tempname);
206: if ((tmp=fopen(tempname, "wb")) == NULL)
207: panic("cannot create temp file");
208: else if (freopen(tempname, "rwb", tmp) == NULL)
209: panic("cannot reopen temp file");
210: tmpseek = ENVSIZE * sizeof (ENV);
211: tmpseek = (tmpseek+DBFSIZE+DBFSIZE-1) & ~(DBFSIZE-1);
212:
213: #ifdef GEMDOS
214: /*
215: * GEMDOS lseek does not produce sparse files;
216: * this makes it necessary to write the beginning of nroff's work file.
217: */
218: memset(diskbuf, '\0', DBFSIZE);
219: for (i = 0; i < tmpseek; i += DBFSIZE) {
220: dprintd(DBGFILE, "initializing tempfile\n");
221: if (write(fileno(tmp), diskbuf, DBFSIZE) != DBFSIZE)
222: panic("temp file write error");
223: }
224: #endif
225: #ifdef COHERENT
226: /*
227: * Unlinking temp file immediately under COHERENT makes it
228: * go away if program is interrupted with <Ctrl-C>;
229: * under GEMDOS it would destroy the file immediately,
230: * so it is done under leave() below.
231: */
232: if (kflag == 0)
233: unlink(tempname);
234: #endif
235:
236: /* Copy .pre-file if it exists. */
237: if (!Dflag) {
238: s = (lflag) ? PRE_L : PRE_P;
239: if (lib_file(s, 0) == 0 & ntroff == TROFF)
240: printe("file \"%s\" not found", s);
241: }
242:
243: /* Initialize globals. */
244: dev_init(); /* output writer-specific initialization */
245: for (i = 0; i < NWIDTH; i++)
246: trantab[i] = i; /* translation table */
247: for (i = 0; i < RHTSIZE; i++)
248: regt[i] = NULL; /* request hash table */
249: for (qp = reqtab; qp->q_name[0]; qp++) { /* built-in requests */
250: rp = makereg(qp->q_name, RTEXT);
251: rp->t_reg.r_macd.r_div.m_next = NULL;
252: rp->t_reg.r_macd.r_div.m_type = MREQS;
253: rp->t_reg.r_macd.r_div.m_func = qp->q_func;
254: }
255:
256: /* Create built in registers. */
257: /* UNDONE: "c.", same as ".c" */
258: nrpnreg = getnreg("%");
259: nrctreg = getnreg("ct");
260: nrdlreg = getnreg("dl");
261: nrdnreg = getnreg("dn");
262: nrdwreg = getnreg("dw");
263: nrdyreg = getnreg("dy");
264: nrhpreg = getnreg("hp");
265: nrlnreg = getnreg("ln");
266: nrmoreg = getnreg("mo");
267: nrnlreg = getnreg("nl");
268: nrsbreg = getnreg("sb");
269: nrstreg = getnreg("st");
270: nryrreg = getnreg("yr");
271: setnreg();
272:
273: /* Environment initialization. */
274: envset();
275: envinit[0] = 1;
276:
277: /* Etc. */
278: iestackx = -1;
279: cdivp = NULL;
280: newdivn("\0\0");
281: mdivp = cdivp;
282: #ifdef GEMDOS
283: if (((long)mdivp) & 1L)
284: panic("diversion buffer odd alignment");
285: #endif
286: endtrap[0] = '\0';
287: strp = NULL;
288: pgl = (lflag) ? unit(17*SMINCH, 2*SDINCH) : unit(11*SMINCH, SDINCH);
289: pno = 1;
290: npn = 2;
291: esc = '\\';
292:
293: /* Load default fonts for troff, initialize font numbers. */
294: i = lib_file("fonts.r", 1);
295: if (ntroff == TROFF && i == 0)
296: panic("fonts.r not found");
297: if (Dflag) {
298: font_display();
299: exit(0);
300: }
301: if (setfont("R", 1) == -1)
302: leave(1); /* font R is mandatory */
303: tfn = curfont; /* tab character font */
304: if ((ufn = font_num("I")) == -1) /* underline font number */
305: ufn = curfont;
306:
307: /* Process special character definitions. */
308: lib_file("specials.r", 1); /* special characters */
309: #if (DDEBUG & DBGCHEK)
310: printd(DBGFUNC, "initialized...\n");
311: #endif
312: }
313:
314: /*
315: * Initialize pre-defined number registers.
316: */
317: setnreg()
318: {
319: time_t curtime;
320: register struct tm *tmp;
321:
322: curtime = time((time_t *)0);
323: tmp = localtime(&curtime);
324: nryrreg->n_reg.r_nval = tmp->tm_year % 100;
325: nrmoreg->n_reg.r_nval = tmp->tm_mon + 1;
326: nrdyreg->n_reg.r_nval = tmp->tm_mday;
327: nrdwreg->n_reg.r_nval = tmp->tm_wday + 1;
328: }
329:
330: /*
331: * Leave.
332: * The passed exit status is:
333: * 0 normal
334: * 1 fatal error
335: * 2 usage error
336: */
337: leave(status) register int status;
338: {
339: char name[2];
340: static int depth = 0;
341:
342: if (status == 0 && depth++ == 0) {
343: if (endtrap[0] != '\0') {
344: name[0] = endtrap[0];
345: name[1] = endtrap[1];
346: endtrap[0] = '\0';
347: execute(name);
348: }
349: setbreak();
350: if (xflag == 0) {
351: byeflag = 1;
352: pspace();
353: }
354: } else if (status == 1 && depth++ == 0) {
355: /* Space to bottom of page if status==1, useful for PS. */
356: if (xflag == 0) {
357: byeflag = 1;
358: pspace();
359: }
360: }
361:
362: #ifndef COHERENT
363: #if (DDEBUG & DBGFILE)
364: {
365: struct stat statblk;
366:
367: fclose(tmp); /* Close the temp file. */
368: stat(tempname, &statblk); /* so we can stat it. */
369: printd(DBGFILE, "deleting temporary file %s, size = %ld\n",
370: tempname, statblk.st_size);
371: }
372: #endif
373: /* Unlink temp file if not COHERENT. */
374: if (kflag == 0)
375: unlink(tempname);
376: #endif
377: exit(status);
378: }
379:
380: /*
381: * Print a fatal usage message and die.
382: */
383: usage()
384: {
385: fprintf(stderr, "Usage: %s [ option ... ] [ file ... ]\n",
386: ntroff == NROFF ? "nroff" : "troff");
387: fprintf(stderr, "Options:\n");
388: fprintf(stderr, "\t-d\tDebug: print each request before executing\n");
389: if (ntroff == TROFF)
390: fprintf(stderr, "\t-D\tDisplay available fonts\n");
391: fprintf(stderr, "\t-f name\tWrite temporary file in file name\n");
392: fprintf(stderr, "\t-i\tRead stdin after each file has been read\n");
393: fprintf(stderr, "\t-k\tKeep temporary file\n");
394: if (ntroff == TROFF)
395: fprintf(stderr, "\t-l\tLandscape mode\n");
396: fprintf(stderr, "\t-mname\tRead macro package /usr/lib/tmac.name\n");
397: fprintf(stderr, "\t-nN\tNumber first page of output N (default, 1)\n");
398: if (ntroff == TROFF)
399: fprintf(stderr, "\t-p\tProduce PostScript output\n");
400: fprintf(stderr, "\t-raN\tSet number register a to value N\n");
401: fprintf(stderr, "\t-x\tDo not eject to bottom of final page\n");
402: leave(2);
403: }
404:
405: /*
406: * cp contains space-separated environmental args to be added to argv.
407: * Change argc/argv accordingly.
408: */
409: addargs(cp, argcp, argvp) char *cp; int *argcp; char ***argvp;
410: {
411: register int n;
412: register char *s, **nargv, **np;
413:
414: for (s = cp, n = 1; *s != '\0'; s++)
415: if (*s == ' ')
416: ++n; /* number of added args */
417: *argcp += n; /* bump argc */
418: np = nargv = (char **)nalloc((*argcp + 1) * sizeof (char *)); /* allocate */
419: *np++ = *(*argvp)++; /* copy old argv0 */
420: for (s = cp; *s != '\0'; ) {
421: *np++ = s; /* store pointer to new arg */
422: while (*s != '\0' && *s != ' ')
423: s++; /* scan to NUL or space */
424: if (*s == ' ')
425: *s++ = '\0'; /* NUL-terminate space-separated args */
426: }
427: while (**argvp != NULL)
428: *np++ = *(*argvp)++; /* copy old argv */
429: *np = NULL; /* NULL-terminate new argv */
430: *argvp = nargv; /* pass back new argv */
431: }
432:
433: /* end of main.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.