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