n1.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
n1.c (20331B) | |
--- | |
1 /* | |
2 * n1.c | |
3 * | |
4 * consume options, initialization, main loop, | |
5 * input routines, escape function calling | |
6 */ | |
7 | |
8 #include <u.h> | |
9 #include "tdef.h" | |
10 #include "fns.h" | |
11 #include "ext.h" | |
12 #include "dwbinit.h" | |
13 | |
14 #include <setjmp.h> | |
15 #include <time.h> | |
16 | |
17 char *Version = "March 11, 1994"; | |
18 | |
19 #ifndef DWBVERSION | |
20 #define DWBVERSION "???" | |
21 #endif | |
22 | |
23 char *DWBfontdir = FONTDIR; | |
24 char *DWBntermdir = NTERMDIR; | |
25 char *DWBalthyphens = ALTHYPHENS; | |
26 char *DWBhomedir = ""; | |
27 | |
28 dwbinit dwbpaths[] = { | |
29 &DWBfontdir, NULL, 0, | |
30 &DWBntermdir, NULL, 0, | |
31 &DWBalthyphens, NULL, 0, | |
32 &DWBhomedir, NULL, 0, | |
33 NULL, nextf, NS, | |
34 NULL, NULL, 0 | |
35 }; | |
36 | |
37 int TROFF = 1; /* assume we started in troff... */ | |
38 | |
39 jmp_buf sjbuf; | |
40 Offset ipl[NSO]; | |
41 | |
42 static FILE *ifile; | |
43 static FILE *ifl[NSO]; /* open input file pointers … | |
44 char cfname[NSO+1][NS] = { "stdin" }; /* file name stack … | |
45 int cfline[NSO]; /* input line count stack */ | |
46 char *progname; /* program name (troff or nroff) */ | |
47 | |
48 int trace = 0; /* tracing mode: default off */ | |
49 int trace1 = 0; | |
50 | |
51 int | |
52 main(int argc, char *argv[]) | |
53 { | |
54 char *p; | |
55 int j; | |
56 Tchar i; | |
57 char buf[100]; | |
58 | |
59 ifile = stdin; /* gcc */ | |
60 ptid = stdout; | |
61 | |
62 buf[0] = '\0'; /* make sure it's empty (silly 3b2… | |
63 progname = argv[0]; | |
64 if ((p = strrchr(progname, '/')) == NULL) | |
65 p = progname; | |
66 else | |
67 p++; | |
68 DWBinit(progname, dwbpaths); | |
69 if (strcmp(p, "nroff") == 0) | |
70 TROFF = 0; | |
71 #ifdef UNICODE | |
72 alphabet = 128; /* unicode for plan 9 */ | |
73 #endif /*UNICODE*/ | |
74 mnspace(); | |
75 nnspace(); | |
76 mrehash(); | |
77 nrehash(); | |
78 numtabp[NL].val = -1; | |
79 | |
80 while (--argc > 0 && (++argv)[0][0] == '-') | |
81 switch (argv[0][1]) { | |
82 | |
83 case 'N': /* ought to be used first... */ | |
84 TROFF = 0; | |
85 break; | |
86 case 'd': | |
87 fprintf(stderr, "troff/nroff version %s\n", Vers… | |
88 break; | |
89 case 'F': /* switch font tables from default */ | |
90 if (argv[0][2] != '\0') { | |
91 strcpy(termtab, &argv[0][2]); | |
92 strcpy(fontdir, &argv[0][2]); | |
93 } else { | |
94 argv++; argc--; | |
95 strcpy(termtab, argv[0]); | |
96 strcpy(fontdir, argv[0]); | |
97 } | |
98 break; | |
99 case 0: | |
100 goto start; | |
101 case 'i': | |
102 stdi++; | |
103 break; | |
104 case 'n': | |
105 npn = atoi(&argv[0][2]); | |
106 break; | |
107 case 'u': /* set emboldening amount */ | |
108 bdtab[3] = atoi(&argv[0][2]); | |
109 if (bdtab[3] < 0 || bdtab[3] > 50) | |
110 bdtab[3] = 0; | |
111 break; | |
112 case 's': | |
113 if (!(stop = atoi(&argv[0][2]))) | |
114 stop++; | |
115 break; | |
116 case 'r': | |
117 sprintf(buf + strlen(buf), ".nr %c %s\n", | |
118 argv[0][2], &argv[0][3]); | |
119 /* not yet cpushback(buf);*/ | |
120 /* dotnr(&argv[0][2], &argv[0][3]); */ | |
121 break; | |
122 case 'm': | |
123 if (mflg++ >= NMF) { | |
124 ERROR "Too many macro packages: %s", arg… | |
125 break; | |
126 } | |
127 strcpy(mfiles[nmfi], nextf); | |
128 strcat(mfiles[nmfi++], &argv[0][2]); | |
129 break; | |
130 case 'o': | |
131 getpn(&argv[0][2]); | |
132 break; | |
133 case 'T': | |
134 strcpy(devname, &argv[0][2]); | |
135 dotT++; | |
136 break; | |
137 case 'a': | |
138 ascii = 1; | |
139 break; | |
140 case 'h': | |
141 hflg++; | |
142 break; | |
143 case 'e': | |
144 eqflg++; | |
145 break; | |
146 case 'q': | |
147 quiet++; | |
148 save_tty(); | |
149 break; | |
150 case 'V': | |
151 fprintf(stdout, "%croff: DWB %s\n", | |
152 TROFF ? 't' : 'n', DWBVERSION); | |
153 exit(0); | |
154 case 't': | |
155 if (argv[0][2] != '\0') | |
156 trace = trace1 = argv[0][2]; | |
157 break; /* for the sake of compati… | |
158 default: | |
159 ERROR "unknown option %s", argv[0] WARN; | |
160 done(02); | |
161 } | |
162 | |
163 start: | |
164 /* | |
165 * cpushback maintains a LIFO, so push pack the -r arguments | |
166 * in reverse order to maintain a FIFO in case someone did -rC1 … | |
167 */ | |
168 if (buf[0]) { | |
169 char *p = buf; | |
170 while(*p++) | |
171 ; | |
172 while(p > buf) { | |
173 while(strncmp(p, ".nr", 3) != 0) | |
174 p--; | |
175 cpushback(p); | |
176 *p-- = '\0'; | |
177 } | |
178 } | |
179 argp = argv; | |
180 rargc = argc; | |
181 nmfi = 0; | |
182 init2(); | |
183 setjmp(sjbuf); | |
184 loop: | |
185 copyf = lgf = nb = nflush = nlflg = 0; | |
186 if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip ==… | |
187 nflush++; | |
188 trap = 0; | |
189 eject((Stack *)0); | |
190 goto loop; | |
191 } | |
192 i = getch(); | |
193 if (pendt) | |
194 goto Lt; | |
195 if ((j = cbits(i)) == XPAR) { | |
196 copyf++; | |
197 tflg++; | |
198 while (cbits(i) != '\n') | |
199 pchar(i = getch()); | |
200 tflg = 0; | |
201 copyf--; | |
202 goto loop; | |
203 } | |
204 if (j == cc || j == c2) { | |
205 if (j == c2) | |
206 nb++; | |
207 copyf++; | |
208 while ((j = cbits(i = getch())) == ' ' || j == '\t') | |
209 ; | |
210 ch = i; | |
211 copyf--; | |
212 control(getrq(), 1); | |
213 flushi(); | |
214 goto loop; | |
215 } | |
216 Lt: | |
217 ch = i; | |
218 text(); | |
219 if (nlflg) | |
220 numtabp[HP].val = 0; | |
221 goto loop; | |
222 } | |
223 | |
224 | |
225 | |
226 void init2(void) | |
227 { | |
228 int i; | |
229 char buf[100]; | |
230 | |
231 for (i = NTRTAB; --i; ) | |
232 trtab[i] = i; | |
233 trtab[UNPAD] = ' '; | |
234 iflg = 0; | |
235 obufp = obuf; | |
236 if (TROFF) | |
237 t_ptinit(); | |
238 else | |
239 n_ptinit(); | |
240 mchbits(); | |
241 cvtime(); | |
242 numtabp[PID].val = getpid(); | |
243 numtabp[HP].val = init = 0; | |
244 numtabp[NL].val = -1; | |
245 nfo = 0; | |
246 copyf = raw = 0; | |
247 sprintf(buf, ".ds .T %s\n", devname); | |
248 cpushback(buf); | |
249 sprintf(buf, ".ds .P %s\n", DWBhomedir); | |
250 cpushback(buf); | |
251 numtabp[CD].val = -1; /* compensation */ | |
252 nx = mflg; | |
253 frame = stk = (Stack *)setbrk(STACKSIZE); | |
254 dip = &d[0]; | |
255 nxf = frame + 1; | |
256 for (i = 1; i < NEV; i++) /* propagate the environment */ | |
257 envcopy(&env[i], &env[0]); | |
258 for (i = 0; i < NEV; i++) { | |
259 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof… | |
260 ERROR "not enough room for word buffers" WARN; | |
261 done2(1); | |
262 } | |
263 env[i]._word._size = WDSIZE; | |
264 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof… | |
265 ERROR "not enough room for line buffers" WARN; | |
266 done2(1); | |
267 } | |
268 env[i]._line._size = LNSIZE; | |
269 } | |
270 if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) { | |
271 ERROR "not enough room for line buffers" WARN; | |
272 done2(1); | |
273 } | |
274 olinep = oline; | |
275 olnsize = OLNSIZE; | |
276 blockinit(); | |
277 } | |
278 | |
279 void cvtime(void) | |
280 { | |
281 time_t tt; | |
282 struct tm *ltime; | |
283 | |
284 time(&tt); | |
285 ltime = localtime(&tt); | |
286 numtabp[YR].val = ltime->tm_year % 100; | |
287 numtabp[YR].fmt = 2; | |
288 numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 … | |
289 numtabp[DY].val = ltime->tm_mday; | |
290 numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 … | |
291 } | |
292 | |
293 | |
294 | |
295 char errbuf[200]; | |
296 | |
297 void errprint(void) /* error message printer */ | |
298 { | |
299 int savecd = numtabp[CD].val; | |
300 | |
301 if (!nlflg) | |
302 numtabp[CD].val++; | |
303 | |
304 fprintf(stderr, "%s: ", progname); | |
305 fputs(errbuf, stderr); | |
306 if (cfname[ifi][0]) | |
307 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val); | |
308 fputs("\n", stderr); | |
309 if (cfname[ifi][0]) | |
310 stackdump(); | |
311 numtabp[CD].val = savecd; | |
312 } | |
313 | |
314 | |
315 int control(int a, int b) | |
316 { | |
317 int j, k; | |
318 extern Contab *contabp; | |
319 | |
320 numerr.type = RQERR; | |
321 numerr.req = a; | |
322 if (a == 0 || (j = findmn(a)) == -1) | |
323 return(0); | |
324 if (contabp[j].f == 0) { | |
325 if (trace & TRMAC) | |
326 fprintf(stderr, "invoke macro %s\n", unpair(a)); | |
327 if (dip != d) | |
328 for (k = dilev; k; k--) | |
329 if (d[k].curd == a) { | |
330 ERROR "diversion %s invokes itse… | |
331 unpair(a… | |
332 edone(0100); | |
333 } | |
334 nxf->nargs = 0; | |
335 if (b) | |
336 collect(); | |
337 flushi(); | |
338 return pushi(contabp[j].mx, a); /* BUG??? all tha… | |
339 } | |
340 if (b) { | |
341 if (trace & TRREQ) | |
342 fprintf(stderr, "invoke request %s\n", unpair(a)… | |
343 (*contabp[j].f)(); | |
344 } | |
345 return(0); | |
346 } | |
347 | |
348 void casept(void) | |
349 { | |
350 int i; | |
351 | |
352 noscale++; | |
353 if (skip()) | |
354 i = trace1; | |
355 else { | |
356 i = max(inumb(&trace), 0); | |
357 if (nonumb) | |
358 i = trace1; | |
359 } | |
360 trace1 = trace; | |
361 trace = i; | |
362 noscale = 0; | |
363 } | |
364 | |
365 | |
366 int getrq(void) | |
367 { | |
368 int i, j; | |
369 | |
370 if ((i = getach()) == 0 || (j = getach()) == 0) | |
371 goto rtn; | |
372 i = PAIR(i, j); | |
373 rtn: | |
374 return(i); | |
375 } | |
376 | |
377 /* | |
378 * table encodes some special characters, to speed up tests | |
379 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch | |
380 */ | |
381 | |
382 char gchtab[NCHARS] = { | |
383 000,004,000,000,010,000,000,000, /* fc, ldr */ | |
384 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */ | |
385 000,000,000,000,000,000,000,000, | |
386 000,001,000,001,000,000,000,000, /* FLSS, ESC */ | |
387 000,000,000,000,000,000,000,000, | |
388 000,000,000,000,000,000,000,000, | |
389 000,000,000,000,000,000,000,000, | |
390 000,000,000,000,000,000,000,000, | |
391 000,000,000,000,000,000,000,000, | |
392 000,000,000,000,000,000,000,000, | |
393 000,000,000,000,000,000,000,000, | |
394 000,000,000,000,000,000,000,000, | |
395 000,000,000,000,000,000,001,000, /* f */ | |
396 000,000,000,000,000,000,000,000, | |
397 000,000,000,000,000,000,000,000, | |
398 000,000,000,000,000,000,000,000 | |
399 }; | |
400 | |
401 int realcbits(Tchar c) /* return character bits, or MOTCH if moti… | |
402 { | |
403 if (ismot(c)) | |
404 return MOTCH; | |
405 else | |
406 return c & 0xFFFF; | |
407 } | |
408 | |
409 Tchar getch(void) | |
410 { | |
411 int k; | |
412 Tchar i, j; | |
413 | |
414 g0: | |
415 if (ch) { | |
416 i = ch; | |
417 if (cbits(i) == '\n') | |
418 nlflg++; | |
419 ch = 0; | |
420 return(i); | |
421 } | |
422 | |
423 if (nlflg) | |
424 return('\n'); | |
425 i = getch0(); | |
426 if (ismot(i)) | |
427 return(i); | |
428 k = cbits(i); | |
429 if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) … | |
430 return(i); | |
431 if (k != ESC) { | |
432 if (k == '\n') { | |
433 nlflg++; | |
434 if (ip == 0) | |
435 numtabp[CD].val++; /* line number */ | |
436 return(k); | |
437 } | |
438 if (k == FLSS) { | |
439 copyf++; | |
440 raw++; | |
441 i = getch0(); | |
442 if (!fi) | |
443 flss = i; | |
444 copyf--; | |
445 raw--; | |
446 goto g0; | |
447 } | |
448 if (k == RPT) { | |
449 setrpt(); | |
450 goto g0; | |
451 } | |
452 if (!copyf) { | |
453 if (k == 'f' && lg && !lgf) { | |
454 i = getlg(i); | |
455 return(i); | |
456 } | |
457 if (k == fc || k == tabch || k == ldrch) { | |
458 if ((i = setfield(k)) == 0) | |
459 goto g0; | |
460 else | |
461 return(i); | |
462 } | |
463 if (k == '\b') { | |
464 i = makem(-width(' ' | chbits)); | |
465 return(i); | |
466 } | |
467 } | |
468 return(i); | |
469 } | |
470 | |
471 k = cbits(j = getch0()); | |
472 if (ismot(j)) | |
473 return(j); | |
474 | |
475 switch (k) { | |
476 case 'n': /* number register */ | |
477 setn(); | |
478 goto g0; | |
479 case '$': /* argument indicator */ | |
480 seta(); | |
481 goto g0; | |
482 case '*': /* string indicator */ | |
483 setstr(); | |
484 goto g0; | |
485 case '{': /* LEFT */ | |
486 i = LEFT; | |
487 goto gx; | |
488 case '}': /* RIGHT */ | |
489 i = RIGHT; | |
490 goto gx; | |
491 case '"': /* comment */ | |
492 while (cbits(i = getch0()) != '\n') | |
493 ; | |
494 if (ip == 0) | |
495 numtabp[CD].val++; /* line number */ | |
496 nlflg++; | |
497 return(i); | |
498 | |
499 /* experiment: put it here instead of copy mode */ | |
500 case '(': /* special char name \(xx */ | |
501 case 'C': /* \C'...' */ | |
502 if ((i = setch(k)) == 0) | |
503 goto g0; | |
504 goto gx; | |
505 | |
506 case ESC: /* double backslash */ | |
507 i = eschar; | |
508 goto gx; | |
509 case 'e': /* printable version of current eschar */ | |
510 i = PRESC; | |
511 goto gx; | |
512 case '\n': /* concealed newline */ | |
513 numtabp[CD].val++; | |
514 goto g0; | |
515 case ' ': /* unpaddable space */ | |
516 i = UNPAD; | |
517 goto gx; | |
518 case '\'': /* \(aa */ | |
519 i = ACUTE; | |
520 goto gx; | |
521 case '`': /* \(ga */ | |
522 i = GRAVE; | |
523 goto gx; | |
524 case '_': /* \(ul */ | |
525 i = UNDERLINE; | |
526 goto gx; | |
527 case '-': /* current font minus */ | |
528 i = MINUS; | |
529 goto gx; | |
530 case '&': /* filler */ | |
531 i = FILLER; | |
532 goto gx; | |
533 case 'c': /* to be continued */ | |
534 i = CONT; | |
535 goto gx; | |
536 case '!': /* transparent indicator */ | |
537 i = XPAR; | |
538 goto gx; | |
539 case 't': /* tab */ | |
540 i = '\t'; | |
541 return(i); | |
542 case 'a': /* leader (SOH) */ | |
543 /* old: *pbp++ = LEADER; goto g0; */ | |
544 i = LEADER; | |
545 return i; | |
546 case '%': /* ohc */ | |
547 i = OHC; | |
548 return(i); | |
549 case 'g': /* return format of a number register */ | |
550 setaf(); /* should this really be in copy mode???… | |
551 goto g0; | |
552 case '.': /* . */ | |
553 i = '.'; | |
554 gx: | |
555 setsfbits(i, sfbits(j)); | |
556 return(i); | |
557 } | |
558 if (copyf) { | |
559 *pbp++ = j; | |
560 return(eschar); | |
561 } | |
562 switch (k) { | |
563 | |
564 case 'f': /* font indicator */ | |
565 setfont(0); | |
566 goto g0; | |
567 case 's': /* size indicator */ | |
568 setps(); | |
569 goto g0; | |
570 case 'v': /* vert mot */ | |
571 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
572 if (i = vmot()) { | |
573 return(i); | |
574 } | |
575 goto g0; | |
576 case 'h': /* horiz mot */ | |
577 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
578 if (i = hmot()) | |
579 return(i); | |
580 goto g0; | |
581 case '|': /* narrow space */ | |
582 if (NROFF) | |
583 goto g0; | |
584 return(makem((int)(EM)/6)); | |
585 case '^': /* half narrow space */ | |
586 if (NROFF) | |
587 goto g0; | |
588 return(makem((int)(EM)/12)); | |
589 case 'w': /* width function */ | |
590 setwd(); | |
591 goto g0; | |
592 case 'p': /* spread */ | |
593 spread++; | |
594 goto g0; | |
595 case 'N': /* absolute character number */ | |
596 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
597 if ((i = setabs()) == 0) | |
598 goto g0; | |
599 return i; | |
600 case 'H': /* character height */ | |
601 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
602 return(setht()); | |
603 case 'S': /* slant */ | |
604 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
605 return(setslant()); | |
606 case 'z': /* zero with char */ | |
607 return(setz()); | |
608 case 'l': /* hor line */ | |
609 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
610 setline(); | |
611 goto g0; | |
612 case 'L': /* vert line */ | |
613 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
614 setvline(); | |
615 goto g0; | |
616 case 'D': /* drawing function */ | |
617 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
618 setdraw(); | |
619 goto g0; | |
620 case 'X': /* \X'...' for copy through */ | |
621 setxon(); | |
622 goto g0; | |
623 case 'b': /* bracket */ | |
624 setbra(); | |
625 goto g0; | |
626 case 'o': /* overstrike */ | |
627 setov(); | |
628 goto g0; | |
629 case 'k': /* mark hor place */ | |
630 if ((k = findr(getsn())) != -1) { | |
631 numtabp[k].val = numtabp[HP].val; | |
632 } | |
633 goto g0; | |
634 case '0': /* number space */ | |
635 return(makem(width('0' | chbits))); | |
636 case 'x': /* extra line space */ | |
637 numerr.type = numerr.escarg = 0; numerr.esc = k; | |
638 if (i = xlss()) | |
639 return(i); | |
640 goto g0; | |
641 case 'u': /* half em up */ | |
642 case 'r': /* full em up */ | |
643 case 'd': /* half em down */ | |
644 return(sethl(k)); | |
645 default: | |
646 return(j); | |
647 } | |
648 /* NOTREACHED */ | |
649 } | |
650 | |
651 void setxon(void) /* \X'...' for copy through */ | |
652 { | |
653 Tchar xbuf[NC]; | |
654 Tchar *i; | |
655 Tchar c; | |
656 int delim, k; | |
657 | |
658 if (ismot(c = getch())) | |
659 return; | |
660 delim = cbits(c); | |
661 i = xbuf; | |
662 *i++ = XON | chbits; | |
663 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbu… | |
664 if (k == ' ') | |
665 setcbits(c, WORDSP); | |
666 *i++ = c | ZBIT; | |
667 } | |
668 *i++ = XOFF | chbits; | |
669 *i = 0; | |
670 pushback(xbuf); | |
671 } | |
672 | |
673 | |
674 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, … | |
675 | |
676 Tchar getch0(void) | |
677 { | |
678 Tchar i; | |
679 | |
680 again: | |
681 if (pbp > lastpbp) | |
682 i = *--pbp; | |
683 else if (ip) { | |
684 /* i = rbf(); */ | |
685 i = rbf0(ip); | |
686 if (i == 0) | |
687 i = rbf(); | |
688 else { | |
689 ++ip; | |
690 if (pastend(ip)) { | |
691 --ip; | |
692 rbf(); | |
693 } | |
694 } | |
695 } else { | |
696 if (donef || ndone) | |
697 done(0); | |
698 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF… | |
699 if (nfo < 0) | |
700 ERROR "in getch0, nfo = %d", nfo WARN; | |
701 if (nfo == 0) { | |
702 g0: | |
703 if (nextfile()) { | |
704 if (ip) | |
705 goto again; | |
706 } | |
707 } | |
708 nx = 0; | |
709 #ifdef UNICODE | |
710 if (MB_CUR_MAX > 1) | |
711 i = get1ch(ifile); | |
712 else | |
713 #endif /*UNICODE*/ | |
714 i = getc(ifile); | |
715 if (i == EOF) | |
716 goto g0; | |
717 if (ip) | |
718 goto again; | |
719 } | |
720 /*g2: */ | |
721 if (i >= 040) /* zapped: && i < 0… | |
722 goto g4; | |
723 i = ifilt[i]; | |
724 } | |
725 if (cbits(i) == IMP && !raw) | |
726 goto again; | |
727 if (i == 0 && !init && !raw) { /* zapped: || i =… | |
728 goto again; | |
729 } | |
730 g4: | |
731 if (ismot(i)) | |
732 return i; | |
733 if (copyf == 0 && sfbits(i) == 0) | |
734 i |= chbits; | |
735 if (cbits(i) == eschar && !raw) | |
736 setcbits(i, ESC); | |
737 return(i); | |
738 } | |
739 | |
740 | |
741 #ifdef UNICODE | |
742 Tchar get1ch(FILE *fp) /* get one "character" from input, figure … | |
743 { | |
744 wchar_t wc; | |
745 char buf[100], *p; | |
746 int i, n, c; | |
747 | |
748 for (i = 0, p = buf; i < MB_CUR_MAX; i++) { | |
749 if ((c = getc(fp)) == EOF) | |
750 return c; | |
751 *p++ = c; | |
752 if ((n = mbtowc(&wc, buf, p-buf)) >= 0) | |
753 break; | |
754 } | |
755 | |
756 if (n == 1) /* real ascii, presumably */ | |
757 return wc; | |
758 if (n == 0) | |
759 return p[-1]; /* illegal, but what else to do? */ | |
760 if (c == EOF) | |
761 return EOF; | |
762 *p = 0; | |
763 return chadd(buf, MBchar, Install); /* add name even if h… | |
764 } | |
765 #endif /*UNICODE*/ | |
766 | |
767 void pushback(Tchar *b) | |
768 { | |
769 Tchar *ob = b; | |
770 | |
771 while (*b++) | |
772 ; | |
773 b--; | |
774 while (b > ob && pbp < &pbbuf[NC-3]) | |
775 *pbp++ = *--b; | |
776 if (pbp >= &pbbuf[NC-3]) { | |
777 ERROR "pushback overflow" WARN; | |
778 done(2); | |
779 } | |
780 } | |
781 | |
782 void cpushback(char *b) | |
783 { | |
784 char *ob = b; | |
785 | |
786 while (*b++) | |
787 ; | |
788 b--; | |
789 while (b > ob && pbp < &pbbuf[NC-3]) | |
790 *pbp++ = *--b; | |
791 if (pbp >= &pbbuf[NC-3]) { | |
792 ERROR "cpushback overflow" WARN; | |
793 done(2); | |
794 } | |
795 } | |
796 | |
797 int nextfile(void) | |
798 { | |
799 char *p; | |
800 | |
801 n0: | |
802 if (ifile != stdin) | |
803 fclose(ifile); | |
804 if (ifi > 0 && !nx) { | |
805 if (popf()) | |
806 goto n0; /* popf error */ | |
807 return(1); /* popf ok */ | |
808 } | |
809 if (nx || nmfi < mflg) { | |
810 p = mfiles[nmfi++]; | |
811 if (*p != 0) | |
812 goto n1; | |
813 } | |
814 if (rargc-- <= 0) { | |
815 if ((nfo -= mflg) && !stdi) { | |
816 done(0); | |
817 } | |
818 nfo++; | |
819 numtabp[CD].val = stdi = mflg = 0; | |
820 ifile = stdin; | |
821 strcpy(cfname[ifi], "stdin"); | |
822 return(0); | |
823 } | |
824 p = (argp++)[0]; | |
825 if (rargc >= 0) | |
826 cfname[ifi][0] = 0; | |
827 n1: | |
828 numtabp[CD].val = 0; | |
829 if (p[0] == '-' && p[1] == 0) { | |
830 ifile = stdin; | |
831 strcpy(cfname[ifi], "stdin"); | |
832 } else if ((ifile = fopen(unsharp(p), "r")) == NULL) { | |
833 ERROR "cannot open file %s", p WARN; | |
834 nfo -= mflg; | |
835 done(02); | |
836 } else | |
837 strcpy(cfname[ifi],p); | |
838 nfo++; | |
839 return(0); | |
840 } | |
841 | |
842 int | |
843 popf(void) | |
844 { | |
845 --ifi; | |
846 if (ifi < 0) { | |
847 ERROR "popf went negative" WARN; | |
848 return 1; | |
849 } | |
850 numtabp[CD].val = cfline[ifi]; /* restore line counter */ | |
851 ip = ipl[ifi]; /* input pointer */ | |
852 ifile = ifl[ifi]; /* input FILE * */ | |
853 return(0); | |
854 } | |
855 | |
856 | |
857 void flushi(void) | |
858 { | |
859 if (nflush) | |
860 return; | |
861 ch = 0; | |
862 copyf++; | |
863 while (!nlflg) { | |
864 if (donef && frame == stk) | |
865 break; | |
866 getch(); | |
867 } | |
868 copyf--; | |
869 } | |
870 | |
871 /* | |
872 * return 16-bit, ascii/alphabetic character, ignore chars with more bit… | |
873 * (internal names), spaces and special cookies (below 040). | |
874 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 t… | |
875 */ | |
876 int | |
877 getach(void) | |
878 { | |
879 Tchar i; | |
880 int j; | |
881 | |
882 lgf++; | |
883 j = cbits(i = getch()); | |
884 if (ismot(i) | |
885 || j > SHORTMASK | |
886 || (j <= 040 && j != 002 /*STX*/ | |
887 && j != 003 /*ETX*/ | |
888 && j != 005 /*ENQ*/ | |
889 && j != 006 /*ACK*/ | |
890 && j != 007)) { /*BELL*/ | |
891 ch = i; | |
892 j = 0; | |
893 } | |
894 lgf--; | |
895 return j; | |
896 } | |
897 | |
898 | |
899 void casenx(void) | |
900 { | |
901 lgf++; | |
902 skip(); | |
903 getname(); | |
904 nx++; | |
905 if (nmfi > 0) | |
906 nmfi--; | |
907 strcpy(mfiles[nmfi], nextf); | |
908 nextfile(); | |
909 nlflg++; | |
910 ip = 0; | |
911 pendt = 0; | |
912 frame = stk; | |
913 nxf = frame + 1; | |
914 } | |
915 | |
916 int | |
917 getname(void) | |
918 { | |
919 int j, k; | |
920 | |
921 lgf++; | |
922 for (k = 0; k < NS - 1; k++) { | |
923 j = getach(); | |
924 if (!j) | |
925 break; | |
926 nextf[k] = j; | |
927 } | |
928 nextf[k] = 0; | |
929 lgf--; | |
930 return(nextf[0]); | |
931 } | |
932 | |
933 | |
934 void caseso(void) | |
935 { | |
936 FILE *fp = 0; | |
937 | |
938 lgf++; | |
939 nextf[0] = 0; | |
940 if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) ==… | |
941 ERROR "can't open file %s", nextf WARN; | |
942 done(02); | |
943 } | |
944 strcpy(cfname[ifi+1], nextf); | |
945 cfline[ifi] = numtabp[CD].val; /*hold line counte… | |
946 numtabp[CD].val = 0; | |
947 flushi(); | |
948 ifl[ifi] = ifile; | |
949 ifile = fp; | |
950 ipl[ifi] = ip; | |
951 ip = 0; | |
952 nx++; | |
953 nflush++; | |
954 ifi++; | |
955 } | |
956 | |
957 void caself(void) /* set line number and file */ | |
958 { | |
959 int n; | |
960 | |
961 if (skip()) | |
962 return; | |
963 n = atoi0(); | |
964 if (!nonumb) | |
965 cfline[ifi] = numtabp[CD].val = n - 1; | |
966 if (!skip()) | |
967 if (getname()) { /* eats '\n' ? */ | |
968 strcpy(cfname[ifi], nextf); | |
969 if (!nonumb) | |
970 numtabp[CD].val--; | |
971 } | |
972 } | |
973 | |
974 void cpout(FILE *fin, char *token) | |
975 { | |
976 int n; | |
977 char buf[1024]; | |
978 | |
979 if (token) { /* BUG: There should be no NULL bytes in inp… | |
980 char *newl = buf; | |
981 while ((fgets(buf, sizeof buf, fin)) != NULL) { | |
982 if (newl) { | |
983 numtabp[CD].val++; /* line number */ | |
984 if (strcmp(token, buf) == 0) | |
985 return; | |
986 } | |
987 newl = strchr(buf, '\n'); | |
988 fputs(buf, ptid); | |
989 } | |
990 } else { | |
991 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > … | |
992 fwrite(buf, n, 1, ptid); | |
993 fclose(fin); | |
994 } | |
995 } | |
996 | |
997 void casecf(void) | |
998 { /* copy file without change */ | |
999 FILE *fd; | |
1000 char *eof, *p; | |
1001 extern int hpos, esc, po; | |
1002 | |
1003 /* this may not make much sense in nroff... */ | |
1004 | |
1005 lgf++; | |
1006 nextf[0] = 0; | |
1007 if (!skip() && getname()) { | |
1008 if (strncmp("<<", nextf, 2) != 0) { | |
1009 if ((fd = fopen(unsharp(nextf), "r")) == NULL) { | |
1010 ERROR "can't open file %s", nextf WARN; | |
1011 done(02); | |
1012 } | |
1013 eof = (char *) NULL; | |
1014 } else { /* current file */ | |
1015 if (pbp > lastpbp || ip) { | |
1016 ERROR "casecf: not reading from file" WA… | |
1017 done(02); | |
1018 } | |
1019 eof = &nextf[2]; | |
1020 if (!*eof) { | |
1021 ERROR "casecf: missing end of input toke… | |
1022 done(02); | |
1023 } | |
1024 p = eof; | |
1025 while(*++p) | |
1026 ; | |
1027 *p++ = '\n'; | |
1028 *p = 0; | |
1029 fd = ifile; | |
1030 } | |
1031 } else { | |
1032 ERROR "casecf: no argument" WARN; | |
1033 lgf--; | |
1034 return; | |
1035 } | |
1036 lgf--; | |
1037 | |
1038 /* make it into a clean state, be sure that everything is out */ | |
1039 tbreak(); | |
1040 hpos = po; | |
1041 esc = 0; | |
1042 ptesc(); /* to left margin */ | |
1043 esc = un; | |
1044 ptesc(); | |
1045 ptlead(); | |
1046 ptps(); | |
1047 ptfont(); | |
1048 flusho(); | |
1049 cpout(fd, eof); | |
1050 ptps(); | |
1051 ptfont(); | |
1052 } | |
1053 | |
1054 void getline(char *s, int n) /* get rest of input line into s */ | |
1055 { | |
1056 int i; | |
1057 | |
1058 lgf++; | |
1059 copyf++; | |
1060 skip(); | |
1061 for (i = 0; i < n-1; i++) | |
1062 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT) | |
1063 break; | |
1064 s[i] = 0; | |
1065 copyf--; | |
1066 lgf--; | |
1067 } | |
1068 | |
1069 void casesy(void) /* call system */ | |
1070 { | |
1071 char sybuf[NTM]; | |
1072 | |
1073 getline(sybuf, NTM); | |
1074 system(sybuf); | |
1075 } | |
1076 | |
1077 | |
1078 void getpn(char *a) | |
1079 { | |
1080 int n, neg; | |
1081 | |
1082 if (*a == 0) | |
1083 return; | |
1084 neg = 0; | |
1085 for ( ; *a; a++) | |
1086 switch (*a) { | |
1087 case '+': | |
1088 case ',': | |
1089 continue; | |
1090 case '-': | |
1091 neg = 1; | |
1092 continue; | |
1093 default: | |
1094 n = 0; | |
1095 if (isdigit((uchar)*a)) { | |
1096 do | |
1097 n = 10 * n + *a++ - '0'; | |
1098 while (isdigit((uchar)*a)); | |
1099 a--; | |
1100 } else | |
1101 n = 9999; | |
1102 *pnp++ = neg ? -n : n; | |
1103 neg = 0; | |
1104 if (pnp >= &pnlist[NPN-2]) { | |
1105 ERROR "too many page numbers" WARN; | |
1106 done3(-3); | |
1107 } | |
1108 } | |
1109 if (neg) | |
1110 *pnp++ = -9999; | |
1111 *pnp = -INT_MAX; | |
1112 print = 0; | |
1113 pnp = pnlist; | |
1114 if (*pnp != -INT_MAX) | |
1115 chkpn(); | |
1116 } | |
1117 | |
1118 | |
1119 void setrpt(void) | |
1120 { | |
1121 Tchar i, j; | |
1122 | |
1123 copyf++; | |
1124 raw++; | |
1125 i = getch0(); | |
1126 copyf--; | |
1127 raw--; | |
1128 if ((long) i < 0 || cbits(j = getch0()) == RPT) | |
1129 return; | |
1130 while (i > 0 && pbp < &pbbuf[NC-3]) { | |
1131 i--; | |
1132 *pbp++ = j; | |
1133 } | |
1134 } |