Annotation of src/usr.bin/m4/eval.c, Revision 1.28
1.28 ! espie 1: /* $OpenBSD: eval.c,v 1.27 2000/07/24 23:08:24 espie Exp $ */
1.7 millert 2: /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Ozan Yigit at York University.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the University of
22: * California, Berkeley and its contributors.
23: * 4. Neither the name of the University nor the names of its contributors
24: * may be used to endorse or promote products derived from this software
25: * without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37: * SUCH DAMAGE.
38: */
39:
40: #ifndef lint
41: #if 0
42: static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95";
43: #else
1.28 ! espie 44: static char rcsid[] = "$OpenBSD: eval.c,v 1.27 2000/07/24 23:08:24 espie Exp $";
1.1 deraadt 45: #endif
46: #endif /* not lint */
47:
48: /*
49: * eval.c
50: * Facility: m4 macro processor
51: * by: oz
52: */
53:
54: #include <sys/types.h>
55: #include <errno.h>
56: #include <unistd.h>
57: #include <stdio.h>
58: #include <stdlib.h>
1.13 espie 59: #include <stddef.h>
1.1 deraadt 60: #include <string.h>
1.6 millert 61: #include <fcntl.h>
1.12 espie 62: #include <err.h>
1.1 deraadt 63: #include "mdef.h"
64: #include "stdd.h"
65: #include "extern.h"
66: #include "pathnames.h"
67:
1.20 espie 68: static void dodefn __P((const char *));
69: static void dopushdef __P((const char *, const char *));
70: static void dodump __P((const char *[], int));
71: static void doifelse __P((const char *[], int));
72: static int doincl __P((const char *));
73: static int dopaste __P((const char *));
74: static void dochq __P((const char *[], int));
75: static void dochc __P((const char *[], int));
76: static void dodiv __P((int));
77: static void doundiv __P((const char *[], int));
78: static void dosub __P((const char *[], int));
79: static void map __P((char *, const char *, const char *, const char *));
1.26 espie 80: static const char *handledash __P((char *, char *, const char *));
1.1 deraadt 81: /*
82: * eval - evaluate built-in macros.
83: * argc - number of elements in argv.
84: * argv - element vector :
85: * argv[0] = definition of a user
86: * macro or nil if built-in.
87: * argv[1] = name of the macro or
88: * built-in.
89: * argv[2] = parameters to user-defined
90: * . macro or built-in.
91: * .
92: *
93: * Note that the minimum value for argc is 3. A call in the form
94: * of macro-or-builtin() will result in:
95: * argv[0] = nullstr
96: * argv[1] = macro-or-builtin
97: * argv[2] = nullstr
98: */
99:
100: void
101: eval(argv, argc, td)
1.20 espie 102: const char *argv[];
1.17 espie 103: int argc;
104: int td;
1.1 deraadt 105: {
1.17 espie 106: int c, n;
1.1 deraadt 107: static int sysval = 0;
108:
109: #ifdef DEBUG
110: printf("argc = %d\n", argc);
111: for (n = 0; n < argc; n++)
112: printf("argv[%d] = %s\n", n, argv[n]);
113: #endif
1.22 espie 114:
115: if (td & RECDEF)
1.24 espie 116: errx(1, "%s at line %lu: expanding recursive definition for %s",
117: CURRENT_NAME, CURRENT_LINE, argv[1]);
1.1 deraadt 118: /*
119: * if argc == 3 and argv[2] is null, then we
120: * have macro-or-builtin() type call. We adjust
121: * argc to avoid further checking..
122: */
123: if (argc == 3 && !*(argv[2]))
124: argc--;
125:
1.22 espie 126: switch (td & TYPEMASK) {
1.1 deraadt 127:
128: case DEFITYPE:
129: if (argc > 2)
130: dodefine(argv[2], (argc > 3) ? argv[3] : null);
131: break;
132:
133: case PUSDTYPE:
134: if (argc > 2)
135: dopushdef(argv[2], (argc > 3) ? argv[3] : null);
136: break;
137:
138: case DUMPTYPE:
139: dodump(argv, argc);
140: break;
141:
142: case EXPRTYPE:
143: /*
144: * doexpr - evaluate arithmetic
145: * expression
146: */
147: if (argc > 2)
148: pbnum(expr(argv[2]));
149: break;
150:
151: case IFELTYPE:
152: if (argc > 4)
153: doifelse(argv, argc);
154: break;
155:
156: case IFDFTYPE:
157: /*
158: * doifdef - select one of two
159: * alternatives based on the existence of
160: * another definition
161: */
162: if (argc > 3) {
163: if (lookup(argv[2]) != nil)
164: pbstr(argv[3]);
165: else if (argc > 4)
166: pbstr(argv[4]);
167: }
168: break;
169:
170: case LENGTYPE:
171: /*
172: * dolen - find the length of the
173: * argument
174: */
1.18 espie 175: pbnum((argc > 2) ? strlen(argv[2]) : 0);
1.1 deraadt 176: break;
177:
178: case INCRTYPE:
179: /*
180: * doincr - increment the value of the
181: * argument
182: */
183: if (argc > 2)
184: pbnum(atoi(argv[2]) + 1);
185: break;
186:
187: case DECRTYPE:
188: /*
189: * dodecr - decrement the value of the
190: * argument
191: */
192: if (argc > 2)
193: pbnum(atoi(argv[2]) - 1);
194: break;
195:
196: case SYSCTYPE:
197: /*
198: * dosys - execute system command
199: */
200: if (argc > 2)
201: sysval = system(argv[2]);
202: break;
203:
204: case SYSVTYPE:
205: /*
206: * dosysval - return value of the last
207: * system call.
208: *
209: */
210: pbnum(sysval);
211: break;
212:
1.27 espie 213: case ESYSCMDTYPE:
214: if (argc > 2)
215: doesyscmd(argv[2]);
216: break;
1.1 deraadt 217: case INCLTYPE:
218: if (argc > 2)
219: if (!doincl(argv[2]))
1.24 espie 220: err(1, "%s at line %lu: include(%s)",
221: CURRENT_NAME, CURRENT_LINE, argv[2]);
1.1 deraadt 222: break;
223:
224: case SINCTYPE:
225: if (argc > 2)
226: (void) doincl(argv[2]);
227: break;
228: #ifdef EXTENDED
229: case PASTTYPE:
230: if (argc > 2)
231: if (!dopaste(argv[2]))
1.24 espie 232: err(1, "%s at line %lu: paste(%s)",
233: CURRENT_NAME, CURRENT_LINE, argv[2]);
1.1 deraadt 234: break;
235:
236: case SPASTYPE:
237: if (argc > 2)
238: (void) dopaste(argv[2]);
239: break;
240: #endif
241: case CHNQTYPE:
242: dochq(argv, argc);
243: break;
244:
245: case CHNCTYPE:
246: dochc(argv, argc);
247: break;
248:
249: case SUBSTYPE:
250: /*
251: * dosub - select substring
252: *
253: */
254: if (argc > 3)
255: dosub(argv, argc);
256: break;
257:
258: case SHIFTYPE:
259: /*
260: * doshift - push back all arguments
261: * except the first one (i.e. skip
262: * argv[2])
263: */
264: if (argc > 3) {
265: for (n = argc - 1; n > 3; n--) {
1.10 deraadt 266: pbstr(rquote);
1.1 deraadt 267: pbstr(argv[n]);
1.10 deraadt 268: pbstr(lquote);
1.7 millert 269: putback(COMMA);
1.1 deraadt 270: }
1.10 deraadt 271: pbstr(rquote);
1.1 deraadt 272: pbstr(argv[3]);
1.10 deraadt 273: pbstr(lquote);
1.1 deraadt 274: }
275: break;
276:
277: case DIVRTYPE:
278: if (argc > 2 && (n = atoi(argv[2])) != 0)
279: dodiv(n);
280: else {
281: active = stdout;
282: oindex = 0;
283: }
284: break;
285:
286: case UNDVTYPE:
287: doundiv(argv, argc);
288: break;
289:
290: case DIVNTYPE:
291: /*
292: * dodivnum - return the number of
293: * current output diversion
294: */
295: pbnum(oindex);
296: break;
297:
298: case UNDFTYPE:
299: /*
300: * doundefine - undefine a previously
301: * defined macro(s) or m4 keyword(s).
302: */
303: if (argc > 2)
304: for (n = 2; n < argc; n++)
305: remhash(argv[n], ALL);
306: break;
307:
308: case POPDTYPE:
309: /*
310: * dopopdef - remove the topmost
311: * definitions of macro(s) or m4
312: * keyword(s).
313: */
314: if (argc > 2)
315: for (n = 2; n < argc; n++)
316: remhash(argv[n], TOP);
317: break;
318:
319: case MKTMTYPE:
320: /*
321: * dotemp - create a temporary file
322: */
1.16 espie 323: if (argc > 2) {
324: int fd;
1.20 espie 325: char *temp;
326:
327: temp = xstrdup(argv[2]);
1.16 espie 328:
1.20 espie 329: fd = mkstemp(temp);
1.16 espie 330: if (fd == -1)
1.24 espie 331: err(1,
332: "%s at line %lu: couldn't make temp file %s",
333: CURRENT_NAME, CURRENT_LINE, argv[2]);
1.16 espie 334: close(fd);
1.20 espie 335: pbstr(temp);
336: free(temp);
1.16 espie 337: }
1.1 deraadt 338: break;
339:
340: case TRNLTYPE:
341: /*
342: * dotranslit - replace all characters in
343: * the source string that appears in the
344: * "from" string with the corresponding
345: * characters in the "to" string.
346: */
347: if (argc > 3) {
1.8 deraadt 348: char temp[STRSPMAX+1];
1.1 deraadt 349: if (argc > 4)
350: map(temp, argv[2], argv[3], argv[4]);
351: else
352: map(temp, argv[2], argv[3], null);
353: pbstr(temp);
1.8 deraadt 354: } else if (argc > 2)
1.1 deraadt 355: pbstr(argv[2]);
356: break;
357:
358: case INDXTYPE:
359: /*
360: * doindex - find the index of the second
361: * argument string in the first argument
362: * string. -1 if not present.
363: */
364: pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
365: break;
366:
367: case ERRPTYPE:
368: /*
369: * doerrp - print the arguments to stderr
370: * file
371: */
372: if (argc > 2) {
373: for (n = 2; n < argc; n++)
374: fprintf(stderr, "%s ", argv[n]);
375: fprintf(stderr, "\n");
376: }
377: break;
378:
379: case DNLNTYPE:
380: /*
381: * dodnl - eat-up-to and including
382: * newline
383: */
384: while ((c = gpbc()) != '\n' && c != EOF)
385: ;
386: break;
387:
388: case M4WRTYPE:
389: /*
390: * dom4wrap - set up for
391: * wrap-up/wind-down activity
392: */
393: m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
394: break;
395:
396: case EXITTYPE:
397: /*
398: * doexit - immediate exit from m4.
399: */
400: killdiv();
401: exit((argc > 2) ? atoi(argv[2]) : 0);
402: break;
403:
404: case DEFNTYPE:
405: if (argc > 2)
406: for (n = 2; n < argc; n++)
407: dodefn(argv[n]);
408: break;
409:
1.25 espie 410: case INDIRTYPE: /* Indirect call */
411: if (argc > 2)
412: doindir(argv, argc);
413: break;
414:
415: case BUILTINTYPE: /* Builtins only */
416: if (argc > 2)
417: dobuiltin(argv, argc);
418: break;
419:
420: case PATSTYPE:
421: if (argc > 2)
422: dopatsubst(argv, argc);
423: break;
424: case REGEXPTYPE:
425: if (argc > 2)
426: doregexp(argv, argc);
427: break;
428: case LINETYPE:
429: doprintlineno(infile+ilevel);
430: break;
431: case FILENAMETYPE:
432: doprintfilename(infile+ilevel);
433: break;
1.23 espie 434: case SELFTYPE:
435: pbstr(rquote);
436: pbstr(argv[1]);
437: pbstr(lquote);
438: break;
1.1 deraadt 439: default:
1.24 espie 440: errx(1, "%s at line %lu: eval: major botch.",
441: CURRENT_NAME, CURRENT_LINE);
1.1 deraadt 442: break;
443: }
444: }
445:
446: char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
447:
448: /*
449: * expand - user-defined macro expansion
450: */
451: void
452: expand(argv, argc)
1.20 espie 453: const char *argv[];
1.17 espie 454: int argc;
1.1 deraadt 455: {
1.20 espie 456: const char *t;
457: const char *p;
1.17 espie 458: int n;
459: int argno;
1.1 deraadt 460:
461: t = argv[0]; /* defn string as a whole */
462: p = t;
463: while (*p)
464: p++;
465: p--; /* last character of defn */
466: while (p > t) {
467: if (*(p - 1) != ARGFLAG)
468: putback(*p);
469: else {
470: switch (*p) {
471:
472: case '#':
473: pbnum(argc - 2);
474: break;
475: case '0':
476: case '1':
477: case '2':
478: case '3':
479: case '4':
480: case '5':
481: case '6':
482: case '7':
483: case '8':
484: case '9':
485: if ((argno = *p - '0') < argc - 1)
486: pbstr(argv[argno + 1]);
487: break;
488: case '*':
489: for (n = argc - 1; n > 2; n--) {
490: pbstr(argv[n]);
1.7 millert 491: putback(COMMA);
1.1 deraadt 492: }
493: pbstr(argv[2]);
494: break;
1.7 millert 495: case '@':
496: for (n = argc - 1; n > 2; n--) {
497: pbstr(rquote);
498: pbstr(argv[n]);
499: pbstr(lquote);
500: putback(COMMA);
501: }
502: pbstr(rquote);
503: pbstr(argv[2]);
504: pbstr(lquote);
505: break;
1.1 deraadt 506: default:
507: putback(*p);
508: putback('$');
509: break;
510: }
511: p--;
512: }
513: p--;
514: }
515: if (p == t) /* do last character */
516: putback(*p);
517: }
518:
519: /*
520: * dodefine - install definition in the table
521: */
522: void
523: dodefine(name, defn)
1.20 espie 524: const char *name;
525: const char *defn;
1.1 deraadt 526: {
1.17 espie 527: ndptr p;
1.1 deraadt 528:
529: if (!*name)
1.24 espie 530: errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
531: CURRENT_LINE);
1.1 deraadt 532: if ((p = lookup(name)) == nil)
533: p = addent(name);
534: else if (p->defn != null)
535: free((char *) p->defn);
536: if (!*defn)
537: p->defn = null;
538: else
539: p->defn = xstrdup(defn);
540: p->type = MACRTYPE;
1.22 espie 541: if (STREQ(name, defn))
542: p->type |= RECDEF;
1.1 deraadt 543: }
544:
545: /*
546: * dodefn - push back a quoted definition of
547: * the given name.
548: */
1.20 espie 549: static void
1.1 deraadt 550: dodefn(name)
1.20 espie 551: const char *name;
1.1 deraadt 552: {
1.17 espie 553: ndptr p;
1.1 deraadt 554:
555: if ((p = lookup(name)) != nil && p->defn != null) {
1.10 deraadt 556: pbstr(rquote);
1.1 deraadt 557: pbstr(p->defn);
1.10 deraadt 558: pbstr(lquote);
1.1 deraadt 559: }
560: }
561:
562: /*
563: * dopushdef - install a definition in the hash table
564: * without removing a previous definition. Since
565: * each new entry is entered in *front* of the
566: * hash bucket, it hides a previous definition from
567: * lookup.
568: */
1.20 espie 569: static void
1.1 deraadt 570: dopushdef(name, defn)
1.20 espie 571: const char *name;
572: const char *defn;
1.1 deraadt 573: {
1.17 espie 574: ndptr p;
1.1 deraadt 575:
576: if (!*name)
1.24 espie 577: errx(1, "%s at line %lu: null definition", CURRENT_NAME,
578: CURRENT_LINE);
1.1 deraadt 579: p = addent(name);
580: if (!*defn)
581: p->defn = null;
582: else
583: p->defn = xstrdup(defn);
584: p->type = MACRTYPE;
1.22 espie 585: if (STREQ(name, defn))
586: p->type |= RECDEF;
1.1 deraadt 587: }
588:
589: /*
590: * dodumpdef - dump the specified definitions in the hash
591: * table to stderr. If nothing is specified, the entire
592: * hash table is dumped.
593: */
1.20 espie 594: static void
1.1 deraadt 595: dodump(argv, argc)
1.20 espie 596: const char *argv[];
1.17 espie 597: int argc;
1.1 deraadt 598: {
1.17 espie 599: int n;
1.1 deraadt 600: ndptr p;
601:
602: if (argc > 2) {
603: for (n = 2; n < argc; n++)
604: if ((p = lookup(argv[n])) != nil)
605: fprintf(stderr, dumpfmt, p->name,
606: p->defn);
1.8 deraadt 607: } else {
1.1 deraadt 608: for (n = 0; n < HASHSIZE; n++)
609: for (p = hashtab[n]; p != nil; p = p->nxtptr)
610: fprintf(stderr, dumpfmt, p->name,
611: p->defn);
612: }
613: }
614:
615: /*
616: * doifelse - select one of two alternatives - loop.
617: */
1.20 espie 618: static void
1.1 deraadt 619: doifelse(argv, argc)
1.20 espie 620: const char *argv[];
1.17 espie 621: int argc;
1.1 deraadt 622: {
623: cycle {
624: if (STREQ(argv[2], argv[3]))
625: pbstr(argv[4]);
626: else if (argc == 6)
627: pbstr(argv[5]);
628: else if (argc > 6) {
629: argv += 3;
630: argc -= 3;
631: continue;
632: }
633: break;
634: }
635: }
636:
637: /*
638: * doinclude - include a given file.
639: */
1.20 espie 640: static int
1.1 deraadt 641: doincl(ifile)
1.20 espie 642: const char *ifile;
1.1 deraadt 643: {
644: if (ilevel + 1 == MAXINP)
1.24 espie 645: errx(1, "%s at line %lu: too many include files.",
646: CURRENT_NAME, CURRENT_LINE);
647: if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
1.1 deraadt 648: ilevel++;
649: bbase[ilevel] = bufbase = bp;
650: return (1);
1.8 deraadt 651: } else
1.1 deraadt 652: return (0);
653: }
654:
655: #ifdef EXTENDED
656: /*
657: * dopaste - include a given file without any
658: * macro processing.
659: */
1.20 espie 660: static int
1.1 deraadt 661: dopaste(pfile)
1.20 espie 662: const char *pfile;
1.1 deraadt 663: {
664: FILE *pf;
1.17 espie 665: int c;
1.1 deraadt 666:
667: if ((pf = fopen(pfile, "r")) != NULL) {
668: while ((c = getc(pf)) != EOF)
669: putc(c, active);
670: (void) fclose(pf);
671: return (1);
1.8 deraadt 672: } else
1.1 deraadt 673: return (0);
674: }
675: #endif
676:
677: /*
678: * dochq - change quote characters
679: */
1.20 espie 680: static void
1.1 deraadt 681: dochq(argv, argc)
1.20 espie 682: const char *argv[];
1.17 espie 683: int argc;
1.1 deraadt 684: {
1.26 espie 685: /* In gnu-m4 mode, having two empty arguments means no quotes at
686: * all. */
687: if (mimic_gnu) {
688: if (argc > 3 && !*argv[2] && !*argv[3]) {
689: lquote[0] = EOS;
690: rquote[0] = EOS;
691: return;
692: }
693: }
1.1 deraadt 694: if (argc > 2) {
1.9 deraadt 695: if (*argv[2])
1.21 espie 696: strlcpy(lquote, argv[2], sizeof(lquote));
1.9 deraadt 697: else {
698: lquote[0] = LQUOTE;
1.14 espie 699: lquote[1] = EOS;
1.9 deraadt 700: }
1.1 deraadt 701: if (argc > 3) {
702: if (*argv[3])
1.21 espie 703: strlcpy(rquote, argv[3], sizeof(rquote));
1.8 deraadt 704: } else
1.2 deraadt 705: strcpy(rquote, lquote);
1.8 deraadt 706: } else {
1.14 espie 707: lquote[0] = LQUOTE, lquote[1] = EOS;
708: rquote[0] = RQUOTE, rquote[1] = EOS;
1.1 deraadt 709: }
710: }
711:
712: /*
713: * dochc - change comment characters
714: */
1.20 espie 715: static void
1.1 deraadt 716: dochc(argv, argc)
1.20 espie 717: const char *argv[];
1.17 espie 718: int argc;
1.1 deraadt 719: {
720: if (argc > 2) {
721: if (*argv[2])
1.21 espie 722: strlcpy(scommt, argv[2], sizeof(scommt));
1.1 deraadt 723: if (argc > 3) {
724: if (*argv[3])
1.21 espie 725: strlcpy(ecommt, argv[3], sizeof(ecommt));
1.1 deraadt 726: }
727: else
1.14 espie 728: ecommt[0] = ECOMMT, ecommt[1] = EOS;
1.1 deraadt 729: }
730: else {
1.14 espie 731: scommt[0] = SCOMMT, scommt[1] = EOS;
732: ecommt[0] = ECOMMT, ecommt[1] = EOS;
1.1 deraadt 733: }
734: }
735:
736: /*
737: * dodivert - divert the output to a temporary file
738: */
1.20 espie 739: static void
1.1 deraadt 740: dodiv(n)
1.17 espie 741: int n;
1.1 deraadt 742: {
1.6 millert 743: int fd;
744:
1.8 deraadt 745: oindex = n;
1.28 ! espie 746: if (n >= maxout) {
! 747: if (mimic_gnu)
! 748: resizedivs(n + 10);
! 749: else
! 750: n = 0; /* bitbucket */
! 751: }
! 752:
! 753: if (n < 0)
1.1 deraadt 754: n = 0; /* bitbucket */
755: if (outfile[n] == NULL) {
1.13 espie 756: char fname[] = _PATH_DIVNAME;
757:
758: if ((fd = mkstemp(fname)) < 0 ||
759: (outfile[n] = fdopen(fd, "w+")) == NULL)
760: err(1, "%s: cannot divert", fname);
761: if (unlink(fname) == -1)
762: err(1, "%s: cannot unlink", fname);
1.1 deraadt 763: }
764: active = outfile[n];
765: }
766:
767: /*
768: * doundivert - undivert a specified output, or all
769: * other outputs, in numerical order.
770: */
1.20 espie 771: static void
1.1 deraadt 772: doundiv(argv, argc)
1.20 espie 773: const char *argv[];
1.17 espie 774: int argc;
1.1 deraadt 775: {
1.17 espie 776: int ind;
777: int n;
1.1 deraadt 778:
779: if (argc > 2) {
780: for (ind = 2; ind < argc; ind++) {
781: n = atoi(argv[ind]);
1.28 ! espie 782: if (n > 0 && n < maxout && outfile[n] != NULL)
1.1 deraadt 783: getdiv(n);
784:
785: }
786: }
787: else
1.28 ! espie 788: for (n = 1; n < maxout; n++)
1.1 deraadt 789: if (outfile[n] != NULL)
790: getdiv(n);
791: }
792:
793: /*
794: * dosub - select substring
795: */
1.20 espie 796: static void
1.1 deraadt 797: dosub(argv, argc)
1.20 espie 798: const char *argv[];
1.17 espie 799: int argc;
1.1 deraadt 800: {
1.20 espie 801: const char *ap, *fc, *k;
1.17 espie 802: int nc;
1.1 deraadt 803:
804: if (argc < 5)
805: nc = MAXTOK;
806: else
807: #ifdef EXPR
808: nc = expr(argv[4]);
809: #else
810: nc = atoi(argv[4]);
811: #endif
812: ap = argv[2]; /* target string */
813: #ifdef EXPR
814: fc = ap + expr(argv[3]); /* first char */
815: #else
816: fc = ap + atoi(argv[3]); /* first char */
817: #endif
818: if (fc >= ap && fc < ap + strlen(ap))
819: for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
820: putback(*k);
821: }
822:
823: /*
824: * map:
825: * map every character of s1 that is specified in from
826: * into s3 and replace in s. (source s1 remains untouched)
827: *
828: * This is a standard implementation of map(s,from,to) function of ICON
829: * language. Within mapvec, we replace every character of "from" with
830: * the corresponding character in "to". If "to" is shorter than "from",
831: * than the corresponding entries are null, which means that those
832: * characters dissapear altogether. Furthermore, imagine
833: * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
834: * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
835: * ultimately maps to `*'. In order to achieve this effect in an efficient
836: * manner (i.e. without multiple passes over the destination string), we
837: * loop over mapvec, starting with the initial source character. if the
838: * character value (dch) in this location is different than the source
839: * character (sch), sch becomes dch, once again to index into mapvec, until
840: * the character value stabilizes (i.e. sch = dch, in other words
841: * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
842: * character, it will stabilize, since mapvec[0] == 0 at all times. At the
843: * end, we restore mapvec* back to normal where mapvec[n] == n for
844: * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
845: * about 5 times faster than any algorithm that makes multiple passes over
846: * destination string.
847: */
1.20 espie 848: static void
1.1 deraadt 849: map(dest, src, from, to)
1.17 espie 850: char *dest;
1.20 espie 851: const char *src;
852: const char *from;
853: const char *to;
1.1 deraadt 854: {
1.20 espie 855: const char *tmp;
1.19 espie 856: unsigned char sch, dch;
1.26 espie 857: static char frombis[257];
858: static char tobis[257];
1.19 espie 859: static unsigned char mapvec[256] = {
860: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
861: 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
862: 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
863: 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
864: 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
865: 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
866: 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
867: 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
868: 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
869: 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
870: 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
871: 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
872: 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
873: 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
874: 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
875: 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
876: 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
877: 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
1.1 deraadt 878: };
879:
880: if (*src) {
1.26 espie 881: if (mimic_gnu) {
882: /*
883: * expand character ranges on the fly
884: */
885: from = handledash(frombis, frombis + 256, from);
886: to = handledash(tobis, tobis + 256, to);
887: }
1.1 deraadt 888: tmp = from;
889: /*
890: * create a mapping between "from" and
891: * "to"
892: */
893: while (*from)
1.19 espie 894: mapvec[(unsigned char)(*from++)] = (*to) ?
895: (unsigned char)(*to++) : 0;
1.1 deraadt 896:
897: while (*src) {
1.19 espie 898: sch = (unsigned char)(*src++);
1.1 deraadt 899: dch = mapvec[sch];
900: while (dch != sch) {
901: sch = dch;
902: dch = mapvec[sch];
903: }
1.19 espie 904: if ((*dest = (char)dch))
1.1 deraadt 905: dest++;
906: }
907: /*
908: * restore all the changed characters
909: */
910: while (*tmp) {
1.19 espie 911: mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1.1 deraadt 912: tmp++;
913: }
914: }
1.19 espie 915: *dest = '\0';
1.1 deraadt 916: }
1.26 espie 917:
918:
919: /*
920: * handledash:
921: * use buffer to copy the src string, expanding character ranges
922: * on the way.
923: */
924: static const char *
925: handledash(buffer, end, src)
926: char *buffer;
927: char *end;
928: const char *src;
929: {
930: char *p;
931:
932: p = buffer;
933: while(*src) {
934: if (src[1] == '-' && src[2]) {
935: unsigned char i;
936: for (i = (unsigned char)src[0];
937: i <= (unsigned char)src[2]; i++) {
938: *p++ = i;
939: if (p == end) {
940: *p = '\0';
941: return buffer;
942: }
943: }
944: src += 3;
945: } else
946: *p++ = *src++;
947: if (p == end)
948: break;
949: }
950: *p = '\0';
951: return buffer;
952: }
953: