|
|
1.1 root 1: /*
2: * misc.c
3: * Nroff/Troff.
4: * Miscellaneous routines.
5: */
6:
7: #include "roff.h"
8: #include <access.h>
9: #include <ctype.h>
10: #include <string.h>
11:
12: /*
13: * Define a macro.
14: * 'mp' is a pointer to a macro descriptor which is
15: * filled in with the appropriate information and name is the name
16: * of the macro upon which the definition ends.
17: */
18: deftext(mp, name) register MAC *mp; char name[2];
19: {
20: static char residue[4];
21: register STR *sp;
22: register char *bp;
23: int nlflag;
24:
25: if (mp != NULL) {
26: mp->t_div.m_next = NULL;
27: mp->t_div.m_type = MTEXT;
28: mp->t_div.m_core = NULL;
29: mp->t_div.m_seek = tmpseek;
30: }
31: #if 0
32: /* Conditionalized out 4/11/91 by steve, seems wrong. */
33: infalse = 1;
34: #endif
35: bp = miscbuf;
36: for (nlflag = 1;;) {
37:
38: /* nlflag indicates if last character was \n. */
39: if (bp > miscbuf)
40: nlflag = (*(bp-1) == '\n');
41:
42: /* Flush if necessary, leaving room for "..\n" or ".XX". */
43: if (bp >= &miscbuf[MSCSIZE-3]) {
44: if (mp != NULL)
45: nwrite(miscbuf, 1, bp-miscbuf);
46: bp = miscbuf;
47: }
48:
49: /* Ignore remainder of line not starting with endmark. */
50: if (!nlflag) {
51: *bp++ = getf(2);
52: continue;
53: }
54:
55: /* Last character was \n, look for endmark on next line. */
56: if (name[0]=='\0') {
57: if ((*bp++ = getf(2))!='.' || escflag!=0)
58: continue;
59: if ((*bp++ = getf(2))!='.' || escflag!=0)
60: continue;
61: if ((*bp++ = getf(2)) != '\n')
62: continue;
63: bp -= 3;
64: break;
65: } else {
66: if ((*bp++ = getf(2))!=ccc || escflag!=0)
67: continue;
68: if ((*bp++ = getf(2))!=name[0] || escflag!=0)
69: continue;
70: if ((*bp++ = getf(2))!=name[1] || escflag!=0)
71: continue;
72: bp -= 3;
73: residue[0] = bp[0];
74: residue[1] = bp[1];
75: residue[2] = bp[2];
76: residue[3] = '\0';
77: sp = allstr(SCORE);
78: sp->x3.s_cp = residue;
79: sp->x3.s_srel = NULL;
80: break;
81: }
82: }
83: *bp++ = '\0';
84: if (mp != NULL)
85: nwrite(miscbuf, 1, bp-miscbuf);
86: #if 0
87: /* Conditionalized out 4/11/91 by steve, as above. */
88: infalse = 0;
89: #endif
90: }
91:
92: /*
93: * Define a special character.
94: */
95: spc_def(name, value) char name[2]; char *value;
96: {
97: register SPECIAL **spp;
98: register int n;
99: int len;
100: SPECIAL *sp;
101: char *cp;
102:
103: len = strlen(value) + 1;
104: for (spp = &spc_list; *spp != NULL; spp = &((*spp)->spc_link)) {
105: sp = *spp;
106: n = strncmp(sp->spc_name, name, 2);
107: if (n < 0)
108: continue; /* keep looking */
109: else if (n > 0)
110: break; /* not found, add it */
111: /* Gotcha, redefine it. */
112: nfree(sp->spc_val); /* free old value */
113: sp->spc_val = nalloc(len); /* allocate new space */
114: strcpy(sp->spc_val, value); /* and copy in value */
115: return;
116: }
117: /* Add new entry. */
118: sp = (SPECIAL *)nalloc(sizeof(*sp)); /* allocate new entry */
119: cp = nalloc(len); /* allocate new value space */
120: sp->spc_link = *spp; /* link into SPECIAL list */
121: *spp = sp;
122: sp->spc_name[0] = name[0];
123: sp->spc_name[1] = name[1];
124: sp->spc_val = cp;
125: strcpy(cp, value);
126: }
127:
128: /*
129: * Find a special character entry in the special character list.
130: * Print error message and return NULL if not found.
131: */
132: SPECIAL *
133: spc_find(name) char name[2];
134: {
135: register SPECIAL *sp;
136: register int n;
137:
138: for (sp = spc_list; sp != NULL; sp = sp->spc_link) {
139: n = strncmp(sp->spc_name, name, 2);
140: if (n < 0)
141: continue;
142: else if (n > 0)
143: break;
144: else
145: return sp;
146: }
147: printe("special character %c%c not found", name[0], name[1]);
148: return NULL;
149: }
150:
151: /*
152: * Process requests from a library file if it exists.
153: * The flag is 1 if file contains requests, 0 if binary data.
154: * Return 1 if it exists, 0 if not.
155: */
156: lib_file(s, flag) char *s; int flag;
157: {
158: register char file[40];
159:
160: /* Look file, process it if found. */
161: sprintf(file, "%s%s%s", LIBDIR,
162: (ntroff == NROFF) ? NRDIR : (pflag) ? TPSDIR : TPCLDIR, s);
163: if (access(file, AREAD) != 0)
164: return 0;
165: if (flag) {
166: adsfile(file);
167: process();
168: return 1;
169: }
170: return copy_file(file);
171: }
172:
173: /*
174: * Copy a file verbatim.
175: * Return 0 if not found or not readable, 1 on success.
176: */
177: copy_file(s) char *s;
178: {
179: register FILE *fp;
180: register int c;
181:
182: if ((fp = fopen(s, "rb")) == NULL)
183: return 0;
184: while ((c = fgetc(fp)) != EOF)
185: putchar(c);
186: fclose(fp);
187: return 1;
188: }
189:
190: /*
191: * Read a block into the buffer 'bp' starting at seek position
192: * 'l' in the temp file.
193: */
194: nread(l, bp)
195: long l;
196: char *bp;
197: {
198: if (tmpseek-l <= DBFSIZE) {
199: copystr(bp, diskbuf, DBFSIZE, 1);
200: return;
201: }
202: lseek(fileno(tmp), (long) l, 0);
203: if (read(fileno(tmp), bp, DBFSIZE) != DBFSIZE)
204: panic("temporary file read error");
205: }
206:
207: /*
208: * Write the buffer 'bp' which contains 'n' elements of size 's'
209: * onto the end of the temp file.
210: */
211: nwrite(bp, s, n) register char *bp; unsigned s; register unsigned n;
212: {
213: unsigned bno, off;
214: register char *dp;
215:
216: bno = tmpseek / DBFSIZE;
217: off = tmpseek % DBFSIZE;
218: if (bno!=0 && off==0) {
219: --bno;
220: off += DBFSIZE;
221: }
222: dp = &diskbuf[off];
223: s = n *= s;
224: while (n--) {
225: if (dp >= &diskbuf[DBFSIZE]) {
226: lseek(fileno(tmp), (long) bno++*DBFSIZE, 0);
227: if (write(fileno(tmp), diskbuf, DBFSIZE) != DBFSIZE)
228: panic("temporary file write error");
229: dp = &diskbuf[0];
230: }
231: *dp++ = *bp++;
232: }
233: tmpseek += s;
234: }
235:
236: /*
237: * Given a string, return a pointer to a copy of it.
238: */
239: char *
240: duplstr(s) register char *s;
241: {
242: return strcpy(nalloc(strlen(s) + 1), s);
243: }
244:
245: /*
246: * Copy the array of 'n' elements containing a structure of size
247: * 'size' from 's2' to 's1'.
248: */
249: copystr(s1, s2, size, n) char *s1, *s2; int size; register int n;
250: {
251: if ((n *= size) == 0)
252: return;
253: memcpy(s1, s2, n);
254: }
255:
256: /*
257: * Allocate 'n' bytes.
258: */
259: char *
260: nalloc(n)
261: {
262: extern char *calloc();
263: register char *cp;
264:
265: if ((cp = calloc(n, 1)) == NULL)
266: #if MSDOS
267: panic("out of space"); /* no memok() in MS-DOS libc */
268: #else
269: panic("out of space - memory %s", (memok() ? "good" : "bad"));
270: #endif
271: return cp;
272: }
273:
274: /*
275: * Release the given storage.
276: */
277: nfree(cp)
278: char *cp;
279: {
280: free(cp);
281: }
282:
283: /*
284: * Execute conditional.
285: * bp points to the remainder of the line.
286: * Called from .el and .ie.
287: */
288: do_cond(cond, bp) int cond; unsigned char *bp;
289: {
290: unsigned char charbuf[CBFSIZE];
291: register unsigned char *cp;
292: unsigned char c;
293:
294: while (isascii(*bp) && isspace(*bp))
295: bp++; /* skip leading space */
296: if (cond) {
297: /* Execute true branch. */
298: cp = charbuf;
299: bracelevel = oldbracelevel; /* restore original brace level */
300: if (*bp == EBEG) {
301: bp++; /* ignore \{ */
302: bracelevel++;
303: }
304: while (c = *bp++)
305: if (cp < &charbuf[CBFSIZE-2])
306: *cp++ = c;
307: *cp++ = '\n';
308: *cp = '\0';
309: cp = duplstr(charbuf);
310: adscore(cp); /* execute remainder */
311: strp->x3.s_srel = cp;
312: } else {
313: /* Skip false branch. */
314: if (*bp != EBEG)
315: return; /* one-line conditional */
316: for (; *bp; bp++) {
317: if (*bp == EBEG)
318: ++infalse;
319: else if (*bp == EEND)
320: --infalse;
321: }
322: if (infalse == 0)
323: return; /* \{ ... \} on one line */
324: while (infalse && (c = getf(0))) {
325: if (c == EBEG)
326: ++infalse;
327: else if (c == EEND)
328: --infalse; /* scan to matching \} */
329: }
330: while (getf(0) != '\n')
331: ; /* then scan to newline */
332: }
333: }
334:
335: /*
336: * Set a value, saving old value.
337: * Called by various requests.
338: */
339: setval(vp, op, arg, mul, div) int *vp, *op; char *arg; long mul, div;
340: {
341: register int val;
342:
343: val = *vp; /* save value */
344: *vp = number(arg, mul, div, val, 0, *op); /* set value */
345: *op = val; /* save old */
346: }
347:
348: /*
349: * Return the number of the named font.
350: * Return -1 if not found.
351: */
352: int
353: font_num(name) char name[2];
354: {
355: register FTB *p;
356:
357: for (p = fontab; p < &fontab[NFNAMES]; p++) {
358: if (p->f_name[0] == '\0')
359: break;
360: else if ((p->f_name[0] == name[0]) && (p->f_name[1] == name[1]))
361: return p->f_font;
362: }
363: return -1;
364: }
365:
366: /*
367: * Return the number of the named font.
368: * Print an error message and return -1 if not found.
369: */
370: int
371: font_number(name, s) char name[2]; char *s;
372: {
373: register int n;
374:
375: if ((n = font_num(name)) == -1)
376: printe("%scannot find font %c%c", (s==NULL) ? "" : s, name[0], name[1]);
377: return n;
378: }
379:
380: /*
381: * Assign a font number to a name.
382: * If there is no font of the given name, add one.
383: * Return the previously assigned font number, or -1 if none.
384: */
385: int
386: assign_font(name, c) char *name; int c;
387: {
388: char a, b;
389: register FTB *p;
390:
391: a = name[0];
392: b = name[1];
393: for (p = fontab; p < &fontab[NFNAMES]; p++) {
394: if ((p->f_name[0] == a) && (p->f_name[1] == b)) {
395:
396: /* Replace existing entry */
397: a = p->f_font;
398: p->f_font = c;
399:
400: /* Watch for current, tab, underline fonts. */
401: if (a == curfont)
402: dev_font(c);
403: if (a == tfn)
404: tfn = c;
405: if (a == ufn)
406: ufn = c;
407:
408: return a;
409: } else if (p->f_name[0] == '\0') {
410: /* Add new entry */
411: p->f_name[0] = a;
412: p->f_name[1] = b;
413: p->f_font = c;
414: return -1;
415: }
416: }
417: printe("no room for new font name %c%c", a, ((b) ? b : ' '));
418: return -1;
419: }
420:
421: /*
422: * Given a font number, change font.
423: */
424: setfontnum(n, setflag) register int n; int setflag;
425: {
426: register FTB *p;
427:
428: for (p = fontab; p < &fontab[NFNAMES]; p++) {
429: if (p->f_font == n) {
430: setfont(p->f_name, setflag);
431: return;
432: } else if (p->f_name[0] == '\0')
433: break;
434: }
435: printe("cannot find font %d", n);
436: }
437:
438: /*
439: * Given a font name, change font.
440: * Understands \fP and \fn, saves previous font in oldfon.
441: * Return the new font number, or -1 if not found.
442: * dev_font() does the real work.
443: */
444: int
445: setfont(name, setflag) char name[2]; int setflag;
446: {
447: register int n;
448:
449: if ((name[0] >= '0') && (name[0] <= '9')) {
450: n = name[0] - '0';
451: name[0] = mapfont[n][0];
452: name[1] = mapfont[n][1];
453: }
454: if (name[0]=='P' && name[1]=='\0') {
455: name[0] = oldfon[0];
456: name[1] = oldfon[1];
457: }
458: if ((n = font_number(name, NULL)) < 0) {
459: if (setflag) {
460: /*
461: * Bogus font change sets oldfon so \fP gets back
462: * from the bogus font to the present font.
463: * The bogus font change is really ignored.
464: */
465: oldfon[0] = fon[0];
466: oldfon[1] = fon[1];
467: }
468: return -1;
469: }
470: dev_font(n);
471: if (setflag) {
472: oldfon[0] = fon[0];
473: oldfon[1] = fon[1];
474: fon[0] = name[0];
475: fon[1] = name[1];
476: }
477: return n;
478: }
479:
480: /*
481: * Print out a warning.
482: */
483: /*VARARGS*/
484: printe(a1) char *a1;
485: {
486: register STR *sp;
487:
488: fprintf(stderr, "%s: ", argv0);
489: for (sp=strp; sp; sp=sp->x1.s_next) {
490: if (sp->x1.s_type == SFILE) {
491: fprintf(stderr, "%s: %d: ", sp->x2.s_fname, sp->x2.s_clnc);
492: break;
493: }
494: }
495: fprintf(stderr, "%r\n", &a1);
496: if (dflag)
497: fprintf(stderr, "Request: %s\n", miscbuf);
498: }
499:
500: /*
501: * Print an unimplemented warning.
502: */
503: printu(s) char *s;
504: {
505: printe("%s not implemented yet", s);
506: }
507:
508: /*
509: * An irrecoverable error was found.
510: * Print out an error message and leave.
511: */
512: /*VARARGS*/
513: panic(s)
514: {
515: fprintf(stderr, "%s: %r\n", argv0, &s);
516: leave(1);
517: }
518:
519: /* Debug stuff follows, used to be in codebug.c. */
520:
521: #if (DDEBUG != 0)
522: #if (DDEBUG & DBGCODE)
523:
524: static char *codtab[] = {
525: "DNULL",
526: "DHMOV (move horizontal)",
527: "DVMOV (move vertical)",
528: "DFONT (change font)",
529: "DPSZE (change pointsize)",
530: "DSPAR (space down and return)",
531: "DPADC (Paddable character)",
532: "DHYPH (Place to hyphenate)",
533: "DHYPC (Hyphen character)"
534: };
535:
536: codebug(code, parm1)
537: {
538: if (code <= 0) {
539: printd(DBGCODE, "%s %u\n", codtab[-code], parm1);
540: } else {
541: printd(DBGCODE, "%c (width=%d)\n", code, parm1);
542: }
543: }
544: #endif
545:
546: static char *dbgtbl[] = {
547: "CHECKpoints",
548: "REGisterS",
549: "REGister eXecution",
550: "output CODEs",
551: "DIVeRsions",
552: "FILEs",
553: "FUNCtions",
554: "CHARacters",
555: "PROCess trace",
556: "MACro eXecution",
557: "MISCelaneous",
558: "MOVEment",
559: "ENViRonment",
560: "CALL tracing"
561: };
562:
563: printd(lvl, fmt)
564: int lvl;
565: char *fmt;
566: {
567: if (lvl & dbglvl)
568: fprintf(stderr, "%r", &fmt);
569: }
570:
571: void dbginit()
572: {
573: register int t=dbglvl;
574: register int j;
575: register int m=1;
576:
577: if (dbglvl == 0)
578: return;
579: for (j=0; j<15; j++) {
580: if (t & m)
581: fprintf(stderr, "debugging %s\n", dbgtbl[j]);
582: m <<= 1;
583: }
584: }
585: #endif
586:
587: /* end of misc.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.