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