1bd2bfb58SJuli Mallett /* $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $ */ 2acc9d408SJuli Mallett /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 3acc9d408SJuli Mallett 49b50d902SRodney W. Grimes /* 59b50d902SRodney W. Grimes * Copyright (c) 1989, 1993 69b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 79b50d902SRodney W. Grimes * 89b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 99b50d902SRodney W. Grimes * Ozan Yigit at York University. 109b50d902SRodney W. Grimes * 119b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 129b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 139b50d902SRodney W. Grimes * are met: 149b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 159b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 169b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 179b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 189b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 199b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 209b50d902SRodney W. Grimes * must display the following acknowledgement: 219b50d902SRodney W. Grimes * This product includes software developed by the University of 229b50d902SRodney W. Grimes * California, Berkeley and its contributors. 239b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 249b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 259b50d902SRodney W. Grimes * without specific prior written permission. 269b50d902SRodney W. Grimes * 279b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 289b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 299b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 309b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 319b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 329b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 339b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 349b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 359b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 369b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 379b50d902SRodney W. Grimes * SUCH DAMAGE. 389b50d902SRodney W. Grimes */ 399b50d902SRodney W. Grimes 40acc9d408SJuli Mallett #include <sys/cdefs.h> 41acc9d408SJuli Mallett __SCCSID("@(#)eval.c 8.2 (Berkeley) 4/27/95"); 42bd2bfb58SJuli Mallett __RCSID_SOURCE("$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $"); 43acc9d408SJuli Mallett __FBSDID("$FreeBSD$"); 449b50d902SRodney W. Grimes 459b50d902SRodney W. Grimes /* 469b50d902SRodney W. Grimes * eval.c 479b50d902SRodney W. Grimes * Facility: m4 macro processor 489b50d902SRodney W. Grimes * by: oz 499b50d902SRodney W. Grimes */ 509b50d902SRodney W. Grimes 519b50d902SRodney W. Grimes #include <sys/types.h> 52acc9d408SJuli Mallett #include <errno.h> 53acc9d408SJuli Mallett #include <unistd.h> 549b50d902SRodney W. Grimes #include <stdio.h> 559b50d902SRodney W. Grimes #include <stdlib.h> 56acc9d408SJuli Mallett #include <stddef.h> 579b50d902SRodney W. Grimes #include <string.h> 58acc9d408SJuli Mallett #include <fcntl.h> 59acc9d408SJuli Mallett #include <err.h> 609b50d902SRodney W. Grimes #include "mdef.h" 619b50d902SRodney W. Grimes #include "stdd.h" 629b50d902SRodney W. Grimes #include "extern.h" 639b50d902SRodney W. Grimes #include "pathnames.h" 649b50d902SRodney W. Grimes 65acc9d408SJuli Mallett #define BUILTIN_MARKER "__builtin_" 66acc9d408SJuli Mallett 67acc9d408SJuli Mallett static void dodefn(const char *); 68acc9d408SJuli Mallett static void dopushdef(const char *, const char *); 69acc9d408SJuli Mallett static void dodump(const char *[], int); 70acc9d408SJuli Mallett static void dotrace(const char *[], int, int); 71acc9d408SJuli Mallett static void doifelse(const char *[], int); 72acc9d408SJuli Mallett static int doincl(const char *); 73acc9d408SJuli Mallett static int dopaste(const char *); 74acc9d408SJuli Mallett static void gnu_dochq(const char *[], int); 75acc9d408SJuli Mallett static void dochq(const char *[], int); 76acc9d408SJuli Mallett static void gnu_dochc(const char *[], int); 77acc9d408SJuli Mallett static void dochc(const char *[], int); 78acc9d408SJuli Mallett static void dodiv(int); 79acc9d408SJuli Mallett static void doundiv(const char *[], int); 80acc9d408SJuli Mallett static void dosub(const char *[], int); 81acc9d408SJuli Mallett static void map(char *, const char *, const char *, const char *); 82acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *); 83acc9d408SJuli Mallett static void expand_builtin(const char *[], int, int); 84acc9d408SJuli Mallett static void expand_macro(const char *[], int); 85acc9d408SJuli Mallett static void dump_one_def(ndptr); 86acc9d408SJuli Mallett 87acc9d408SJuli Mallett unsigned long expansion_id; 88acc9d408SJuli Mallett 899b50d902SRodney W. Grimes /* 90acc9d408SJuli Mallett * eval - eval all macros and builtins calls 919b50d902SRodney W. Grimes * argc - number of elements in argv. 929b50d902SRodney W. Grimes * argv - element vector : 939b50d902SRodney W. Grimes * argv[0] = definition of a user 949b50d902SRodney W. Grimes * macro or nil if built-in. 959b50d902SRodney W. Grimes * argv[1] = name of the macro or 969b50d902SRodney W. Grimes * built-in. 979b50d902SRodney W. Grimes * argv[2] = parameters to user-defined 989b50d902SRodney W. Grimes * . macro or built-in. 999b50d902SRodney W. Grimes * . 1009b50d902SRodney W. Grimes * 101acc9d408SJuli Mallett * A call in the form of macro-or-builtin() will result in: 1029b50d902SRodney W. Grimes * argv[0] = nullstr 1039b50d902SRodney W. Grimes * argv[1] = macro-or-builtin 1049b50d902SRodney W. Grimes * argv[2] = nullstr 105acc9d408SJuli Mallett * 106acc9d408SJuli Mallett * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 1079b50d902SRodney W. Grimes */ 1089b50d902SRodney W. Grimes void 109bd2bfb58SJuli Mallett eval(const char *argv[], int argc, int td) 1109b50d902SRodney W. Grimes { 111acc9d408SJuli Mallett ssize_t mark = -1; 112acc9d408SJuli Mallett 113acc9d408SJuli Mallett expansion_id++; 114acc9d408SJuli Mallett if (td & RECDEF) 115acc9d408SJuli Mallett errx(1, "%s at line %lu: expanding recursive definition for %s", 116acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[1]); 117acc9d408SJuli Mallett if (traced_macros && is_traced(argv[1])) 118acc9d408SJuli Mallett mark = trace(argv, argc, infile+ilevel); 119acc9d408SJuli Mallett if (td == MACRTYPE) 120acc9d408SJuli Mallett expand_macro(argv, argc); 121acc9d408SJuli Mallett else 122acc9d408SJuli Mallett expand_builtin(argv, argc, td); 123acc9d408SJuli Mallett if (mark != -1) 124acc9d408SJuli Mallett finish_trace(mark); 125acc9d408SJuli Mallett } 126acc9d408SJuli Mallett 127acc9d408SJuli Mallett /* 128acc9d408SJuli Mallett * expand_builtin - evaluate built-in macros. 129acc9d408SJuli Mallett */ 130acc9d408SJuli Mallett void 131bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td) 132acc9d408SJuli Mallett { 133acc9d408SJuli Mallett int c, n; 134acc9d408SJuli Mallett int ac; 1359b50d902SRodney W. Grimes static int sysval = 0; 1369b50d902SRodney W. Grimes 1379b50d902SRodney W. Grimes #ifdef DEBUG 1389b50d902SRodney W. Grimes printf("argc = %d\n", argc); 1399b50d902SRodney W. Grimes for (n = 0; n < argc; n++) 1409b50d902SRodney W. Grimes printf("argv[%d] = %s\n", n, argv[n]); 141acc9d408SJuli Mallett fflush(stdout); 1429b50d902SRodney W. Grimes #endif 143acc9d408SJuli Mallett 1449b50d902SRodney W. Grimes /* 1459b50d902SRodney W. Grimes * if argc == 3 and argv[2] is null, then we 1469b50d902SRodney W. Grimes * have macro-or-builtin() type call. We adjust 1479b50d902SRodney W. Grimes * argc to avoid further checking.. 1489b50d902SRodney W. Grimes */ 149acc9d408SJuli Mallett ac = argc; 150acc9d408SJuli Mallett 1519b50d902SRodney W. Grimes if (argc == 3 && !*(argv[2])) 1529b50d902SRodney W. Grimes argc--; 1539b50d902SRodney W. Grimes 154acc9d408SJuli Mallett switch (td & TYPEMASK) { 1559b50d902SRodney W. Grimes 1569b50d902SRodney W. Grimes case DEFITYPE: 1579b50d902SRodney W. Grimes if (argc > 2) 1589b50d902SRodney W. Grimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1599b50d902SRodney W. Grimes break; 1609b50d902SRodney W. Grimes 1619b50d902SRodney W. Grimes case PUSDTYPE: 1629b50d902SRodney W. Grimes if (argc > 2) 1639b50d902SRodney W. Grimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1649b50d902SRodney W. Grimes break; 1659b50d902SRodney W. Grimes 1669b50d902SRodney W. Grimes case DUMPTYPE: 1679b50d902SRodney W. Grimes dodump(argv, argc); 1689b50d902SRodney W. Grimes break; 1699b50d902SRodney W. Grimes 170acc9d408SJuli Mallett case TRACEONTYPE: 171acc9d408SJuli Mallett dotrace(argv, argc, 1); 172acc9d408SJuli Mallett break; 173acc9d408SJuli Mallett 174acc9d408SJuli Mallett case TRACEOFFTYPE: 175acc9d408SJuli Mallett dotrace(argv, argc, 0); 176acc9d408SJuli Mallett break; 177acc9d408SJuli Mallett 1789b50d902SRodney W. Grimes case EXPRTYPE: 1799b50d902SRodney W. Grimes /* 1809b50d902SRodney W. Grimes * doexpr - evaluate arithmetic 1819b50d902SRodney W. Grimes * expression 1829b50d902SRodney W. Grimes */ 1839b50d902SRodney W. Grimes if (argc > 2) 1849b50d902SRodney W. Grimes pbnum(expr(argv[2])); 1859b50d902SRodney W. Grimes break; 1869b50d902SRodney W. Grimes 1879b50d902SRodney W. Grimes case IFELTYPE: 1889b50d902SRodney W. Grimes if (argc > 4) 1899b50d902SRodney W. Grimes doifelse(argv, argc); 1909b50d902SRodney W. Grimes break; 1919b50d902SRodney W. Grimes 1929b50d902SRodney W. Grimes case IFDFTYPE: 1939b50d902SRodney W. Grimes /* 1949b50d902SRodney W. Grimes * doifdef - select one of two 1959b50d902SRodney W. Grimes * alternatives based on the existence of 1969b50d902SRodney W. Grimes * another definition 1979b50d902SRodney W. Grimes */ 1989b50d902SRodney W. Grimes if (argc > 3) { 1999b50d902SRodney W. Grimes if (lookup(argv[2]) != nil) 2009b50d902SRodney W. Grimes pbstr(argv[3]); 2019b50d902SRodney W. Grimes else if (argc > 4) 2029b50d902SRodney W. Grimes pbstr(argv[4]); 2039b50d902SRodney W. Grimes } 2049b50d902SRodney W. Grimes break; 2059b50d902SRodney W. Grimes 2069b50d902SRodney W. Grimes case LENGTYPE: 2079b50d902SRodney W. Grimes /* 2089b50d902SRodney W. Grimes * dolen - find the length of the 2099b50d902SRodney W. Grimes * argument 2109b50d902SRodney W. Grimes */ 2119b50d902SRodney W. Grimes pbnum((argc > 2) ? strlen(argv[2]) : 0); 2129b50d902SRodney W. Grimes break; 2139b50d902SRodney W. Grimes 2149b50d902SRodney W. Grimes case INCRTYPE: 2159b50d902SRodney W. Grimes /* 2169b50d902SRodney W. Grimes * doincr - increment the value of the 2179b50d902SRodney W. Grimes * argument 2189b50d902SRodney W. Grimes */ 2199b50d902SRodney W. Grimes if (argc > 2) 2209b50d902SRodney W. Grimes pbnum(atoi(argv[2]) + 1); 2219b50d902SRodney W. Grimes break; 2229b50d902SRodney W. Grimes 2239b50d902SRodney W. Grimes case DECRTYPE: 2249b50d902SRodney W. Grimes /* 2259b50d902SRodney W. Grimes * dodecr - decrement the value of the 2269b50d902SRodney W. Grimes * argument 2279b50d902SRodney W. Grimes */ 2289b50d902SRodney W. Grimes if (argc > 2) 2299b50d902SRodney W. Grimes pbnum(atoi(argv[2]) - 1); 2309b50d902SRodney W. Grimes break; 2319b50d902SRodney W. Grimes 2329b50d902SRodney W. Grimes case SYSCTYPE: 2339b50d902SRodney W. Grimes /* 2349b50d902SRodney W. Grimes * dosys - execute system command 2359b50d902SRodney W. Grimes */ 2369b50d902SRodney W. Grimes if (argc > 2) 2379b50d902SRodney W. Grimes sysval = system(argv[2]); 2389b50d902SRodney W. Grimes break; 2399b50d902SRodney W. Grimes 2409b50d902SRodney W. Grimes case SYSVTYPE: 2419b50d902SRodney W. Grimes /* 2429b50d902SRodney W. Grimes * dosysval - return value of the last 2439b50d902SRodney W. Grimes * system call. 2449b50d902SRodney W. Grimes * 2459b50d902SRodney W. Grimes */ 2469b50d902SRodney W. Grimes pbnum(sysval); 2479b50d902SRodney W. Grimes break; 2489b50d902SRodney W. Grimes 249acc9d408SJuli Mallett case ESYSCMDTYPE: 250acc9d408SJuli Mallett if (argc > 2) 251acc9d408SJuli Mallett doesyscmd(argv[2]); 252acc9d408SJuli Mallett break; 2539b50d902SRodney W. Grimes case INCLTYPE: 2549b50d902SRodney W. Grimes if (argc > 2) 2559b50d902SRodney W. Grimes if (!doincl(argv[2])) 256acc9d408SJuli Mallett err(1, "%s at line %lu: include(%s)", 257acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 2589b50d902SRodney W. Grimes break; 2599b50d902SRodney W. Grimes 2609b50d902SRodney W. Grimes case SINCTYPE: 2619b50d902SRodney W. Grimes if (argc > 2) 2629b50d902SRodney W. Grimes (void) doincl(argv[2]); 2639b50d902SRodney W. Grimes break; 2649b50d902SRodney W. Grimes #ifdef EXTENDED 2659b50d902SRodney W. Grimes case PASTTYPE: 2669b50d902SRodney W. Grimes if (argc > 2) 2679b50d902SRodney W. Grimes if (!dopaste(argv[2])) 268acc9d408SJuli Mallett err(1, "%s at line %lu: paste(%s)", 269acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 2709b50d902SRodney W. Grimes break; 2719b50d902SRodney W. Grimes 2729b50d902SRodney W. Grimes case SPASTYPE: 2739b50d902SRodney W. Grimes if (argc > 2) 2749b50d902SRodney W. Grimes (void) dopaste(argv[2]); 2759b50d902SRodney W. Grimes break; 2769b50d902SRodney W. Grimes #endif 2779b50d902SRodney W. Grimes case CHNQTYPE: 278acc9d408SJuli Mallett if (mimic_gnu) 279acc9d408SJuli Mallett gnu_dochq(argv, ac); 280acc9d408SJuli Mallett else 2819b50d902SRodney W. Grimes dochq(argv, argc); 2829b50d902SRodney W. Grimes break; 2839b50d902SRodney W. Grimes 2849b50d902SRodney W. Grimes case CHNCTYPE: 285acc9d408SJuli Mallett if (mimic_gnu) 286acc9d408SJuli Mallett gnu_dochc(argv, ac); 287acc9d408SJuli Mallett else 2889b50d902SRodney W. Grimes dochc(argv, argc); 2899b50d902SRodney W. Grimes break; 2909b50d902SRodney W. Grimes 2919b50d902SRodney W. Grimes case SUBSTYPE: 2929b50d902SRodney W. Grimes /* 2939b50d902SRodney W. Grimes * dosub - select substring 2949b50d902SRodney W. Grimes * 2959b50d902SRodney W. Grimes */ 2969b50d902SRodney W. Grimes if (argc > 3) 2979b50d902SRodney W. Grimes dosub(argv, argc); 2989b50d902SRodney W. Grimes break; 2999b50d902SRodney W. Grimes 3009b50d902SRodney W. Grimes case SHIFTYPE: 3019b50d902SRodney W. Grimes /* 3029b50d902SRodney W. Grimes * doshift - push back all arguments 3039b50d902SRodney W. Grimes * except the first one (i.e. skip 3049b50d902SRodney W. Grimes * argv[2]) 3059b50d902SRodney W. Grimes */ 3069b50d902SRodney W. Grimes if (argc > 3) { 3079b50d902SRodney W. Grimes for (n = argc - 1; n > 3; n--) { 308acc9d408SJuli Mallett pbstr(rquote); 3099b50d902SRodney W. Grimes pbstr(argv[n]); 310acc9d408SJuli Mallett pbstr(lquote); 311acc9d408SJuli Mallett putback(COMMA); 3129b50d902SRodney W. Grimes } 313acc9d408SJuli Mallett pbstr(rquote); 3149b50d902SRodney W. Grimes pbstr(argv[3]); 315acc9d408SJuli Mallett pbstr(lquote); 3169b50d902SRodney W. Grimes } 3179b50d902SRodney W. Grimes break; 3189b50d902SRodney W. Grimes 3199b50d902SRodney W. Grimes case DIVRTYPE: 3209b50d902SRodney W. Grimes if (argc > 2 && (n = atoi(argv[2])) != 0) 3219b50d902SRodney W. Grimes dodiv(n); 3229b50d902SRodney W. Grimes else { 3239b50d902SRodney W. Grimes active = stdout; 3249b50d902SRodney W. Grimes oindex = 0; 3259b50d902SRodney W. Grimes } 3269b50d902SRodney W. Grimes break; 3279b50d902SRodney W. Grimes 3289b50d902SRodney W. Grimes case UNDVTYPE: 3299b50d902SRodney W. Grimes doundiv(argv, argc); 3309b50d902SRodney W. Grimes break; 3319b50d902SRodney W. Grimes 3329b50d902SRodney W. Grimes case DIVNTYPE: 3339b50d902SRodney W. Grimes /* 3349b50d902SRodney W. Grimes * dodivnum - return the number of 3359b50d902SRodney W. Grimes * current output diversion 3369b50d902SRodney W. Grimes */ 3379b50d902SRodney W. Grimes pbnum(oindex); 3389b50d902SRodney W. Grimes break; 3399b50d902SRodney W. Grimes 3409b50d902SRodney W. Grimes case UNDFTYPE: 3419b50d902SRodney W. Grimes /* 3429b50d902SRodney W. Grimes * doundefine - undefine a previously 3439b50d902SRodney W. Grimes * defined macro(s) or m4 keyword(s). 3449b50d902SRodney W. Grimes */ 3459b50d902SRodney W. Grimes if (argc > 2) 3469b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 3479b50d902SRodney W. Grimes remhash(argv[n], ALL); 3489b50d902SRodney W. Grimes break; 3499b50d902SRodney W. Grimes 3509b50d902SRodney W. Grimes case POPDTYPE: 3519b50d902SRodney W. Grimes /* 3529b50d902SRodney W. Grimes * dopopdef - remove the topmost 3539b50d902SRodney W. Grimes * definitions of macro(s) or m4 3549b50d902SRodney W. Grimes * keyword(s). 3559b50d902SRodney W. Grimes */ 3569b50d902SRodney W. Grimes if (argc > 2) 3579b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 3589b50d902SRodney W. Grimes remhash(argv[n], TOP); 3599b50d902SRodney W. Grimes break; 3609b50d902SRodney W. Grimes 3619b50d902SRodney W. Grimes case MKTMTYPE: 3629b50d902SRodney W. Grimes /* 3639b50d902SRodney W. Grimes * dotemp - create a temporary file 3649b50d902SRodney W. Grimes */ 365acc9d408SJuli Mallett if (argc > 2) { 366acc9d408SJuli Mallett int fd; 367acc9d408SJuli Mallett char *temp; 368acc9d408SJuli Mallett 369acc9d408SJuli Mallett temp = xstrdup(argv[2]); 370acc9d408SJuli Mallett 371acc9d408SJuli Mallett fd = mkstemp(temp); 372acc9d408SJuli Mallett if (fd == -1) 373acc9d408SJuli Mallett err(1, 374acc9d408SJuli Mallett "%s at line %lu: couldn't make temp file %s", 375acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE, argv[2]); 376acc9d408SJuli Mallett close(fd); 377acc9d408SJuli Mallett pbstr(temp); 378acc9d408SJuli Mallett free(temp); 379acc9d408SJuli Mallett } 3809b50d902SRodney W. Grimes break; 3819b50d902SRodney W. Grimes 3829b50d902SRodney W. Grimes case TRNLTYPE: 3839b50d902SRodney W. Grimes /* 3849b50d902SRodney W. Grimes * dotranslit - replace all characters in 3859b50d902SRodney W. Grimes * the source string that appears in the 3869b50d902SRodney W. Grimes * "from" string with the corresponding 3879b50d902SRodney W. Grimes * characters in the "to" string. 3889b50d902SRodney W. Grimes */ 3899b50d902SRodney W. Grimes if (argc > 3) { 390acc9d408SJuli Mallett char *temp; 391acc9d408SJuli Mallett 392acc9d408SJuli Mallett temp = xalloc(strlen(argv[2])+1); 3939b50d902SRodney W. Grimes if (argc > 4) 3949b50d902SRodney W. Grimes map(temp, argv[2], argv[3], argv[4]); 3959b50d902SRodney W. Grimes else 3969b50d902SRodney W. Grimes map(temp, argv[2], argv[3], null); 3979b50d902SRodney W. Grimes pbstr(temp); 398acc9d408SJuli Mallett free(temp); 399acc9d408SJuli Mallett } else if (argc > 2) 4009b50d902SRodney W. Grimes pbstr(argv[2]); 4019b50d902SRodney W. Grimes break; 4029b50d902SRodney W. Grimes 4039b50d902SRodney W. Grimes case INDXTYPE: 4049b50d902SRodney W. Grimes /* 4059b50d902SRodney W. Grimes * doindex - find the index of the second 4069b50d902SRodney W. Grimes * argument string in the first argument 4079b50d902SRodney W. Grimes * string. -1 if not present. 4089b50d902SRodney W. Grimes */ 4099b50d902SRodney W. Grimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 4109b50d902SRodney W. Grimes break; 4119b50d902SRodney W. Grimes 4129b50d902SRodney W. Grimes case ERRPTYPE: 4139b50d902SRodney W. Grimes /* 4149b50d902SRodney W. Grimes * doerrp - print the arguments to stderr 4159b50d902SRodney W. Grimes * file 4169b50d902SRodney W. Grimes */ 4179b50d902SRodney W. Grimes if (argc > 2) { 4189b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 4199b50d902SRodney W. Grimes fprintf(stderr, "%s ", argv[n]); 4209b50d902SRodney W. Grimes fprintf(stderr, "\n"); 4219b50d902SRodney W. Grimes } 4229b50d902SRodney W. Grimes break; 4239b50d902SRodney W. Grimes 4249b50d902SRodney W. Grimes case DNLNTYPE: 4259b50d902SRodney W. Grimes /* 4269b50d902SRodney W. Grimes * dodnl - eat-up-to and including 4279b50d902SRodney W. Grimes * newline 4289b50d902SRodney W. Grimes */ 4299b50d902SRodney W. Grimes while ((c = gpbc()) != '\n' && c != EOF) 4309b50d902SRodney W. Grimes ; 4319b50d902SRodney W. Grimes break; 4329b50d902SRodney W. Grimes 4339b50d902SRodney W. Grimes case M4WRTYPE: 4349b50d902SRodney W. Grimes /* 4359b50d902SRodney W. Grimes * dom4wrap - set up for 4369b50d902SRodney W. Grimes * wrap-up/wind-down activity 4379b50d902SRodney W. Grimes */ 438acc9d408SJuli Mallett m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 4399b50d902SRodney W. Grimes break; 4409b50d902SRodney W. Grimes 4419b50d902SRodney W. Grimes case EXITTYPE: 4429b50d902SRodney W. Grimes /* 4439b50d902SRodney W. Grimes * doexit - immediate exit from m4. 4449b50d902SRodney W. Grimes */ 445cac6992aSAndrey A. Chernov killdiv(); 4469b50d902SRodney W. Grimes exit((argc > 2) ? atoi(argv[2]) : 0); 4479b50d902SRodney W. Grimes break; 4489b50d902SRodney W. Grimes 4499b50d902SRodney W. Grimes case DEFNTYPE: 4509b50d902SRodney W. Grimes if (argc > 2) 4519b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 4529b50d902SRodney W. Grimes dodefn(argv[n]); 4539b50d902SRodney W. Grimes break; 4549b50d902SRodney W. Grimes 455acc9d408SJuli Mallett case INDIRTYPE: /* Indirect call */ 456acc9d408SJuli Mallett if (argc > 2) 457acc9d408SJuli Mallett doindir(argv, argc); 458bbfd1447SSteve Price break; 459bbfd1447SSteve Price 460acc9d408SJuli Mallett case BUILTINTYPE: /* Builtins only */ 461acc9d408SJuli Mallett if (argc > 2) 462acc9d408SJuli Mallett dobuiltin(argv, argc); 463acc9d408SJuli Mallett break; 464acc9d408SJuli Mallett 465acc9d408SJuli Mallett case PATSTYPE: 466acc9d408SJuli Mallett if (argc > 2) 467acc9d408SJuli Mallett dopatsubst(argv, argc); 468acc9d408SJuli Mallett break; 469acc9d408SJuli Mallett case REGEXPTYPE: 470acc9d408SJuli Mallett if (argc > 2) 471acc9d408SJuli Mallett doregexp(argv, argc); 472acc9d408SJuli Mallett break; 473acc9d408SJuli Mallett case LINETYPE: 474acc9d408SJuli Mallett doprintlineno(infile+ilevel); 475acc9d408SJuli Mallett break; 476acc9d408SJuli Mallett case FILENAMETYPE: 477acc9d408SJuli Mallett doprintfilename(infile+ilevel); 478acc9d408SJuli Mallett break; 479acc9d408SJuli Mallett case SELFTYPE: 480acc9d408SJuli Mallett pbstr(rquote); 481acc9d408SJuli Mallett pbstr(argv[1]); 482acc9d408SJuli Mallett pbstr(lquote); 483acc9d408SJuli Mallett break; 4849b50d902SRodney W. Grimes default: 485acc9d408SJuli Mallett errx(1, "%s at line %lu: eval: major botch.", 486acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE); 4879b50d902SRodney W. Grimes break; 4889b50d902SRodney W. Grimes } 4899b50d902SRodney W. Grimes } 4909b50d902SRodney W. Grimes 4919b50d902SRodney W. Grimes /* 492acc9d408SJuli Mallett * expand_macro - user-defined macro expansion 4939b50d902SRodney W. Grimes */ 4949b50d902SRodney W. Grimes void 495bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc) 4969b50d902SRodney W. Grimes { 497acc9d408SJuli Mallett const char *t; 498acc9d408SJuli Mallett const char *p; 499acc9d408SJuli Mallett int n; 500acc9d408SJuli Mallett int argno; 5019b50d902SRodney W. Grimes 5029b50d902SRodney W. Grimes t = argv[0]; /* defn string as a whole */ 5039b50d902SRodney W. Grimes p = t; 5049b50d902SRodney W. Grimes while (*p) 5059b50d902SRodney W. Grimes p++; 5069b50d902SRodney W. Grimes p--; /* last character of defn */ 5079b50d902SRodney W. Grimes while (p > t) { 5089b50d902SRodney W. Grimes if (*(p - 1) != ARGFLAG) 509acc9d408SJuli Mallett PUTBACK(*p); 5109b50d902SRodney W. Grimes else { 5119b50d902SRodney W. Grimes switch (*p) { 5129b50d902SRodney W. Grimes 5139b50d902SRodney W. Grimes case '#': 5149b50d902SRodney W. Grimes pbnum(argc - 2); 5159b50d902SRodney W. Grimes break; 5169b50d902SRodney W. Grimes case '0': 5179b50d902SRodney W. Grimes case '1': 5189b50d902SRodney W. Grimes case '2': 5199b50d902SRodney W. Grimes case '3': 5209b50d902SRodney W. Grimes case '4': 5219b50d902SRodney W. Grimes case '5': 5229b50d902SRodney W. Grimes case '6': 5239b50d902SRodney W. Grimes case '7': 5249b50d902SRodney W. Grimes case '8': 5259b50d902SRodney W. Grimes case '9': 5269b50d902SRodney W. Grimes if ((argno = *p - '0') < argc - 1) 5279b50d902SRodney W. Grimes pbstr(argv[argno + 1]); 5289b50d902SRodney W. Grimes break; 5299b50d902SRodney W. Grimes case '*': 530acc9d408SJuli Mallett if (argc > 2) { 5319b50d902SRodney W. Grimes for (n = argc - 1; n > 2; n--) { 5329b50d902SRodney W. Grimes pbstr(argv[n]); 533acc9d408SJuli Mallett putback(COMMA); 5349b50d902SRodney W. Grimes } 5359b50d902SRodney W. Grimes pbstr(argv[2]); 536acc9d408SJuli Mallett } 5379b50d902SRodney W. Grimes break; 538232eaee6SJoerg Wunsch case '@': 539acc9d408SJuli Mallett if (argc > 2) { 540acc9d408SJuli Mallett for (n = argc - 1; n > 2; n--) { 541acc9d408SJuli Mallett pbstr(rquote); 542232eaee6SJoerg Wunsch pbstr(argv[n]); 543acc9d408SJuli Mallett pbstr(lquote); 544acc9d408SJuli Mallett putback(COMMA); 545acc9d408SJuli Mallett } 546acc9d408SJuli Mallett pbstr(rquote); 547acc9d408SJuli Mallett pbstr(argv[2]); 548acc9d408SJuli Mallett pbstr(lquote); 549232eaee6SJoerg Wunsch } 550232eaee6SJoerg Wunsch break; 5519b50d902SRodney W. Grimes default: 552acc9d408SJuli Mallett PUTBACK(*p); 553acc9d408SJuli Mallett PUTBACK('$'); 5549b50d902SRodney W. Grimes break; 5559b50d902SRodney W. Grimes } 5569b50d902SRodney W. Grimes p--; 5579b50d902SRodney W. Grimes } 5589b50d902SRodney W. Grimes p--; 5599b50d902SRodney W. Grimes } 5609b50d902SRodney W. Grimes if (p == t) /* do last character */ 561acc9d408SJuli Mallett PUTBACK(*p); 5629b50d902SRodney W. Grimes } 5639b50d902SRodney W. Grimes 5649b50d902SRodney W. Grimes /* 5659b50d902SRodney W. Grimes * dodefine - install definition in the table 5669b50d902SRodney W. Grimes */ 5679b50d902SRodney W. Grimes void 568bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn) 5699b50d902SRodney W. Grimes { 570acc9d408SJuli Mallett ndptr p; 571acc9d408SJuli Mallett int n; 5729b50d902SRodney W. Grimes 5739b50d902SRodney W. Grimes if (!*name) 574acc9d408SJuli Mallett errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 575acc9d408SJuli Mallett CURRENT_LINE); 5769b50d902SRodney W. Grimes if ((p = lookup(name)) == nil) 5779b50d902SRodney W. Grimes p = addent(name); 5789b50d902SRodney W. Grimes else if (p->defn != null) 5799b50d902SRodney W. Grimes free((char *) p->defn); 580acc9d408SJuli Mallett if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { 581acc9d408SJuli Mallett n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); 582acc9d408SJuli Mallett if (n != -1) { 583acc9d408SJuli Mallett p->type = n & TYPEMASK; 584acc9d408SJuli Mallett if ((n & NOARGS) == 0) 585acc9d408SJuli Mallett p->type |= NEEDARGS; 586ccc5b4e6SJuli Mallett p->defn = xstrdup(null); 587acc9d408SJuli Mallett return; 588acc9d408SJuli Mallett } 589acc9d408SJuli Mallett } 5909b50d902SRodney W. Grimes if (!*defn) 591ccc5b4e6SJuli Mallett p->defn = xstrdup(null); 5929b50d902SRodney W. Grimes else 593acc9d408SJuli Mallett p->defn = xstrdup(defn); 5949b50d902SRodney W. Grimes p->type = MACRTYPE; 595acc9d408SJuli Mallett if (STREQ(name, defn)) 596acc9d408SJuli Mallett p->type |= RECDEF; 5979b50d902SRodney W. Grimes } 5989b50d902SRodney W. Grimes 5999b50d902SRodney W. Grimes /* 6009b50d902SRodney W. Grimes * dodefn - push back a quoted definition of 6019b50d902SRodney W. Grimes * the given name. 6029b50d902SRodney W. Grimes */ 603acc9d408SJuli Mallett static void 604bd2bfb58SJuli Mallett dodefn(const char *name) 6059b50d902SRodney W. Grimes { 606acc9d408SJuli Mallett ndptr p; 607ccc5b4e6SJuli Mallett const char *real; 6089b50d902SRodney W. Grimes 609acc9d408SJuli Mallett if ((p = lookup(name)) != nil) { 610acc9d408SJuli Mallett if (p->defn != null) { 611acc9d408SJuli Mallett pbstr(rquote); 6129b50d902SRodney W. Grimes pbstr(p->defn); 613acc9d408SJuli Mallett pbstr(lquote); 614acc9d408SJuli Mallett } else if ((real = builtin_realname(p->type)) != NULL) { 615acc9d408SJuli Mallett pbstr(real); 616acc9d408SJuli Mallett pbstr(BUILTIN_MARKER); 617acc9d408SJuli Mallett } 6189b50d902SRodney W. Grimes } 6199b50d902SRodney W. Grimes } 6209b50d902SRodney W. Grimes 6219b50d902SRodney W. Grimes /* 6229b50d902SRodney W. Grimes * dopushdef - install a definition in the hash table 6239b50d902SRodney W. Grimes * without removing a previous definition. Since 6249b50d902SRodney W. Grimes * each new entry is entered in *front* of the 6259b50d902SRodney W. Grimes * hash bucket, it hides a previous definition from 6269b50d902SRodney W. Grimes * lookup. 6279b50d902SRodney W. Grimes */ 628acc9d408SJuli Mallett static void 629bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn) 6309b50d902SRodney W. Grimes { 631acc9d408SJuli Mallett ndptr p; 6329b50d902SRodney W. Grimes 6339b50d902SRodney W. Grimes if (!*name) 634acc9d408SJuli Mallett errx(1, "%s at line %lu: null definition", CURRENT_NAME, 635acc9d408SJuli Mallett CURRENT_LINE); 6369b50d902SRodney W. Grimes p = addent(name); 6379b50d902SRodney W. Grimes if (!*defn) 638ccc5b4e6SJuli Mallett p->defn = xstrdup(null); 6399b50d902SRodney W. Grimes else 640acc9d408SJuli Mallett p->defn = xstrdup(defn); 6419b50d902SRodney W. Grimes p->type = MACRTYPE; 642acc9d408SJuli Mallett if (STREQ(name, defn)) 643acc9d408SJuli Mallett p->type |= RECDEF; 644acc9d408SJuli Mallett } 645acc9d408SJuli Mallett 646acc9d408SJuli Mallett /* 647acc9d408SJuli Mallett * dump_one_def - dump the specified definition. 648acc9d408SJuli Mallett */ 649acc9d408SJuli Mallett static void 650bd2bfb58SJuli Mallett dump_one_def(ndptr p) 651acc9d408SJuli Mallett { 652ccc5b4e6SJuli Mallett const char *real; 653acc9d408SJuli Mallett 654acc9d408SJuli Mallett if (mimic_gnu) { 655acc9d408SJuli Mallett if ((p->type & TYPEMASK) == MACRTYPE) 656acc9d408SJuli Mallett fprintf(traceout, "%s:\t%s\n", p->name, p->defn); 657acc9d408SJuli Mallett else { 658acc9d408SJuli Mallett real = builtin_realname(p->type); 659acc9d408SJuli Mallett if (real == NULL) 660acc9d408SJuli Mallett real = null; 661acc9d408SJuli Mallett fprintf(traceout, "%s:\t<%s>\n", p->name, real); 662acc9d408SJuli Mallett } 663acc9d408SJuli Mallett } else 664acc9d408SJuli Mallett fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn); 6659b50d902SRodney W. Grimes } 6669b50d902SRodney W. Grimes 6679b50d902SRodney W. Grimes /* 6689b50d902SRodney W. Grimes * dodumpdef - dump the specified definitions in the hash 6699b50d902SRodney W. Grimes * table to stderr. If nothing is specified, the entire 6709b50d902SRodney W. Grimes * hash table is dumped. 6719b50d902SRodney W. Grimes */ 672acc9d408SJuli Mallett static void 673bd2bfb58SJuli Mallett dodump(const char *argv[], int argc) 6749b50d902SRodney W. Grimes { 675acc9d408SJuli Mallett int n; 6769b50d902SRodney W. Grimes ndptr p; 6779b50d902SRodney W. Grimes 6789b50d902SRodney W. Grimes if (argc > 2) { 6799b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 6809b50d902SRodney W. Grimes if ((p = lookup(argv[n])) != nil) 681acc9d408SJuli Mallett dump_one_def(p); 682acc9d408SJuli Mallett } else { 6839b50d902SRodney W. Grimes for (n = 0; n < HASHSIZE; n++) 6849b50d902SRodney W. Grimes for (p = hashtab[n]; p != nil; p = p->nxtptr) 685acc9d408SJuli Mallett dump_one_def(p); 6869b50d902SRodney W. Grimes } 6879b50d902SRodney W. Grimes } 6889b50d902SRodney W. Grimes 6899b50d902SRodney W. Grimes /* 690acc9d408SJuli Mallett * dotrace - mark some macros as traced/untraced depending upon on. 691acc9d408SJuli Mallett */ 692acc9d408SJuli Mallett static void 693bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on) 694acc9d408SJuli Mallett { 695acc9d408SJuli Mallett int n; 696acc9d408SJuli Mallett 697acc9d408SJuli Mallett if (argc > 2) { 698acc9d408SJuli Mallett for (n = 2; n < argc; n++) 699acc9d408SJuli Mallett mark_traced(argv[n], on); 700acc9d408SJuli Mallett } else 701acc9d408SJuli Mallett mark_traced(NULL, on); 702acc9d408SJuli Mallett } 703acc9d408SJuli Mallett 704acc9d408SJuli Mallett /* 7059b50d902SRodney W. Grimes * doifelse - select one of two alternatives - loop. 7069b50d902SRodney W. Grimes */ 707acc9d408SJuli Mallett static void 708bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc) 7099b50d902SRodney W. Grimes { 7109b50d902SRodney W. Grimes cycle { 7119b50d902SRodney W. Grimes if (STREQ(argv[2], argv[3])) 7129b50d902SRodney W. Grimes pbstr(argv[4]); 7139b50d902SRodney W. Grimes else if (argc == 6) 7149b50d902SRodney W. Grimes pbstr(argv[5]); 7159b50d902SRodney W. Grimes else if (argc > 6) { 7169b50d902SRodney W. Grimes argv += 3; 7179b50d902SRodney W. Grimes argc -= 3; 7189b50d902SRodney W. Grimes continue; 7199b50d902SRodney W. Grimes } 7209b50d902SRodney W. Grimes break; 7219b50d902SRodney W. Grimes } 7229b50d902SRodney W. Grimes } 7239b50d902SRodney W. Grimes 7249b50d902SRodney W. Grimes /* 7259b50d902SRodney W. Grimes * doinclude - include a given file. 7269b50d902SRodney W. Grimes */ 727acc9d408SJuli Mallett static int 728bd2bfb58SJuli Mallett doincl(const char *ifile) 7299b50d902SRodney W. Grimes { 7309b50d902SRodney W. Grimes if (ilevel + 1 == MAXINP) 731acc9d408SJuli Mallett errx(1, "%s at line %lu: too many include files.", 732acc9d408SJuli Mallett CURRENT_NAME, CURRENT_LINE); 733acc9d408SJuli Mallett if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 7349b50d902SRodney W. Grimes ilevel++; 735b1ea3d46SJuli Mallett if ((inname[ilevel] = strdup(ifile)) == NULL) 736b1ea3d46SJuli Mallett err(1, NULL); 737b1ea3d46SJuli Mallett inlineno[ilevel] = 1; 7389b50d902SRodney W. Grimes bbase[ilevel] = bufbase = bp; 739b1ea3d46SJuli Mallett emitline(); 7409b50d902SRodney W. Grimes return (1); 741acc9d408SJuli Mallett } else 7429b50d902SRodney W. Grimes return (0); 7439b50d902SRodney W. Grimes } 7449b50d902SRodney W. Grimes 7459b50d902SRodney W. Grimes #ifdef EXTENDED 7469b50d902SRodney W. Grimes /* 7479b50d902SRodney W. Grimes * dopaste - include a given file without any 7489b50d902SRodney W. Grimes * macro processing. 7499b50d902SRodney W. Grimes */ 750acc9d408SJuli Mallett static int 751bd2bfb58SJuli Mallett dopaste(const char *pfile) 7529b50d902SRodney W. Grimes { 7539b50d902SRodney W. Grimes FILE *pf; 754acc9d408SJuli Mallett int c; 7559b50d902SRodney W. Grimes 7569b50d902SRodney W. Grimes if ((pf = fopen(pfile, "r")) != NULL) { 757b1ea3d46SJuli Mallett fprintf(active, "#line 1 \"%s\"\n", pfile); 7589b50d902SRodney W. Grimes while ((c = getc(pf)) != EOF) 7599b50d902SRodney W. Grimes putc(c, active); 7609b50d902SRodney W. Grimes (void) fclose(pf); 761b1ea3d46SJuli Mallett emitline(); 7629b50d902SRodney W. Grimes return (1); 763acc9d408SJuli Mallett } else 7649b50d902SRodney W. Grimes return (0); 7659b50d902SRodney W. Grimes } 7669b50d902SRodney W. Grimes #endif 7679b50d902SRodney W. Grimes 768acc9d408SJuli Mallett static void 769bd2bfb58SJuli Mallett gnu_dochq(const char *argv[], int ac) 7709b50d902SRodney W. Grimes { 771acc9d408SJuli Mallett /* In gnu-m4 mode, the only way to restore quotes is to have no 772acc9d408SJuli Mallett * arguments at all. */ 773acc9d408SJuli Mallett if (ac == 2) { 774acc9d408SJuli Mallett lquote[0] = LQUOTE, lquote[1] = EOS; 775acc9d408SJuli Mallett rquote[0] = RQUOTE, rquote[1] = EOS; 776acc9d408SJuli Mallett } else { 777acc9d408SJuli Mallett strlcpy(lquote, argv[2], sizeof(lquote)); 778acc9d408SJuli Mallett if(ac > 3) 779acc9d408SJuli Mallett strlcpy(rquote, argv[3], sizeof(rquote)); 780ef2cea81SJonathan Lemon else 781acc9d408SJuli Mallett rquote[0] = EOS; 7829b50d902SRodney W. Grimes } 7839b50d902SRodney W. Grimes } 7849b50d902SRodney W. Grimes 7859b50d902SRodney W. Grimes /* 786acc9d408SJuli Mallett * dochq - change quote characters 7879b50d902SRodney W. Grimes */ 788acc9d408SJuli Mallett static void 789bd2bfb58SJuli Mallett dochq(const char *argv[], int argc) 7909b50d902SRodney W. Grimes { 7919b50d902SRodney W. Grimes if (argc > 2) { 7929b50d902SRodney W. Grimes if (*argv[2]) 793acc9d408SJuli Mallett strlcpy(lquote, argv[2], sizeof(lquote)); 794acc9d408SJuli Mallett else { 795acc9d408SJuli Mallett lquote[0] = LQUOTE; 796acc9d408SJuli Mallett lquote[1] = EOS; 797acc9d408SJuli Mallett } 7989b50d902SRodney W. Grimes if (argc > 3) { 7999b50d902SRodney W. Grimes if (*argv[3]) 800acc9d408SJuli Mallett strlcpy(rquote, argv[3], sizeof(rquote)); 801acc9d408SJuli Mallett } else 802acc9d408SJuli Mallett strcpy(rquote, lquote); 803acc9d408SJuli Mallett } else { 804acc9d408SJuli Mallett lquote[0] = LQUOTE, lquote[1] = EOS; 805acc9d408SJuli Mallett rquote[0] = RQUOTE, rquote[1] = EOS; 806acc9d408SJuli Mallett } 807acc9d408SJuli Mallett } 808acc9d408SJuli Mallett 809acc9d408SJuli Mallett static void 810bd2bfb58SJuli Mallett gnu_dochc(const char *argv[], int ac) 811acc9d408SJuli Mallett { 812acc9d408SJuli Mallett /* In gnu-m4 mode, no arguments mean no comment 813acc9d408SJuli Mallett * arguments at all. */ 814acc9d408SJuli Mallett if (ac == 2) { 815acc9d408SJuli Mallett scommt[0] = EOS; 816acc9d408SJuli Mallett ecommt[0] = EOS; 817acc9d408SJuli Mallett } else { 818acc9d408SJuli Mallett if (*argv[2]) 819acc9d408SJuli Mallett strlcpy(scommt, argv[2], sizeof(scommt)); 820acc9d408SJuli Mallett else 821acc9d408SJuli Mallett scommt[0] = SCOMMT, scommt[1] = EOS; 822acc9d408SJuli Mallett if(ac > 3 && *argv[3]) 823acc9d408SJuli Mallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 824acc9d408SJuli Mallett else 825acc9d408SJuli Mallett ecommt[0] = ECOMMT, ecommt[1] = EOS; 826acc9d408SJuli Mallett } 827acc9d408SJuli Mallett } 828acc9d408SJuli Mallett /* 829acc9d408SJuli Mallett * dochc - change comment characters 830acc9d408SJuli Mallett */ 831acc9d408SJuli Mallett static void 832bd2bfb58SJuli Mallett dochc(const char *argv[], int argc) 833acc9d408SJuli Mallett { 834acc9d408SJuli Mallett if (argc > 2) { 835acc9d408SJuli Mallett if (*argv[2]) 836acc9d408SJuli Mallett strlcpy(scommt, argv[2], sizeof(scommt)); 837acc9d408SJuli Mallett if (argc > 3) { 838acc9d408SJuli Mallett if (*argv[3]) 839acc9d408SJuli Mallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 8409b50d902SRodney W. Grimes } 8419b50d902SRodney W. Grimes else 842acc9d408SJuli Mallett ecommt[0] = ECOMMT, ecommt[1] = EOS; 8439b50d902SRodney W. Grimes } 8449b50d902SRodney W. Grimes else { 845acc9d408SJuli Mallett scommt[0] = SCOMMT, scommt[1] = EOS; 846acc9d408SJuli Mallett ecommt[0] = ECOMMT, ecommt[1] = EOS; 8479b50d902SRodney W. Grimes } 8489b50d902SRodney W. Grimes } 8499b50d902SRodney W. Grimes 8509b50d902SRodney W. Grimes /* 8519b50d902SRodney W. Grimes * dodivert - divert the output to a temporary file 8529b50d902SRodney W. Grimes */ 853acc9d408SJuli Mallett static void 854bd2bfb58SJuli Mallett dodiv(int n) 8559b50d902SRodney W. Grimes { 856acc9d408SJuli Mallett int fd; 857acc9d408SJuli Mallett 858ef2cea81SJonathan Lemon oindex = n; 859acc9d408SJuli Mallett if (n >= maxout) { 860acc9d408SJuli Mallett if (mimic_gnu) 861acc9d408SJuli Mallett resizedivs(n + 10); 862acc9d408SJuli Mallett else 863acc9d408SJuli Mallett n = 0; /* bitbucket */ 864acc9d408SJuli Mallett } 865acc9d408SJuli Mallett 866acc9d408SJuli Mallett if (n < 0) 8679b50d902SRodney W. Grimes n = 0; /* bitbucket */ 8689b50d902SRodney W. Grimes if (outfile[n] == NULL) { 869acc9d408SJuli Mallett char fname[] = _PATH_DIVNAME; 870acc9d408SJuli Mallett 871acc9d408SJuli Mallett if ((fd = mkstemp(fname)) < 0 || 872acc9d408SJuli Mallett (outfile[n] = fdopen(fd, "w+")) == NULL) 873acc9d408SJuli Mallett err(1, "%s: cannot divert", fname); 874acc9d408SJuli Mallett if (unlink(fname) == -1) 875acc9d408SJuli Mallett err(1, "%s: cannot unlink", fname); 8769b50d902SRodney W. Grimes } 8779b50d902SRodney W. Grimes active = outfile[n]; 8789b50d902SRodney W. Grimes } 8799b50d902SRodney W. Grimes 8809b50d902SRodney W. Grimes /* 8819b50d902SRodney W. Grimes * doundivert - undivert a specified output, or all 8829b50d902SRodney W. Grimes * other outputs, in numerical order. 8839b50d902SRodney W. Grimes */ 884acc9d408SJuli Mallett static void 885bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc) 8869b50d902SRodney W. Grimes { 887acc9d408SJuli Mallett int ind; 888acc9d408SJuli Mallett int n; 8899b50d902SRodney W. Grimes 8909b50d902SRodney W. Grimes if (argc > 2) { 8919b50d902SRodney W. Grimes for (ind = 2; ind < argc; ind++) { 8929b50d902SRodney W. Grimes n = atoi(argv[ind]); 893acc9d408SJuli Mallett if (n > 0 && n < maxout && outfile[n] != NULL) 8949b50d902SRodney W. Grimes getdiv(n); 8959b50d902SRodney W. Grimes 8969b50d902SRodney W. Grimes } 8979b50d902SRodney W. Grimes } 8989b50d902SRodney W. Grimes else 899acc9d408SJuli Mallett for (n = 1; n < maxout; n++) 9009b50d902SRodney W. Grimes if (outfile[n] != NULL) 9019b50d902SRodney W. Grimes getdiv(n); 9029b50d902SRodney W. Grimes } 9039b50d902SRodney W. Grimes 9049b50d902SRodney W. Grimes /* 9059b50d902SRodney W. Grimes * dosub - select substring 9069b50d902SRodney W. Grimes */ 907acc9d408SJuli Mallett static void 908bd2bfb58SJuli Mallett dosub(const char *argv[], int argc) 9099b50d902SRodney W. Grimes { 910acc9d408SJuli Mallett const char *ap, *fc, *k; 911acc9d408SJuli Mallett int nc; 9129b50d902SRodney W. Grimes 9139b50d902SRodney W. Grimes ap = argv[2]; /* target string */ 9149b50d902SRodney W. Grimes #ifdef EXPR 9159b50d902SRodney W. Grimes fc = ap + expr(argv[3]); /* first char */ 9169b50d902SRodney W. Grimes #else 9179b50d902SRodney W. Grimes fc = ap + atoi(argv[3]); /* first char */ 9189b50d902SRodney W. Grimes #endif 9194ba4d387SGregory Neil Shapiro nc = strlen(fc); 920acc9d408SJuli Mallett if (argc >= 5) 9214ba4d387SGregory Neil Shapiro #ifdef EXPR 922acc9d408SJuli Mallett nc = min(nc, expr(argv[4])); 9234ba4d387SGregory Neil Shapiro #else 924acc9d408SJuli Mallett nc = min(nc, atoi(argv[4])); 9254ba4d387SGregory Neil Shapiro #endif 9269b50d902SRodney W. Grimes if (fc >= ap && fc < ap + strlen(ap)) 9274ba4d387SGregory Neil Shapiro for (k = fc + nc - 1; k >= fc; k--) 9289b50d902SRodney W. Grimes putback(*k); 9299b50d902SRodney W. Grimes } 9309b50d902SRodney W. Grimes 9319b50d902SRodney W. Grimes /* 9329b50d902SRodney W. Grimes * map: 9339b50d902SRodney W. Grimes * map every character of s1 that is specified in from 9349b50d902SRodney W. Grimes * into s3 and replace in s. (source s1 remains untouched) 9359b50d902SRodney W. Grimes * 9369b50d902SRodney W. Grimes * This is a standard implementation of map(s,from,to) function of ICON 9379b50d902SRodney W. Grimes * language. Within mapvec, we replace every character of "from" with 9389b50d902SRodney W. Grimes * the corresponding character in "to". If "to" is shorter than "from", 9399b50d902SRodney W. Grimes * than the corresponding entries are null, which means that those 9409b50d902SRodney W. Grimes * characters dissapear altogether. Furthermore, imagine 9419b50d902SRodney W. Grimes * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 9429b50d902SRodney W. Grimes * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 9439b50d902SRodney W. Grimes * ultimately maps to `*'. In order to achieve this effect in an efficient 9449b50d902SRodney W. Grimes * manner (i.e. without multiple passes over the destination string), we 9459b50d902SRodney W. Grimes * loop over mapvec, starting with the initial source character. if the 9469b50d902SRodney W. Grimes * character value (dch) in this location is different than the source 9479b50d902SRodney W. Grimes * character (sch), sch becomes dch, once again to index into mapvec, until 9489b50d902SRodney W. Grimes * the character value stabilizes (i.e. sch = dch, in other words 9499b50d902SRodney W. Grimes * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 9509b50d902SRodney W. Grimes * character, it will stabilize, since mapvec[0] == 0 at all times. At the 9519b50d902SRodney W. Grimes * end, we restore mapvec* back to normal where mapvec[n] == n for 9529b50d902SRodney W. Grimes * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 9539b50d902SRodney W. Grimes * about 5 times faster than any algorithm that makes multiple passes over 9549b50d902SRodney W. Grimes * destination string. 9559b50d902SRodney W. Grimes */ 956acc9d408SJuli Mallett static void 957bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to) 9589b50d902SRodney W. Grimes { 959acc9d408SJuli Mallett const char *tmp; 960acc9d408SJuli Mallett unsigned char sch, dch; 961acc9d408SJuli Mallett static char frombis[257]; 962acc9d408SJuli Mallett static char tobis[257]; 963acc9d408SJuli Mallett static unsigned char mapvec[256] = { 964acc9d408SJuli Mallett 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 965acc9d408SJuli Mallett 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 966acc9d408SJuli Mallett 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 967acc9d408SJuli Mallett 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 968acc9d408SJuli Mallett 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 969acc9d408SJuli Mallett 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 970acc9d408SJuli Mallett 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 971acc9d408SJuli Mallett 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 972acc9d408SJuli Mallett 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 973acc9d408SJuli Mallett 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 974acc9d408SJuli Mallett 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 975acc9d408SJuli Mallett 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 976acc9d408SJuli Mallett 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 977acc9d408SJuli Mallett 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 978acc9d408SJuli Mallett 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 979acc9d408SJuli Mallett 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 980acc9d408SJuli Mallett 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 981acc9d408SJuli Mallett 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 9829b50d902SRodney W. Grimes }; 9839b50d902SRodney W. Grimes 9849b50d902SRodney W. Grimes if (*src) { 985acc9d408SJuli Mallett if (mimic_gnu) { 986acc9d408SJuli Mallett /* 987acc9d408SJuli Mallett * expand character ranges on the fly 988acc9d408SJuli Mallett */ 989acc9d408SJuli Mallett from = handledash(frombis, frombis + 256, from); 990acc9d408SJuli Mallett to = handledash(tobis, tobis + 256, to); 991acc9d408SJuli Mallett } 9929b50d902SRodney W. Grimes tmp = from; 9939b50d902SRodney W. Grimes /* 9949b50d902SRodney W. Grimes * create a mapping between "from" and 9959b50d902SRodney W. Grimes * "to" 9969b50d902SRodney W. Grimes */ 9979b50d902SRodney W. Grimes while (*from) 998acc9d408SJuli Mallett mapvec[(unsigned char)(*from++)] = (*to) ? 999acc9d408SJuli Mallett (unsigned char)(*to++) : 0; 10009b50d902SRodney W. Grimes 10019b50d902SRodney W. Grimes while (*src) { 1002acc9d408SJuli Mallett sch = (unsigned char)(*src++); 10039b50d902SRodney W. Grimes dch = mapvec[sch]; 10049b50d902SRodney W. Grimes while (dch != sch) { 10059b50d902SRodney W. Grimes sch = dch; 10069b50d902SRodney W. Grimes dch = mapvec[sch]; 10079b50d902SRodney W. Grimes } 1008acc9d408SJuli Mallett if ((*dest = (char)dch)) 10099b50d902SRodney W. Grimes dest++; 10109b50d902SRodney W. Grimes } 10119b50d902SRodney W. Grimes /* 10129b50d902SRodney W. Grimes * restore all the changed characters 10139b50d902SRodney W. Grimes */ 10149b50d902SRodney W. Grimes while (*tmp) { 1015acc9d408SJuli Mallett mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 10169b50d902SRodney W. Grimes tmp++; 10179b50d902SRodney W. Grimes } 10189b50d902SRodney W. Grimes } 1019acc9d408SJuli Mallett *dest = '\0'; 10209b50d902SRodney W. Grimes } 1021acc9d408SJuli Mallett 1022acc9d408SJuli Mallett 1023acc9d408SJuli Mallett /* 1024acc9d408SJuli Mallett * handledash: 1025acc9d408SJuli Mallett * use buffer to copy the src string, expanding character ranges 1026acc9d408SJuli Mallett * on the way. 1027acc9d408SJuli Mallett */ 1028acc9d408SJuli Mallett static const char * 1029bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src) 1030acc9d408SJuli Mallett { 1031acc9d408SJuli Mallett char *p; 1032acc9d408SJuli Mallett 1033acc9d408SJuli Mallett p = buffer; 1034acc9d408SJuli Mallett while(*src) { 1035acc9d408SJuli Mallett if (src[1] == '-' && src[2]) { 1036acc9d408SJuli Mallett unsigned char i; 1037acc9d408SJuli Mallett for (i = (unsigned char)src[0]; 1038acc9d408SJuli Mallett i <= (unsigned char)src[2]; i++) { 1039acc9d408SJuli Mallett *p++ = i; 1040acc9d408SJuli Mallett if (p == end) { 1041acc9d408SJuli Mallett *p = '\0'; 1042acc9d408SJuli Mallett return buffer; 1043acc9d408SJuli Mallett } 1044acc9d408SJuli Mallett } 1045acc9d408SJuli Mallett src += 3; 1046acc9d408SJuli Mallett } else 1047acc9d408SJuli Mallett *p++ = *src++; 1048acc9d408SJuli Mallett if (p == end) 1049acc9d408SJuli Mallett break; 1050acc9d408SJuli Mallett } 1051acc9d408SJuli Mallett *p = '\0'; 1052acc9d408SJuli Mallett return buffer; 1053acc9d408SJuli Mallett } 1054