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