]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/m4/eval.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / usr.bin / m4 / eval.c
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
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         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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 }