12e8d1edaSArun Thomas /* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */
2*0a6a1f1dSLionel Sambuc /* $NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $ */
32e8d1edaSArun Thomas
42e8d1edaSArun Thomas /*
52e8d1edaSArun Thomas * Copyright (c) 1989, 1993
62e8d1edaSArun Thomas * The Regents of the University of California. All rights reserved.
72e8d1edaSArun Thomas *
82e8d1edaSArun Thomas * This code is derived from software contributed to Berkeley by
92e8d1edaSArun Thomas * Ozan Yigit at York University.
102e8d1edaSArun Thomas *
112e8d1edaSArun Thomas * Redistribution and use in source and binary forms, with or without
122e8d1edaSArun Thomas * modification, are permitted provided that the following conditions
132e8d1edaSArun Thomas * are met:
142e8d1edaSArun Thomas * 1. Redistributions of source code must retain the above copyright
152e8d1edaSArun Thomas * notice, this list of conditions and the following disclaimer.
162e8d1edaSArun Thomas * 2. Redistributions in binary form must reproduce the above copyright
172e8d1edaSArun Thomas * notice, this list of conditions and the following disclaimer in the
182e8d1edaSArun Thomas * documentation and/or other materials provided with the distribution.
192e8d1edaSArun Thomas * 3. Neither the name of the University nor the names of its contributors
202e8d1edaSArun Thomas * may be used to endorse or promote products derived from this software
212e8d1edaSArun Thomas * without specific prior written permission.
222e8d1edaSArun Thomas *
232e8d1edaSArun Thomas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
242e8d1edaSArun Thomas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
252e8d1edaSArun Thomas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
262e8d1edaSArun Thomas * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
272e8d1edaSArun Thomas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
282e8d1edaSArun Thomas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
292e8d1edaSArun Thomas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
302e8d1edaSArun Thomas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
312e8d1edaSArun Thomas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
322e8d1edaSArun Thomas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
332e8d1edaSArun Thomas * SUCH DAMAGE.
342e8d1edaSArun Thomas */
352e8d1edaSArun Thomas
362e8d1edaSArun Thomas /*
372e8d1edaSArun Thomas * eval.c
382e8d1edaSArun Thomas * Facility: m4 macro processor
392e8d1edaSArun Thomas * by: oz
402e8d1edaSArun Thomas */
412e8d1edaSArun Thomas #if HAVE_NBTOOL_CONFIG_H
422e8d1edaSArun Thomas #include "nbtool_config.h"
432e8d1edaSArun Thomas #endif
442e8d1edaSArun Thomas #include <sys/cdefs.h>
45*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $");
462e8d1edaSArun Thomas
472e8d1edaSArun Thomas #include <sys/types.h>
482e8d1edaSArun Thomas #include <err.h>
492e8d1edaSArun Thomas #include <errno.h>
502e8d1edaSArun Thomas #include <limits.h>
512e8d1edaSArun Thomas #include <unistd.h>
522e8d1edaSArun Thomas #include <stdio.h>
532e8d1edaSArun Thomas #include <stdlib.h>
542e8d1edaSArun Thomas #include <stddef.h>
5571c7dcb9SLionel Sambuc #include <stdint.h>
562e8d1edaSArun Thomas #include <string.h>
57*0a6a1f1dSLionel Sambuc #include <inttypes.h>
582e8d1edaSArun Thomas #include <fcntl.h>
592e8d1edaSArun Thomas #include "mdef.h"
602e8d1edaSArun Thomas #include "stdd.h"
612e8d1edaSArun Thomas #include "extern.h"
622e8d1edaSArun Thomas #include "pathnames.h"
632e8d1edaSArun Thomas
642e8d1edaSArun Thomas static void dodefn(const char *);
652e8d1edaSArun Thomas static void dopushdef(const char *, const char *);
662e8d1edaSArun Thomas static void dodump(const char *[], int);
672e8d1edaSArun Thomas static void dotrace(const char *[], int, int);
682e8d1edaSArun Thomas static void doifelse(const char *[], int);
692e8d1edaSArun Thomas static int doincl(const char *);
702e8d1edaSArun Thomas static int dopaste(const char *);
712e8d1edaSArun Thomas static void dochq(const char *[], int);
722e8d1edaSArun Thomas static void dochc(const char *[], int);
732e8d1edaSArun Thomas static void dom4wrap(const char *);
742e8d1edaSArun Thomas static void dodiv(int);
752e8d1edaSArun Thomas static void doundiv(const char *[], int);
762e8d1edaSArun Thomas static void dosub(const char *[], int);
772e8d1edaSArun Thomas static void map(char *, const char *, const char *, const char *);
782e8d1edaSArun Thomas static const char *handledash(char *, char *, const char *);
792e8d1edaSArun Thomas static void expand_builtin(const char *[], int, int);
802e8d1edaSArun Thomas static void expand_macro(const char *[], int);
812e8d1edaSArun Thomas static void dump_one_def(const char *, struct macro_definition *);
822e8d1edaSArun Thomas
832e8d1edaSArun Thomas unsigned long expansion_id;
842e8d1edaSArun Thomas
852e8d1edaSArun Thomas /*
862e8d1edaSArun Thomas * eval - eval all macros and builtins calls
872e8d1edaSArun Thomas * argc - number of elements in argv.
882e8d1edaSArun Thomas * argv - element vector :
892e8d1edaSArun Thomas * argv[0] = definition of a user
902e8d1edaSArun Thomas * macro or NULL if built-in.
912e8d1edaSArun Thomas * argv[1] = name of the macro or
922e8d1edaSArun Thomas * built-in.
932e8d1edaSArun Thomas * argv[2] = parameters to user-defined
942e8d1edaSArun Thomas * . macro or built-in.
952e8d1edaSArun Thomas * .
962e8d1edaSArun Thomas *
972e8d1edaSArun Thomas * A call in the form of macro-or-builtin() will result in:
982e8d1edaSArun Thomas * argv[0] = nullstr
992e8d1edaSArun Thomas * argv[1] = macro-or-builtin
1002e8d1edaSArun Thomas * argv[2] = nullstr
1012e8d1edaSArun Thomas *
1022e8d1edaSArun Thomas * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1032e8d1edaSArun Thomas */
1042e8d1edaSArun Thomas void
eval(const char * argv[],int argc,int td,int is_traced)1052e8d1edaSArun Thomas eval(const char *argv[], int argc, int td, int is_traced)
1062e8d1edaSArun Thomas {
1072e8d1edaSArun Thomas size_t mark = SIZE_MAX;
1082e8d1edaSArun Thomas
1092e8d1edaSArun Thomas expansion_id++;
1102e8d1edaSArun Thomas if (td & RECDEF)
1112e8d1edaSArun Thomas m4errx(1, "expanding recursive definition for %s.", argv[1]);
1122e8d1edaSArun Thomas if (is_traced)
1132e8d1edaSArun Thomas mark = trace(argv, argc, infile+ilevel);
1142e8d1edaSArun Thomas if (td == MACRTYPE)
1152e8d1edaSArun Thomas expand_macro(argv, argc);
1162e8d1edaSArun Thomas else
1172e8d1edaSArun Thomas expand_builtin(argv, argc, td);
1182e8d1edaSArun Thomas if (mark != SIZE_MAX)
1192e8d1edaSArun Thomas finish_trace(mark);
1202e8d1edaSArun Thomas }
1212e8d1edaSArun Thomas
1222e8d1edaSArun Thomas /*
1232e8d1edaSArun Thomas * expand_builtin - evaluate built-in macros.
1242e8d1edaSArun Thomas */
1252e8d1edaSArun Thomas void
expand_builtin(const char * argv[],int argc,int td)1262e8d1edaSArun Thomas expand_builtin(const char *argv[], int argc, int td)
1272e8d1edaSArun Thomas {
1282e8d1edaSArun Thomas int c, n;
1292e8d1edaSArun Thomas int ac;
1302e8d1edaSArun Thomas static int sysval = 0;
1312e8d1edaSArun Thomas
1322e8d1edaSArun Thomas #ifdef DEBUG
1332e8d1edaSArun Thomas printf("argc = %d\n", argc);
1342e8d1edaSArun Thomas for (n = 0; n < argc; n++)
1352e8d1edaSArun Thomas printf("argv[%d] = %s\n", n, argv[n]);
1362e8d1edaSArun Thomas fflush(stdout);
1372e8d1edaSArun Thomas #endif
1382e8d1edaSArun Thomas
1392e8d1edaSArun Thomas /*
1402e8d1edaSArun Thomas * if argc == 3 and argv[2] is null, then we
1412e8d1edaSArun Thomas * have macro-or-builtin() type call. We adjust
1422e8d1edaSArun Thomas * argc to avoid further checking..
1432e8d1edaSArun Thomas */
1442e8d1edaSArun Thomas /* we keep the initial value for those built-ins that differentiate
1452e8d1edaSArun Thomas * between builtin() and builtin.
1462e8d1edaSArun Thomas */
1472e8d1edaSArun Thomas ac = argc;
1482e8d1edaSArun Thomas
1492e8d1edaSArun Thomas if (argc == 3 && !*(argv[2]) && !mimic_gnu)
1502e8d1edaSArun Thomas argc--;
1512e8d1edaSArun Thomas
1522e8d1edaSArun Thomas switch (td & TYPEMASK) {
1532e8d1edaSArun Thomas
1542e8d1edaSArun Thomas case DEFITYPE:
1552e8d1edaSArun Thomas if (argc > 2)
1562e8d1edaSArun Thomas dodefine(argv[2], (argc > 3) ? argv[3] : null);
1572e8d1edaSArun Thomas break;
1582e8d1edaSArun Thomas
1592e8d1edaSArun Thomas case PUSDTYPE:
1602e8d1edaSArun Thomas if (argc > 2)
1612e8d1edaSArun Thomas dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1622e8d1edaSArun Thomas break;
1632e8d1edaSArun Thomas
1642e8d1edaSArun Thomas case DUMPTYPE:
1652e8d1edaSArun Thomas dodump(argv, argc);
1662e8d1edaSArun Thomas break;
1672e8d1edaSArun Thomas
1682e8d1edaSArun Thomas case TRACEONTYPE:
1692e8d1edaSArun Thomas dotrace(argv, argc, 1);
1702e8d1edaSArun Thomas break;
1712e8d1edaSArun Thomas
1722e8d1edaSArun Thomas case TRACEOFFTYPE:
1732e8d1edaSArun Thomas dotrace(argv, argc, 0);
1742e8d1edaSArun Thomas break;
1752e8d1edaSArun Thomas
1762e8d1edaSArun Thomas case EXPRTYPE:
1772e8d1edaSArun Thomas /*
1782e8d1edaSArun Thomas * doexpr - evaluate arithmetic
1792e8d1edaSArun Thomas * expression
1802e8d1edaSArun Thomas */
1812e8d1edaSArun Thomas {
1822e8d1edaSArun Thomas int base = 10;
1832e8d1edaSArun Thomas int maxdigits = 0;
184*0a6a1f1dSLionel Sambuc int e;
1852e8d1edaSArun Thomas
1862e8d1edaSArun Thomas if (argc > 3) {
187*0a6a1f1dSLionel Sambuc base = strtoi(argv[3], NULL, 0, 2, 36, &e);
188*0a6a1f1dSLionel Sambuc if (e) {
1892e8d1edaSArun Thomas m4errx(1, "expr: base %s invalid.", argv[3]);
1902e8d1edaSArun Thomas }
1912e8d1edaSArun Thomas }
1922e8d1edaSArun Thomas if (argc > 4) {
193*0a6a1f1dSLionel Sambuc maxdigits = strtoi(argv[4], NULL, 0, 0, INT_MAX, &e);
194*0a6a1f1dSLionel Sambuc if (e) {
1952e8d1edaSArun Thomas m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
1962e8d1edaSArun Thomas }
1972e8d1edaSArun Thomas }
1982e8d1edaSArun Thomas if (argc > 2)
1992e8d1edaSArun Thomas pbnumbase(expr(argv[2]), base, maxdigits);
2002e8d1edaSArun Thomas break;
2012e8d1edaSArun Thomas }
2022e8d1edaSArun Thomas
2032e8d1edaSArun Thomas case IFELTYPE:
2042e8d1edaSArun Thomas if (argc > 4)
2052e8d1edaSArun Thomas doifelse(argv, argc);
2062e8d1edaSArun Thomas break;
2072e8d1edaSArun Thomas
2082e8d1edaSArun Thomas case IFDFTYPE:
2092e8d1edaSArun Thomas /*
2102e8d1edaSArun Thomas * doifdef - select one of two
2112e8d1edaSArun Thomas * alternatives based on the existence of
2122e8d1edaSArun Thomas * another definition
2132e8d1edaSArun Thomas */
2142e8d1edaSArun Thomas if (argc > 3) {
2152e8d1edaSArun Thomas if (lookup_macro_definition(argv[2]) != NULL)
2162e8d1edaSArun Thomas pbstr(argv[3]);
2172e8d1edaSArun Thomas else if (argc > 4)
2182e8d1edaSArun Thomas pbstr(argv[4]);
2192e8d1edaSArun Thomas }
2202e8d1edaSArun Thomas break;
2212e8d1edaSArun Thomas
2222e8d1edaSArun Thomas case LENGTYPE:
2232e8d1edaSArun Thomas /*
2242e8d1edaSArun Thomas * dolen - find the length of the
2252e8d1edaSArun Thomas * argument
2262e8d1edaSArun Thomas */
2272e8d1edaSArun Thomas pbnum((argc > 2) ? strlen(argv[2]) : 0);
2282e8d1edaSArun Thomas break;
2292e8d1edaSArun Thomas
2302e8d1edaSArun Thomas case INCRTYPE:
2312e8d1edaSArun Thomas /*
2322e8d1edaSArun Thomas * doincr - increment the value of the
2332e8d1edaSArun Thomas * argument
2342e8d1edaSArun Thomas */
2352e8d1edaSArun Thomas if (argc > 2)
2362e8d1edaSArun Thomas pbnum(atoi(argv[2]) + 1);
2372e8d1edaSArun Thomas break;
2382e8d1edaSArun Thomas
2392e8d1edaSArun Thomas case DECRTYPE:
2402e8d1edaSArun Thomas /*
2412e8d1edaSArun Thomas * dodecr - decrement the value of the
2422e8d1edaSArun Thomas * argument
2432e8d1edaSArun Thomas */
2442e8d1edaSArun Thomas if (argc > 2)
2452e8d1edaSArun Thomas pbnum(atoi(argv[2]) - 1);
2462e8d1edaSArun Thomas break;
2472e8d1edaSArun Thomas
2482e8d1edaSArun Thomas case SYSCTYPE:
2492e8d1edaSArun Thomas /*
2502e8d1edaSArun Thomas * dosys - execute system command
2512e8d1edaSArun Thomas */
2522e8d1edaSArun Thomas if (argc > 2) {
2532e8d1edaSArun Thomas fflush(stdout);
2542e8d1edaSArun Thomas sysval = system(argv[2]);
2552e8d1edaSArun Thomas }
2562e8d1edaSArun Thomas break;
2572e8d1edaSArun Thomas
2582e8d1edaSArun Thomas case SYSVTYPE:
2592e8d1edaSArun Thomas /*
2602e8d1edaSArun Thomas * dosysval - return value of the last
2612e8d1edaSArun Thomas * system call.
2622e8d1edaSArun Thomas *
2632e8d1edaSArun Thomas */
2642e8d1edaSArun Thomas pbnum(sysval);
2652e8d1edaSArun Thomas break;
2662e8d1edaSArun Thomas
2672e8d1edaSArun Thomas case ESYSCMDTYPE:
2682e8d1edaSArun Thomas if (argc > 2)
2692e8d1edaSArun Thomas doesyscmd(argv[2]);
2702e8d1edaSArun Thomas break;
2712e8d1edaSArun Thomas case INCLTYPE:
2722e8d1edaSArun Thomas if (argc > 2)
2732e8d1edaSArun Thomas if (!doincl(argv[2]))
2742e8d1edaSArun Thomas err(1, "%s at line %lu: include(%s)",
2752e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]);
2762e8d1edaSArun Thomas break;
2772e8d1edaSArun Thomas
2782e8d1edaSArun Thomas case SINCTYPE:
2792e8d1edaSArun Thomas if (argc > 2)
2802e8d1edaSArun Thomas (void) doincl(argv[2]);
2812e8d1edaSArun Thomas break;
2822e8d1edaSArun Thomas #ifdef EXTENDED
2832e8d1edaSArun Thomas case PASTTYPE:
2842e8d1edaSArun Thomas if (argc > 2)
2852e8d1edaSArun Thomas if (!dopaste(argv[2]))
2862e8d1edaSArun Thomas err(1, "%s at line %lu: paste(%s)",
2872e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]);
2882e8d1edaSArun Thomas break;
2892e8d1edaSArun Thomas
2902e8d1edaSArun Thomas case SPASTYPE:
2912e8d1edaSArun Thomas if (argc > 2)
2922e8d1edaSArun Thomas (void) dopaste(argv[2]);
2932e8d1edaSArun Thomas break;
2942e8d1edaSArun Thomas case FORMATTYPE:
2952e8d1edaSArun Thomas doformat(argv, argc);
2962e8d1edaSArun Thomas break;
2972e8d1edaSArun Thomas #endif
2982e8d1edaSArun Thomas case CHNQTYPE:
2992e8d1edaSArun Thomas dochq(argv, ac);
3002e8d1edaSArun Thomas break;
3012e8d1edaSArun Thomas
3022e8d1edaSArun Thomas case CHNCTYPE:
3032e8d1edaSArun Thomas dochc(argv, argc);
3042e8d1edaSArun Thomas break;
3052e8d1edaSArun Thomas
3062e8d1edaSArun Thomas case SUBSTYPE:
3072e8d1edaSArun Thomas /*
3082e8d1edaSArun Thomas * dosub - select substring
3092e8d1edaSArun Thomas *
3102e8d1edaSArun Thomas */
3112e8d1edaSArun Thomas if (argc > 3)
3122e8d1edaSArun Thomas dosub(argv, argc);
3132e8d1edaSArun Thomas break;
3142e8d1edaSArun Thomas
3152e8d1edaSArun Thomas case SHIFTYPE:
3162e8d1edaSArun Thomas /*
3172e8d1edaSArun Thomas * doshift - push back all arguments
3182e8d1edaSArun Thomas * except the first one (i.e. skip
3192e8d1edaSArun Thomas * argv[2])
3202e8d1edaSArun Thomas */
3212e8d1edaSArun Thomas if (argc > 3) {
3222e8d1edaSArun Thomas for (n = argc - 1; n > 3; n--) {
3232e8d1edaSArun Thomas pbstr(rquote);
3242e8d1edaSArun Thomas pbstr(argv[n]);
3252e8d1edaSArun Thomas pbstr(lquote);
3262e8d1edaSArun Thomas pushback(COMMA);
3272e8d1edaSArun Thomas }
3282e8d1edaSArun Thomas pbstr(rquote);
3292e8d1edaSArun Thomas pbstr(argv[3]);
3302e8d1edaSArun Thomas pbstr(lquote);
3312e8d1edaSArun Thomas }
3322e8d1edaSArun Thomas break;
3332e8d1edaSArun Thomas
3342e8d1edaSArun Thomas case DIVRTYPE:
3352e8d1edaSArun Thomas if (argc > 2 && (n = atoi(argv[2])) != 0)
3362e8d1edaSArun Thomas dodiv(n);
3372e8d1edaSArun Thomas else {
3382e8d1edaSArun Thomas active = stdout;
3392e8d1edaSArun Thomas oindex = 0;
3402e8d1edaSArun Thomas }
3412e8d1edaSArun Thomas break;
3422e8d1edaSArun Thomas
3432e8d1edaSArun Thomas case UNDVTYPE:
3442e8d1edaSArun Thomas doundiv(argv, argc);
3452e8d1edaSArun Thomas break;
3462e8d1edaSArun Thomas
3472e8d1edaSArun Thomas case DIVNTYPE:
3482e8d1edaSArun Thomas /*
3492e8d1edaSArun Thomas * dodivnum - return the number of
3502e8d1edaSArun Thomas * current output diversion
3512e8d1edaSArun Thomas */
3522e8d1edaSArun Thomas pbnum(oindex);
3532e8d1edaSArun Thomas break;
3542e8d1edaSArun Thomas
3552e8d1edaSArun Thomas case UNDFTYPE:
3562e8d1edaSArun Thomas /*
3572e8d1edaSArun Thomas * doundefine - undefine a previously
3582e8d1edaSArun Thomas * defined macro(s) or m4 keyword(s).
3592e8d1edaSArun Thomas */
3602e8d1edaSArun Thomas if (argc > 2)
3612e8d1edaSArun Thomas for (n = 2; n < argc; n++)
3622e8d1edaSArun Thomas macro_undefine(argv[n]);
3632e8d1edaSArun Thomas break;
3642e8d1edaSArun Thomas
3652e8d1edaSArun Thomas case POPDTYPE:
3662e8d1edaSArun Thomas /*
3672e8d1edaSArun Thomas * dopopdef - remove the topmost
3682e8d1edaSArun Thomas * definitions of macro(s) or m4
3692e8d1edaSArun Thomas * keyword(s).
3702e8d1edaSArun Thomas */
3712e8d1edaSArun Thomas if (argc > 2)
3722e8d1edaSArun Thomas for (n = 2; n < argc; n++)
3732e8d1edaSArun Thomas macro_popdef(argv[n]);
3742e8d1edaSArun Thomas break;
3752e8d1edaSArun Thomas
3762e8d1edaSArun Thomas case MKTMTYPE:
3772e8d1edaSArun Thomas /*
3782e8d1edaSArun Thomas * dotemp - create a temporary file
3792e8d1edaSArun Thomas */
3802e8d1edaSArun Thomas if (argc > 2) {
3812e8d1edaSArun Thomas int fd;
3822e8d1edaSArun Thomas char *temp;
3832e8d1edaSArun Thomas
3842e8d1edaSArun Thomas temp = xstrdup(argv[2]);
3852e8d1edaSArun Thomas
3862e8d1edaSArun Thomas fd = mkstemp(temp);
3872e8d1edaSArun Thomas if (fd == -1)
3882e8d1edaSArun Thomas err(1,
3892e8d1edaSArun Thomas "%s at line %lu: couldn't make temp file %s",
3902e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]);
3912e8d1edaSArun Thomas close(fd);
3922e8d1edaSArun Thomas pbstr(temp);
3932e8d1edaSArun Thomas free(temp);
3942e8d1edaSArun Thomas }
3952e8d1edaSArun Thomas break;
3962e8d1edaSArun Thomas
3972e8d1edaSArun Thomas case TRNLTYPE:
3982e8d1edaSArun Thomas /*
3992e8d1edaSArun Thomas * dotranslit - replace all characters in
4002e8d1edaSArun Thomas * the source string that appears in the
4012e8d1edaSArun Thomas * "from" string with the corresponding
4022e8d1edaSArun Thomas * characters in the "to" string.
4032e8d1edaSArun Thomas */
4042e8d1edaSArun Thomas if (argc > 3) {
4052e8d1edaSArun Thomas char *temp;
4062e8d1edaSArun Thomas
4072e8d1edaSArun Thomas temp = xalloc(strlen(argv[2])+1, NULL);
4082e8d1edaSArun Thomas if (argc > 4)
4092e8d1edaSArun Thomas map(temp, argv[2], argv[3], argv[4]);
4102e8d1edaSArun Thomas else
4112e8d1edaSArun Thomas map(temp, argv[2], argv[3], null);
4122e8d1edaSArun Thomas pbstr(temp);
4132e8d1edaSArun Thomas free(temp);
4142e8d1edaSArun Thomas } else if (argc > 2)
4152e8d1edaSArun Thomas pbstr(argv[2]);
4162e8d1edaSArun Thomas break;
4172e8d1edaSArun Thomas
4182e8d1edaSArun Thomas case INDXTYPE:
4192e8d1edaSArun Thomas /*
4202e8d1edaSArun Thomas * doindex - find the index of the second
4212e8d1edaSArun Thomas * argument string in the first argument
4222e8d1edaSArun Thomas * string. -1 if not present.
4232e8d1edaSArun Thomas */
4242e8d1edaSArun Thomas pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4252e8d1edaSArun Thomas break;
4262e8d1edaSArun Thomas
4272e8d1edaSArun Thomas case ERRPTYPE:
4282e8d1edaSArun Thomas /*
4292e8d1edaSArun Thomas * doerrp - print the arguments to stderr
4302e8d1edaSArun Thomas * file
4312e8d1edaSArun Thomas */
4322e8d1edaSArun Thomas if (argc > 2) {
4332e8d1edaSArun Thomas for (n = 2; n < argc; n++)
43471c7dcb9SLionel Sambuc fprintf(stderr, "%s%s",
43571c7dcb9SLionel Sambuc mimic_gnu && n == 2 ? "" : " ",
43671c7dcb9SLionel Sambuc argv[n]);
43771c7dcb9SLionel Sambuc if (!mimic_gnu)
4382e8d1edaSArun Thomas fprintf(stderr, "\n");
4392e8d1edaSArun Thomas }
4402e8d1edaSArun Thomas break;
4412e8d1edaSArun Thomas
4422e8d1edaSArun Thomas case DNLNTYPE:
4432e8d1edaSArun Thomas /*
4442e8d1edaSArun Thomas * dodnl - eat-up-to and including
4452e8d1edaSArun Thomas * newline
4462e8d1edaSArun Thomas */
4472e8d1edaSArun Thomas while ((c = gpbc()) != '\n' && c != EOF)
4482e8d1edaSArun Thomas ;
4492e8d1edaSArun Thomas break;
4502e8d1edaSArun Thomas
4512e8d1edaSArun Thomas case M4WRTYPE:
4522e8d1edaSArun Thomas /*
4532e8d1edaSArun Thomas * dom4wrap - set up for
4542e8d1edaSArun Thomas * wrap-up/wind-down activity
4552e8d1edaSArun Thomas */
4562e8d1edaSArun Thomas if (argc > 2)
4572e8d1edaSArun Thomas dom4wrap(argv[2]);
4582e8d1edaSArun Thomas break;
4592e8d1edaSArun Thomas
4602e8d1edaSArun Thomas case EXITTYPE:
4612e8d1edaSArun Thomas /*
4622e8d1edaSArun Thomas * doexit - immediate exit from m4.
4632e8d1edaSArun Thomas */
4642e8d1edaSArun Thomas killdiv();
4652e8d1edaSArun Thomas exit((argc > 2) ? atoi(argv[2]) : 0);
4662e8d1edaSArun Thomas break;
4672e8d1edaSArun Thomas
4682e8d1edaSArun Thomas case DEFNTYPE:
4692e8d1edaSArun Thomas if (argc > 2)
4702e8d1edaSArun Thomas for (n = 2; n < argc; n++)
4712e8d1edaSArun Thomas dodefn(argv[n]);
4722e8d1edaSArun Thomas break;
4732e8d1edaSArun Thomas
4742e8d1edaSArun Thomas case INDIRTYPE: /* Indirect call */
4752e8d1edaSArun Thomas if (argc > 2)
4762e8d1edaSArun Thomas doindir(argv, argc);
4772e8d1edaSArun Thomas break;
4782e8d1edaSArun Thomas
4792e8d1edaSArun Thomas case BUILTINTYPE: /* Builtins only */
4802e8d1edaSArun Thomas if (argc > 2)
4812e8d1edaSArun Thomas dobuiltin(argv, argc);
4822e8d1edaSArun Thomas break;
4832e8d1edaSArun Thomas
4842e8d1edaSArun Thomas case PATSTYPE:
4852e8d1edaSArun Thomas if (argc > 2)
4862e8d1edaSArun Thomas dopatsubst(argv, argc);
4872e8d1edaSArun Thomas break;
4882e8d1edaSArun Thomas case REGEXPTYPE:
4892e8d1edaSArun Thomas if (argc > 2)
4902e8d1edaSArun Thomas doregexp(argv, argc);
4912e8d1edaSArun Thomas break;
4922e8d1edaSArun Thomas case LINETYPE:
4932e8d1edaSArun Thomas doprintlineno(infile+ilevel);
4942e8d1edaSArun Thomas break;
4952e8d1edaSArun Thomas case FILENAMETYPE:
4962e8d1edaSArun Thomas doprintfilename(infile+ilevel);
4972e8d1edaSArun Thomas break;
4982e8d1edaSArun Thomas case SELFTYPE:
4992e8d1edaSArun Thomas pbstr(rquote);
5002e8d1edaSArun Thomas pbstr(argv[1]);
5012e8d1edaSArun Thomas pbstr(lquote);
5022e8d1edaSArun Thomas break;
5032e8d1edaSArun Thomas default:
5042e8d1edaSArun Thomas m4errx(1, "eval: major botch.");
5052e8d1edaSArun Thomas break;
5062e8d1edaSArun Thomas }
5072e8d1edaSArun Thomas }
5082e8d1edaSArun Thomas
5092e8d1edaSArun Thomas /*
5102e8d1edaSArun Thomas * expand_macro - user-defined macro expansion
5112e8d1edaSArun Thomas */
5122e8d1edaSArun Thomas void
expand_macro(const char * argv[],int argc)5132e8d1edaSArun Thomas expand_macro(const char *argv[], int argc)
5142e8d1edaSArun Thomas {
5152e8d1edaSArun Thomas const char *t;
5162e8d1edaSArun Thomas const char *p;
5172e8d1edaSArun Thomas int n;
5182e8d1edaSArun Thomas int argno;
5192e8d1edaSArun Thomas
5202e8d1edaSArun Thomas t = argv[0]; /* defn string as a whole */
5212e8d1edaSArun Thomas p = t;
5222e8d1edaSArun Thomas while (*p)
5232e8d1edaSArun Thomas p++;
5242e8d1edaSArun Thomas p--; /* last character of defn */
5252e8d1edaSArun Thomas while (p > t) {
5262e8d1edaSArun Thomas if (*(p - 1) != ARGFLAG)
5272e8d1edaSArun Thomas PUSHBACK(*p);
5282e8d1edaSArun Thomas else {
5292e8d1edaSArun Thomas switch (*p) {
5302e8d1edaSArun Thomas
5312e8d1edaSArun Thomas case '#':
5322e8d1edaSArun Thomas pbnum(argc - 2);
5332e8d1edaSArun Thomas break;
5342e8d1edaSArun Thomas case '0':
5352e8d1edaSArun Thomas case '1':
5362e8d1edaSArun Thomas case '2':
5372e8d1edaSArun Thomas case '3':
5382e8d1edaSArun Thomas case '4':
5392e8d1edaSArun Thomas case '5':
5402e8d1edaSArun Thomas case '6':
5412e8d1edaSArun Thomas case '7':
5422e8d1edaSArun Thomas case '8':
5432e8d1edaSArun Thomas case '9':
5442e8d1edaSArun Thomas if ((argno = *p - '0') < argc - 1)
5452e8d1edaSArun Thomas pbstr(argv[argno + 1]);
5462e8d1edaSArun Thomas break;
5472e8d1edaSArun Thomas case '*':
5482e8d1edaSArun Thomas if (argc > 2) {
5492e8d1edaSArun Thomas for (n = argc - 1; n > 2; n--) {
5502e8d1edaSArun Thomas pbstr(argv[n]);
5512e8d1edaSArun Thomas pushback(COMMA);
5522e8d1edaSArun Thomas }
5532e8d1edaSArun Thomas pbstr(argv[2]);
5542e8d1edaSArun Thomas }
5552e8d1edaSArun Thomas break;
5562e8d1edaSArun Thomas case '@':
5572e8d1edaSArun Thomas if (argc > 2) {
5582e8d1edaSArun Thomas for (n = argc - 1; n > 2; n--) {
5592e8d1edaSArun Thomas pbstr(rquote);
5602e8d1edaSArun Thomas pbstr(argv[n]);
5612e8d1edaSArun Thomas pbstr(lquote);
5622e8d1edaSArun Thomas pushback(COMMA);
5632e8d1edaSArun Thomas }
5642e8d1edaSArun Thomas pbstr(rquote);
5652e8d1edaSArun Thomas pbstr(argv[2]);
5662e8d1edaSArun Thomas pbstr(lquote);
5672e8d1edaSArun Thomas }
5682e8d1edaSArun Thomas break;
5692e8d1edaSArun Thomas default:
5702e8d1edaSArun Thomas PUSHBACK(*p);
5712e8d1edaSArun Thomas PUSHBACK('$');
5722e8d1edaSArun Thomas break;
5732e8d1edaSArun Thomas }
5742e8d1edaSArun Thomas p--;
5752e8d1edaSArun Thomas }
5762e8d1edaSArun Thomas p--;
5772e8d1edaSArun Thomas }
5782e8d1edaSArun Thomas if (p == t) /* do last character */
5792e8d1edaSArun Thomas PUSHBACK(*p);
5802e8d1edaSArun Thomas }
5812e8d1edaSArun Thomas
5822e8d1edaSArun Thomas
5832e8d1edaSArun Thomas /*
5842e8d1edaSArun Thomas * dodefine - install definition in the table
5852e8d1edaSArun Thomas */
5862e8d1edaSArun Thomas void
dodefine(const char * name,const char * defn)5872e8d1edaSArun Thomas dodefine(const char *name, const char *defn)
5882e8d1edaSArun Thomas {
5892e8d1edaSArun Thomas if (!*name && !mimic_gnu)
5902e8d1edaSArun Thomas m4errx(1, "null definition.");
5912e8d1edaSArun Thomas else
5922e8d1edaSArun Thomas macro_define(name, defn);
5932e8d1edaSArun Thomas }
5942e8d1edaSArun Thomas
5952e8d1edaSArun Thomas /*
5962e8d1edaSArun Thomas * dodefn - push back a quoted definition of
5972e8d1edaSArun Thomas * the given name.
5982e8d1edaSArun Thomas */
5992e8d1edaSArun Thomas static void
dodefn(const char * name)6002e8d1edaSArun Thomas dodefn(const char *name)
6012e8d1edaSArun Thomas {
6022e8d1edaSArun Thomas struct macro_definition *p;
6032e8d1edaSArun Thomas
6042e8d1edaSArun Thomas if ((p = lookup_macro_definition(name)) != NULL) {
6052e8d1edaSArun Thomas if ((p->type & TYPEMASK) == MACRTYPE) {
6062e8d1edaSArun Thomas pbstr(rquote);
6072e8d1edaSArun Thomas pbstr(p->defn);
6082e8d1edaSArun Thomas pbstr(lquote);
6092e8d1edaSArun Thomas } else {
6102e8d1edaSArun Thomas pbstr(p->defn);
6112e8d1edaSArun Thomas pbstr(BUILTIN_MARKER);
6122e8d1edaSArun Thomas }
6132e8d1edaSArun Thomas }
6142e8d1edaSArun Thomas }
6152e8d1edaSArun Thomas
6162e8d1edaSArun Thomas /*
6172e8d1edaSArun Thomas * dopushdef - install a definition in the hash table
6182e8d1edaSArun Thomas * without removing a previous definition. Since
6192e8d1edaSArun Thomas * each new entry is entered in *front* of the
6202e8d1edaSArun Thomas * hash bucket, it hides a previous definition from
6212e8d1edaSArun Thomas * lookup.
6222e8d1edaSArun Thomas */
6232e8d1edaSArun Thomas static void
dopushdef(const char * name,const char * defn)6242e8d1edaSArun Thomas dopushdef(const char *name, const char *defn)
6252e8d1edaSArun Thomas {
6262e8d1edaSArun Thomas if (!*name && !mimic_gnu)
6272e8d1edaSArun Thomas m4errx(1, "null definition.");
6282e8d1edaSArun Thomas else
6292e8d1edaSArun Thomas macro_pushdef(name, defn);
6302e8d1edaSArun Thomas }
6312e8d1edaSArun Thomas
6322e8d1edaSArun Thomas /*
6332e8d1edaSArun Thomas * dump_one_def - dump the specified definition.
6342e8d1edaSArun Thomas */
6352e8d1edaSArun Thomas static void
dump_one_def(const char * name,struct macro_definition * p)6362e8d1edaSArun Thomas dump_one_def(const char *name, struct macro_definition *p)
6372e8d1edaSArun Thomas {
6382e8d1edaSArun Thomas if (!traceout)
6392e8d1edaSArun Thomas traceout = stderr;
6402e8d1edaSArun Thomas if (mimic_gnu) {
6412e8d1edaSArun Thomas if ((p->type & TYPEMASK) == MACRTYPE)
6422e8d1edaSArun Thomas fprintf(traceout, "%s:\t%s\n", name, p->defn);
6432e8d1edaSArun Thomas else {
6442e8d1edaSArun Thomas fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
6452e8d1edaSArun Thomas }
6462e8d1edaSArun Thomas } else
6472e8d1edaSArun Thomas fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
6482e8d1edaSArun Thomas }
6492e8d1edaSArun Thomas
6502e8d1edaSArun Thomas /*
6512e8d1edaSArun Thomas * dodumpdef - dump the specified definitions in the hash
6522e8d1edaSArun Thomas * table to stderr. If nothing is specified, the entire
6532e8d1edaSArun Thomas * hash table is dumped.
6542e8d1edaSArun Thomas */
6552e8d1edaSArun Thomas static void
dodump(const char * argv[],int argc)6562e8d1edaSArun Thomas dodump(const char *argv[], int argc)
6572e8d1edaSArun Thomas {
6582e8d1edaSArun Thomas int n;
6592e8d1edaSArun Thomas struct macro_definition *p;
6602e8d1edaSArun Thomas
6612e8d1edaSArun Thomas if (argc > 2) {
6622e8d1edaSArun Thomas for (n = 2; n < argc; n++)
6632e8d1edaSArun Thomas if ((p = lookup_macro_definition(argv[n])) != NULL)
6642e8d1edaSArun Thomas dump_one_def(argv[n], p);
6652e8d1edaSArun Thomas } else
6662e8d1edaSArun Thomas macro_for_all(dump_one_def);
6672e8d1edaSArun Thomas }
6682e8d1edaSArun Thomas
6692e8d1edaSArun Thomas /*
6702e8d1edaSArun Thomas * dotrace - mark some macros as traced/untraced depending upon on.
6712e8d1edaSArun Thomas */
6722e8d1edaSArun Thomas static void
dotrace(const char * argv[],int argc,int on)6732e8d1edaSArun Thomas dotrace(const char *argv[], int argc, int on)
6742e8d1edaSArun Thomas {
6752e8d1edaSArun Thomas int n;
6762e8d1edaSArun Thomas
6772e8d1edaSArun Thomas if (argc > 2) {
6782e8d1edaSArun Thomas for (n = 2; n < argc; n++)
6792e8d1edaSArun Thomas mark_traced(argv[n], on);
6802e8d1edaSArun Thomas } else
6812e8d1edaSArun Thomas mark_traced(NULL, on);
6822e8d1edaSArun Thomas }
6832e8d1edaSArun Thomas
6842e8d1edaSArun Thomas /*
6852e8d1edaSArun Thomas * doifelse - select one of two alternatives - loop.
6862e8d1edaSArun Thomas */
6872e8d1edaSArun Thomas static void
doifelse(const char * argv[],int argc)6882e8d1edaSArun Thomas doifelse(const char *argv[], int argc)
6892e8d1edaSArun Thomas {
6902e8d1edaSArun Thomas cycle {
6912e8d1edaSArun Thomas if (STREQ(argv[2], argv[3]))
6922e8d1edaSArun Thomas pbstr(argv[4]);
6932e8d1edaSArun Thomas else if (argc == 6)
6942e8d1edaSArun Thomas pbstr(argv[5]);
6952e8d1edaSArun Thomas else if (argc > 6) {
6962e8d1edaSArun Thomas argv += 3;
6972e8d1edaSArun Thomas argc -= 3;
6982e8d1edaSArun Thomas continue;
6992e8d1edaSArun Thomas }
7002e8d1edaSArun Thomas break;
7012e8d1edaSArun Thomas }
7022e8d1edaSArun Thomas }
7032e8d1edaSArun Thomas
7042e8d1edaSArun Thomas /*
7052e8d1edaSArun Thomas * doinclude - include a given file.
7062e8d1edaSArun Thomas */
7072e8d1edaSArun Thomas static int
doincl(const char * ifile)7082e8d1edaSArun Thomas doincl(const char *ifile)
7092e8d1edaSArun Thomas {
7102e8d1edaSArun Thomas if (ilevel + 1 == MAXINP)
7112e8d1edaSArun Thomas m4errx(1, "too many include files.");
7122e8d1edaSArun Thomas if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7132e8d1edaSArun Thomas ilevel++;
7142e8d1edaSArun Thomas bbase[ilevel] = bufbase = bp;
7152e8d1edaSArun Thomas return (1);
7162e8d1edaSArun Thomas } else
7172e8d1edaSArun Thomas return (0);
7182e8d1edaSArun Thomas }
7192e8d1edaSArun Thomas
7202e8d1edaSArun Thomas #ifdef EXTENDED
7212e8d1edaSArun Thomas /*
7222e8d1edaSArun Thomas * dopaste - include a given file without any
7232e8d1edaSArun Thomas * macro processing.
7242e8d1edaSArun Thomas */
7252e8d1edaSArun Thomas static int
dopaste(const char * pfile)7262e8d1edaSArun Thomas dopaste(const char *pfile)
7272e8d1edaSArun Thomas {
7282e8d1edaSArun Thomas FILE *pf;
7292e8d1edaSArun Thomas int c;
7302e8d1edaSArun Thomas
7312e8d1edaSArun Thomas if ((pf = fopen(pfile, "r")) != NULL) {
7322e8d1edaSArun Thomas if (synch_lines)
7332e8d1edaSArun Thomas fprintf(active, "#line 1 \"%s\"\n", pfile);
7342e8d1edaSArun Thomas while ((c = getc(pf)) != EOF)
7352e8d1edaSArun Thomas putc(c, active);
7362e8d1edaSArun Thomas (void) fclose(pf);
7372e8d1edaSArun Thomas emit_synchline();
7382e8d1edaSArun Thomas return (1);
7392e8d1edaSArun Thomas } else
7402e8d1edaSArun Thomas return (0);
7412e8d1edaSArun Thomas }
7422e8d1edaSArun Thomas #endif
7432e8d1edaSArun Thomas
7442e8d1edaSArun Thomas /*
7452e8d1edaSArun Thomas * dochq - change quote characters
7462e8d1edaSArun Thomas */
7472e8d1edaSArun Thomas static void
dochq(const char * argv[],int ac)7482e8d1edaSArun Thomas dochq(const char *argv[], int ac)
7492e8d1edaSArun Thomas {
7502e8d1edaSArun Thomas if (ac == 2) {
7512e8d1edaSArun Thomas lquote[0] = LQUOTE; lquote[1] = EOS;
7522e8d1edaSArun Thomas rquote[0] = RQUOTE; rquote[1] = EOS;
7532e8d1edaSArun Thomas } else {
7542e8d1edaSArun Thomas strlcpy(lquote, argv[2], sizeof(lquote));
7552e8d1edaSArun Thomas if (ac > 3) {
7562e8d1edaSArun Thomas strlcpy(rquote, argv[3], sizeof(rquote));
7572e8d1edaSArun Thomas } else {
7582e8d1edaSArun Thomas rquote[0] = ECOMMT; rquote[1] = EOS;
7592e8d1edaSArun Thomas }
7602e8d1edaSArun Thomas }
7612e8d1edaSArun Thomas }
7622e8d1edaSArun Thomas
7632e8d1edaSArun Thomas /*
7642e8d1edaSArun Thomas * dochc - change comment characters
7652e8d1edaSArun Thomas */
7662e8d1edaSArun Thomas static void
dochc(const char * argv[],int argc)7672e8d1edaSArun Thomas dochc(const char *argv[], int argc)
7682e8d1edaSArun Thomas {
7692e8d1edaSArun Thomas /* XXX Note that there is no difference between no argument and a single
7702e8d1edaSArun Thomas * empty argument.
7712e8d1edaSArun Thomas */
7722e8d1edaSArun Thomas if (argc == 2) {
7732e8d1edaSArun Thomas scommt[0] = EOS;
7742e8d1edaSArun Thomas ecommt[0] = EOS;
7752e8d1edaSArun Thomas } else {
7762e8d1edaSArun Thomas strlcpy(scommt, argv[2], sizeof(scommt));
7772e8d1edaSArun Thomas if (argc == 3) {
7782e8d1edaSArun Thomas ecommt[0] = ECOMMT; ecommt[1] = EOS;
7792e8d1edaSArun Thomas } else {
7802e8d1edaSArun Thomas strlcpy(ecommt, argv[3], sizeof(ecommt));
7812e8d1edaSArun Thomas }
7822e8d1edaSArun Thomas }
7832e8d1edaSArun Thomas }
7842e8d1edaSArun Thomas
7852e8d1edaSArun Thomas /*
7862e8d1edaSArun Thomas * dom4wrap - expand text at EOF
7872e8d1edaSArun Thomas */
7882e8d1edaSArun Thomas static void
dom4wrap(const char * text)7892e8d1edaSArun Thomas dom4wrap(const char *text)
7902e8d1edaSArun Thomas {
7912e8d1edaSArun Thomas if (wrapindex >= maxwraps) {
7922e8d1edaSArun Thomas if (maxwraps == 0)
7932e8d1edaSArun Thomas maxwraps = 16;
7942e8d1edaSArun Thomas else
7952e8d1edaSArun Thomas maxwraps *= 2;
7962e8d1edaSArun Thomas m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
7972e8d1edaSArun Thomas "too many m4wraps");
7982e8d1edaSArun Thomas }
7992e8d1edaSArun Thomas m4wraps[wrapindex++] = xstrdup(text);
8002e8d1edaSArun Thomas }
8012e8d1edaSArun Thomas
8022e8d1edaSArun Thomas /*
8032e8d1edaSArun Thomas * dodivert - divert the output to a temporary file
8042e8d1edaSArun Thomas */
8052e8d1edaSArun Thomas static void
dodiv(int n)8062e8d1edaSArun Thomas dodiv(int n)
8072e8d1edaSArun Thomas {
8082e8d1edaSArun Thomas int fd;
8092e8d1edaSArun Thomas
8102e8d1edaSArun Thomas oindex = n;
8112e8d1edaSArun Thomas if (n >= maxout) {
8122e8d1edaSArun Thomas if (mimic_gnu)
8132e8d1edaSArun Thomas resizedivs(n + 10);
8142e8d1edaSArun Thomas else
8152e8d1edaSArun Thomas n = 0; /* bitbucket */
8162e8d1edaSArun Thomas }
8172e8d1edaSArun Thomas
8182e8d1edaSArun Thomas if (n < 0)
8192e8d1edaSArun Thomas n = 0; /* bitbucket */
8202e8d1edaSArun Thomas if (outfile[n] == NULL) {
8212e8d1edaSArun Thomas char fname[] = _PATH_DIVNAME;
8222e8d1edaSArun Thomas
8232e8d1edaSArun Thomas if ((fd = mkstemp(fname)) < 0 ||
8242e8d1edaSArun Thomas (outfile[n] = fdopen(fd, "w+")) == NULL)
8252e8d1edaSArun Thomas err(1, "%s: cannot divert", fname);
8262e8d1edaSArun Thomas if (unlink(fname) == -1)
8272e8d1edaSArun Thomas err(1, "%s: cannot unlink", fname);
8282e8d1edaSArun Thomas }
8292e8d1edaSArun Thomas active = outfile[n];
8302e8d1edaSArun Thomas }
8312e8d1edaSArun Thomas
8322e8d1edaSArun Thomas /*
8332e8d1edaSArun Thomas * doundivert - undivert a specified output, or all
8342e8d1edaSArun Thomas * other outputs, in numerical order.
8352e8d1edaSArun Thomas */
8362e8d1edaSArun Thomas static void
doundiv(const char * argv[],int argc)8372e8d1edaSArun Thomas doundiv(const char *argv[], int argc)
8382e8d1edaSArun Thomas {
8392e8d1edaSArun Thomas int ind;
8402e8d1edaSArun Thomas int n;
8412e8d1edaSArun Thomas
8422e8d1edaSArun Thomas if (argc > 2) {
8432e8d1edaSArun Thomas for (ind = 2; ind < argc; ind++) {
844*0a6a1f1dSLionel Sambuc int e;
845*0a6a1f1dSLionel Sambuc n = strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e);
846*0a6a1f1dSLionel Sambuc if (e) {
8472e8d1edaSArun Thomas if (errno == EINVAL && mimic_gnu)
8482e8d1edaSArun Thomas getdivfile(argv[ind]);
8492e8d1edaSArun Thomas } else {
8502e8d1edaSArun Thomas if (n < maxout && outfile[n] != NULL)
8512e8d1edaSArun Thomas getdiv(n);
8522e8d1edaSArun Thomas }
8532e8d1edaSArun Thomas }
8542e8d1edaSArun Thomas }
8552e8d1edaSArun Thomas else
8562e8d1edaSArun Thomas for (n = 1; n < maxout; n++)
8572e8d1edaSArun Thomas if (outfile[n] != NULL)
8582e8d1edaSArun Thomas getdiv(n);
8592e8d1edaSArun Thomas }
8602e8d1edaSArun Thomas
8612e8d1edaSArun Thomas /*
8622e8d1edaSArun Thomas * dosub - select substring
8632e8d1edaSArun Thomas */
8642e8d1edaSArun Thomas static void
dosub(const char * argv[],int argc)8652e8d1edaSArun Thomas dosub(const char *argv[], int argc)
8662e8d1edaSArun Thomas {
8672e8d1edaSArun Thomas const char *ap, *fc, *k;
8682e8d1edaSArun Thomas int nc;
8692e8d1edaSArun Thomas
8702e8d1edaSArun Thomas ap = argv[2]; /* target string */
8712e8d1edaSArun Thomas #ifdef EXPR
8722e8d1edaSArun Thomas fc = ap + expr(argv[3]); /* first char */
8732e8d1edaSArun Thomas #else
8742e8d1edaSArun Thomas fc = ap + atoi(argv[3]); /* first char */
8752e8d1edaSArun Thomas #endif
8762e8d1edaSArun Thomas nc = strlen(fc);
8772e8d1edaSArun Thomas if (argc >= 5)
8782e8d1edaSArun Thomas #ifdef EXPR
8792e8d1edaSArun Thomas nc = min(nc, expr(argv[4]));
8802e8d1edaSArun Thomas #else
8812e8d1edaSArun Thomas nc = min(nc, atoi(argv[4]));
8822e8d1edaSArun Thomas #endif
8832e8d1edaSArun Thomas if (fc >= ap && fc < ap + strlen(ap))
8842e8d1edaSArun Thomas for (k = fc + nc - 1; k >= fc; k--)
8852e8d1edaSArun Thomas pushback(*k);
8862e8d1edaSArun Thomas }
8872e8d1edaSArun Thomas
8882e8d1edaSArun Thomas /*
8892e8d1edaSArun Thomas * map:
8902e8d1edaSArun Thomas * map every character of s1 that is specified in from
8912e8d1edaSArun Thomas * into s3 and replace in s. (source s1 remains untouched)
8922e8d1edaSArun Thomas *
8932e8d1edaSArun Thomas * This is a standard implementation of map(s,from,to) function of ICON
8942e8d1edaSArun Thomas * language. Within mapvec, we replace every character of "from" with
8952e8d1edaSArun Thomas * the corresponding character in "to". If "to" is shorter than "from",
8962e8d1edaSArun Thomas * than the corresponding entries are null, which means that those
8972e8d1edaSArun Thomas * characters dissapear altogether. Furthermore, imagine
8982e8d1edaSArun Thomas * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
8992e8d1edaSArun Thomas * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
9002e8d1edaSArun Thomas * ultimately maps to `*'. In order to achieve this effect in an efficient
9012e8d1edaSArun Thomas * manner (i.e. without multiple passes over the destination string), we
9022e8d1edaSArun Thomas * loop over mapvec, starting with the initial source character. if the
9032e8d1edaSArun Thomas * character value (dch) in this location is different than the source
9042e8d1edaSArun Thomas * character (sch), sch becomes dch, once again to index into mapvec, until
9052e8d1edaSArun Thomas * the character value stabilizes (i.e. sch = dch, in other words
9062e8d1edaSArun Thomas * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
9072e8d1edaSArun Thomas * character, it will stabilize, since mapvec[0] == 0 at all times. At the
9082e8d1edaSArun Thomas * end, we restore mapvec* back to normal where mapvec[n] == n for
9092e8d1edaSArun Thomas * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
9102e8d1edaSArun Thomas * about 5 times faster than any algorithm that makes multiple passes over
9112e8d1edaSArun Thomas * destination string.
9122e8d1edaSArun Thomas */
9132e8d1edaSArun Thomas static void
map(char * dest,const char * src,const char * from,const char * to)9142e8d1edaSArun Thomas map(char *dest, const char *src, const char *from, const char *to)
9152e8d1edaSArun Thomas {
9162e8d1edaSArun Thomas const char *tmp;
9172e8d1edaSArun Thomas unsigned char sch, dch;
9182e8d1edaSArun Thomas static char frombis[257];
9192e8d1edaSArun Thomas static char tobis[257];
9202e8d1edaSArun Thomas static unsigned char mapvec[256] = {
9212e8d1edaSArun Thomas 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
9222e8d1edaSArun Thomas 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
9232e8d1edaSArun Thomas 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
9242e8d1edaSArun Thomas 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
9252e8d1edaSArun Thomas 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
9262e8d1edaSArun Thomas 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
9272e8d1edaSArun Thomas 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
9282e8d1edaSArun Thomas 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
9292e8d1edaSArun Thomas 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
9302e8d1edaSArun Thomas 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
9312e8d1edaSArun Thomas 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
9322e8d1edaSArun Thomas 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
9332e8d1edaSArun Thomas 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
9342e8d1edaSArun Thomas 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
9352e8d1edaSArun Thomas 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
9362e8d1edaSArun Thomas 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
9372e8d1edaSArun Thomas 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
9382e8d1edaSArun Thomas 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9392e8d1edaSArun Thomas };
9402e8d1edaSArun Thomas
9412e8d1edaSArun Thomas if (*src) {
9422e8d1edaSArun Thomas if (mimic_gnu) {
9432e8d1edaSArun Thomas /*
9442e8d1edaSArun Thomas * expand character ranges on the fly
9452e8d1edaSArun Thomas */
9462e8d1edaSArun Thomas from = handledash(frombis, frombis + 256, from);
9472e8d1edaSArun Thomas to = handledash(tobis, tobis + 256, to);
9482e8d1edaSArun Thomas }
9492e8d1edaSArun Thomas tmp = from;
9502e8d1edaSArun Thomas /*
9512e8d1edaSArun Thomas * create a mapping between "from" and
9522e8d1edaSArun Thomas * "to"
9532e8d1edaSArun Thomas */
9542e8d1edaSArun Thomas while (*from)
9552e8d1edaSArun Thomas mapvec[(unsigned char)(*from++)] = (*to) ?
9562e8d1edaSArun Thomas (unsigned char)(*to++) : 0;
9572e8d1edaSArun Thomas
9582e8d1edaSArun Thomas while (*src) {
9592e8d1edaSArun Thomas sch = (unsigned char)(*src++);
9602e8d1edaSArun Thomas dch = mapvec[sch];
9612e8d1edaSArun Thomas while (dch != sch) {
9622e8d1edaSArun Thomas sch = dch;
9632e8d1edaSArun Thomas dch = mapvec[sch];
9642e8d1edaSArun Thomas }
9652e8d1edaSArun Thomas if ((*dest = (char)dch))
9662e8d1edaSArun Thomas dest++;
9672e8d1edaSArun Thomas }
9682e8d1edaSArun Thomas /*
9692e8d1edaSArun Thomas * restore all the changed characters
9702e8d1edaSArun Thomas */
9712e8d1edaSArun Thomas while (*tmp) {
9722e8d1edaSArun Thomas mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9732e8d1edaSArun Thomas tmp++;
9742e8d1edaSArun Thomas }
9752e8d1edaSArun Thomas }
9762e8d1edaSArun Thomas *dest = '\0';
9772e8d1edaSArun Thomas }
9782e8d1edaSArun Thomas
9792e8d1edaSArun Thomas
9802e8d1edaSArun Thomas /*
9812e8d1edaSArun Thomas * handledash:
9822e8d1edaSArun Thomas * use buffer to copy the src string, expanding character ranges
9832e8d1edaSArun Thomas * on the way.
9842e8d1edaSArun Thomas */
9852e8d1edaSArun Thomas static const char *
handledash(char * buffer,char * end,const char * src)9862e8d1edaSArun Thomas handledash(char *buffer, char *end, const char *src)
9872e8d1edaSArun Thomas {
9882e8d1edaSArun Thomas char *p;
9892e8d1edaSArun Thomas
9902e8d1edaSArun Thomas p = buffer;
9912e8d1edaSArun Thomas while(*src) {
9922e8d1edaSArun Thomas if (src[1] == '-' && src[2]) {
9932e8d1edaSArun Thomas unsigned char i;
9942e8d1edaSArun Thomas if ((unsigned char)src[0] <= (unsigned char)src[2]) {
9952e8d1edaSArun Thomas for (i = (unsigned char)src[0];
9962e8d1edaSArun Thomas i <= (unsigned char)src[2]; i++) {
9972e8d1edaSArun Thomas *p++ = i;
9982e8d1edaSArun Thomas if (p == end) {
9992e8d1edaSArun Thomas *p = '\0';
10002e8d1edaSArun Thomas return buffer;
10012e8d1edaSArun Thomas }
10022e8d1edaSArun Thomas }
10032e8d1edaSArun Thomas } else {
10042e8d1edaSArun Thomas for (i = (unsigned char)src[0];
10052e8d1edaSArun Thomas i >= (unsigned char)src[2]; i--) {
10062e8d1edaSArun Thomas *p++ = i;
10072e8d1edaSArun Thomas if (p == end) {
10082e8d1edaSArun Thomas *p = '\0';
10092e8d1edaSArun Thomas return buffer;
10102e8d1edaSArun Thomas }
10112e8d1edaSArun Thomas }
10122e8d1edaSArun Thomas }
10132e8d1edaSArun Thomas src += 3;
10142e8d1edaSArun Thomas } else
10152e8d1edaSArun Thomas *p++ = *src++;
10162e8d1edaSArun Thomas if (p == end)
10172e8d1edaSArun Thomas break;
10182e8d1edaSArun Thomas }
10192e8d1edaSArun Thomas *p = '\0';
10202e8d1edaSArun Thomas return buffer;
10212e8d1edaSArun Thomas }
1022