19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1989, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 69b50d902SRodney W. Grimes * Ozan Yigit at York University. 79b50d902SRodney W. Grimes * 89b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 99b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 109b50d902SRodney W. Grimes * are met: 119b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 129b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 139b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 159b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 169b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 179b50d902SRodney W. Grimes * must display the following acknowledgement: 189b50d902SRodney W. Grimes * This product includes software developed by the University of 199b50d902SRodney W. Grimes * California, Berkeley and its contributors. 209b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 219b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 229b50d902SRodney W. Grimes * without specific prior written permission. 239b50d902SRodney W. Grimes * 249b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 259b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 269b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 279b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 289b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 299b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 309b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 319b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 329b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 339b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349b50d902SRodney W. Grimes * SUCH DAMAGE. 359b50d902SRodney W. Grimes */ 369b50d902SRodney W. Grimes 379b50d902SRodney W. Grimes #ifndef lint 389b50d902SRodney W. Grimes static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; 399b50d902SRodney W. Grimes #endif /* not lint */ 409b50d902SRodney W. Grimes 419b50d902SRodney W. Grimes /* 429b50d902SRodney W. Grimes * eval.c 439b50d902SRodney W. Grimes * Facility: m4 macro processor 449b50d902SRodney W. Grimes * by: oz 459b50d902SRodney W. Grimes */ 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes #include <sys/types.h> 489b50d902SRodney W. Grimes #include <errno.h> 499b50d902SRodney W. Grimes #include <unistd.h> 509b50d902SRodney W. Grimes #include <stdio.h> 519b50d902SRodney W. Grimes #include <stdlib.h> 529b50d902SRodney W. Grimes #include <string.h> 539b50d902SRodney W. Grimes #include "mdef.h" 549b50d902SRodney W. Grimes #include "stdd.h" 559b50d902SRodney W. Grimes #include "extern.h" 569b50d902SRodney W. Grimes #include "pathnames.h" 579b50d902SRodney W. Grimes 589b50d902SRodney W. Grimes /* 599b50d902SRodney W. Grimes * eval - evaluate built-in macros. 609b50d902SRodney W. Grimes * argc - number of elements in argv. 619b50d902SRodney W. Grimes * argv - element vector : 629b50d902SRodney W. Grimes * argv[0] = definition of a user 639b50d902SRodney W. Grimes * macro or nil if built-in. 649b50d902SRodney W. Grimes * argv[1] = name of the macro or 659b50d902SRodney W. Grimes * built-in. 669b50d902SRodney W. Grimes * argv[2] = parameters to user-defined 679b50d902SRodney W. Grimes * . macro or built-in. 689b50d902SRodney W. Grimes * . 699b50d902SRodney W. Grimes * 709b50d902SRodney W. Grimes * Note that the minimum value for argc is 3. A call in the form 719b50d902SRodney W. Grimes * of macro-or-builtin() will result in: 729b50d902SRodney W. Grimes * argv[0] = nullstr 739b50d902SRodney W. Grimes * argv[1] = macro-or-builtin 749b50d902SRodney W. Grimes * argv[2] = nullstr 759b50d902SRodney W. Grimes */ 769b50d902SRodney W. Grimes 779b50d902SRodney W. Grimes void 789b50d902SRodney W. Grimes eval(argv, argc, td) 799b50d902SRodney W. Grimes register char *argv[]; 809b50d902SRodney W. Grimes register int argc; 819b50d902SRodney W. Grimes register int td; 829b50d902SRodney W. Grimes { 839b50d902SRodney W. Grimes register int c, n; 849b50d902SRodney W. Grimes static int sysval = 0; 859b50d902SRodney W. Grimes 869b50d902SRodney W. Grimes #ifdef DEBUG 879b50d902SRodney W. Grimes printf("argc = %d\n", argc); 889b50d902SRodney W. Grimes for (n = 0; n < argc; n++) 899b50d902SRodney W. Grimes printf("argv[%d] = %s\n", n, argv[n]); 909b50d902SRodney W. Grimes #endif 919b50d902SRodney W. Grimes /* 929b50d902SRodney W. Grimes * if argc == 3 and argv[2] is null, then we 939b50d902SRodney W. Grimes * have macro-or-builtin() type call. We adjust 949b50d902SRodney W. Grimes * argc to avoid further checking.. 959b50d902SRodney W. Grimes */ 969b50d902SRodney W. Grimes if (argc == 3 && !*(argv[2])) 979b50d902SRodney W. Grimes argc--; 989b50d902SRodney W. Grimes 999b50d902SRodney W. Grimes switch (td & ~STATIC) { 1009b50d902SRodney W. Grimes 1019b50d902SRodney W. Grimes case DEFITYPE: 1029b50d902SRodney W. Grimes if (argc > 2) 1039b50d902SRodney W. Grimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1049b50d902SRodney W. Grimes break; 1059b50d902SRodney W. Grimes 1069b50d902SRodney W. Grimes case PUSDTYPE: 1079b50d902SRodney W. Grimes if (argc > 2) 1089b50d902SRodney W. Grimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1099b50d902SRodney W. Grimes break; 1109b50d902SRodney W. Grimes 1119b50d902SRodney W. Grimes case DUMPTYPE: 1129b50d902SRodney W. Grimes dodump(argv, argc); 1139b50d902SRodney W. Grimes break; 1149b50d902SRodney W. Grimes 1159b50d902SRodney W. Grimes case EXPRTYPE: 1169b50d902SRodney W. Grimes /* 1179b50d902SRodney W. Grimes * doexpr - evaluate arithmetic 1189b50d902SRodney W. Grimes * expression 1199b50d902SRodney W. Grimes */ 1209b50d902SRodney W. Grimes if (argc > 2) 1219b50d902SRodney W. Grimes pbnum(expr(argv[2])); 1229b50d902SRodney W. Grimes break; 1239b50d902SRodney W. Grimes 1249b50d902SRodney W. Grimes case IFELTYPE: 1259b50d902SRodney W. Grimes if (argc > 4) 1269b50d902SRodney W. Grimes doifelse(argv, argc); 1279b50d902SRodney W. Grimes break; 1289b50d902SRodney W. Grimes 1299b50d902SRodney W. Grimes case IFDFTYPE: 1309b50d902SRodney W. Grimes /* 1319b50d902SRodney W. Grimes * doifdef - select one of two 1329b50d902SRodney W. Grimes * alternatives based on the existence of 1339b50d902SRodney W. Grimes * another definition 1349b50d902SRodney W. Grimes */ 1359b50d902SRodney W. Grimes if (argc > 3) { 1369b50d902SRodney W. Grimes if (lookup(argv[2]) != nil) 1379b50d902SRodney W. Grimes pbstr(argv[3]); 1389b50d902SRodney W. Grimes else if (argc > 4) 1399b50d902SRodney W. Grimes pbstr(argv[4]); 1409b50d902SRodney W. Grimes } 1419b50d902SRodney W. Grimes break; 1429b50d902SRodney W. Grimes 1439b50d902SRodney W. Grimes case LENGTYPE: 1449b50d902SRodney W. Grimes /* 1459b50d902SRodney W. Grimes * dolen - find the length of the 1469b50d902SRodney W. Grimes * argument 1479b50d902SRodney W. Grimes */ 1489b50d902SRodney W. Grimes if (argc > 2) 1499b50d902SRodney W. Grimes pbnum((argc > 2) ? strlen(argv[2]) : 0); 1509b50d902SRodney W. Grimes break; 1519b50d902SRodney W. Grimes 1529b50d902SRodney W. Grimes case INCRTYPE: 1539b50d902SRodney W. Grimes /* 1549b50d902SRodney W. Grimes * doincr - increment the value of the 1559b50d902SRodney W. Grimes * argument 1569b50d902SRodney W. Grimes */ 1579b50d902SRodney W. Grimes if (argc > 2) 1589b50d902SRodney W. Grimes pbnum(atoi(argv[2]) + 1); 1599b50d902SRodney W. Grimes break; 1609b50d902SRodney W. Grimes 1619b50d902SRodney W. Grimes case DECRTYPE: 1629b50d902SRodney W. Grimes /* 1639b50d902SRodney W. Grimes * dodecr - decrement the value of the 1649b50d902SRodney W. Grimes * argument 1659b50d902SRodney W. Grimes */ 1669b50d902SRodney W. Grimes if (argc > 2) 1679b50d902SRodney W. Grimes pbnum(atoi(argv[2]) - 1); 1689b50d902SRodney W. Grimes break; 1699b50d902SRodney W. Grimes 1709b50d902SRodney W. Grimes case SYSCTYPE: 1719b50d902SRodney W. Grimes /* 1729b50d902SRodney W. Grimes * dosys - execute system command 1739b50d902SRodney W. Grimes */ 1743ee80812SAndrey A. Chernov /* Make sure m4 output is NOT interrupted */ 1753ee80812SAndrey A. Chernov fflush(stdout); 1763ee80812SAndrey A. Chernov fflush(stderr); 1779b50d902SRodney W. Grimes if (argc > 2) 1789b50d902SRodney W. Grimes sysval = system(argv[2]); 1799b50d902SRodney W. Grimes break; 1809b50d902SRodney W. Grimes 1819b50d902SRodney W. Grimes case SYSVTYPE: 1829b50d902SRodney W. Grimes /* 1839b50d902SRodney W. Grimes * dosysval - return value of the last 1849b50d902SRodney W. Grimes * system call. 1859b50d902SRodney W. Grimes * 1869b50d902SRodney W. Grimes */ 1879b50d902SRodney W. Grimes pbnum(sysval); 1889b50d902SRodney W. Grimes break; 1899b50d902SRodney W. Grimes 1909b50d902SRodney W. Grimes case INCLTYPE: 1919b50d902SRodney W. Grimes if (argc > 2) 1929b50d902SRodney W. Grimes if (!doincl(argv[2])) 1939b50d902SRodney W. Grimes oops("%s: %s", argv[2], strerror(errno)); 1949b50d902SRodney W. Grimes break; 1959b50d902SRodney W. Grimes 1969b50d902SRodney W. Grimes case SINCTYPE: 1979b50d902SRodney W. Grimes if (argc > 2) 1989b50d902SRodney W. Grimes (void) doincl(argv[2]); 1999b50d902SRodney W. Grimes break; 2009b50d902SRodney W. Grimes #ifdef EXTENDED 2019b50d902SRodney W. Grimes case PASTTYPE: 2029b50d902SRodney W. Grimes if (argc > 2) 2039b50d902SRodney W. Grimes if (!dopaste(argv[2])) 2049b50d902SRodney W. Grimes oops("%s: %s", argv[2], strerror(errno)); 2059b50d902SRodney W. Grimes break; 2069b50d902SRodney W. Grimes 2079b50d902SRodney W. Grimes case SPASTYPE: 2089b50d902SRodney W. Grimes if (argc > 2) 2099b50d902SRodney W. Grimes (void) dopaste(argv[2]); 2109b50d902SRodney W. Grimes break; 2119b50d902SRodney W. Grimes #endif 2129b50d902SRodney W. Grimes case CHNQTYPE: 2139b50d902SRodney W. Grimes dochq(argv, argc); 2149b50d902SRodney W. Grimes break; 2159b50d902SRodney W. Grimes 2169b50d902SRodney W. Grimes case CHNCTYPE: 2179b50d902SRodney W. Grimes dochc(argv, argc); 2189b50d902SRodney W. Grimes break; 2199b50d902SRodney W. Grimes 2209b50d902SRodney W. Grimes case SUBSTYPE: 2219b50d902SRodney W. Grimes /* 2229b50d902SRodney W. Grimes * dosub - select substring 2239b50d902SRodney W. Grimes * 2249b50d902SRodney W. Grimes */ 2259b50d902SRodney W. Grimes if (argc > 3) 2269b50d902SRodney W. Grimes dosub(argv, argc); 2279b50d902SRodney W. Grimes break; 2289b50d902SRodney W. Grimes 2299b50d902SRodney W. Grimes case SHIFTYPE: 2309b50d902SRodney W. Grimes /* 2319b50d902SRodney W. Grimes * doshift - push back all arguments 2329b50d902SRodney W. Grimes * except the first one (i.e. skip 2339b50d902SRodney W. Grimes * argv[2]) 2349b50d902SRodney W. Grimes */ 2359b50d902SRodney W. Grimes if (argc > 3) { 2369b50d902SRodney W. Grimes for (n = argc - 1; n > 3; n--) { 2379b50d902SRodney W. Grimes putback(rquote); 2389b50d902SRodney W. Grimes pbstr(argv[n]); 2399b50d902SRodney W. Grimes putback(lquote); 2409b50d902SRodney W. Grimes putback(','); 2419b50d902SRodney W. Grimes } 2429b50d902SRodney W. Grimes putback(rquote); 2439b50d902SRodney W. Grimes pbstr(argv[3]); 2449b50d902SRodney W. Grimes putback(lquote); 2459b50d902SRodney W. Grimes } 2469b50d902SRodney W. Grimes break; 2479b50d902SRodney W. Grimes 2489b50d902SRodney W. Grimes case DIVRTYPE: 2499b50d902SRodney W. Grimes if (argc > 2 && (n = atoi(argv[2])) != 0) 2509b50d902SRodney W. Grimes dodiv(n); 2519b50d902SRodney W. Grimes else { 2529b50d902SRodney W. Grimes active = stdout; 2539b50d902SRodney W. Grimes oindex = 0; 2549b50d902SRodney W. Grimes } 2559b50d902SRodney W. Grimes break; 2569b50d902SRodney W. Grimes 2579b50d902SRodney W. Grimes case UNDVTYPE: 2589b50d902SRodney W. Grimes doundiv(argv, argc); 2599b50d902SRodney W. Grimes break; 2609b50d902SRodney W. Grimes 2619b50d902SRodney W. Grimes case DIVNTYPE: 2629b50d902SRodney W. Grimes /* 2639b50d902SRodney W. Grimes * dodivnum - return the number of 2649b50d902SRodney W. Grimes * current output diversion 2659b50d902SRodney W. Grimes */ 2669b50d902SRodney W. Grimes pbnum(oindex); 2679b50d902SRodney W. Grimes break; 2689b50d902SRodney W. Grimes 2699b50d902SRodney W. Grimes case UNDFTYPE: 2709b50d902SRodney W. Grimes /* 2719b50d902SRodney W. Grimes * doundefine - undefine a previously 2729b50d902SRodney W. Grimes * defined macro(s) or m4 keyword(s). 2739b50d902SRodney W. Grimes */ 2749b50d902SRodney W. Grimes if (argc > 2) 2759b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 2769b50d902SRodney W. Grimes remhash(argv[n], ALL); 2779b50d902SRodney W. Grimes break; 2789b50d902SRodney W. Grimes 2799b50d902SRodney W. Grimes case POPDTYPE: 2809b50d902SRodney W. Grimes /* 2819b50d902SRodney W. Grimes * dopopdef - remove the topmost 2829b50d902SRodney W. Grimes * definitions of macro(s) or m4 2839b50d902SRodney W. Grimes * keyword(s). 2849b50d902SRodney W. Grimes */ 2859b50d902SRodney W. Grimes if (argc > 2) 2869b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 2879b50d902SRodney W. Grimes remhash(argv[n], TOP); 2889b50d902SRodney W. Grimes break; 2899b50d902SRodney W. Grimes 2909b50d902SRodney W. Grimes case MKTMTYPE: 2919b50d902SRodney W. Grimes /* 2929b50d902SRodney W. Grimes * dotemp - create a temporary file 2939b50d902SRodney W. Grimes */ 2949b50d902SRodney W. Grimes if (argc > 2) 2959b50d902SRodney W. Grimes pbstr(mktemp(argv[2])); 2969b50d902SRodney W. Grimes break; 2979b50d902SRodney W. Grimes 2989b50d902SRodney W. Grimes case TRNLTYPE: 2999b50d902SRodney W. Grimes /* 3009b50d902SRodney W. Grimes * dotranslit - replace all characters in 3019b50d902SRodney W. Grimes * the source string that appears in the 3029b50d902SRodney W. Grimes * "from" string with the corresponding 3039b50d902SRodney W. Grimes * characters in the "to" string. 3049b50d902SRodney W. Grimes */ 3059b50d902SRodney W. Grimes if (argc > 3) { 3069b50d902SRodney W. Grimes char temp[MAXTOK]; 3079b50d902SRodney W. Grimes if (argc > 4) 3089b50d902SRodney W. Grimes map(temp, argv[2], argv[3], argv[4]); 3099b50d902SRodney W. Grimes else 3109b50d902SRodney W. Grimes map(temp, argv[2], argv[3], null); 3119b50d902SRodney W. Grimes pbstr(temp); 3129b50d902SRodney W. Grimes } 3139b50d902SRodney W. Grimes else if (argc > 2) 3149b50d902SRodney W. Grimes pbstr(argv[2]); 3159b50d902SRodney W. Grimes break; 3169b50d902SRodney W. Grimes 3179b50d902SRodney W. Grimes case INDXTYPE: 3189b50d902SRodney W. Grimes /* 3199b50d902SRodney W. Grimes * doindex - find the index of the second 3209b50d902SRodney W. Grimes * argument string in the first argument 3219b50d902SRodney W. Grimes * string. -1 if not present. 3229b50d902SRodney W. Grimes */ 3239b50d902SRodney W. Grimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 3249b50d902SRodney W. Grimes break; 3259b50d902SRodney W. Grimes 3269b50d902SRodney W. Grimes case ERRPTYPE: 3279b50d902SRodney W. Grimes /* 3289b50d902SRodney W. Grimes * doerrp - print the arguments to stderr 3299b50d902SRodney W. Grimes * file 3309b50d902SRodney W. Grimes */ 3319b50d902SRodney W. Grimes if (argc > 2) { 3329b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 3339b50d902SRodney W. Grimes fprintf(stderr, "%s ", argv[n]); 3349b50d902SRodney W. Grimes fprintf(stderr, "\n"); 3359b50d902SRodney W. Grimes } 3369b50d902SRodney W. Grimes break; 3379b50d902SRodney W. Grimes 3389b50d902SRodney W. Grimes case DNLNTYPE: 3399b50d902SRodney W. Grimes /* 3409b50d902SRodney W. Grimes * dodnl - eat-up-to and including 3419b50d902SRodney W. Grimes * newline 3429b50d902SRodney W. Grimes */ 3439b50d902SRodney W. Grimes while ((c = gpbc()) != '\n' && c != EOF) 3449b50d902SRodney W. Grimes ; 3459b50d902SRodney W. Grimes break; 3469b50d902SRodney W. Grimes 3479b50d902SRodney W. Grimes case M4WRTYPE: 3489b50d902SRodney W. Grimes /* 3499b50d902SRodney W. Grimes * dom4wrap - set up for 3509b50d902SRodney W. Grimes * wrap-up/wind-down activity 3519b50d902SRodney W. Grimes */ 3529b50d902SRodney W. Grimes m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 3539b50d902SRodney W. Grimes break; 3549b50d902SRodney W. Grimes 3559b50d902SRodney W. Grimes case EXITTYPE: 3569b50d902SRodney W. Grimes /* 3579b50d902SRodney W. Grimes * doexit - immediate exit from m4. 3589b50d902SRodney W. Grimes */ 359cac6992aSAndrey A. Chernov killdiv(); 3609b50d902SRodney W. Grimes exit((argc > 2) ? atoi(argv[2]) : 0); 3619b50d902SRodney W. Grimes break; 3629b50d902SRodney W. Grimes 3639b50d902SRodney W. Grimes case DEFNTYPE: 3649b50d902SRodney W. Grimes if (argc > 2) 3659b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 3669b50d902SRodney W. Grimes dodefn(argv[n]); 3679b50d902SRodney W. Grimes break; 3689b50d902SRodney W. Grimes 3699b50d902SRodney W. Grimes default: 3709b50d902SRodney W. Grimes oops("%s: major botch.", "eval"); 3719b50d902SRodney W. Grimes break; 3729b50d902SRodney W. Grimes } 3739b50d902SRodney W. Grimes } 3749b50d902SRodney W. Grimes 3759b50d902SRodney W. Grimes char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 3769b50d902SRodney W. Grimes 3779b50d902SRodney W. Grimes /* 3789b50d902SRodney W. Grimes * expand - user-defined macro expansion 3799b50d902SRodney W. Grimes */ 3809b50d902SRodney W. Grimes void 3819b50d902SRodney W. Grimes expand(argv, argc) 3829b50d902SRodney W. Grimes register char *argv[]; 3839b50d902SRodney W. Grimes register int argc; 3849b50d902SRodney W. Grimes { 3857c5eeb39SAndrey A. Chernov register unsigned char *t; 3867c5eeb39SAndrey A. Chernov register unsigned char *p; 3879b50d902SRodney W. Grimes register int n; 3889b50d902SRodney W. Grimes register int argno; 3899b50d902SRodney W. Grimes 3909b50d902SRodney W. Grimes t = argv[0]; /* defn string as a whole */ 3919b50d902SRodney W. Grimes p = t; 3929b50d902SRodney W. Grimes while (*p) 3939b50d902SRodney W. Grimes p++; 3949b50d902SRodney W. Grimes p--; /* last character of defn */ 3959b50d902SRodney W. Grimes while (p > t) { 3969b50d902SRodney W. Grimes if (*(p - 1) != ARGFLAG) 3979b50d902SRodney W. Grimes putback(*p); 3989b50d902SRodney W. Grimes else { 3999b50d902SRodney W. Grimes switch (*p) { 4009b50d902SRodney W. Grimes 4019b50d902SRodney W. Grimes case '#': 4029b50d902SRodney W. Grimes pbnum(argc - 2); 4039b50d902SRodney W. Grimes break; 4049b50d902SRodney W. Grimes case '0': 4059b50d902SRodney W. Grimes case '1': 4069b50d902SRodney W. Grimes case '2': 4079b50d902SRodney W. Grimes case '3': 4089b50d902SRodney W. Grimes case '4': 4099b50d902SRodney W. Grimes case '5': 4109b50d902SRodney W. Grimes case '6': 4119b50d902SRodney W. Grimes case '7': 4129b50d902SRodney W. Grimes case '8': 4139b50d902SRodney W. Grimes case '9': 4149b50d902SRodney W. Grimes if ((argno = *p - '0') < argc - 1) 4159b50d902SRodney W. Grimes pbstr(argv[argno + 1]); 4169b50d902SRodney W. Grimes break; 4179b50d902SRodney W. Grimes case '*': 4189b50d902SRodney W. Grimes for (n = argc - 1; n > 2; n--) { 4199b50d902SRodney W. Grimes pbstr(argv[n]); 4209b50d902SRodney W. Grimes putback(','); 4219b50d902SRodney W. Grimes } 4229b50d902SRodney W. Grimes pbstr(argv[2]); 4239b50d902SRodney W. Grimes break; 424232eaee6SJoerg Wunsch case '@': 425232eaee6SJoerg Wunsch for( n = argc - 1; n >= 2; n-- ) 426232eaee6SJoerg Wunsch { 427232eaee6SJoerg Wunsch putback(rquote); 428232eaee6SJoerg Wunsch pbstr(argv[n]); 429232eaee6SJoerg Wunsch putback(lquote); 430232eaee6SJoerg Wunsch if( n > 2 ) 431232eaee6SJoerg Wunsch putback(','); 432232eaee6SJoerg Wunsch } 433232eaee6SJoerg Wunsch break; 4349b50d902SRodney W. Grimes default: 4359b50d902SRodney W. Grimes putback(*p); 4369b50d902SRodney W. Grimes putback('$'); 4379b50d902SRodney W. Grimes break; 4389b50d902SRodney W. Grimes } 4399b50d902SRodney W. Grimes p--; 4409b50d902SRodney W. Grimes } 4419b50d902SRodney W. Grimes p--; 4429b50d902SRodney W. Grimes } 4439b50d902SRodney W. Grimes if (p == t) /* do last character */ 4449b50d902SRodney W. Grimes putback(*p); 4459b50d902SRodney W. Grimes } 4469b50d902SRodney W. Grimes 4479b50d902SRodney W. Grimes /* 4489b50d902SRodney W. Grimes * dodefine - install definition in the table 4499b50d902SRodney W. Grimes */ 4509b50d902SRodney W. Grimes void 4519b50d902SRodney W. Grimes dodefine(name, defn) 4529b50d902SRodney W. Grimes register char *name; 4539b50d902SRodney W. Grimes register char *defn; 4549b50d902SRodney W. Grimes { 4559b50d902SRodney W. Grimes register ndptr p; 4569b50d902SRodney W. Grimes 4579b50d902SRodney W. Grimes if (!*name) 4589b50d902SRodney W. Grimes oops("null definition."); 4599b50d902SRodney W. Grimes if (STREQ(name, defn)) 4609b50d902SRodney W. Grimes oops("%s: recursive definition.", name); 4619b50d902SRodney W. Grimes if ((p = lookup(name)) == nil) 4629b50d902SRodney W. Grimes p = addent(name); 4639b50d902SRodney W. Grimes else if (p->defn != null) 4649b50d902SRodney W. Grimes free((char *) p->defn); 4659b50d902SRodney W. Grimes if (!*defn) 4669b50d902SRodney W. Grimes p->defn = null; 4679b50d902SRodney W. Grimes else 4689b50d902SRodney W. Grimes p->defn = xstrdup(defn); 4699b50d902SRodney W. Grimes p->type = MACRTYPE; 4709b50d902SRodney W. Grimes } 4719b50d902SRodney W. Grimes 4729b50d902SRodney W. Grimes /* 4739b50d902SRodney W. Grimes * dodefn - push back a quoted definition of 4749b50d902SRodney W. Grimes * the given name. 4759b50d902SRodney W. Grimes */ 4769b50d902SRodney W. Grimes void 4779b50d902SRodney W. Grimes dodefn(name) 4789b50d902SRodney W. Grimes char *name; 4799b50d902SRodney W. Grimes { 4809b50d902SRodney W. Grimes register ndptr p; 4819b50d902SRodney W. Grimes 4829b50d902SRodney W. Grimes if ((p = lookup(name)) != nil && p->defn != null) { 4839b50d902SRodney W. Grimes putback(rquote); 4849b50d902SRodney W. Grimes pbstr(p->defn); 4859b50d902SRodney W. Grimes putback(lquote); 4869b50d902SRodney W. Grimes } 4879b50d902SRodney W. Grimes } 4889b50d902SRodney W. Grimes 4899b50d902SRodney W. Grimes /* 4909b50d902SRodney W. Grimes * dopushdef - install a definition in the hash table 4919b50d902SRodney W. Grimes * without removing a previous definition. Since 4929b50d902SRodney W. Grimes * each new entry is entered in *front* of the 4939b50d902SRodney W. Grimes * hash bucket, it hides a previous definition from 4949b50d902SRodney W. Grimes * lookup. 4959b50d902SRodney W. Grimes */ 4969b50d902SRodney W. Grimes void 4979b50d902SRodney W. Grimes dopushdef(name, defn) 4989b50d902SRodney W. Grimes register char *name; 4999b50d902SRodney W. Grimes register char *defn; 5009b50d902SRodney W. Grimes { 5019b50d902SRodney W. Grimes register ndptr p; 5029b50d902SRodney W. Grimes 5039b50d902SRodney W. Grimes if (!*name) 5049b50d902SRodney W. Grimes oops("null definition"); 5059b50d902SRodney W. Grimes if (STREQ(name, defn)) 5069b50d902SRodney W. Grimes oops("%s: recursive definition.", name); 5079b50d902SRodney W. Grimes p = addent(name); 5089b50d902SRodney W. Grimes if (!*defn) 5099b50d902SRodney W. Grimes p->defn = null; 5109b50d902SRodney W. Grimes else 5119b50d902SRodney W. Grimes p->defn = xstrdup(defn); 5129b50d902SRodney W. Grimes p->type = MACRTYPE; 5139b50d902SRodney W. Grimes } 5149b50d902SRodney W. Grimes 5159b50d902SRodney W. Grimes /* 5169b50d902SRodney W. Grimes * dodumpdef - dump the specified definitions in the hash 5179b50d902SRodney W. Grimes * table to stderr. If nothing is specified, the entire 5189b50d902SRodney W. Grimes * hash table is dumped. 5199b50d902SRodney W. Grimes */ 5209b50d902SRodney W. Grimes void 5219b50d902SRodney W. Grimes dodump(argv, argc) 5229b50d902SRodney W. Grimes register char *argv[]; 5239b50d902SRodney W. Grimes register int argc; 5249b50d902SRodney W. Grimes { 5259b50d902SRodney W. Grimes register int n; 5269b50d902SRodney W. Grimes ndptr p; 5279b50d902SRodney W. Grimes 5289b50d902SRodney W. Grimes if (argc > 2) { 5299b50d902SRodney W. Grimes for (n = 2; n < argc; n++) 5309b50d902SRodney W. Grimes if ((p = lookup(argv[n])) != nil) 5319b50d902SRodney W. Grimes fprintf(stderr, dumpfmt, p->name, 5329b50d902SRodney W. Grimes p->defn); 5339b50d902SRodney W. Grimes } 5349b50d902SRodney W. Grimes else { 5359b50d902SRodney W. Grimes for (n = 0; n < HASHSIZE; n++) 5369b50d902SRodney W. Grimes for (p = hashtab[n]; p != nil; p = p->nxtptr) 5379b50d902SRodney W. Grimes fprintf(stderr, dumpfmt, p->name, 5389b50d902SRodney W. Grimes p->defn); 5399b50d902SRodney W. Grimes } 5409b50d902SRodney W. Grimes } 5419b50d902SRodney W. Grimes 5429b50d902SRodney W. Grimes /* 5439b50d902SRodney W. Grimes * doifelse - select one of two alternatives - loop. 5449b50d902SRodney W. Grimes */ 5459b50d902SRodney W. Grimes void 5469b50d902SRodney W. Grimes doifelse(argv, argc) 5479b50d902SRodney W. Grimes register char *argv[]; 5489b50d902SRodney W. Grimes register int argc; 5499b50d902SRodney W. Grimes { 5509b50d902SRodney W. Grimes cycle { 5519b50d902SRodney W. Grimes if (STREQ(argv[2], argv[3])) 5529b50d902SRodney W. Grimes pbstr(argv[4]); 5539b50d902SRodney W. Grimes else if (argc == 6) 5549b50d902SRodney W. Grimes pbstr(argv[5]); 5559b50d902SRodney W. Grimes else if (argc > 6) { 5569b50d902SRodney W. Grimes argv += 3; 5579b50d902SRodney W. Grimes argc -= 3; 5589b50d902SRodney W. Grimes continue; 5599b50d902SRodney W. Grimes } 5609b50d902SRodney W. Grimes break; 5619b50d902SRodney W. Grimes } 5629b50d902SRodney W. Grimes } 5639b50d902SRodney W. Grimes 5649b50d902SRodney W. Grimes /* 5659b50d902SRodney W. Grimes * doinclude - include a given file. 5669b50d902SRodney W. Grimes */ 5679b50d902SRodney W. Grimes int 5689b50d902SRodney W. Grimes doincl(ifile) 5699b50d902SRodney W. Grimes char *ifile; 5709b50d902SRodney W. Grimes { 5719b50d902SRodney W. Grimes if (ilevel + 1 == MAXINP) 5729b50d902SRodney W. Grimes oops("too many include files."); 5739b50d902SRodney W. Grimes if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 5749b50d902SRodney W. Grimes ilevel++; 5759b50d902SRodney W. Grimes bbase[ilevel] = bufbase = bp; 5769b50d902SRodney W. Grimes return (1); 5779b50d902SRodney W. Grimes } 5789b50d902SRodney W. Grimes else 5799b50d902SRodney W. Grimes return (0); 5809b50d902SRodney W. Grimes } 5819b50d902SRodney W. Grimes 5829b50d902SRodney W. Grimes #ifdef EXTENDED 5839b50d902SRodney W. Grimes /* 5849b50d902SRodney W. Grimes * dopaste - include a given file without any 5859b50d902SRodney W. Grimes * macro processing. 5869b50d902SRodney W. Grimes */ 5879b50d902SRodney W. Grimes int 5889b50d902SRodney W. Grimes dopaste(pfile) 5899b50d902SRodney W. Grimes char *pfile; 5909b50d902SRodney W. Grimes { 5919b50d902SRodney W. Grimes FILE *pf; 5929b50d902SRodney W. Grimes register int c; 5939b50d902SRodney W. Grimes 5949b50d902SRodney W. Grimes if ((pf = fopen(pfile, "r")) != NULL) { 5959b50d902SRodney W. Grimes while ((c = getc(pf)) != EOF) 5969b50d902SRodney W. Grimes putc(c, active); 5979b50d902SRodney W. Grimes (void) fclose(pf); 5989b50d902SRodney W. Grimes return (1); 5999b50d902SRodney W. Grimes } 6009b50d902SRodney W. Grimes else 6019b50d902SRodney W. Grimes return (0); 6029b50d902SRodney W. Grimes } 6039b50d902SRodney W. Grimes #endif 6049b50d902SRodney W. Grimes 6059b50d902SRodney W. Grimes /* 6069b50d902SRodney W. Grimes * dochq - change quote characters 6079b50d902SRodney W. Grimes */ 6089b50d902SRodney W. Grimes void 6099b50d902SRodney W. Grimes dochq(argv, argc) 6109b50d902SRodney W. Grimes register char *argv[]; 6119b50d902SRodney W. Grimes register int argc; 6129b50d902SRodney W. Grimes { 6139b50d902SRodney W. Grimes if (argc > 2) { 6149b50d902SRodney W. Grimes if (*argv[2]) 6159b50d902SRodney W. Grimes lquote = *argv[2]; 6169b50d902SRodney W. Grimes if (argc > 3) { 6179b50d902SRodney W. Grimes if (*argv[3]) 6189b50d902SRodney W. Grimes rquote = *argv[3]; 6199b50d902SRodney W. Grimes } 6209b50d902SRodney W. Grimes else 6219b50d902SRodney W. Grimes rquote = lquote; 6229b50d902SRodney W. Grimes } 6239b50d902SRodney W. Grimes else { 6249b50d902SRodney W. Grimes lquote = LQUOTE; 6259b50d902SRodney W. Grimes rquote = RQUOTE; 6269b50d902SRodney W. Grimes } 6279b50d902SRodney W. Grimes } 6289b50d902SRodney W. Grimes 6299b50d902SRodney W. Grimes /* 6309b50d902SRodney W. Grimes * dochc - change comment characters 6319b50d902SRodney W. Grimes */ 6329b50d902SRodney W. Grimes void 6339b50d902SRodney W. Grimes dochc(argv, argc) 6349b50d902SRodney W. Grimes register char *argv[]; 6359b50d902SRodney W. Grimes register int argc; 6369b50d902SRodney W. Grimes { 6379b50d902SRodney W. Grimes if (argc > 2) { 6389b50d902SRodney W. Grimes if (*argv[2]) 6399b50d902SRodney W. Grimes scommt = *argv[2]; 6409b50d902SRodney W. Grimes if (argc > 3) { 6419b50d902SRodney W. Grimes if (*argv[3]) 6429b50d902SRodney W. Grimes ecommt = *argv[3]; 6439b50d902SRodney W. Grimes } 6449b50d902SRodney W. Grimes else 6459b50d902SRodney W. Grimes ecommt = ECOMMT; 6469b50d902SRodney W. Grimes } 6479b50d902SRodney W. Grimes else { 6489b50d902SRodney W. Grimes scommt = SCOMMT; 6499b50d902SRodney W. Grimes ecommt = ECOMMT; 6509b50d902SRodney W. Grimes } 6519b50d902SRodney W. Grimes } 6529b50d902SRodney W. Grimes 6539b50d902SRodney W. Grimes /* 6549b50d902SRodney W. Grimes * dodivert - divert the output to a temporary file 6559b50d902SRodney W. Grimes */ 6569b50d902SRodney W. Grimes void 6579b50d902SRodney W. Grimes dodiv(n) 6589b50d902SRodney W. Grimes register int n; 6599b50d902SRodney W. Grimes { 6609b50d902SRodney W. Grimes if (n < 0 || n >= MAXOUT) 6619b50d902SRodney W. Grimes n = 0; /* bitbucket */ 6629b50d902SRodney W. Grimes if (outfile[n] == NULL) { 6639b50d902SRodney W. Grimes m4temp[UNIQUE] = n + '0'; 6649b50d902SRodney W. Grimes if ((outfile[n] = fopen(m4temp, "w")) == NULL) 6659b50d902SRodney W. Grimes oops("%s: cannot divert.", m4temp); 6669b50d902SRodney W. Grimes } 6679b50d902SRodney W. Grimes oindex = n; 6689b50d902SRodney W. Grimes active = outfile[n]; 6699b50d902SRodney W. Grimes } 6709b50d902SRodney W. Grimes 6719b50d902SRodney W. Grimes /* 6729b50d902SRodney W. Grimes * doundivert - undivert a specified output, or all 6739b50d902SRodney W. Grimes * other outputs, in numerical order. 6749b50d902SRodney W. Grimes */ 6759b50d902SRodney W. Grimes void 6769b50d902SRodney W. Grimes doundiv(argv, argc) 6779b50d902SRodney W. Grimes register char *argv[]; 6789b50d902SRodney W. Grimes register int argc; 6799b50d902SRodney W. Grimes { 6809b50d902SRodney W. Grimes register int ind; 6819b50d902SRodney W. Grimes register int n; 6829b50d902SRodney W. Grimes 6839b50d902SRodney W. Grimes if (argc > 2) { 6849b50d902SRodney W. Grimes for (ind = 2; ind < argc; ind++) { 6859b50d902SRodney W. Grimes n = atoi(argv[ind]); 6869b50d902SRodney W. Grimes if (n > 0 && n < MAXOUT && outfile[n] != NULL) 6879b50d902SRodney W. Grimes getdiv(n); 6889b50d902SRodney W. Grimes 6899b50d902SRodney W. Grimes } 6909b50d902SRodney W. Grimes } 6919b50d902SRodney W. Grimes else 6929b50d902SRodney W. Grimes for (n = 1; n < MAXOUT; n++) 6939b50d902SRodney W. Grimes if (outfile[n] != NULL) 6949b50d902SRodney W. Grimes getdiv(n); 6959b50d902SRodney W. Grimes } 6969b50d902SRodney W. Grimes 6979b50d902SRodney W. Grimes /* 6989b50d902SRodney W. Grimes * dosub - select substring 6999b50d902SRodney W. Grimes */ 7009b50d902SRodney W. Grimes void 7019b50d902SRodney W. Grimes dosub(argv, argc) 7029b50d902SRodney W. Grimes register char *argv[]; 7039b50d902SRodney W. Grimes register int argc; 7049b50d902SRodney W. Grimes { 7057c5eeb39SAndrey A. Chernov register unsigned char *ap, *fc, *k; 7069b50d902SRodney W. Grimes register int nc; 7079b50d902SRodney W. Grimes 7089b50d902SRodney W. Grimes if (argc < 5) 7099b50d902SRodney W. Grimes nc = MAXTOK; 7109b50d902SRodney W. Grimes else 7119b50d902SRodney W. Grimes #ifdef EXPR 7129b50d902SRodney W. Grimes nc = expr(argv[4]); 7139b50d902SRodney W. Grimes #else 7149b50d902SRodney W. Grimes nc = atoi(argv[4]); 7159b50d902SRodney W. Grimes #endif 7169b50d902SRodney W. Grimes ap = argv[2]; /* target string */ 7179b50d902SRodney W. Grimes #ifdef EXPR 7189b50d902SRodney W. Grimes fc = ap + expr(argv[3]); /* first char */ 7199b50d902SRodney W. Grimes #else 7209b50d902SRodney W. Grimes fc = ap + atoi(argv[3]); /* first char */ 7219b50d902SRodney W. Grimes #endif 7229b50d902SRodney W. Grimes if (fc >= ap && fc < ap + strlen(ap)) 7239b50d902SRodney W. Grimes for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 7249b50d902SRodney W. Grimes putback(*k); 7259b50d902SRodney W. Grimes } 7269b50d902SRodney W. Grimes 7279b50d902SRodney W. Grimes /* 7289b50d902SRodney W. Grimes * map: 7299b50d902SRodney W. Grimes * map every character of s1 that is specified in from 7309b50d902SRodney W. Grimes * into s3 and replace in s. (source s1 remains untouched) 7319b50d902SRodney W. Grimes * 7329b50d902SRodney W. Grimes * This is a standard implementation of map(s,from,to) function of ICON 7339b50d902SRodney W. Grimes * language. Within mapvec, we replace every character of "from" with 7349b50d902SRodney W. Grimes * the corresponding character in "to". If "to" is shorter than "from", 7359b50d902SRodney W. Grimes * than the corresponding entries are null, which means that those 7369b50d902SRodney W. Grimes * characters dissapear altogether. Furthermore, imagine 7379b50d902SRodney W. Grimes * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 7389b50d902SRodney W. Grimes * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 7399b50d902SRodney W. Grimes * ultimately maps to `*'. In order to achieve this effect in an efficient 7409b50d902SRodney W. Grimes * manner (i.e. without multiple passes over the destination string), we 7419b50d902SRodney W. Grimes * loop over mapvec, starting with the initial source character. if the 7429b50d902SRodney W. Grimes * character value (dch) in this location is different than the source 7439b50d902SRodney W. Grimes * character (sch), sch becomes dch, once again to index into mapvec, until 7449b50d902SRodney W. Grimes * the character value stabilizes (i.e. sch = dch, in other words 7459b50d902SRodney W. Grimes * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 7469b50d902SRodney W. Grimes * character, it will stabilize, since mapvec[0] == 0 at all times. At the 7479b50d902SRodney W. Grimes * end, we restore mapvec* back to normal where mapvec[n] == n for 7489b50d902SRodney W. Grimes * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 7499b50d902SRodney W. Grimes * about 5 times faster than any algorithm that makes multiple passes over 7509b50d902SRodney W. Grimes * destination string. 7519b50d902SRodney W. Grimes */ 7529b50d902SRodney W. Grimes void 7539b50d902SRodney W. Grimes map(dest, src, from, to) 7549b50d902SRodney W. Grimes register char *dest; 7559b50d902SRodney W. Grimes register char *src; 7569b50d902SRodney W. Grimes register char *from; 7579b50d902SRodney W. Grimes register char *to; 7589b50d902SRodney W. Grimes { 7599b50d902SRodney W. Grimes register char *tmp; 7609b50d902SRodney W. Grimes register char sch, dch; 7619b50d902SRodney W. Grimes static char mapvec[128] = { 7629b50d902SRodney W. Grimes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 7639b50d902SRodney W. Grimes 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 7649b50d902SRodney W. Grimes 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 7659b50d902SRodney W. Grimes 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 7669b50d902SRodney W. Grimes 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 7679b50d902SRodney W. Grimes 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 7689b50d902SRodney W. Grimes 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 7699b50d902SRodney W. Grimes 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 7709b50d902SRodney W. Grimes 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 7719b50d902SRodney W. Grimes 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 7729b50d902SRodney W. Grimes 120, 121, 122, 123, 124, 125, 126, 127 7739b50d902SRodney W. Grimes }; 7749b50d902SRodney W. Grimes 7759b50d902SRodney W. Grimes if (*src) { 7769b50d902SRodney W. Grimes tmp = from; 7779b50d902SRodney W. Grimes /* 7789b50d902SRodney W. Grimes * create a mapping between "from" and 7799b50d902SRodney W. Grimes * "to" 7809b50d902SRodney W. Grimes */ 7819b50d902SRodney W. Grimes while (*from) 7829b50d902SRodney W. Grimes mapvec[*from++] = (*to) ? *to++ : (char) 0; 7839b50d902SRodney W. Grimes 7849b50d902SRodney W. Grimes while (*src) { 7859b50d902SRodney W. Grimes sch = *src++; 7869b50d902SRodney W. Grimes dch = mapvec[sch]; 7879b50d902SRodney W. Grimes while (dch != sch) { 7889b50d902SRodney W. Grimes sch = dch; 7899b50d902SRodney W. Grimes dch = mapvec[sch]; 7909b50d902SRodney W. Grimes } 7919b50d902SRodney W. Grimes if (*dest = dch) 7929b50d902SRodney W. Grimes dest++; 7939b50d902SRodney W. Grimes } 7949b50d902SRodney W. Grimes /* 7959b50d902SRodney W. Grimes * restore all the changed characters 7969b50d902SRodney W. Grimes */ 7979b50d902SRodney W. Grimes while (*tmp) { 7989b50d902SRodney W. Grimes mapvec[*tmp] = *tmp; 7999b50d902SRodney W. Grimes tmp++; 8009b50d902SRodney W. Grimes } 8019b50d902SRodney W. Grimes } 8029b50d902SRodney W. Grimes *dest = (char) 0; 8039b50d902SRodney W. Grimes } 804