eval.c revision 69246
1254885Sdumbbell/* 2254885Sdumbbell * Copyright (c) 1989, 1993 3254885Sdumbbell * The Regents of the University of California. All rights reserved. 4254885Sdumbbell * 5254885Sdumbbell * This code is derived from software contributed to Berkeley by 6254885Sdumbbell * Ozan Yigit at York University. 7254885Sdumbbell * 8254885Sdumbbell * Redistribution and use in source and binary forms, with or without 9254885Sdumbbell * modification, are permitted provided that the following conditions 10254885Sdumbbell * are met: 11254885Sdumbbell * 1. Redistributions of source code must retain the above copyright 12254885Sdumbbell * notice, this list of conditions and the following disclaimer. 13254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 14254885Sdumbbell * notice, this list of conditions and the following disclaimer in the 15254885Sdumbbell * documentation and/or other materials provided with the distribution. 16254885Sdumbbell * 3. All advertising materials mentioning features or use of this software 17254885Sdumbbell * must display the following acknowledgement: 18254885Sdumbbell * This product includes software developed by the University of 19254885Sdumbbell * California, Berkeley and its contributors. 20254885Sdumbbell * 4. Neither the name of the University nor the names of its contributors 21254885Sdumbbell * may be used to endorse or promote products derived from this software 22254885Sdumbbell * without specific prior written permission. 23254885Sdumbbell * 24254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27254885Sdumbbell * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34254885Sdumbbell * SUCH DAMAGE. 35254885Sdumbbell */ 36254885Sdumbbell 37254885Sdumbbell#ifndef lint 38254885Sdumbbell#if 0 39254885Sdumbbellstatic char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; 40254885Sdumbbell#endif 41254885Sdumbbellstatic const char rcsid[] = 42254885Sdumbbell "$FreeBSD: head/usr.bin/m4/eval.c 69246 2000-11-27 04:26:39Z kris $"; 43254885Sdumbbell#endif /* not lint */ 44254885Sdumbbell 45254885Sdumbbell/* 46254885Sdumbbell * eval.c 47254885Sdumbbell * Facility: m4 macro processor 48254885Sdumbbell * by: oz 49254885Sdumbbell */ 50254885Sdumbbell 51254885Sdumbbell#include <sys/types.h> 52254885Sdumbbell#include <err.h> 53254885Sdumbbell#include <stdio.h> 54254885Sdumbbell#include <stdlib.h> 55254885Sdumbbell#include <string.h> 56254885Sdumbbell#include <unistd.h> 57254885Sdumbbell#include "mdef.h" 58254885Sdumbbell#include "stdd.h" 59254885Sdumbbell#include "extern.h" 60254885Sdumbbell#include "pathnames.h" 61254885Sdumbbell 62254885Sdumbbell/* 63254885Sdumbbell * eval - evaluate built-in macros. 64254885Sdumbbell * argc - number of elements in argv. 65254885Sdumbbell * argv - element vector : 66254885Sdumbbell * argv[0] = definition of a user 67254885Sdumbbell * macro or nil if built-in. 68254885Sdumbbell * argv[1] = name of the macro or 69254885Sdumbbell * built-in. 70254885Sdumbbell * argv[2] = parameters to user-defined 71254885Sdumbbell * . macro or built-in. 72254885Sdumbbell * . 73254885Sdumbbell * 74254885Sdumbbell * Note that the minimum value for argc is 3. A call in the form 75254885Sdumbbell * of macro-or-builtin() will result in: 76254885Sdumbbell * argv[0] = nullstr 77254885Sdumbbell * argv[1] = macro-or-builtin 78254885Sdumbbell * argv[2] = nullstr 79254885Sdumbbell */ 80254885Sdumbbell 81254885Sdumbbellvoid 82254885Sdumbbelleval(argv, argc, td) 83254885Sdumbbellregister char *argv[]; 84254885Sdumbbellregister int argc; 85254885Sdumbbellregister int td; 86254885Sdumbbell{ 87254885Sdumbbell register int c, n; 88254885Sdumbbell static int sysval = 0; 89254885Sdumbbell 90254885Sdumbbell#ifdef DEBUG 91254885Sdumbbell printf("argc = %d\n", argc); 92254885Sdumbbell for (n = 0; n < argc; n++) 93254885Sdumbbell printf("argv[%d] = %s\n", n, argv[n]); 94254885Sdumbbell#endif 95254885Sdumbbell /* 96254885Sdumbbell * if argc == 3 and argv[2] is null, then we 97254885Sdumbbell * have macro-or-builtin() type call. We adjust 98254885Sdumbbell * argc to avoid further checking.. 99254885Sdumbbell */ 100254885Sdumbbell if (argc == 3 && !*(argv[2])) 101254885Sdumbbell argc--; 102254885Sdumbbell 103254885Sdumbbell switch (td & ~STATIC) { 104254885Sdumbbell 105254885Sdumbbell case DEFITYPE: 106254885Sdumbbell if (argc > 2) 107254885Sdumbbell dodefine(argv[2], (argc > 3) ? argv[3] : null); 108254885Sdumbbell break; 109254885Sdumbbell 110254885Sdumbbell case PUSDTYPE: 111254885Sdumbbell if (argc > 2) 112254885Sdumbbell dopushdef(argv[2], (argc > 3) ? argv[3] : null); 113254885Sdumbbell break; 114254885Sdumbbell 115254885Sdumbbell case DUMPTYPE: 116254885Sdumbbell dodump(argv, argc); 117254885Sdumbbell break; 118254885Sdumbbell 119254885Sdumbbell case EXPRTYPE: 120254885Sdumbbell /* 121254885Sdumbbell * doexpr - evaluate arithmetic 122254885Sdumbbell * expression 123254885Sdumbbell */ 124254885Sdumbbell if (argc > 2) 125254885Sdumbbell pbnum(expr(argv[2])); 126254885Sdumbbell break; 127254885Sdumbbell 128254885Sdumbbell case IFELTYPE: 129254885Sdumbbell if (argc > 4) 130254885Sdumbbell doifelse(argv, argc); 131254885Sdumbbell break; 132254885Sdumbbell 133254885Sdumbbell case IFDFTYPE: 134254885Sdumbbell /* 135254885Sdumbbell * doifdef - select one of two 136254885Sdumbbell * alternatives based on the existence of 137254885Sdumbbell * another definition 138254885Sdumbbell */ 139254885Sdumbbell if (argc > 3) { 140254885Sdumbbell if (lookup(argv[2]) != nil) 141254885Sdumbbell pbstr(argv[3]); 142254885Sdumbbell else if (argc > 4) 143254885Sdumbbell pbstr(argv[4]); 144254885Sdumbbell } 145254885Sdumbbell break; 146254885Sdumbbell 147254885Sdumbbell case LENGTYPE: 148254885Sdumbbell /* 149254885Sdumbbell * dolen - find the length of the 150254885Sdumbbell * argument 151254885Sdumbbell */ 152254885Sdumbbell if (argc > 2) 153254885Sdumbbell pbnum((argc > 2) ? strlen(argv[2]) : 0); 154254885Sdumbbell break; 155254885Sdumbbell 156254885Sdumbbell case INCRTYPE: 157254885Sdumbbell /* 158254885Sdumbbell * doincr - increment the value of the 159254885Sdumbbell * argument 160254885Sdumbbell */ 161254885Sdumbbell if (argc > 2) 162254885Sdumbbell pbnum(atoi(argv[2]) + 1); 163254885Sdumbbell break; 164254885Sdumbbell 165254885Sdumbbell case DECRTYPE: 166254885Sdumbbell /* 167254885Sdumbbell * dodecr - decrement the value of the 168254885Sdumbbell * argument 169254885Sdumbbell */ 170254885Sdumbbell if (argc > 2) 171254885Sdumbbell pbnum(atoi(argv[2]) - 1); 172254885Sdumbbell break; 173254885Sdumbbell 174254885Sdumbbell case SYSCTYPE: 175254885Sdumbbell /* 176254885Sdumbbell * dosys - execute system command 177254885Sdumbbell */ 178254885Sdumbbell /* Make sure m4 output is NOT interrupted */ 179254885Sdumbbell fflush(stdout); 180254885Sdumbbell fflush(stderr); 181254885Sdumbbell if (argc > 2) 182254885Sdumbbell sysval = system(argv[2]); 183254885Sdumbbell break; 184254885Sdumbbell 185254885Sdumbbell case SYSVTYPE: 186254885Sdumbbell /* 187254885Sdumbbell * dosysval - return value of the last 188254885Sdumbbell * system call. 189254885Sdumbbell * 190254885Sdumbbell */ 191254885Sdumbbell pbnum(sysval); 192254885Sdumbbell break; 193254885Sdumbbell 194254885Sdumbbell case INCLTYPE: 195254885Sdumbbell if (argc > 2) 196254885Sdumbbell if (!doincl(argv[2])) 197254885Sdumbbell err(1, "%s", argv[2]); 198254885Sdumbbell break; 199254885Sdumbbell 200254885Sdumbbell case SINCTYPE: 201254885Sdumbbell if (argc > 2) 202254885Sdumbbell (void) doincl(argv[2]); 203254885Sdumbbell break; 204254885Sdumbbell#ifdef EXTENDED 205254885Sdumbbell case PASTTYPE: 206254885Sdumbbell if (argc > 2) 207254885Sdumbbell if (!dopaste(argv[2])) 208254885Sdumbbell err(1, "%s", argv[2]); 209254885Sdumbbell break; 210254885Sdumbbell 211254885Sdumbbell case SPASTYPE: 212254885Sdumbbell if (argc > 2) 213254885Sdumbbell (void) dopaste(argv[2]); 214254885Sdumbbell break; 215254885Sdumbbell#endif 216254885Sdumbbell case CHNQTYPE: 217254885Sdumbbell dochq(argv, argc); 218254885Sdumbbell break; 219254885Sdumbbell 220254885Sdumbbell case CHNCTYPE: 221254885Sdumbbell dochc(argv, argc); 222254885Sdumbbell break; 223254885Sdumbbell 224254885Sdumbbell case SUBSTYPE: 225254885Sdumbbell /* 226254885Sdumbbell * dosub - select substring 227254885Sdumbbell * 228254885Sdumbbell */ 229254885Sdumbbell if (argc > 3) 230254885Sdumbbell dosub(argv, argc); 231254885Sdumbbell break; 232254885Sdumbbell 233254885Sdumbbell case SHIFTYPE: 234254885Sdumbbell /* 235254885Sdumbbell * doshift - push back all arguments 236254885Sdumbbell * except the first one (i.e. skip 237254885Sdumbbell * argv[2]) 238254885Sdumbbell */ 239254885Sdumbbell if (argc > 3) { 240254885Sdumbbell for (n = argc - 1; n > 3; n--) { 241254885Sdumbbell putback(rquote); 242254885Sdumbbell pbstr(argv[n]); 243254885Sdumbbell putback(lquote); 244254885Sdumbbell putback(','); 245254885Sdumbbell } 246254885Sdumbbell putback(rquote); 247254885Sdumbbell pbstr(argv[3]); 248254885Sdumbbell putback(lquote); 249254885Sdumbbell } 250254885Sdumbbell break; 251254885Sdumbbell 252254885Sdumbbell case DIVRTYPE: 253254885Sdumbbell if (argc > 2 && (n = atoi(argv[2])) != 0) 254254885Sdumbbell dodiv(n); 255254885Sdumbbell else { 256254885Sdumbbell active = stdout; 257254885Sdumbbell oindex = 0; 258254885Sdumbbell } 259254885Sdumbbell break; 260254885Sdumbbell 261254885Sdumbbell case UNDVTYPE: 262254885Sdumbbell doundiv(argv, argc); 263254885Sdumbbell break; 264254885Sdumbbell 265254885Sdumbbell case DIVNTYPE: 266254885Sdumbbell /* 267254885Sdumbbell * dodivnum - return the number of 268254885Sdumbbell * current output diversion 269254885Sdumbbell */ 270254885Sdumbbell pbnum(oindex); 271254885Sdumbbell break; 272254885Sdumbbell 273254885Sdumbbell case UNDFTYPE: 274254885Sdumbbell /* 275254885Sdumbbell * doundefine - undefine a previously 276254885Sdumbbell * defined macro(s) or m4 keyword(s). 277254885Sdumbbell */ 278254885Sdumbbell if (argc > 2) 279254885Sdumbbell for (n = 2; n < argc; n++) 280254885Sdumbbell remhash(argv[n], ALL); 281254885Sdumbbell break; 282254885Sdumbbell 283254885Sdumbbell case POPDTYPE: 284254885Sdumbbell /* 285254885Sdumbbell * dopopdef - remove the topmost 286254885Sdumbbell * definitions of macro(s) or m4 287254885Sdumbbell * keyword(s). 288254885Sdumbbell */ 289254885Sdumbbell if (argc > 2) 290254885Sdumbbell for (n = 2; n < argc; n++) 291254885Sdumbbell remhash(argv[n], TOP); 292254885Sdumbbell break; 293254885Sdumbbell 294254885Sdumbbell case MKTMTYPE: 295254885Sdumbbell /* 296254885Sdumbbell * dotemp - create a temporary file 297254885Sdumbbell */ 298254885Sdumbbell if (argc > 2) 299254885Sdumbbell pbstr(mktemp(argv[2])); 300254885Sdumbbell break; 301254885Sdumbbell 302254885Sdumbbell case TRNLTYPE: 303254885Sdumbbell /* 304254885Sdumbbell * dotranslit - replace all characters in 305254885Sdumbbell * the source string that appears in the 306254885Sdumbbell * "from" string with the corresponding 307254885Sdumbbell * characters in the "to" string. 308254885Sdumbbell */ 309254885Sdumbbell if (argc > 3) { 310254885Sdumbbell char temp[STRSPMAX+1]; 311254885Sdumbbell if (argc > 4) 312254885Sdumbbell map(temp, argv[2], argv[3], argv[4]); 313254885Sdumbbell else 314254885Sdumbbell map(temp, argv[2], argv[3], null); 315254885Sdumbbell pbstr(temp); 316254885Sdumbbell } 317254885Sdumbbell else if (argc > 2) 318254885Sdumbbell pbstr(argv[2]); 319254885Sdumbbell break; 320254885Sdumbbell 321254885Sdumbbell case INDXTYPE: 322254885Sdumbbell /* 323254885Sdumbbell * doindex - find the index of the second 324254885Sdumbbell * argument string in the first argument 325254885Sdumbbell * string. -1 if not present. 326254885Sdumbbell */ 327254885Sdumbbell pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 328254885Sdumbbell break; 329254885Sdumbbell 330254885Sdumbbell case ERRPTYPE: 331254885Sdumbbell /* 332254885Sdumbbell * doerrp - print the arguments to stderr 333254885Sdumbbell * file 334254885Sdumbbell */ 335254885Sdumbbell if (argc > 2) { 336254885Sdumbbell for (n = 2; n < argc; n++) 337254885Sdumbbell fprintf(stderr, "%s ", argv[n]); 338254885Sdumbbell fprintf(stderr, "\n"); 339254885Sdumbbell } 340254885Sdumbbell break; 341254885Sdumbbell 342254885Sdumbbell case DNLNTYPE: 343254885Sdumbbell /* 344254885Sdumbbell * dodnl - eat-up-to and including 345254885Sdumbbell * newline 346254885Sdumbbell */ 347254885Sdumbbell while ((c = gpbc()) != '\n' && c != EOF) 348254885Sdumbbell ; 349254885Sdumbbell break; 350254885Sdumbbell 351254885Sdumbbell case M4WRTYPE: 352254885Sdumbbell /* 353254885Sdumbbell * dom4wrap - set up for 354254885Sdumbbell * wrap-up/wind-down activity 355254885Sdumbbell */ 356254885Sdumbbell m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 357254885Sdumbbell break; 358254885Sdumbbell 359254885Sdumbbell case EXITTYPE: 360254885Sdumbbell /* 361254885Sdumbbell * doexit - immediate exit from m4. 362254885Sdumbbell */ 363254885Sdumbbell killdiv(); 364254885Sdumbbell exit((argc > 2) ? atoi(argv[2]) : 0); 365254885Sdumbbell break; 366254885Sdumbbell 367254885Sdumbbell case DEFNTYPE: 368254885Sdumbbell if (argc > 2) 369254885Sdumbbell for (n = 2; n < argc; n++) 370254885Sdumbbell dodefn(argv[n]); 371254885Sdumbbell break; 372254885Sdumbbell 373254885Sdumbbell case MACRTYPE: 374254885Sdumbbell pbstr(""); 375254885Sdumbbell break; 376254885Sdumbbell 377254885Sdumbbell default: 378254885Sdumbbell errx(1, "eval: major botch"); 379254885Sdumbbell break; 380254885Sdumbbell } 381254885Sdumbbell} 382254885Sdumbbell 383254885Sdumbbellconst char dumpfmt[] = "`%s'\t`%s'\n"; /* format string for dumpdef */ 384254885Sdumbbell 385254885Sdumbbell/* 386254885Sdumbbell * expand - user-defined macro expansion 387254885Sdumbbell */ 388254885Sdumbbellvoid 389254885Sdumbbellexpand(argv, argc) 390254885Sdumbbellregister char *argv[]; 391254885Sdumbbellregister int argc; 392254885Sdumbbell{ 393254885Sdumbbell register unsigned char *t; 394254885Sdumbbell register unsigned char *p; 395254885Sdumbbell register int n; 396254885Sdumbbell register int argno; 397254885Sdumbbell 398254885Sdumbbell t = argv[0]; /* defn string as a whole */ 399254885Sdumbbell p = t; 400254885Sdumbbell while (*p) 401254885Sdumbbell p++; 402254885Sdumbbell p--; /* last character of defn */ 403254885Sdumbbell while (p > t) { 404254885Sdumbbell if (*(p - 1) != ARGFLAG) 405254885Sdumbbell putback(*p); 406254885Sdumbbell else { 407254885Sdumbbell switch (*p) { 408254885Sdumbbell 409254885Sdumbbell case '#': 410254885Sdumbbell pbnum(argc - 2); 411254885Sdumbbell break; 412254885Sdumbbell case '0': 413254885Sdumbbell case '1': 414254885Sdumbbell case '2': 415254885Sdumbbell case '3': 416254885Sdumbbell case '4': 417254885Sdumbbell case '5': 418254885Sdumbbell case '6': 419254885Sdumbbell case '7': 420254885Sdumbbell case '8': 421254885Sdumbbell case '9': 422254885Sdumbbell if ((argno = *p - '0') < argc - 1) 423254885Sdumbbell pbstr(argv[argno + 1]); 424254885Sdumbbell break; 425254885Sdumbbell case '*': 426254885Sdumbbell for (n = argc - 1; n > 2; n--) { 427254885Sdumbbell pbstr(argv[n]); 428254885Sdumbbell putback(','); 429254885Sdumbbell } 430254885Sdumbbell pbstr(argv[2]); 431254885Sdumbbell break; 432254885Sdumbbell case '@': 433254885Sdumbbell for( n = argc - 1; n >= 2; n-- ) 434254885Sdumbbell { 435254885Sdumbbell putback(rquote); 436254885Sdumbbell pbstr(argv[n]); 437254885Sdumbbell putback(lquote); 438254885Sdumbbell if( n > 2 ) 439254885Sdumbbell putback(','); 440254885Sdumbbell } 441254885Sdumbbell break; 442254885Sdumbbell default: 443254885Sdumbbell putback(*p); 444254885Sdumbbell putback('$'); 445254885Sdumbbell break; 446254885Sdumbbell } 447254885Sdumbbell p--; 448254885Sdumbbell } 449254885Sdumbbell p--; 450254885Sdumbbell } 451254885Sdumbbell if (p == t) /* do last character */ 452254885Sdumbbell putback(*p); 453254885Sdumbbell} 454254885Sdumbbell 455254885Sdumbbell/* 456254885Sdumbbell * dodefine - install definition in the table 457254885Sdumbbell */ 458254885Sdumbbellvoid 459254885Sdumbbelldodefine(name, defn) 460254885Sdumbbellregister char *name; 461254885Sdumbbellregister char *defn; 462254885Sdumbbell{ 463254885Sdumbbell register ndptr p; 464254885Sdumbbell 465254885Sdumbbell if (!*name) 466254885Sdumbbell errx(1, "null definition"); 467254885Sdumbbell if (STREQ(name, defn)) 468254885Sdumbbell errx(1, "%s: recursive definition", name); 469254885Sdumbbell if ((p = lookup(name)) == nil) 470254885Sdumbbell p = addent(name); 471254885Sdumbbell else if (p->defn != null) 472254885Sdumbbell free((char *) p->defn); 473254885Sdumbbell if (!*defn) 474254885Sdumbbell p->defn = null; 475254885Sdumbbell else 476254885Sdumbbell p->defn = xstrdup(defn); 477254885Sdumbbell p->type = MACRTYPE; 478254885Sdumbbell} 479254885Sdumbbell 480254885Sdumbbell/* 481254885Sdumbbell * dodefn - push back a quoted definition of 482254885Sdumbbell * the given name. 483254885Sdumbbell */ 484254885Sdumbbellvoid 485254885Sdumbbelldodefn(name) 486254885Sdumbbellchar *name; 487254885Sdumbbell{ 488254885Sdumbbell register ndptr p; 489254885Sdumbbell 490254885Sdumbbell if ((p = lookup(name)) != nil && p->defn != null) { 491254885Sdumbbell putback(rquote); 492254885Sdumbbell pbstr(p->defn); 493254885Sdumbbell putback(lquote); 494254885Sdumbbell } 495254885Sdumbbell} 496254885Sdumbbell 497254885Sdumbbell/* 498254885Sdumbbell * dopushdef - install a definition in the hash table 499254885Sdumbbell * without removing a previous definition. Since 500254885Sdumbbell * each new entry is entered in *front* of the 501254885Sdumbbell * hash bucket, it hides a previous definition from 502254885Sdumbbell * lookup. 503254885Sdumbbell */ 504254885Sdumbbellvoid 505254885Sdumbbelldopushdef(name, defn) 506254885Sdumbbellregister char *name; 507254885Sdumbbellregister char *defn; 508254885Sdumbbell{ 509254885Sdumbbell register ndptr p; 510254885Sdumbbell 511254885Sdumbbell if (!*name) 512254885Sdumbbell errx(1, "null definition"); 513254885Sdumbbell if (STREQ(name, defn)) 514254885Sdumbbell errx(1, "%s: recursive definition", name); 515254885Sdumbbell p = addent(name); 516254885Sdumbbell if (!*defn) 517254885Sdumbbell p->defn = null; 518254885Sdumbbell else 519254885Sdumbbell p->defn = xstrdup(defn); 520254885Sdumbbell p->type = MACRTYPE; 521254885Sdumbbell} 522254885Sdumbbell 523254885Sdumbbell/* 524254885Sdumbbell * dodumpdef - dump the specified definitions in the hash 525254885Sdumbbell * table to stderr. If nothing is specified, the entire 526254885Sdumbbell * hash table is dumped. 527254885Sdumbbell */ 528254885Sdumbbellvoid 529254885Sdumbbelldodump(argv, argc) 530254885Sdumbbellregister char *argv[]; 531254885Sdumbbellregister int argc; 532254885Sdumbbell{ 533254885Sdumbbell register int n; 534254885Sdumbbell ndptr p; 535254885Sdumbbell 536254885Sdumbbell if (argc > 2) { 537254885Sdumbbell for (n = 2; n < argc; n++) 538254885Sdumbbell if ((p = lookup(argv[n])) != nil) 539254885Sdumbbell fprintf(stderr, dumpfmt, p->name, 540254885Sdumbbell p->defn); 541254885Sdumbbell } 542254885Sdumbbell else { 543254885Sdumbbell for (n = 0; n < HASHSIZE; n++) 544254885Sdumbbell for (p = hashtab[n]; p != nil; p = p->nxtptr) 545254885Sdumbbell fprintf(stderr, dumpfmt, p->name, 546254885Sdumbbell p->defn); 547254885Sdumbbell } 548254885Sdumbbell} 549254885Sdumbbell 550254885Sdumbbell/* 551254885Sdumbbell * doifelse - select one of two alternatives - loop. 552254885Sdumbbell */ 553254885Sdumbbellvoid 554254885Sdumbbelldoifelse(argv, argc) 555254885Sdumbbellregister char *argv[]; 556254885Sdumbbellregister int argc; 557254885Sdumbbell{ 558254885Sdumbbell cycle { 559254885Sdumbbell if (STREQ(argv[2], argv[3])) 560254885Sdumbbell pbstr(argv[4]); 561254885Sdumbbell else if (argc == 6) 562254885Sdumbbell pbstr(argv[5]); 563254885Sdumbbell else if (argc > 6) { 564254885Sdumbbell argv += 3; 565254885Sdumbbell argc -= 3; 566254885Sdumbbell continue; 567254885Sdumbbell } 568254885Sdumbbell break; 569254885Sdumbbell } 570254885Sdumbbell} 571254885Sdumbbell 572254885Sdumbbell/* 573254885Sdumbbell * doinclude - include a given file. 574254885Sdumbbell */ 575254885Sdumbbellint 576254885Sdumbbelldoincl(ifile) 577254885Sdumbbellchar *ifile; 578254885Sdumbbell{ 579254885Sdumbbell if (ilevel + 1 == MAXINP) 580254885Sdumbbell errx(1, "too many include files"); 581254885Sdumbbell if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 582254885Sdumbbell ilevel++; 583254885Sdumbbell bbase[ilevel] = bufbase = bp; 584254885Sdumbbell return (1); 585254885Sdumbbell } 586254885Sdumbbell else 587254885Sdumbbell return (0); 588254885Sdumbbell} 589254885Sdumbbell 590254885Sdumbbell#ifdef EXTENDED 591254885Sdumbbell/* 592254885Sdumbbell * dopaste - include a given file without any 593254885Sdumbbell * macro processing. 594254885Sdumbbell */ 595254885Sdumbbellint 596254885Sdumbbelldopaste(pfile) 597254885Sdumbbellchar *pfile; 598254885Sdumbbell{ 599254885Sdumbbell FILE *pf; 600254885Sdumbbell register int c; 601254885Sdumbbell 602254885Sdumbbell if ((pf = fopen(pfile, "r")) != NULL) { 603254885Sdumbbell while ((c = getc(pf)) != EOF) 604254885Sdumbbell putc(c, active); 605254885Sdumbbell (void) fclose(pf); 606254885Sdumbbell return (1); 607254885Sdumbbell } 608254885Sdumbbell else 609254885Sdumbbell return (0); 610254885Sdumbbell} 611254885Sdumbbell#endif 612254885Sdumbbell 613254885Sdumbbell/* 614254885Sdumbbell * dochq - change quote characters 615254885Sdumbbell */ 616254885Sdumbbellvoid 617254885Sdumbbelldochq(argv, argc) 618254885Sdumbbellregister char *argv[]; 619254885Sdumbbellregister int argc; 620254885Sdumbbell{ 621254885Sdumbbell if (argc > 2) { 622254885Sdumbbell if (*argv[2]) 623254885Sdumbbell lquote = *argv[2]; 624254885Sdumbbell else 625254885Sdumbbell lquote = LQUOTE; 626254885Sdumbbell if (argc > 3) { 627254885Sdumbbell if (*argv[3]) 628254885Sdumbbell rquote = *argv[3]; 629254885Sdumbbell else 630254885Sdumbbell rquote = RQUOTE; 631254885Sdumbbell } 632254885Sdumbbell else 633254885Sdumbbell rquote = lquote; 634254885Sdumbbell } 635254885Sdumbbell else { 636254885Sdumbbell lquote = LQUOTE; 637254885Sdumbbell rquote = RQUOTE; 638254885Sdumbbell } 639254885Sdumbbell} 640254885Sdumbbell 641254885Sdumbbell/* 642254885Sdumbbell * dochc - change comment characters 643254885Sdumbbell */ 644254885Sdumbbellvoid 645254885Sdumbbelldochc(argv, argc) 646254885Sdumbbellregister char *argv[]; 647254885Sdumbbellregister int argc; 648254885Sdumbbell{ 649254885Sdumbbell if (argc > 2) { 650254885Sdumbbell if (*argv[2]) 651254885Sdumbbell scommt = *argv[2]; 652254885Sdumbbell if (argc > 3) { 653254885Sdumbbell if (*argv[3]) 654254885Sdumbbell ecommt = *argv[3]; 655254885Sdumbbell } 656254885Sdumbbell else 657254885Sdumbbell ecommt = ECOMMT; 658254885Sdumbbell } 659254885Sdumbbell else { 660254885Sdumbbell scommt = SCOMMT; 661254885Sdumbbell ecommt = ECOMMT; 662254885Sdumbbell } 663254885Sdumbbell} 664254885Sdumbbell 665254885Sdumbbell/* 666254885Sdumbbell * dodivert - divert the output to a temporary file 667254885Sdumbbell */ 668254885Sdumbbellvoid 669254885Sdumbbelldodiv(n) 670254885Sdumbbellregister int n; 671254885Sdumbbell{ 672254885Sdumbbell oindex = n; 673254885Sdumbbell if (n < 0 || n >= MAXOUT) 674254885Sdumbbell n = 0; /* bitbucket */ 675254885Sdumbbell if (outfile[n] == NULL) { 676254885Sdumbbell m4temp[UNIQUE] = n + '0'; 677254885Sdumbbell if ((outfile[n] = fopen(m4temp, "w")) == NULL) 678254885Sdumbbell errx(1, "%s: cannot divert", m4temp); 679254885Sdumbbell } 680254885Sdumbbell active = outfile[n]; 681254885Sdumbbell} 682254885Sdumbbell 683254885Sdumbbell/* 684254885Sdumbbell * doundivert - undivert a specified output, or all 685254885Sdumbbell * other outputs, in numerical order. 686254885Sdumbbell */ 687254885Sdumbbellvoid 688254885Sdumbbelldoundiv(argv, argc) 689254885Sdumbbellregister char *argv[]; 690254885Sdumbbellregister int argc; 691254885Sdumbbell{ 692254885Sdumbbell register int ind; 693254885Sdumbbell register int n; 694254885Sdumbbell 695254885Sdumbbell if (argc > 2) { 696254885Sdumbbell for (ind = 2; ind < argc; ind++) { 697254885Sdumbbell n = atoi(argv[ind]); 698254885Sdumbbell if (n > 0 && n < MAXOUT && outfile[n] != NULL) 699254885Sdumbbell getdiv(n); 700254885Sdumbbell 701254885Sdumbbell } 702254885Sdumbbell } 703254885Sdumbbell else 704254885Sdumbbell for (n = 1; n < MAXOUT; n++) 705254885Sdumbbell if (outfile[n] != NULL) 706254885Sdumbbell getdiv(n); 707254885Sdumbbell} 708254885Sdumbbell 709254885Sdumbbell/* 710254885Sdumbbell * dosub - select substring 711254885Sdumbbell */ 712254885Sdumbbellvoid 713254885Sdumbbelldosub(argv, argc) 714254885Sdumbbellregister char *argv[]; 715254885Sdumbbellregister int argc; 716254885Sdumbbell{ 717254885Sdumbbell register unsigned char *ap, *fc, *k; 718254885Sdumbbell register int nc; 719254885Sdumbbell 720254885Sdumbbell if (argc < 5) 721254885Sdumbbell nc = MAXTOK; 722254885Sdumbbell else 723254885Sdumbbell#ifdef EXPR 724254885Sdumbbell nc = expr(argv[4]); 725254885Sdumbbell#else 726254885Sdumbbell nc = atoi(argv[4]); 727254885Sdumbbell#endif 728254885Sdumbbell ap = argv[2]; /* target string */ 729254885Sdumbbell#ifdef EXPR 730254885Sdumbbell fc = ap + expr(argv[3]); /* first char */ 731254885Sdumbbell#else 732254885Sdumbbell fc = ap + atoi(argv[3]); /* first char */ 733254885Sdumbbell#endif 734254885Sdumbbell if (fc >= ap && fc < ap + strlen(ap)) 735254885Sdumbbell for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 736254885Sdumbbell putback(*k); 737254885Sdumbbell} 738254885Sdumbbell 739254885Sdumbbell/* 740254885Sdumbbell * map: 741254885Sdumbbell * map every character of s1 that is specified in from 742254885Sdumbbell * into s3 and replace in s. (source s1 remains untouched) 743254885Sdumbbell * 744254885Sdumbbell * This is a standard implementation of map(s,from,to) function of ICON 745254885Sdumbbell * language. Within mapvec, we replace every character of "from" with 746254885Sdumbbell * the corresponding character in "to". If "to" is shorter than "from", 747254885Sdumbbell * than the corresponding entries are null, which means that those 748254885Sdumbbell * characters dissapear altogether. Furthermore, imagine 749254885Sdumbbell * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 750254885Sdumbbell * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 751254885Sdumbbell * ultimately maps to `*'. In order to achieve this effect in an efficient 752254885Sdumbbell * manner (i.e. without multiple passes over the destination string), we 753254885Sdumbbell * loop over mapvec, starting with the initial source character. if the 754254885Sdumbbell * character value (dch) in this location is different than the source 755254885Sdumbbell * character (sch), sch becomes dch, once again to index into mapvec, until 756254885Sdumbbell * the character value stabilizes (i.e. sch = dch, in other words 757254885Sdumbbell * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 758254885Sdumbbell * character, it will stabilize, since mapvec[0] == 0 at all times. At the 759254885Sdumbbell * end, we restore mapvec* back to normal where mapvec[n] == n for 760254885Sdumbbell * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 761254885Sdumbbell * about 5 times faster than any algorithm that makes multiple passes over 762254885Sdumbbell * destination string. 763254885Sdumbbell */ 764254885Sdumbbellvoid 765254885Sdumbbellmap(dest, src, from, to) 766254885Sdumbbellregister char *dest; 767254885Sdumbbellregister char *src; 768254885Sdumbbellregister char *from; 769254885Sdumbbellregister char *to; 770254885Sdumbbell{ 771254885Sdumbbell register char *tmp; 772254885Sdumbbell register char sch, dch; 773254885Sdumbbell static char mapvec[128] = { 774254885Sdumbbell 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 775254885Sdumbbell 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 776254885Sdumbbell 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 777254885Sdumbbell 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 778254885Sdumbbell 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 779254885Sdumbbell 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 780254885Sdumbbell 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 781254885Sdumbbell 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 782254885Sdumbbell 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 783254885Sdumbbell 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 784254885Sdumbbell 120, 121, 122, 123, 124, 125, 126, 127 785254885Sdumbbell }; 786254885Sdumbbell 787254885Sdumbbell if (*src) { 788254885Sdumbbell tmp = from; 789254885Sdumbbell /* 790254885Sdumbbell * create a mapping between "from" and 791254885Sdumbbell * "to" 792254885Sdumbbell */ 793254885Sdumbbell while (*from) 794254885Sdumbbell mapvec[*from++] = (*to) ? *to++ : (char) 0; 795254885Sdumbbell 796254885Sdumbbell while (*src) { 797254885Sdumbbell sch = *src++; 798254885Sdumbbell dch = mapvec[sch]; 799254885Sdumbbell while (dch != sch) { 800254885Sdumbbell sch = dch; 801254885Sdumbbell dch = mapvec[sch]; 802254885Sdumbbell } 803254885Sdumbbell if (*dest = dch) 804254885Sdumbbell dest++; 805254885Sdumbbell } 806254885Sdumbbell /* 807254885Sdumbbell * restore all the changed characters 808254885Sdumbbell */ 809254885Sdumbbell while (*tmp) { 810254885Sdumbbell mapvec[*tmp] = *tmp; 811254885Sdumbbell tmp++; 812254885Sdumbbell } 813254885Sdumbbell } 814254885Sdumbbell *dest = (char) 0; 815254885Sdumbbell} 816254885Sdumbbell