1*ee3599c7Sespie /* $OpenBSD: eval.c,v 1.19 1999/11/17 14:57:21 espie Exp $ */ 2aa676ce1Smillert /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1989, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley by 9df930be7Sderaadt * Ozan Yigit at York University. 10df930be7Sderaadt * 11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 12df930be7Sderaadt * modification, are permitted provided that the following conditions 13df930be7Sderaadt * are met: 14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 15df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 18df930be7Sderaadt * documentation and/or other materials provided with the distribution. 19df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 20df930be7Sderaadt * must display the following acknowledgement: 21df930be7Sderaadt * This product includes software developed by the University of 22df930be7Sderaadt * California, Berkeley and its contributors. 23df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 24df930be7Sderaadt * may be used to endorse or promote products derived from this software 25df930be7Sderaadt * without specific prior written permission. 26df930be7Sderaadt * 27df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df930be7Sderaadt * SUCH DAMAGE. 38df930be7Sderaadt */ 39df930be7Sderaadt 40df930be7Sderaadt #ifndef lint 41df930be7Sderaadt #if 0 42df930be7Sderaadt static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 43df930be7Sderaadt #else 44*ee3599c7Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.19 1999/11/17 14:57:21 espie Exp $"; 45df930be7Sderaadt #endif 46df930be7Sderaadt #endif /* not lint */ 47df930be7Sderaadt 48df930be7Sderaadt /* 49df930be7Sderaadt * eval.c 50df930be7Sderaadt * Facility: m4 macro processor 51df930be7Sderaadt * by: oz 52df930be7Sderaadt */ 53df930be7Sderaadt 54df930be7Sderaadt #include <sys/types.h> 55df930be7Sderaadt #include <errno.h> 56df930be7Sderaadt #include <unistd.h> 57df930be7Sderaadt #include <stdio.h> 58df930be7Sderaadt #include <stdlib.h> 593f42598dSespie #include <stddef.h> 60df930be7Sderaadt #include <string.h> 61445b77f7Smillert #include <fcntl.h> 6281c2181eSespie #include <err.h> 63df930be7Sderaadt #include "mdef.h" 64df930be7Sderaadt #include "stdd.h" 65df930be7Sderaadt #include "extern.h" 66df930be7Sderaadt #include "pathnames.h" 67df930be7Sderaadt 68df930be7Sderaadt /* 69df930be7Sderaadt * eval - evaluate built-in macros. 70df930be7Sderaadt * argc - number of elements in argv. 71df930be7Sderaadt * argv - element vector : 72df930be7Sderaadt * argv[0] = definition of a user 73df930be7Sderaadt * macro or nil if built-in. 74df930be7Sderaadt * argv[1] = name of the macro or 75df930be7Sderaadt * built-in. 76df930be7Sderaadt * argv[2] = parameters to user-defined 77df930be7Sderaadt * . macro or built-in. 78df930be7Sderaadt * . 79df930be7Sderaadt * 80df930be7Sderaadt * Note that the minimum value for argc is 3. A call in the form 81df930be7Sderaadt * of macro-or-builtin() will result in: 82df930be7Sderaadt * argv[0] = nullstr 83df930be7Sderaadt * argv[1] = macro-or-builtin 84df930be7Sderaadt * argv[2] = nullstr 85df930be7Sderaadt */ 86df930be7Sderaadt 87df930be7Sderaadt void 88df930be7Sderaadt eval(argv, argc, td) 8953f6f6bfSespie char *argv[]; 9053f6f6bfSespie int argc; 9153f6f6bfSespie int td; 92df930be7Sderaadt { 9353f6f6bfSespie int c, n; 94df930be7Sderaadt static int sysval = 0; 95df930be7Sderaadt 96df930be7Sderaadt #ifdef DEBUG 97df930be7Sderaadt printf("argc = %d\n", argc); 98df930be7Sderaadt for (n = 0; n < argc; n++) 99df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 100df930be7Sderaadt #endif 101df930be7Sderaadt /* 102df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 103df930be7Sderaadt * have macro-or-builtin() type call. We adjust 104df930be7Sderaadt * argc to avoid further checking.. 105df930be7Sderaadt */ 106df930be7Sderaadt if (argc == 3 && !*(argv[2])) 107df930be7Sderaadt argc--; 108df930be7Sderaadt 109df930be7Sderaadt switch (td & ~STATIC) { 110df930be7Sderaadt 111df930be7Sderaadt case DEFITYPE: 112df930be7Sderaadt if (argc > 2) 113df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 114df930be7Sderaadt break; 115df930be7Sderaadt 116df930be7Sderaadt case PUSDTYPE: 117df930be7Sderaadt if (argc > 2) 118df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 119df930be7Sderaadt break; 120df930be7Sderaadt 121df930be7Sderaadt case DUMPTYPE: 122df930be7Sderaadt dodump(argv, argc); 123df930be7Sderaadt break; 124df930be7Sderaadt 125df930be7Sderaadt case EXPRTYPE: 126df930be7Sderaadt /* 127df930be7Sderaadt * doexpr - evaluate arithmetic 128df930be7Sderaadt * expression 129df930be7Sderaadt */ 130df930be7Sderaadt if (argc > 2) 131df930be7Sderaadt pbnum(expr(argv[2])); 132df930be7Sderaadt break; 133df930be7Sderaadt 134df930be7Sderaadt case IFELTYPE: 135df930be7Sderaadt if (argc > 4) 136df930be7Sderaadt doifelse(argv, argc); 137df930be7Sderaadt break; 138df930be7Sderaadt 139df930be7Sderaadt case IFDFTYPE: 140df930be7Sderaadt /* 141df930be7Sderaadt * doifdef - select one of two 142df930be7Sderaadt * alternatives based on the existence of 143df930be7Sderaadt * another definition 144df930be7Sderaadt */ 145df930be7Sderaadt if (argc > 3) { 146df930be7Sderaadt if (lookup(argv[2]) != nil) 147df930be7Sderaadt pbstr(argv[3]); 148df930be7Sderaadt else if (argc > 4) 149df930be7Sderaadt pbstr(argv[4]); 150df930be7Sderaadt } 151df930be7Sderaadt break; 152df930be7Sderaadt 153df930be7Sderaadt case LENGTYPE: 154df930be7Sderaadt /* 155df930be7Sderaadt * dolen - find the length of the 156df930be7Sderaadt * argument 157df930be7Sderaadt */ 158df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 159df930be7Sderaadt break; 160df930be7Sderaadt 161df930be7Sderaadt case INCRTYPE: 162df930be7Sderaadt /* 163df930be7Sderaadt * doincr - increment the value of the 164df930be7Sderaadt * argument 165df930be7Sderaadt */ 166df930be7Sderaadt if (argc > 2) 167df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 168df930be7Sderaadt break; 169df930be7Sderaadt 170df930be7Sderaadt case DECRTYPE: 171df930be7Sderaadt /* 172df930be7Sderaadt * dodecr - decrement the value of the 173df930be7Sderaadt * argument 174df930be7Sderaadt */ 175df930be7Sderaadt if (argc > 2) 176df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 177df930be7Sderaadt break; 178df930be7Sderaadt 179df930be7Sderaadt case SYSCTYPE: 180df930be7Sderaadt /* 181df930be7Sderaadt * dosys - execute system command 182df930be7Sderaadt */ 183df930be7Sderaadt if (argc > 2) 184df930be7Sderaadt sysval = system(argv[2]); 185df930be7Sderaadt break; 186df930be7Sderaadt 187df930be7Sderaadt case SYSVTYPE: 188df930be7Sderaadt /* 189df930be7Sderaadt * dosysval - return value of the last 190df930be7Sderaadt * system call. 191df930be7Sderaadt * 192df930be7Sderaadt */ 193df930be7Sderaadt pbnum(sysval); 194df930be7Sderaadt break; 195df930be7Sderaadt 196df930be7Sderaadt case INCLTYPE: 197df930be7Sderaadt if (argc > 2) 198df930be7Sderaadt if (!doincl(argv[2])) 19981c2181eSespie err(1, "%s", argv[2]); 200df930be7Sderaadt break; 201df930be7Sderaadt 202df930be7Sderaadt case SINCTYPE: 203df930be7Sderaadt if (argc > 2) 204df930be7Sderaadt (void) doincl(argv[2]); 205df930be7Sderaadt break; 206df930be7Sderaadt #ifdef EXTENDED 207df930be7Sderaadt case PASTTYPE: 208df930be7Sderaadt if (argc > 2) 209df930be7Sderaadt if (!dopaste(argv[2])) 21081c2181eSespie err(1, "%s", argv[2]); 211df930be7Sderaadt break; 212df930be7Sderaadt 213df930be7Sderaadt case SPASTYPE: 214df930be7Sderaadt if (argc > 2) 215df930be7Sderaadt (void) dopaste(argv[2]); 216df930be7Sderaadt break; 217df930be7Sderaadt #endif 218df930be7Sderaadt case CHNQTYPE: 219df930be7Sderaadt dochq(argv, argc); 220df930be7Sderaadt break; 221df930be7Sderaadt 222df930be7Sderaadt case CHNCTYPE: 223df930be7Sderaadt dochc(argv, argc); 224df930be7Sderaadt break; 225df930be7Sderaadt 226df930be7Sderaadt case SUBSTYPE: 227df930be7Sderaadt /* 228df930be7Sderaadt * dosub - select substring 229df930be7Sderaadt * 230df930be7Sderaadt */ 231df930be7Sderaadt if (argc > 3) 232df930be7Sderaadt dosub(argv, argc); 233df930be7Sderaadt break; 234df930be7Sderaadt 235df930be7Sderaadt case SHIFTYPE: 236df930be7Sderaadt /* 237df930be7Sderaadt * doshift - push back all arguments 238df930be7Sderaadt * except the first one (i.e. skip 239df930be7Sderaadt * argv[2]) 240df930be7Sderaadt */ 241df930be7Sderaadt if (argc > 3) { 242df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 2433a73db8cSderaadt pbstr(rquote); 244df930be7Sderaadt pbstr(argv[n]); 2453a73db8cSderaadt pbstr(lquote); 246aa676ce1Smillert putback(COMMA); 247df930be7Sderaadt } 2483a73db8cSderaadt pbstr(rquote); 249df930be7Sderaadt pbstr(argv[3]); 2503a73db8cSderaadt pbstr(lquote); 251df930be7Sderaadt } 252df930be7Sderaadt break; 253df930be7Sderaadt 254df930be7Sderaadt case DIVRTYPE: 255df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 256df930be7Sderaadt dodiv(n); 257df930be7Sderaadt else { 258df930be7Sderaadt active = stdout; 259df930be7Sderaadt oindex = 0; 260df930be7Sderaadt } 261df930be7Sderaadt break; 262df930be7Sderaadt 263df930be7Sderaadt case UNDVTYPE: 264df930be7Sderaadt doundiv(argv, argc); 265df930be7Sderaadt break; 266df930be7Sderaadt 267df930be7Sderaadt case DIVNTYPE: 268df930be7Sderaadt /* 269df930be7Sderaadt * dodivnum - return the number of 270df930be7Sderaadt * current output diversion 271df930be7Sderaadt */ 272df930be7Sderaadt pbnum(oindex); 273df930be7Sderaadt break; 274df930be7Sderaadt 275df930be7Sderaadt case UNDFTYPE: 276df930be7Sderaadt /* 277df930be7Sderaadt * doundefine - undefine a previously 278df930be7Sderaadt * defined macro(s) or m4 keyword(s). 279df930be7Sderaadt */ 280df930be7Sderaadt if (argc > 2) 281df930be7Sderaadt for (n = 2; n < argc; n++) 282df930be7Sderaadt remhash(argv[n], ALL); 283df930be7Sderaadt break; 284df930be7Sderaadt 285df930be7Sderaadt case POPDTYPE: 286df930be7Sderaadt /* 287df930be7Sderaadt * dopopdef - remove the topmost 288df930be7Sderaadt * definitions of macro(s) or m4 289df930be7Sderaadt * keyword(s). 290df930be7Sderaadt */ 291df930be7Sderaadt if (argc > 2) 292df930be7Sderaadt for (n = 2; n < argc; n++) 293df930be7Sderaadt remhash(argv[n], TOP); 294df930be7Sderaadt break; 295df930be7Sderaadt 296df930be7Sderaadt case MKTMTYPE: 297df930be7Sderaadt /* 298df930be7Sderaadt * dotemp - create a temporary file 299df930be7Sderaadt */ 30001e71e69Sespie if (argc > 2) { 30101e71e69Sespie int fd; 30201e71e69Sespie 30301e71e69Sespie fd = mkstemp(argv[2]); 30401e71e69Sespie if (fd == -1) 30501e71e69Sespie err(1, "couldn't make temp file %s", argv[2]); 30601e71e69Sespie close(fd); 30701e71e69Sespie pbstr(argv[2]); 30801e71e69Sespie } 309df930be7Sderaadt break; 310df930be7Sderaadt 311df930be7Sderaadt case TRNLTYPE: 312df930be7Sderaadt /* 313df930be7Sderaadt * dotranslit - replace all characters in 314df930be7Sderaadt * the source string that appears in the 315df930be7Sderaadt * "from" string with the corresponding 316df930be7Sderaadt * characters in the "to" string. 317df930be7Sderaadt */ 318df930be7Sderaadt if (argc > 3) { 3197d3e0b6bSderaadt char temp[STRSPMAX+1]; 320df930be7Sderaadt if (argc > 4) 321df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 322df930be7Sderaadt else 323df930be7Sderaadt map(temp, argv[2], argv[3], null); 324df930be7Sderaadt pbstr(temp); 3257d3e0b6bSderaadt } else if (argc > 2) 326df930be7Sderaadt pbstr(argv[2]); 327df930be7Sderaadt break; 328df930be7Sderaadt 329df930be7Sderaadt case INDXTYPE: 330df930be7Sderaadt /* 331df930be7Sderaadt * doindex - find the index of the second 332df930be7Sderaadt * argument string in the first argument 333df930be7Sderaadt * string. -1 if not present. 334df930be7Sderaadt */ 335df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 336df930be7Sderaadt break; 337df930be7Sderaadt 338df930be7Sderaadt case ERRPTYPE: 339df930be7Sderaadt /* 340df930be7Sderaadt * doerrp - print the arguments to stderr 341df930be7Sderaadt * file 342df930be7Sderaadt */ 343df930be7Sderaadt if (argc > 2) { 344df930be7Sderaadt for (n = 2; n < argc; n++) 345df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 346df930be7Sderaadt fprintf(stderr, "\n"); 347df930be7Sderaadt } 348df930be7Sderaadt break; 349df930be7Sderaadt 350df930be7Sderaadt case DNLNTYPE: 351df930be7Sderaadt /* 352df930be7Sderaadt * dodnl - eat-up-to and including 353df930be7Sderaadt * newline 354df930be7Sderaadt */ 355df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 356df930be7Sderaadt ; 357df930be7Sderaadt break; 358df930be7Sderaadt 359df930be7Sderaadt case M4WRTYPE: 360df930be7Sderaadt /* 361df930be7Sderaadt * dom4wrap - set up for 362df930be7Sderaadt * wrap-up/wind-down activity 363df930be7Sderaadt */ 364df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 365df930be7Sderaadt break; 366df930be7Sderaadt 367df930be7Sderaadt case EXITTYPE: 368df930be7Sderaadt /* 369df930be7Sderaadt * doexit - immediate exit from m4. 370df930be7Sderaadt */ 371df930be7Sderaadt killdiv(); 372df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 373df930be7Sderaadt break; 374df930be7Sderaadt 375df930be7Sderaadt case DEFNTYPE: 376df930be7Sderaadt if (argc > 2) 377df930be7Sderaadt for (n = 2; n < argc; n++) 378df930be7Sderaadt dodefn(argv[n]); 379df930be7Sderaadt break; 380df930be7Sderaadt 381df930be7Sderaadt default: 38281c2181eSespie errx(1, "eval: major botch."); 383df930be7Sderaadt break; 384df930be7Sderaadt } 385df930be7Sderaadt } 386df930be7Sderaadt 387df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 388df930be7Sderaadt 389df930be7Sderaadt /* 390df930be7Sderaadt * expand - user-defined macro expansion 391df930be7Sderaadt */ 392df930be7Sderaadt void 393df930be7Sderaadt expand(argv, argc) 39453f6f6bfSespie char *argv[]; 39553f6f6bfSespie int argc; 396df930be7Sderaadt { 39753f6f6bfSespie char *t; 39853f6f6bfSespie char *p; 39953f6f6bfSespie int n; 40053f6f6bfSespie int argno; 401df930be7Sderaadt 402df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 403df930be7Sderaadt p = t; 404df930be7Sderaadt while (*p) 405df930be7Sderaadt p++; 406df930be7Sderaadt p--; /* last character of defn */ 407df930be7Sderaadt while (p > t) { 408df930be7Sderaadt if (*(p - 1) != ARGFLAG) 409df930be7Sderaadt putback(*p); 410df930be7Sderaadt else { 411df930be7Sderaadt switch (*p) { 412df930be7Sderaadt 413df930be7Sderaadt case '#': 414df930be7Sderaadt pbnum(argc - 2); 415df930be7Sderaadt break; 416df930be7Sderaadt case '0': 417df930be7Sderaadt case '1': 418df930be7Sderaadt case '2': 419df930be7Sderaadt case '3': 420df930be7Sderaadt case '4': 421df930be7Sderaadt case '5': 422df930be7Sderaadt case '6': 423df930be7Sderaadt case '7': 424df930be7Sderaadt case '8': 425df930be7Sderaadt case '9': 426df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 427df930be7Sderaadt pbstr(argv[argno + 1]); 428df930be7Sderaadt break; 429df930be7Sderaadt case '*': 430df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 431df930be7Sderaadt pbstr(argv[n]); 432aa676ce1Smillert putback(COMMA); 433df930be7Sderaadt } 434df930be7Sderaadt pbstr(argv[2]); 435df930be7Sderaadt break; 436aa676ce1Smillert case '@': 437aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 438aa676ce1Smillert pbstr(rquote); 439aa676ce1Smillert pbstr(argv[n]); 440aa676ce1Smillert pbstr(lquote); 441aa676ce1Smillert putback(COMMA); 442aa676ce1Smillert } 443aa676ce1Smillert pbstr(rquote); 444aa676ce1Smillert pbstr(argv[2]); 445aa676ce1Smillert pbstr(lquote); 446aa676ce1Smillert break; 447df930be7Sderaadt default: 448df930be7Sderaadt putback(*p); 449df930be7Sderaadt putback('$'); 450df930be7Sderaadt break; 451df930be7Sderaadt } 452df930be7Sderaadt p--; 453df930be7Sderaadt } 454df930be7Sderaadt p--; 455df930be7Sderaadt } 456df930be7Sderaadt if (p == t) /* do last character */ 457df930be7Sderaadt putback(*p); 458df930be7Sderaadt } 459df930be7Sderaadt 460df930be7Sderaadt /* 461df930be7Sderaadt * dodefine - install definition in the table 462df930be7Sderaadt */ 463df930be7Sderaadt void 464df930be7Sderaadt dodefine(name, defn) 46553f6f6bfSespie char *name; 46653f6f6bfSespie char *defn; 467df930be7Sderaadt { 46853f6f6bfSespie ndptr p; 469df930be7Sderaadt 470df930be7Sderaadt if (!*name) 47181c2181eSespie errx(1, "null definition."); 472df930be7Sderaadt if (STREQ(name, defn)) 47381c2181eSespie errx(1, "%s: recursive definition.", name); 474df930be7Sderaadt if ((p = lookup(name)) == nil) 475df930be7Sderaadt p = addent(name); 476df930be7Sderaadt else if (p->defn != null) 477df930be7Sderaadt free((char *) p->defn); 478df930be7Sderaadt if (!*defn) 479df930be7Sderaadt p->defn = null; 480df930be7Sderaadt else 481df930be7Sderaadt p->defn = xstrdup(defn); 482df930be7Sderaadt p->type = MACRTYPE; 483df930be7Sderaadt } 484df930be7Sderaadt 485df930be7Sderaadt /* 486df930be7Sderaadt * dodefn - push back a quoted definition of 487df930be7Sderaadt * the given name. 488df930be7Sderaadt */ 489df930be7Sderaadt void 490df930be7Sderaadt dodefn(name) 491df930be7Sderaadt char *name; 492df930be7Sderaadt { 49353f6f6bfSespie ndptr p; 494df930be7Sderaadt 495df930be7Sderaadt if ((p = lookup(name)) != nil && p->defn != null) { 4963a73db8cSderaadt pbstr(rquote); 497df930be7Sderaadt pbstr(p->defn); 4983a73db8cSderaadt pbstr(lquote); 499df930be7Sderaadt } 500df930be7Sderaadt } 501df930be7Sderaadt 502df930be7Sderaadt /* 503df930be7Sderaadt * dopushdef - install a definition in the hash table 504df930be7Sderaadt * without removing a previous definition. Since 505df930be7Sderaadt * each new entry is entered in *front* of the 506df930be7Sderaadt * hash bucket, it hides a previous definition from 507df930be7Sderaadt * lookup. 508df930be7Sderaadt */ 509df930be7Sderaadt void 510df930be7Sderaadt dopushdef(name, defn) 51153f6f6bfSespie char *name; 51253f6f6bfSespie char *defn; 513df930be7Sderaadt { 51453f6f6bfSespie ndptr p; 515df930be7Sderaadt 516df930be7Sderaadt if (!*name) 51781c2181eSespie errx(1, "null definition"); 518df930be7Sderaadt if (STREQ(name, defn)) 51981c2181eSespie errx(1, "%s: recursive definition.", name); 520df930be7Sderaadt p = addent(name); 521df930be7Sderaadt if (!*defn) 522df930be7Sderaadt p->defn = null; 523df930be7Sderaadt else 524df930be7Sderaadt p->defn = xstrdup(defn); 525df930be7Sderaadt p->type = MACRTYPE; 526df930be7Sderaadt } 527df930be7Sderaadt 528df930be7Sderaadt /* 529df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 530df930be7Sderaadt * table to stderr. If nothing is specified, the entire 531df930be7Sderaadt * hash table is dumped. 532df930be7Sderaadt */ 533df930be7Sderaadt void 534df930be7Sderaadt dodump(argv, argc) 53553f6f6bfSespie char *argv[]; 53653f6f6bfSespie int argc; 537df930be7Sderaadt { 53853f6f6bfSespie int n; 539df930be7Sderaadt ndptr p; 540df930be7Sderaadt 541df930be7Sderaadt if (argc > 2) { 542df930be7Sderaadt for (n = 2; n < argc; n++) 543df930be7Sderaadt if ((p = lookup(argv[n])) != nil) 544df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 545df930be7Sderaadt p->defn); 5467d3e0b6bSderaadt } else { 547df930be7Sderaadt for (n = 0; n < HASHSIZE; n++) 548df930be7Sderaadt for (p = hashtab[n]; p != nil; p = p->nxtptr) 549df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 550df930be7Sderaadt p->defn); 551df930be7Sderaadt } 552df930be7Sderaadt } 553df930be7Sderaadt 554df930be7Sderaadt /* 555df930be7Sderaadt * doifelse - select one of two alternatives - loop. 556df930be7Sderaadt */ 557df930be7Sderaadt void 558df930be7Sderaadt doifelse(argv, argc) 55953f6f6bfSespie char *argv[]; 56053f6f6bfSespie int argc; 561df930be7Sderaadt { 562df930be7Sderaadt cycle { 563df930be7Sderaadt if (STREQ(argv[2], argv[3])) 564df930be7Sderaadt pbstr(argv[4]); 565df930be7Sderaadt else if (argc == 6) 566df930be7Sderaadt pbstr(argv[5]); 567df930be7Sderaadt else if (argc > 6) { 568df930be7Sderaadt argv += 3; 569df930be7Sderaadt argc -= 3; 570df930be7Sderaadt continue; 571df930be7Sderaadt } 572df930be7Sderaadt break; 573df930be7Sderaadt } 574df930be7Sderaadt } 575df930be7Sderaadt 576df930be7Sderaadt /* 577df930be7Sderaadt * doinclude - include a given file. 578df930be7Sderaadt */ 579df930be7Sderaadt int 580df930be7Sderaadt doincl(ifile) 581df930be7Sderaadt char *ifile; 582df930be7Sderaadt { 583df930be7Sderaadt if (ilevel + 1 == MAXINP) 58481c2181eSespie errx(1, "too many include files."); 5854a769388Sespie if ((infile[ilevel + 1] = fopen_trypath(ifile)) != NULL) { 586df930be7Sderaadt ilevel++; 587df930be7Sderaadt bbase[ilevel] = bufbase = bp; 588df930be7Sderaadt return (1); 5897d3e0b6bSderaadt } else 590df930be7Sderaadt return (0); 591df930be7Sderaadt } 592df930be7Sderaadt 593df930be7Sderaadt #ifdef EXTENDED 594df930be7Sderaadt /* 595df930be7Sderaadt * dopaste - include a given file without any 596df930be7Sderaadt * macro processing. 597df930be7Sderaadt */ 598df930be7Sderaadt int 599df930be7Sderaadt dopaste(pfile) 600df930be7Sderaadt char *pfile; 601df930be7Sderaadt { 602df930be7Sderaadt FILE *pf; 60353f6f6bfSespie int c; 604df930be7Sderaadt 605df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 606df930be7Sderaadt while ((c = getc(pf)) != EOF) 607df930be7Sderaadt putc(c, active); 608df930be7Sderaadt (void) fclose(pf); 609df930be7Sderaadt return (1); 6107d3e0b6bSderaadt } else 611df930be7Sderaadt return (0); 612df930be7Sderaadt } 613df930be7Sderaadt #endif 614df930be7Sderaadt 615df930be7Sderaadt /* 616df930be7Sderaadt * dochq - change quote characters 617df930be7Sderaadt */ 618df930be7Sderaadt void 619df930be7Sderaadt dochq(argv, argc) 62053f6f6bfSespie char *argv[]; 62153f6f6bfSespie int argc; 622df930be7Sderaadt { 623df930be7Sderaadt if (argc > 2) { 62418a1973bSderaadt if (*argv[2]) 62529a0bfdcSderaadt strncpy(lquote, argv[2], MAXCCHARS); 62618a1973bSderaadt else { 62718a1973bSderaadt lquote[0] = LQUOTE; 628f0484631Sespie lquote[1] = EOS; 62918a1973bSderaadt } 630df930be7Sderaadt if (argc > 3) { 631df930be7Sderaadt if (*argv[3]) 63229a0bfdcSderaadt strncpy(rquote, argv[3], MAXCCHARS); 6337d3e0b6bSderaadt } else 63429a0bfdcSderaadt strcpy(rquote, lquote); 6357d3e0b6bSderaadt } else { 636f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 637f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 638df930be7Sderaadt } 639df930be7Sderaadt } 640df930be7Sderaadt 641df930be7Sderaadt /* 642df930be7Sderaadt * dochc - change comment characters 643df930be7Sderaadt */ 644df930be7Sderaadt void 645df930be7Sderaadt dochc(argv, argc) 64653f6f6bfSespie char *argv[]; 64753f6f6bfSespie int argc; 648df930be7Sderaadt { 649df930be7Sderaadt if (argc > 2) { 650df930be7Sderaadt if (*argv[2]) 65129a0bfdcSderaadt strncpy(scommt, argv[2], MAXCCHARS); 652df930be7Sderaadt if (argc > 3) { 653df930be7Sderaadt if (*argv[3]) 65429a0bfdcSderaadt strncpy(ecommt, argv[3], MAXCCHARS); 655df930be7Sderaadt } 656df930be7Sderaadt else 657f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 658df930be7Sderaadt } 659df930be7Sderaadt else { 660f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 661f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 662df930be7Sderaadt } 663df930be7Sderaadt } 664df930be7Sderaadt 665df930be7Sderaadt /* 666df930be7Sderaadt * dodivert - divert the output to a temporary file 667df930be7Sderaadt */ 668df930be7Sderaadt void 669df930be7Sderaadt dodiv(n) 67053f6f6bfSespie int n; 671df930be7Sderaadt { 672445b77f7Smillert int fd; 673445b77f7Smillert 6747d3e0b6bSderaadt oindex = n; 675df930be7Sderaadt if (n < 0 || n >= MAXOUT) 676df930be7Sderaadt n = 0; /* bitbucket */ 677df930be7Sderaadt if (outfile[n] == NULL) { 6783f42598dSespie char fname[] = _PATH_DIVNAME; 6793f42598dSespie 6803f42598dSespie if ((fd = mkstemp(fname)) < 0 || 6813f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 6823f42598dSespie err(1, "%s: cannot divert", fname); 6833f42598dSespie if (unlink(fname) == -1) 6843f42598dSespie err(1, "%s: cannot unlink", fname); 685df930be7Sderaadt } 686df930be7Sderaadt active = outfile[n]; 687df930be7Sderaadt } 688df930be7Sderaadt 689df930be7Sderaadt /* 690df930be7Sderaadt * doundivert - undivert a specified output, or all 691df930be7Sderaadt * other outputs, in numerical order. 692df930be7Sderaadt */ 693df930be7Sderaadt void 694df930be7Sderaadt doundiv(argv, argc) 69553f6f6bfSespie char *argv[]; 69653f6f6bfSespie int argc; 697df930be7Sderaadt { 69853f6f6bfSespie int ind; 69953f6f6bfSespie int n; 700df930be7Sderaadt 701df930be7Sderaadt if (argc > 2) { 702df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 703df930be7Sderaadt n = atoi(argv[ind]); 704df930be7Sderaadt if (n > 0 && n < MAXOUT && outfile[n] != NULL) 705df930be7Sderaadt getdiv(n); 706df930be7Sderaadt 707df930be7Sderaadt } 708df930be7Sderaadt } 709df930be7Sderaadt else 710df930be7Sderaadt for (n = 1; n < MAXOUT; n++) 711df930be7Sderaadt if (outfile[n] != NULL) 712df930be7Sderaadt getdiv(n); 713df930be7Sderaadt } 714df930be7Sderaadt 715df930be7Sderaadt /* 716df930be7Sderaadt * dosub - select substring 717df930be7Sderaadt */ 718df930be7Sderaadt void 719df930be7Sderaadt dosub(argv, argc) 72053f6f6bfSespie char *argv[]; 72153f6f6bfSespie int argc; 722df930be7Sderaadt { 72353f6f6bfSespie char *ap, *fc, *k; 72453f6f6bfSespie int nc; 725df930be7Sderaadt 726df930be7Sderaadt if (argc < 5) 727df930be7Sderaadt nc = MAXTOK; 728df930be7Sderaadt else 729df930be7Sderaadt #ifdef EXPR 730df930be7Sderaadt nc = expr(argv[4]); 731df930be7Sderaadt #else 732df930be7Sderaadt nc = atoi(argv[4]); 733df930be7Sderaadt #endif 734df930be7Sderaadt ap = argv[2]; /* target string */ 735df930be7Sderaadt #ifdef EXPR 736df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 737df930be7Sderaadt #else 738df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 739df930be7Sderaadt #endif 740df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 741df930be7Sderaadt for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 742df930be7Sderaadt putback(*k); 743df930be7Sderaadt } 744df930be7Sderaadt 745df930be7Sderaadt /* 746df930be7Sderaadt * map: 747df930be7Sderaadt * map every character of s1 that is specified in from 748df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 749df930be7Sderaadt * 750df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 751df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 752df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 753df930be7Sderaadt * than the corresponding entries are null, which means that those 754df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 755df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 756df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 757df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 758df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 759df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 760df930be7Sderaadt * character value (dch) in this location is different than the source 761df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 762df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 763df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 764df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 765df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 766df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 767df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 768df930be7Sderaadt * destination string. 769df930be7Sderaadt */ 770df930be7Sderaadt void 771df930be7Sderaadt map(dest, src, from, to) 77253f6f6bfSespie char *dest; 77353f6f6bfSespie char *src; 77453f6f6bfSespie char *from; 77553f6f6bfSespie char *to; 776df930be7Sderaadt { 77753f6f6bfSespie char *tmp; 778*ee3599c7Sespie unsigned char sch, dch; 779*ee3599c7Sespie static unsigned char mapvec[256] = { 780*ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 781*ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 782*ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 783*ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 784*ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 785*ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 786*ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 787*ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 788*ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 789*ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 790*ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 791*ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 792*ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 793*ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 794*ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 795*ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 796*ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 797*ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 798df930be7Sderaadt }; 799df930be7Sderaadt 800df930be7Sderaadt if (*src) { 801df930be7Sderaadt tmp = from; 802df930be7Sderaadt /* 803df930be7Sderaadt * create a mapping between "from" and 804df930be7Sderaadt * "to" 805df930be7Sderaadt */ 806df930be7Sderaadt while (*from) 807*ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 808*ee3599c7Sespie (unsigned char)(*to++) : 0; 809df930be7Sderaadt 810df930be7Sderaadt while (*src) { 811*ee3599c7Sespie sch = (unsigned char)(*src++); 812df930be7Sderaadt dch = mapvec[sch]; 813df930be7Sderaadt while (dch != sch) { 814df930be7Sderaadt sch = dch; 815df930be7Sderaadt dch = mapvec[sch]; 816df930be7Sderaadt } 817*ee3599c7Sespie if ((*dest = (char)dch)) 818df930be7Sderaadt dest++; 819df930be7Sderaadt } 820df930be7Sderaadt /* 821df930be7Sderaadt * restore all the changed characters 822df930be7Sderaadt */ 823df930be7Sderaadt while (*tmp) { 824*ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 825df930be7Sderaadt tmp++; 826df930be7Sderaadt } 827df930be7Sderaadt } 828*ee3599c7Sespie *dest = '\0'; 829df930be7Sderaadt } 830