1*db531a5dSBaptiste Daroussin /* $OpenBSD: eval.c,v 1.77 2017/11/11 12:55:59 espie Exp $ */ 2acc9d408SJuli Mallett /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 3acc9d408SJuli Mallett 48a16b7a1SPedro F. Giffuni /*- 58a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 68a16b7a1SPedro F. Giffuni * 79b50d902SRodney W. Grimes * Copyright (c) 1989, 1993 89b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 99b50d902SRodney W. Grimes * 109b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 119b50d902SRodney W. Grimes * Ozan Yigit at York University. 129b50d902SRodney W. Grimes * 139b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 149b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 159b50d902SRodney W. Grimes * are met: 169b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 179b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 189b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 199b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 209b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 21a841e1ebSBaptiste Daroussin * 3. Neither the name of the University nor the names of its contributors 229b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 239b50d902SRodney W. Grimes * without specific prior written permission. 249b50d902SRodney W. Grimes * 259b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 269b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 279b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 289b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 299b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 309b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 319b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 329b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 339b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 349b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 359b50d902SRodney W. Grimes * SUCH DAMAGE. 369b50d902SRodney W. Grimes */ 379b50d902SRodney W. Grimes 38acc9d408SJuli Mallett #include <sys/cdefs.h> 39acc9d408SJuli Mallett __FBSDID("$FreeBSD$"); 409b50d902SRodney W. Grimes 41a841e1ebSBaptiste Daroussin 429b50d902SRodney W. Grimes /* 439b50d902SRodney W. Grimes * eval.c 449b50d902SRodney W. Grimes * Facility: m4 macro processor 459b50d902SRodney W. Grimes * by: oz 469b50d902SRodney W. Grimes */ 479b50d902SRodney W. Grimes 489b50d902SRodney W. Grimes #include <sys/types.h> 49a841e1ebSBaptiste Daroussin #include <err.h> 50acc9d408SJuli Mallett #include <errno.h> 51a841e1ebSBaptiste Daroussin #include <limits.h> 52acc9d408SJuli Mallett #include <unistd.h> 539b50d902SRodney W. Grimes #include <stdio.h> 5446ef9581SBaptiste Daroussin #include <stdint.h> 559b50d902SRodney W. Grimes #include <stdlib.h> 56acc9d408SJuli Mallett #include <stddef.h> 579b50d902SRodney W. Grimes #include <string.h> 58acc9d408SJuli Mallett #include <fcntl.h> 599b50d902SRodney W. Grimes #include "mdef.h" 609b50d902SRodney W. Grimes #include "stdd.h" 619b50d902SRodney W. Grimes #include "extern.h" 629b50d902SRodney W. Grimes #include "pathnames.h" 639b50d902SRodney W. Grimes 64acc9d408SJuli Mallett static void dodefn(const char *); 65acc9d408SJuli Mallett static void dopushdef(const char *, const char *); 66acc9d408SJuli Mallett static void dodump(const char *[], int); 67acc9d408SJuli Mallett static void dotrace(const char *[], int, int); 68acc9d408SJuli Mallett static void doifelse(const char *[], int); 69acc9d408SJuli Mallett static int doincl(const char *); 70acc9d408SJuli Mallett static int dopaste(const char *); 71acc9d408SJuli Mallett static void dochq(const char *[], int); 72acc9d408SJuli Mallett static void dochc(const char *[], int); 73a841e1ebSBaptiste Daroussin static void dom4wrap(const char *); 74acc9d408SJuli Mallett static void dodiv(int); 75acc9d408SJuli Mallett static void doundiv(const char *[], int); 76acc9d408SJuli Mallett static void dosub(const char *[], int); 77acc9d408SJuli Mallett static void map(char *, const char *, const char *, const char *); 78acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *); 79acc9d408SJuli Mallett static void expand_builtin(const char *[], int, int); 80acc9d408SJuli Mallett static void expand_macro(const char *[], int); 81a841e1ebSBaptiste Daroussin static void dump_one_def(const char *, struct macro_definition *); 82acc9d408SJuli Mallett 83acc9d408SJuli Mallett unsigned long expansion_id; 84acc9d408SJuli Mallett 859b50d902SRodney W. Grimes /* 86acc9d408SJuli Mallett * eval - eval all macros and builtins calls 879b50d902SRodney W. Grimes * argc - number of elements in argv. 889b50d902SRodney W. Grimes * argv - element vector : 899b50d902SRodney W. Grimes * argv[0] = definition of a user 90a841e1ebSBaptiste Daroussin * macro or NULL if built-in. 919b50d902SRodney W. Grimes * argv[1] = name of the macro or 929b50d902SRodney W. Grimes * built-in. 939b50d902SRodney W. Grimes * argv[2] = parameters to user-defined 949b50d902SRodney W. Grimes * . macro or built-in. 959b50d902SRodney W. Grimes * . 969b50d902SRodney W. Grimes * 97acc9d408SJuli Mallett * A call in the form of macro-or-builtin() will result in: 989b50d902SRodney W. Grimes * argv[0] = nullstr 999b50d902SRodney W. Grimes * argv[1] = macro-or-builtin 1009b50d902SRodney W. Grimes * argv[2] = nullstr 101acc9d408SJuli Mallett * 102acc9d408SJuli Mallett * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 1039b50d902SRodney W. Grimes */ 1049b50d902SRodney W. Grimes void 105a841e1ebSBaptiste Daroussin eval(const char *argv[], int argc, int td, int is_traced) 1069b50d902SRodney W. Grimes { 107a841e1ebSBaptiste Daroussin size_t mark = SIZE_MAX; 108acc9d408SJuli Mallett 109acc9d408SJuli Mallett expansion_id++; 110acc9d408SJuli Mallett if (td & RECDEF) 111a841e1ebSBaptiste Daroussin m4errx(1, "expanding recursive definition for %s.", argv[1]); 112a841e1ebSBaptiste Daroussin if (is_traced) 113acc9d408SJuli Mallett mark = trace(argv, argc, infile+ilevel); 114acc9d408SJuli Mallett if (td == MACRTYPE) 115acc9d408SJuli Mallett expand_macro(argv, argc); 116acc9d408SJuli Mallett else 117acc9d408SJuli Mallett expand_builtin(argv, argc, td); 118a841e1ebSBaptiste Daroussin if (mark != SIZE_MAX) 119acc9d408SJuli Mallett finish_trace(mark); 120acc9d408SJuli Mallett } 121acc9d408SJuli Mallett 122acc9d408SJuli Mallett /* 123acc9d408SJuli Mallett * expand_builtin - evaluate built-in macros. 124acc9d408SJuli Mallett */ 125acc9d408SJuli Mallett void 126bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td) 127acc9d408SJuli Mallett { 128acc9d408SJuli Mallett int c, n; 129*db531a5dSBaptiste Daroussin const char *errstr; 130acc9d408SJuli Mallett int ac; 1319b50d902SRodney W. Grimes static int sysval = 0; 1329b50d902SRodney W. Grimes 1339b50d902SRodney W. Grimes #ifdef DEBUG 1349b50d902SRodney W. Grimes printf("argc = %d\n", argc); 1359b50d902SRodney W. Grimes for (n = 0; n < argc; n++) 1369b50d902SRodney W. Grimes printf("argv[%d] = %s\n", n, argv[n]); 137acc9d408SJuli Mallett fflush(stdout); 1389b50d902SRodney W. Grimes #endif 139acc9d408SJuli Mallett 1409b50d902SRodney W. Grimes /* 1419b50d902SRodney W. Grimes * if argc == 3 and argv[2] is null, then we 1429b50d902SRodney W. Grimes * have macro-or-builtin() type call. We adjust 1439b50d902SRodney W. Grimes * argc to avoid further checking.. 1449b50d902SRodney W. Grimes */ 145a841e1ebSBaptiste Daroussin /* we keep the initial value for those built-ins that differentiate 146a841e1ebSBaptiste Daroussin * between builtin() and builtin. 147a841e1ebSBaptiste Daroussin */ 148acc9d408SJuli Mallett ac = argc; 149acc9d408SJuli Mallett 150a841e1ebSBaptiste Daroussin if (argc == 3 && !*(argv[2]) && !mimic_gnu) 1519b50d902SRodney W. Grimes argc--; 1529b50d902SRodney W. Grimes 153acc9d408SJuli Mallett switch (td & TYPEMASK) { 1549b50d902SRodney W. Grimes 1559b50d902SRodney W. Grimes case DEFITYPE: 1569b50d902SRodney W. Grimes if (argc > 2) 1579b50d902SRodney W. Grimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1589b50d902SRodney W. Grimes break; 1599b50d902SRodney W. Grimes 1609b50d902SRodney W. Grimes case PUSDTYPE: 1619b50d902SRodney W. Grimes if (argc > 2) 1629b50d902SRodney W. Grimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1639b50d902SRodney W. Grimes break; 1649b50d902SRodney W. Grimes 1659b50d902SRodney W. Grimes case DUMPTYPE: 1669b50d902SRodney W. Grimes dodump(argv, argc); 1679b50d902SRodney W. Grimes break; 1689b50d902SRodney W. Grimes 169acc9d408SJuli Mallett case TRACEONTYPE: 170acc9d408SJuli Mallett dotrace(argv, argc, 1); 171acc9d408SJuli Mallett break; 172acc9d408SJuli Mallett 173acc9d408SJuli Mallett case TRACEOFFTYPE: 174acc9d408SJuli Mallett dotrace(argv, argc, 0); 175acc9d408SJuli Mallett break; 176acc9d408SJuli Mallett 1779b50d902SRodney W. Grimes case EXPRTYPE: 1789b50d902SRodney W. Grimes /* 1799b50d902SRodney W. Grimes * doexpr - evaluate arithmetic 1809b50d902SRodney W. Grimes * expression 1819b50d902SRodney W. Grimes */ 182a841e1ebSBaptiste Daroussin { 183a841e1ebSBaptiste Daroussin int base = 10; 184a841e1ebSBaptiste Daroussin int maxdigits = 0; 185a841e1ebSBaptiste Daroussin const char *errstr; 186a841e1ebSBaptiste Daroussin 187a841e1ebSBaptiste Daroussin if (argc > 3) { 188a841e1ebSBaptiste Daroussin base = strtonum(argv[3], 2, 36, &errstr); 189a841e1ebSBaptiste Daroussin if (errstr) { 190*db531a5dSBaptiste Daroussin m4errx(1, "expr: base is %s: %s.", 191*db531a5dSBaptiste Daroussin errstr, argv[3]); 192a841e1ebSBaptiste Daroussin } 193a841e1ebSBaptiste Daroussin } 194a841e1ebSBaptiste Daroussin if (argc > 4) { 195a841e1ebSBaptiste Daroussin maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); 196a841e1ebSBaptiste Daroussin if (errstr) { 197*db531a5dSBaptiste Daroussin m4errx(1, "expr: maxdigits is %s: %s.", 198*db531a5dSBaptiste Daroussin errstr, argv[4]); 199a841e1ebSBaptiste Daroussin } 200a841e1ebSBaptiste Daroussin } 2019b50d902SRodney W. Grimes if (argc > 2) 202a841e1ebSBaptiste Daroussin pbnumbase(expr(argv[2]), base, maxdigits); 2039b50d902SRodney W. Grimes break; 204a841e1ebSBaptiste Daroussin } 2059b50d902SRodney W. Grimes 2069b50d902SRodney W. Grimes case IFELTYPE: 2079b50d902SRodney W. Grimes doifelse(argv, argc); 2089b50d902SRodney W. Grimes break; 2099b50d902SRodney W. Grimes 2109b50d902SRodney W. Grimes case IFDFTYPE: 2119b50d902SRodney W. Grimes /* 2129b50d902SRodney W. Grimes * doifdef - select one of two 2139b50d902SRodney W. Grimes * alternatives based on the existence of 2149b50d902SRodney W. Grimes * another definition 2159b50d902SRodney W. Grimes */ 2169b50d902SRodney W. Grimes if (argc > 3) { 217a841e1ebSBaptiste Daroussin if (lookup_macro_definition(argv[2]) != NULL) 2189b50d902SRodney W. Grimes pbstr(argv[3]); 2199b50d902SRodney W. Grimes else if (argc > 4) 2209b50d902SRodney W. Grimes pbstr(argv[4]); 2219b50d902SRodney W. Grimes } 2229b50d902SRodney W. Grimes break; 2239b50d902SRodney W. Grimes 2249b50d902SRodney W. Grimes case LENGTYPE: 2259b50d902SRodney W. Grimes /* 2269b50d902SRodney W. Grimes * dolen - find the length of the 2279b50d902SRodney W. Grimes * argument 2289b50d902SRodney W. Grimes */ 2299b50d902SRodney W. Grimes pbnum((argc > 2) ? strlen(argv[2]) : 0); 2309b50d902SRodney W. Grimes break; 2319b50d902SRodney W. Grimes 2329b50d902SRodney W. Grimes case INCRTYPE: 2339b50d902SRodney W. Grimes /* 2349b50d902SRodney W. Grimes * doincr - increment the value of the 2359b50d902SRodney W. Grimes * argument 2369b50d902SRodney W. Grimes */ 237*db531a5dSBaptiste Daroussin if (argc > 2) { 238*db531a5dSBaptiste Daroussin n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr); 239*db531a5dSBaptiste Daroussin if (errstr != NULL) 240*db531a5dSBaptiste Daroussin m4errx(1, "incr: argument is %s: %s.", 241*db531a5dSBaptiste Daroussin errstr, argv[2]); 242*db531a5dSBaptiste Daroussin pbnum(n + 1); 243*db531a5dSBaptiste Daroussin } 2449b50d902SRodney W. Grimes break; 2459b50d902SRodney W. Grimes 2469b50d902SRodney W. Grimes case DECRTYPE: 2479b50d902SRodney W. Grimes /* 2489b50d902SRodney W. Grimes * dodecr - decrement the value of the 2499b50d902SRodney W. Grimes * argument 2509b50d902SRodney W. Grimes */ 251*db531a5dSBaptiste Daroussin if (argc > 2) { 252*db531a5dSBaptiste Daroussin n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr); 253*db531a5dSBaptiste Daroussin if (errstr) 254*db531a5dSBaptiste Daroussin m4errx(1, "decr: argument is %s: %s.", 255*db531a5dSBaptiste Daroussin errstr, argv[2]); 256*db531a5dSBaptiste Daroussin pbnum(n - 1); 257*db531a5dSBaptiste Daroussin } 2589b50d902SRodney W. Grimes break; 2599b50d902SRodney W. Grimes 2609b50d902SRodney W. Grimes case SYSCTYPE: 2619b50d902SRodney W. Grimes /* 2629b50d902SRodney W. Grimes * dosys - execute system command 2639b50d902SRodney W. Grimes */ 264aef4bb33STim J. Robbins if (argc > 2) { 265a841e1ebSBaptiste Daroussin fflush(stdout); 2669b50d902SRodney W. Grimes sysval = system(argv[2]); 267aef4bb33STim J. Robbins } 2689b50d902SRodney W. Grimes break; 2699b50d902SRodney W. Grimes 2709b50d902SRodney W. Grimes case SYSVTYPE: 2719b50d902SRodney W. Grimes /* 2729b50d902SRodney W. Grimes * dosysval - return value of the last 2739b50d902SRodney W. Grimes * system call. 2749b50d902SRodney W. Grimes * 2759b50d902SRodney W. Grimes */ 2769b50d902SRodney W. Grimes pbnum(sysval); 2779b50d902SRodney W. Grimes break; 2789b50d902SRodney W. Grimes 279acc9d408SJuli Mallett case ESYSCMDTYPE: 280acc9d408SJuli Mallett if (argc > 2) 281acc9d408SJuli Mallett doesyscmd(argv[2]); 282acc9d408SJuli Mallett break; 2839b50d902SRodney W. Grimes case INCLTYPE: 28488497f0cSBaptiste Daroussin if (argc > 2) { 2852cce1b69SBjoern A. Zeeb if (!doincl(argv[2])) { 286fb3f3d7cSBaptiste Daroussin if (mimic_gnu) { 2874fff7a14SBaptiste Daroussin warn("%s at line %lu: include(%s)", 2884fff7a14SBaptiste Daroussin CURRENT_NAME, CURRENT_LINE, argv[2]); 289fb3f3d7cSBaptiste Daroussin exit_code = 1; 290c560b67cSBaptiste Daroussin if (fatal_warns) { 291c560b67cSBaptiste Daroussin killdiv(); 292c560b67cSBaptiste Daroussin exit(exit_code); 293c560b67cSBaptiste Daroussin } 294fb3f3d7cSBaptiste Daroussin } else 295acc9d408SJuli Mallett err(1, "%s at line %lu: include(%s)", 296acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 2972cce1b69SBjoern A. Zeeb } 29888497f0cSBaptiste Daroussin } 2999b50d902SRodney W. Grimes break; 3009b50d902SRodney W. Grimes 3019b50d902SRodney W. Grimes case SINCTYPE: 3029b50d902SRodney W. Grimes if (argc > 2) 3039b50d902SRodney W. Grimes (void) doincl(argv[2]); 3049b50d902SRodney W. Grimes break; 3059b50d902SRodney W. Grimes #ifdef EXTENDED 3069b50d902SRodney W. Grimes case PASTTYPE: 3079b50d902SRodney W. Grimes if (argc > 2) 3089b50d902SRodney W. Grimes if (!dopaste(argv[2])) 309acc9d408SJuli Mallett err(1, "%s at line %lu: paste(%s)", 310acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 3119b50d902SRodney W. Grimes break; 3129b50d902SRodney W. Grimes 3139b50d902SRodney W. Grimes case SPASTYPE: 3149b50d902SRodney W. Grimes if (argc > 2) 3159b50d902SRodney W. Grimes (void) dopaste(argv[2]); 3169b50d902SRodney W. Grimes break; 317a841e1ebSBaptiste Daroussin case FORMATTYPE: 318a841e1ebSBaptiste Daroussin doformat(argv, argc); 319a841e1ebSBaptiste Daroussin break; 3209b50d902SRodney W. Grimes #endif 3219b50d902SRodney W. Grimes case CHNQTYPE: 322a841e1ebSBaptiste Daroussin dochq(argv, ac); 3239b50d902SRodney W. Grimes break; 3249b50d902SRodney W. Grimes 3259b50d902SRodney W. Grimes case CHNCTYPE: 3269b50d902SRodney W. Grimes dochc(argv, argc); 3279b50d902SRodney W. Grimes break; 3289b50d902SRodney W. Grimes 3299b50d902SRodney W. Grimes case SUBSTYPE: 3309b50d902SRodney W. Grimes /* 3319b50d902SRodney W. Grimes * dosub - select substring 3329b50d902SRodney W. Grimes * 3339b50d902SRodney W. Grimes */ 3349b50d902SRodney W. Grimes if (argc > 3) 3359b50d902SRodney W. Grimes dosub(argv, argc); 3369b50d902SRodney W. Grimes break; 3379b50d902SRodney W. Grimes 3389b50d902SRodney W. Grimes case SHIFTYPE: 3399b50d902SRodney W. Grimes /* 3409b50d902SRodney W. Grimes * doshift - push back all arguments 3419b50d902SRodney W. Grimes * except the first one (i.e. skip 3429b50d902SRodney W. Grimes * argv[2]) 3439b50d902SRodney W. Grimes */ 3449b50d902SRodney W. Grimes if (argc > 3) { 3459b50d902SRodney W. Grimes for (n = argc - 1; n > 3; n--) { 346acc9d408SJuli Mallett pbstr(rquote); 3479b50d902SRodney W. Grimes pbstr(argv[n]); 348acc9d408SJuli Mallett pbstr(lquote); 349a841e1ebSBaptiste Daroussin pushback(COMMA); 3509b50d902SRodney W. Grimes } 351acc9d408SJuli Mallett pbstr(rquote); 3529b50d902SRodney W. Grimes pbstr(argv[3]); 353acc9d408SJuli Mallett pbstr(lquote); 3549b50d902SRodney W. Grimes } 3559b50d902SRodney W. Grimes break; 3569b50d902SRodney W. Grimes 3579b50d902SRodney W. Grimes case DIVRTYPE: 358*db531a5dSBaptiste Daroussin if (argc > 2) { 359*db531a5dSBaptiste Daroussin n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr); 360*db531a5dSBaptiste Daroussin if (errstr) 361*db531a5dSBaptiste Daroussin m4errx(1, "divert: argument is %s: %s.", 362*db531a5dSBaptiste Daroussin errstr, argv[2]); 363*db531a5dSBaptiste Daroussin if (n != 0) { 3649b50d902SRodney W. Grimes dodiv(n); 365*db531a5dSBaptiste Daroussin break; 366*db531a5dSBaptiste Daroussin } 367*db531a5dSBaptiste Daroussin } 3689b50d902SRodney W. Grimes active = stdout; 3699b50d902SRodney W. Grimes oindex = 0; 3709b50d902SRodney W. Grimes break; 3719b50d902SRodney W. Grimes 3729b50d902SRodney W. Grimes case UNDVTYPE: 3739b50d902SRodney W. Grimes doundiv(argv, argc); 3749b50d902SRodney W. Grimes break; 3759b50d902SRodney W. Grimes 3769b50d902SRodney W. Grimes case DIVNTYPE: 3779b50d902SRodney W. Grimes /* 3789b50d902SRodney W. Grimes * dodivnum - return the number of 3799b50d902SRodney W. Grimes * current output diversion 3809b50d902SRodney W. Grimes */ 3819b50d902SRodney W. Grimes pbnum(oindex); 3829b50d902SRodney W. Grimes break; 3839b50d902SRodney W. Grimes 3849b50d902SRodney W. Grimes case UNDFTYPE: 3859b50d902SRodney W. Grimes /* 3869b50d902SRodney W. Grimes * doundefine - undefine a previously 3879b50d902SRodney W. Grimes * defined macro(s) or m4 keyword(s). 3889b50d902SRodney W. Grimes */ 3899b50d902SRodney W. Grimes if (argc > 2) 3909b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 391a841e1ebSBaptiste Daroussin macro_undefine(argv[n]); 3929b50d902SRodney W. Grimes break; 3939b50d902SRodney W. Grimes 3949b50d902SRodney W. Grimes case POPDTYPE: 3959b50d902SRodney W. Grimes /* 3969b50d902SRodney W. Grimes * dopopdef - remove the topmost 3979b50d902SRodney W. Grimes * definitions of macro(s) or m4 3989b50d902SRodney W. Grimes * keyword(s). 3999b50d902SRodney W. Grimes */ 4009b50d902SRodney W. Grimes if (argc > 2) 4019b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 402a841e1ebSBaptiste Daroussin macro_popdef(argv[n]); 4039b50d902SRodney W. Grimes break; 4049b50d902SRodney W. Grimes 4059b50d902SRodney W. Grimes case MKTMTYPE: 4069b50d902SRodney W. Grimes /* 4079b50d902SRodney W. Grimes * dotemp - create a temporary file 4089b50d902SRodney W. Grimes */ 409acc9d408SJuli Mallett if (argc > 2) { 410acc9d408SJuli Mallett int fd; 411acc9d408SJuli Mallett char *temp; 412acc9d408SJuli Mallett 413acc9d408SJuli Mallett temp = xstrdup(argv[2]); 414acc9d408SJuli Mallett 415acc9d408SJuli Mallett fd = mkstemp(temp); 416acc9d408SJuli Mallett if (fd == -1) 417acc9d408SJuli Mallett err(1, 418acc9d408SJuli Mallett "%s at line %lu: couldn't make temp file %s", 419acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 420acc9d408SJuli Mallett close(fd); 421acc9d408SJuli Mallett pbstr(temp); 422acc9d408SJuli Mallett free(temp); 423acc9d408SJuli Mallett } 4249b50d902SRodney W. Grimes break; 4259b50d902SRodney W. Grimes 4269b50d902SRodney W. Grimes case TRNLTYPE: 4279b50d902SRodney W. Grimes /* 4289b50d902SRodney W. Grimes * dotranslit - replace all characters in 4299b50d902SRodney W. Grimes * the source string that appears in the 4309b50d902SRodney W. Grimes * "from" string with the corresponding 4319b50d902SRodney W. Grimes * characters in the "to" string. 4329b50d902SRodney W. Grimes */ 4339b50d902SRodney W. Grimes if (argc > 3) { 434acc9d408SJuli Mallett char *temp; 435acc9d408SJuli Mallett 436a841e1ebSBaptiste Daroussin temp = xalloc(strlen(argv[2])+1, NULL); 4379b50d902SRodney W. Grimes if (argc > 4) 4389b50d902SRodney W. Grimes map(temp, argv[2], argv[3], argv[4]); 4399b50d902SRodney W. Grimes else 4409b50d902SRodney W. Grimes map(temp, argv[2], argv[3], null); 4419b50d902SRodney W. Grimes pbstr(temp); 442acc9d408SJuli Mallett free(temp); 443acc9d408SJuli Mallett } else if (argc > 2) 4449b50d902SRodney W. Grimes pbstr(argv[2]); 4459b50d902SRodney W. Grimes break; 4469b50d902SRodney W. Grimes 4479b50d902SRodney W. Grimes case INDXTYPE: 4489b50d902SRodney W. Grimes /* 4499b50d902SRodney W. Grimes * doindex - find the index of the second 4509b50d902SRodney W. Grimes * argument string in the first argument 4519b50d902SRodney W. Grimes * string. -1 if not present. 4529b50d902SRodney W. Grimes */ 4539b50d902SRodney W. Grimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 4549b50d902SRodney W. Grimes break; 4559b50d902SRodney W. Grimes 4569b50d902SRodney W. Grimes case ERRPTYPE: 4579b50d902SRodney W. Grimes /* 4589b50d902SRodney W. Grimes * doerrp - print the arguments to stderr 4599b50d902SRodney W. Grimes * file 4609b50d902SRodney W. Grimes */ 4619b50d902SRodney W. Grimes if (argc > 2) { 4629b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 4639b50d902SRodney W. Grimes fprintf(stderr, "%s ", argv[n]); 4649b50d902SRodney W. Grimes fprintf(stderr, "\n"); 4659b50d902SRodney W. Grimes } 4669b50d902SRodney W. Grimes break; 4679b50d902SRodney W. Grimes 4689b50d902SRodney W. Grimes case DNLNTYPE: 4699b50d902SRodney W. Grimes /* 4709b50d902SRodney W. Grimes * dodnl - eat-up-to and including 4719b50d902SRodney W. Grimes * newline 4729b50d902SRodney W. Grimes */ 4739b50d902SRodney W. Grimes while ((c = gpbc()) != '\n' && c != EOF) 4749b50d902SRodney W. Grimes ; 4759b50d902SRodney W. Grimes break; 4769b50d902SRodney W. Grimes 4779b50d902SRodney W. Grimes case M4WRTYPE: 4789b50d902SRodney W. Grimes /* 4799b50d902SRodney W. Grimes * dom4wrap - set up for 4809b50d902SRodney W. Grimes * wrap-up/wind-down activity 4819b50d902SRodney W. Grimes */ 482a841e1ebSBaptiste Daroussin if (argc > 2) 483a841e1ebSBaptiste Daroussin dom4wrap(argv[2]); 4849b50d902SRodney W. Grimes break; 4859b50d902SRodney W. Grimes 4869b50d902SRodney W. Grimes case EXITTYPE: 4879b50d902SRodney W. Grimes /* 4889b50d902SRodney W. Grimes * doexit - immediate exit from m4. 4899b50d902SRodney W. Grimes */ 490cac6992aSAndrey A. Chernov killdiv(); 4919b50d902SRodney W. Grimes exit((argc > 2) ? atoi(argv[2]) : 0); 4929b50d902SRodney W. Grimes break; 4939b50d902SRodney W. Grimes 4949b50d902SRodney W. Grimes case DEFNTYPE: 4959b50d902SRodney W. Grimes if (argc > 2) 4969b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 4979b50d902SRodney W. Grimes dodefn(argv[n]); 4989b50d902SRodney W. Grimes break; 4999b50d902SRodney W. Grimes 500acc9d408SJuli Mallett case INDIRTYPE: /* Indirect call */ 501acc9d408SJuli Mallett if (argc > 2) 502acc9d408SJuli Mallett doindir(argv, argc); 503bbfd1447SSteve Price break; 504bbfd1447SSteve Price 505acc9d408SJuli Mallett case BUILTINTYPE: /* Builtins only */ 506acc9d408SJuli Mallett if (argc > 2) 507acc9d408SJuli Mallett dobuiltin(argv, argc); 508acc9d408SJuli Mallett break; 509acc9d408SJuli Mallett 510acc9d408SJuli Mallett case PATSTYPE: 511acc9d408SJuli Mallett if (argc > 2) 512acc9d408SJuli Mallett dopatsubst(argv, argc); 513acc9d408SJuli Mallett break; 514acc9d408SJuli Mallett case REGEXPTYPE: 515acc9d408SJuli Mallett if (argc > 2) 516acc9d408SJuli Mallett doregexp(argv, argc); 517acc9d408SJuli Mallett break; 518acc9d408SJuli Mallett case LINETYPE: 519acc9d408SJuli Mallett doprintlineno(infile+ilevel); 520acc9d408SJuli Mallett break; 521acc9d408SJuli Mallett case FILENAMETYPE: 522acc9d408SJuli Mallett doprintfilename(infile+ilevel); 523acc9d408SJuli Mallett break; 524acc9d408SJuli Mallett case SELFTYPE: 525acc9d408SJuli Mallett pbstr(rquote); 526acc9d408SJuli Mallett pbstr(argv[1]); 527acc9d408SJuli Mallett pbstr(lquote); 528acc9d408SJuli Mallett break; 5299b50d902SRodney W. Grimes default: 530a841e1ebSBaptiste Daroussin m4errx(1, "eval: major botch."); 5319b50d902SRodney W. Grimes break; 5329b50d902SRodney W. Grimes } 5339b50d902SRodney W. Grimes } 5349b50d902SRodney W. Grimes 5359b50d902SRodney W. Grimes /* 536acc9d408SJuli Mallett * expand_macro - user-defined macro expansion 5379b50d902SRodney W. Grimes */ 5389b50d902SRodney W. Grimes void 539bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc) 5409b50d902SRodney W. Grimes { 541acc9d408SJuli Mallett const char *t; 542acc9d408SJuli Mallett const char *p; 543acc9d408SJuli Mallett int n; 544acc9d408SJuli Mallett int argno; 5459b50d902SRodney W. Grimes 5469b50d902SRodney W. Grimes t = argv[0]; /* defn string as a whole */ 5479b50d902SRodney W. Grimes p = t; 5489b50d902SRodney W. Grimes while (*p) 5499b50d902SRodney W. Grimes p++; 5509b50d902SRodney W. Grimes p--; /* last character of defn */ 5519b50d902SRodney W. Grimes while (p > t) { 5529b50d902SRodney W. Grimes if (*(p - 1) != ARGFLAG) 553a841e1ebSBaptiste Daroussin PUSHBACK(*p); 5549b50d902SRodney W. Grimes else { 5559b50d902SRodney W. Grimes switch (*p) { 5569b50d902SRodney W. Grimes 5579b50d902SRodney W. Grimes case '#': 5589b50d902SRodney W. Grimes pbnum(argc - 2); 5599b50d902SRodney W. Grimes break; 5609b50d902SRodney W. Grimes case '0': 5619b50d902SRodney W. Grimes case '1': 5629b50d902SRodney W. Grimes case '2': 5639b50d902SRodney W. Grimes case '3': 5649b50d902SRodney W. Grimes case '4': 5659b50d902SRodney W. Grimes case '5': 5669b50d902SRodney W. Grimes case '6': 5679b50d902SRodney W. Grimes case '7': 5689b50d902SRodney W. Grimes case '8': 5699b50d902SRodney W. Grimes case '9': 5709b50d902SRodney W. Grimes if ((argno = *p - '0') < argc - 1) 5719b50d902SRodney W. Grimes pbstr(argv[argno + 1]); 5729b50d902SRodney W. Grimes break; 5739b50d902SRodney W. Grimes case '*': 574acc9d408SJuli Mallett if (argc > 2) { 5759b50d902SRodney W. Grimes for (n = argc - 1; n > 2; n--) { 5769b50d902SRodney W. Grimes pbstr(argv[n]); 577a841e1ebSBaptiste Daroussin pushback(COMMA); 5789b50d902SRodney W. Grimes } 5799b50d902SRodney W. Grimes pbstr(argv[2]); 580acc9d408SJuli Mallett } 5819b50d902SRodney W. Grimes break; 582232eaee6SJoerg Wunsch case '@': 583acc9d408SJuli Mallett if (argc > 2) { 584acc9d408SJuli Mallett for (n = argc - 1; n > 2; n--) { 585acc9d408SJuli Mallett pbstr(rquote); 586232eaee6SJoerg Wunsch pbstr(argv[n]); 587acc9d408SJuli Mallett pbstr(lquote); 588a841e1ebSBaptiste Daroussin pushback(COMMA); 589acc9d408SJuli Mallett } 590acc9d408SJuli Mallett pbstr(rquote); 591acc9d408SJuli Mallett pbstr(argv[2]); 592acc9d408SJuli Mallett pbstr(lquote); 593232eaee6SJoerg Wunsch } 594232eaee6SJoerg Wunsch break; 5959b50d902SRodney W. Grimes default: 596a841e1ebSBaptiste Daroussin PUSHBACK(*p); 597a841e1ebSBaptiste Daroussin PUSHBACK('$'); 5989b50d902SRodney W. Grimes break; 5999b50d902SRodney W. Grimes } 6009b50d902SRodney W. Grimes p--; 6019b50d902SRodney W. Grimes } 6029b50d902SRodney W. Grimes p--; 6039b50d902SRodney W. Grimes } 6049b50d902SRodney W. Grimes if (p == t) /* do last character */ 605a841e1ebSBaptiste Daroussin PUSHBACK(*p); 6069b50d902SRodney W. Grimes } 6079b50d902SRodney W. Grimes 608a841e1ebSBaptiste Daroussin 6099b50d902SRodney W. Grimes /* 6109b50d902SRodney W. Grimes * dodefine - install definition in the table 6119b50d902SRodney W. Grimes */ 6129b50d902SRodney W. Grimes void 613bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn) 6149b50d902SRodney W. Grimes { 615a841e1ebSBaptiste Daroussin if (!*name && !mimic_gnu) 616a841e1ebSBaptiste Daroussin m4errx(1, "null definition."); 6179b50d902SRodney W. Grimes else 618a841e1ebSBaptiste Daroussin macro_define(name, defn); 6199b50d902SRodney W. Grimes } 6209b50d902SRodney W. Grimes 6219b50d902SRodney W. Grimes /* 6229b50d902SRodney W. Grimes * dodefn - push back a quoted definition of 6239b50d902SRodney W. Grimes * the given name. 6249b50d902SRodney W. Grimes */ 625acc9d408SJuli Mallett static void 626bd2bfb58SJuli Mallett dodefn(const char *name) 6279b50d902SRodney W. Grimes { 628a841e1ebSBaptiste Daroussin struct macro_definition *p; 6299b50d902SRodney W. Grimes 630a841e1ebSBaptiste Daroussin if ((p = lookup_macro_definition(name)) != NULL) { 631a841e1ebSBaptiste Daroussin if ((p->type & TYPEMASK) == MACRTYPE) { 632acc9d408SJuli Mallett pbstr(rquote); 6339b50d902SRodney W. Grimes pbstr(p->defn); 634acc9d408SJuli Mallett pbstr(lquote); 635a841e1ebSBaptiste Daroussin } else { 636a841e1ebSBaptiste Daroussin pbstr(p->defn); 637acc9d408SJuli Mallett pbstr(BUILTIN_MARKER); 638acc9d408SJuli Mallett } 6399b50d902SRodney W. Grimes } 6409b50d902SRodney W. Grimes } 6419b50d902SRodney W. Grimes 6429b50d902SRodney W. Grimes /* 6439b50d902SRodney W. Grimes * dopushdef - install a definition in the hash table 6449b50d902SRodney W. Grimes * without removing a previous definition. Since 6459b50d902SRodney W. Grimes * each new entry is entered in *front* of the 6469b50d902SRodney W. Grimes * hash bucket, it hides a previous definition from 6479b50d902SRodney W. Grimes * lookup. 6489b50d902SRodney W. Grimes */ 649acc9d408SJuli Mallett static void 650bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn) 6519b50d902SRodney W. Grimes { 652a841e1ebSBaptiste Daroussin if (!*name && !mimic_gnu) 653a841e1ebSBaptiste Daroussin m4errx(1, "null definition."); 6549b50d902SRodney W. Grimes else 655a841e1ebSBaptiste Daroussin macro_pushdef(name, defn); 656acc9d408SJuli Mallett } 657acc9d408SJuli Mallett 658acc9d408SJuli Mallett /* 659acc9d408SJuli Mallett * dump_one_def - dump the specified definition. 660acc9d408SJuli Mallett */ 661acc9d408SJuli Mallett static void 662a841e1ebSBaptiste Daroussin dump_one_def(const char *name, struct macro_definition *p) 663acc9d408SJuli Mallett { 664a841e1ebSBaptiste Daroussin if (!traceout) 665a841e1ebSBaptiste Daroussin traceout = stderr; 666acc9d408SJuli Mallett if (mimic_gnu) { 667acc9d408SJuli Mallett if ((p->type & TYPEMASK) == MACRTYPE) 668a841e1ebSBaptiste Daroussin fprintf(traceout, "%s:\t%s\n", name, p->defn); 669acc9d408SJuli Mallett else { 670a841e1ebSBaptiste Daroussin fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 671acc9d408SJuli Mallett } 672acc9d408SJuli Mallett } else 673a841e1ebSBaptiste Daroussin fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 6749b50d902SRodney W. Grimes } 6759b50d902SRodney W. Grimes 6769b50d902SRodney W. Grimes /* 6779b50d902SRodney W. Grimes * dodumpdef - dump the specified definitions in the hash 6789b50d902SRodney W. Grimes * table to stderr. If nothing is specified, the entire 6799b50d902SRodney W. Grimes * hash table is dumped. 6809b50d902SRodney W. Grimes */ 681acc9d408SJuli Mallett static void 682bd2bfb58SJuli Mallett dodump(const char *argv[], int argc) 6839b50d902SRodney W. Grimes { 684acc9d408SJuli Mallett int n; 685a841e1ebSBaptiste Daroussin struct macro_definition *p; 6869b50d902SRodney W. Grimes 6879b50d902SRodney W. Grimes if (argc > 2) { 6889b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 689a841e1ebSBaptiste Daroussin if ((p = lookup_macro_definition(argv[n])) != NULL) 690a841e1ebSBaptiste Daroussin dump_one_def(argv[n], p); 691a841e1ebSBaptiste Daroussin } else 692a841e1ebSBaptiste Daroussin macro_for_all(dump_one_def); 6939b50d902SRodney W. Grimes } 6949b50d902SRodney W. Grimes 6959b50d902SRodney W. Grimes /* 696acc9d408SJuli Mallett * dotrace - mark some macros as traced/untraced depending upon on. 697acc9d408SJuli Mallett */ 698acc9d408SJuli Mallett static void 699bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on) 700acc9d408SJuli Mallett { 701acc9d408SJuli Mallett int n; 702acc9d408SJuli Mallett 703acc9d408SJuli Mallett if (argc > 2) { 704acc9d408SJuli Mallett for (n = 2; n < argc; n++) 705acc9d408SJuli Mallett mark_traced(argv[n], on); 706acc9d408SJuli Mallett } else 707acc9d408SJuli Mallett mark_traced(NULL, on); 708acc9d408SJuli Mallett } 709acc9d408SJuli Mallett 710acc9d408SJuli Mallett /* 7119b50d902SRodney W. Grimes * doifelse - select one of two alternatives - loop. 7129b50d902SRodney W. Grimes */ 713acc9d408SJuli Mallett static void 714bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc) 7159b50d902SRodney W. Grimes { 716e0f4e041SBaptiste Daroussin while (argc > 4) { 717e0f4e041SBaptiste Daroussin if (STREQ(argv[2], argv[3])) { 7189b50d902SRodney W. Grimes pbstr(argv[4]); 719e0f4e041SBaptiste Daroussin break; 720e0f4e041SBaptiste Daroussin } else if (argc == 6) { 7219b50d902SRodney W. Grimes pbstr(argv[5]); 722e0f4e041SBaptiste Daroussin break; 723e0f4e041SBaptiste Daroussin } else { 7249b50d902SRodney W. Grimes argv += 3; 7259b50d902SRodney W. Grimes argc -= 3; 7269b50d902SRodney W. Grimes } 7279b50d902SRodney W. Grimes } 7289b50d902SRodney W. Grimes } 7299b50d902SRodney W. Grimes 7309b50d902SRodney W. Grimes /* 7319b50d902SRodney W. Grimes * doinclude - include a given file. 7329b50d902SRodney W. Grimes */ 733acc9d408SJuli Mallett static int 734bd2bfb58SJuli Mallett doincl(const char *ifile) 7359b50d902SRodney W. Grimes { 7369b50d902SRodney W. Grimes if (ilevel + 1 == MAXINP) 737a841e1ebSBaptiste Daroussin m4errx(1, "too many include files."); 738acc9d408SJuli Mallett if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 7399b50d902SRodney W. Grimes ilevel++; 7409b50d902SRodney W. Grimes bbase[ilevel] = bufbase = bp; 7419b50d902SRodney W. Grimes return (1); 742acc9d408SJuli Mallett } else 7439b50d902SRodney W. Grimes return (0); 7449b50d902SRodney W. Grimes } 7459b50d902SRodney W. Grimes 7469b50d902SRodney W. Grimes #ifdef EXTENDED 7479b50d902SRodney W. Grimes /* 7489b50d902SRodney W. Grimes * dopaste - include a given file without any 7499b50d902SRodney W. Grimes * macro processing. 7509b50d902SRodney W. Grimes */ 751acc9d408SJuli Mallett static int 752bd2bfb58SJuli Mallett dopaste(const char *pfile) 7539b50d902SRodney W. Grimes { 7549b50d902SRodney W. Grimes FILE *pf; 755acc9d408SJuli Mallett int c; 7569b50d902SRodney W. Grimes 7579b50d902SRodney W. Grimes if ((pf = fopen(pfile, "r")) != NULL) { 758a841e1ebSBaptiste Daroussin if (synch_lines) 759b1ea3d46SJuli Mallett fprintf(active, "#line 1 \"%s\"\n", pfile); 7609b50d902SRodney W. Grimes while ((c = getc(pf)) != EOF) 7619b50d902SRodney W. Grimes putc(c, active); 7629b50d902SRodney W. Grimes (void) fclose(pf); 763a841e1ebSBaptiste Daroussin emit_synchline(); 7649b50d902SRodney W. Grimes return (1); 765acc9d408SJuli Mallett } else 7669b50d902SRodney W. Grimes return (0); 7679b50d902SRodney W. Grimes } 7689b50d902SRodney W. Grimes #endif 7699b50d902SRodney W. Grimes 7709b50d902SRodney W. Grimes /* 771acc9d408SJuli Mallett * dochq - change quote characters 7729b50d902SRodney W. Grimes */ 773acc9d408SJuli Mallett static void 774a841e1ebSBaptiste Daroussin dochq(const char *argv[], int ac) 7759b50d902SRodney W. Grimes { 776a841e1ebSBaptiste Daroussin if (ac == 2) { 777a841e1ebSBaptiste Daroussin lquote[0] = LQUOTE; lquote[1] = EOS; 778a841e1ebSBaptiste Daroussin rquote[0] = RQUOTE; rquote[1] = EOS; 779acc9d408SJuli Mallett } else { 780a841e1ebSBaptiste Daroussin strlcpy(lquote, argv[2], sizeof(lquote)); 781a841e1ebSBaptiste Daroussin if (ac > 3) { 782a841e1ebSBaptiste Daroussin strlcpy(rquote, argv[3], sizeof(rquote)); 783a841e1ebSBaptiste Daroussin } else { 784a841e1ebSBaptiste Daroussin rquote[0] = ECOMMT; rquote[1] = EOS; 785a841e1ebSBaptiste Daroussin } 786acc9d408SJuli Mallett } 787acc9d408SJuli Mallett } 788acc9d408SJuli Mallett 789acc9d408SJuli Mallett /* 790acc9d408SJuli Mallett * dochc - change comment characters 791acc9d408SJuli Mallett */ 792acc9d408SJuli Mallett static void 793bd2bfb58SJuli Mallett dochc(const char *argv[], int argc) 794acc9d408SJuli Mallett { 795a841e1ebSBaptiste Daroussin /* XXX Note that there is no difference between no argument and a single 796a841e1ebSBaptiste Daroussin * empty argument. 797a841e1ebSBaptiste Daroussin */ 798a841e1ebSBaptiste Daroussin if (argc == 2) { 799a841e1ebSBaptiste Daroussin scommt[0] = EOS; 800a841e1ebSBaptiste Daroussin ecommt[0] = EOS; 801a841e1ebSBaptiste Daroussin } else { 802acc9d408SJuli Mallett strlcpy(scommt, argv[2], sizeof(scommt)); 803a841e1ebSBaptiste Daroussin if (argc == 3) { 804a841e1ebSBaptiste Daroussin ecommt[0] = ECOMMT; ecommt[1] = EOS; 805a841e1ebSBaptiste Daroussin } else { 806acc9d408SJuli Mallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 8079b50d902SRodney W. Grimes } 808a841e1ebSBaptiste Daroussin } 809a841e1ebSBaptiste Daroussin } 810a841e1ebSBaptiste Daroussin 811a841e1ebSBaptiste Daroussin /* 812a841e1ebSBaptiste Daroussin * dom4wrap - expand text at EOF 813a841e1ebSBaptiste Daroussin */ 814a841e1ebSBaptiste Daroussin static void 815a841e1ebSBaptiste Daroussin dom4wrap(const char *text) 816a841e1ebSBaptiste Daroussin { 817a841e1ebSBaptiste Daroussin if (wrapindex >= maxwraps) { 818a841e1ebSBaptiste Daroussin if (maxwraps == 0) 819a841e1ebSBaptiste Daroussin maxwraps = 16; 8209b50d902SRodney W. Grimes else 821a841e1ebSBaptiste Daroussin maxwraps *= 2; 82288497f0cSBaptiste Daroussin m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps), 823a841e1ebSBaptiste Daroussin "too many m4wraps"); 8249b50d902SRodney W. Grimes } 825a841e1ebSBaptiste Daroussin m4wraps[wrapindex++] = xstrdup(text); 8269b50d902SRodney W. Grimes } 8279b50d902SRodney W. Grimes 8289b50d902SRodney W. Grimes /* 8299b50d902SRodney W. Grimes * dodivert - divert the output to a temporary file 8309b50d902SRodney W. Grimes */ 831acc9d408SJuli Mallett static void 832bd2bfb58SJuli Mallett dodiv(int n) 8339b50d902SRodney W. Grimes { 834acc9d408SJuli Mallett int fd; 835acc9d408SJuli Mallett 836ef2cea81SJonathan Lemon oindex = n; 837acc9d408SJuli Mallett if (n >= maxout) { 838acc9d408SJuli Mallett if (mimic_gnu) 839acc9d408SJuli Mallett resizedivs(n + 10); 840acc9d408SJuli Mallett else 841acc9d408SJuli Mallett n = 0; /* bitbucket */ 842acc9d408SJuli Mallett } 843acc9d408SJuli Mallett 844acc9d408SJuli Mallett if (n < 0) 8459b50d902SRodney W. Grimes n = 0; /* bitbucket */ 8469b50d902SRodney W. Grimes if (outfile[n] == NULL) { 847acc9d408SJuli Mallett char fname[] = _PATH_DIVNAME; 848acc9d408SJuli Mallett 849acc9d408SJuli Mallett if ((fd = mkstemp(fname)) < 0 || 85088497f0cSBaptiste Daroussin unlink(fname) == -1 || 851acc9d408SJuli Mallett (outfile[n] = fdopen(fd, "w+")) == NULL) 852acc9d408SJuli Mallett err(1, "%s: cannot divert", fname); 8539b50d902SRodney W. Grimes } 8549b50d902SRodney W. Grimes active = outfile[n]; 8559b50d902SRodney W. Grimes } 8569b50d902SRodney W. Grimes 8579b50d902SRodney W. Grimes /* 8589b50d902SRodney W. Grimes * doundivert - undivert a specified output, or all 8599b50d902SRodney W. Grimes * other outputs, in numerical order. 8609b50d902SRodney W. Grimes */ 861acc9d408SJuli Mallett static void 862bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc) 8639b50d902SRodney W. Grimes { 864acc9d408SJuli Mallett int ind; 865acc9d408SJuli Mallett int n; 8669b50d902SRodney W. Grimes 8679b50d902SRodney W. Grimes if (argc > 2) { 8689b50d902SRodney W. Grimes for (ind = 2; ind < argc; ind++) { 869a841e1ebSBaptiste Daroussin const char *errstr; 870a841e1ebSBaptiste Daroussin n = strtonum(argv[ind], 1, INT_MAX, &errstr); 871a841e1ebSBaptiste Daroussin if (errstr) { 872a841e1ebSBaptiste Daroussin if (errno == EINVAL && mimic_gnu) 873a841e1ebSBaptiste Daroussin getdivfile(argv[ind]); 874a841e1ebSBaptiste Daroussin } else { 875a841e1ebSBaptiste Daroussin if (n < maxout && outfile[n] != NULL) 8769b50d902SRodney W. Grimes getdiv(n); 877a841e1ebSBaptiste Daroussin } 8789b50d902SRodney W. Grimes } 8799b50d902SRodney W. Grimes } 8809b50d902SRodney W. Grimes else 881acc9d408SJuli Mallett for (n = 1; n < maxout; n++) 8829b50d902SRodney W. Grimes if (outfile[n] != NULL) 8839b50d902SRodney W. Grimes getdiv(n); 8849b50d902SRodney W. Grimes } 8859b50d902SRodney W. Grimes 8869b50d902SRodney W. Grimes /* 8879b50d902SRodney W. Grimes * dosub - select substring 8889b50d902SRodney W. Grimes */ 889acc9d408SJuli Mallett static void 890bd2bfb58SJuli Mallett dosub(const char *argv[], int argc) 8919b50d902SRodney W. Grimes { 892acc9d408SJuli Mallett const char *ap, *fc, *k; 893acc9d408SJuli Mallett int nc; 8949b50d902SRodney W. Grimes 8959b50d902SRodney W. Grimes ap = argv[2]; /* target string */ 8969b50d902SRodney W. Grimes #ifdef EXPR 8979b50d902SRodney W. Grimes fc = ap + expr(argv[3]); /* first char */ 8989b50d902SRodney W. Grimes #else 8999b50d902SRodney W. Grimes fc = ap + atoi(argv[3]); /* first char */ 9009b50d902SRodney W. Grimes #endif 9014ba4d387SGregory Neil Shapiro nc = strlen(fc); 902acc9d408SJuli Mallett if (argc >= 5) 9034ba4d387SGregory Neil Shapiro #ifdef EXPR 904acc9d408SJuli Mallett nc = min(nc, expr(argv[4])); 9054ba4d387SGregory Neil Shapiro #else 906acc9d408SJuli Mallett nc = min(nc, atoi(argv[4])); 9074ba4d387SGregory Neil Shapiro #endif 9089b50d902SRodney W. Grimes if (fc >= ap && fc < ap + strlen(ap)) 9094ba4d387SGregory Neil Shapiro for (k = fc + nc - 1; k >= fc; k--) 910a841e1ebSBaptiste Daroussin pushback(*k); 9119b50d902SRodney W. Grimes } 9129b50d902SRodney W. Grimes 9139b50d902SRodney W. Grimes /* 9149b50d902SRodney W. Grimes * map: 9159b50d902SRodney W. Grimes * map every character of s1 that is specified in from 9169b50d902SRodney W. Grimes * into s3 and replace in s. (source s1 remains untouched) 9179b50d902SRodney W. Grimes * 918a841e1ebSBaptiste Daroussin * This is derived from the a standard implementation of map(s,from,to) 919a841e1ebSBaptiste Daroussin * function of ICON language. Within mapvec, we replace every character 920a841e1ebSBaptiste Daroussin * of "from" with the corresponding character in "to". 921a841e1ebSBaptiste Daroussin * If "to" is shorter than "from", than the corresponding entries are null, 922af7ca7c8SPedro F. Giffuni * which means that those characters disappear altogether. 9239b50d902SRodney W. Grimes */ 924acc9d408SJuli Mallett static void 925bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to) 9269b50d902SRodney W. Grimes { 927acc9d408SJuli Mallett const char *tmp; 928acc9d408SJuli Mallett unsigned char sch, dch; 929acc9d408SJuli Mallett static char frombis[257]; 930acc9d408SJuli Mallett static char tobis[257]; 931a841e1ebSBaptiste Daroussin int i; 932a841e1ebSBaptiste Daroussin char seen[256]; 933acc9d408SJuli Mallett static unsigned char mapvec[256] = { 934acc9d408SJuli Mallett 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 935acc9d408SJuli Mallett 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 936acc9d408SJuli Mallett 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 937acc9d408SJuli Mallett 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 938acc9d408SJuli Mallett 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 939acc9d408SJuli Mallett 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 940acc9d408SJuli Mallett 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 941acc9d408SJuli Mallett 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 942acc9d408SJuli Mallett 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 943acc9d408SJuli Mallett 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 944acc9d408SJuli Mallett 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 945acc9d408SJuli Mallett 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 946acc9d408SJuli Mallett 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 947acc9d408SJuli Mallett 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 948acc9d408SJuli Mallett 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 949acc9d408SJuli Mallett 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 950acc9d408SJuli Mallett 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 951acc9d408SJuli Mallett 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 9529b50d902SRodney W. Grimes }; 9539b50d902SRodney W. Grimes 9549b50d902SRodney W. Grimes if (*src) { 955acc9d408SJuli Mallett if (mimic_gnu) { 956acc9d408SJuli Mallett /* 957acc9d408SJuli Mallett * expand character ranges on the fly 958acc9d408SJuli Mallett */ 959acc9d408SJuli Mallett from = handledash(frombis, frombis + 256, from); 960acc9d408SJuli Mallett to = handledash(tobis, tobis + 256, to); 961acc9d408SJuli Mallett } 9629b50d902SRodney W. Grimes tmp = from; 9639b50d902SRodney W. Grimes /* 9649b50d902SRodney W. Grimes * create a mapping between "from" and 9659b50d902SRodney W. Grimes * "to" 9669b50d902SRodney W. Grimes */ 967a841e1ebSBaptiste Daroussin for (i = 0; i < 256; i++) 968a841e1ebSBaptiste Daroussin seen[i] = 0; 969a841e1ebSBaptiste Daroussin while (*from) { 970a841e1ebSBaptiste Daroussin if (!seen[(unsigned char)(*from)]) { 971a841e1ebSBaptiste Daroussin mapvec[(unsigned char)(*from)] = (unsigned char)(*to); 972a841e1ebSBaptiste Daroussin seen[(unsigned char)(*from)] = 1; 973a841e1ebSBaptiste Daroussin } 974a841e1ebSBaptiste Daroussin from++; 975a841e1ebSBaptiste Daroussin if (*to) 976a841e1ebSBaptiste Daroussin to++; 977a841e1ebSBaptiste Daroussin } 9789b50d902SRodney W. Grimes 9799b50d902SRodney W. Grimes while (*src) { 980acc9d408SJuli Mallett sch = (unsigned char)(*src++); 9819b50d902SRodney W. Grimes dch = mapvec[sch]; 982acc9d408SJuli Mallett if ((*dest = (char)dch)) 9839b50d902SRodney W. Grimes dest++; 9849b50d902SRodney W. Grimes } 9859b50d902SRodney W. Grimes /* 9869b50d902SRodney W. Grimes * restore all the changed characters 9879b50d902SRodney W. Grimes */ 9889b50d902SRodney W. Grimes while (*tmp) { 989acc9d408SJuli Mallett mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 9909b50d902SRodney W. Grimes tmp++; 9919b50d902SRodney W. Grimes } 9929b50d902SRodney W. Grimes } 993acc9d408SJuli Mallett *dest = '\0'; 9949b50d902SRodney W. Grimes } 995acc9d408SJuli Mallett 996acc9d408SJuli Mallett 997acc9d408SJuli Mallett /* 998acc9d408SJuli Mallett * handledash: 999acc9d408SJuli Mallett * use buffer to copy the src string, expanding character ranges 1000acc9d408SJuli Mallett * on the way. 1001acc9d408SJuli Mallett */ 1002acc9d408SJuli Mallett static const char * 1003bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src) 1004acc9d408SJuli Mallett { 1005acc9d408SJuli Mallett char *p; 1006acc9d408SJuli Mallett 1007acc9d408SJuli Mallett p = buffer; 1008acc9d408SJuli Mallett while(*src) { 1009acc9d408SJuli Mallett if (src[1] == '-' && src[2]) { 1010acc9d408SJuli Mallett unsigned char i; 1011a841e1ebSBaptiste Daroussin if ((unsigned char)src[0] <= (unsigned char)src[2]) { 1012acc9d408SJuli Mallett for (i = (unsigned char)src[0]; 1013acc9d408SJuli Mallett i <= (unsigned char)src[2]; i++) { 1014acc9d408SJuli Mallett *p++ = i; 1015acc9d408SJuli Mallett if (p == end) { 1016acc9d408SJuli Mallett *p = '\0'; 1017acc9d408SJuli Mallett return buffer; 1018acc9d408SJuli Mallett } 1019acc9d408SJuli Mallett } 1020a841e1ebSBaptiste Daroussin } else { 1021a841e1ebSBaptiste Daroussin for (i = (unsigned char)src[0]; 1022a841e1ebSBaptiste Daroussin i >= (unsigned char)src[2]; i--) { 1023a841e1ebSBaptiste Daroussin *p++ = i; 1024a841e1ebSBaptiste Daroussin if (p == end) { 1025a841e1ebSBaptiste Daroussin *p = '\0'; 1026a841e1ebSBaptiste Daroussin return buffer; 1027a841e1ebSBaptiste Daroussin } 1028a841e1ebSBaptiste Daroussin } 1029a841e1ebSBaptiste Daroussin } 1030acc9d408SJuli Mallett src += 3; 1031acc9d408SJuli Mallett } else 1032acc9d408SJuli Mallett *p++ = *src++; 1033acc9d408SJuli Mallett if (p == end) 1034acc9d408SJuli Mallett break; 1035acc9d408SJuli Mallett } 1036acc9d408SJuli Mallett *p = '\0'; 1037acc9d408SJuli Mallett return buffer; 1038acc9d408SJuli Mallett } 1039