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