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