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