main.c revision 94957
1/*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ozan Yigit at York University. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static const char copyright[] = 39"@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 46#endif 47static const char rcsid[] = 48 "$FreeBSD: head/usr.bin/m4/main.c 94957 2002-04-17 17:26:32Z jmallett $"; 49#endif /* not lint */ 50 51/* 52 * main.c 53 * Facility: m4 macro processor 54 * by: oz 55 */ 56 57#include <sys/types.h> 58#include <ctype.h> 59#include <err.h> 60#include <signal.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <unistd.h> 65#include "mdef.h" 66#include "stdd.h" 67#include "extern.h" 68#include "pathnames.h" 69 70ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 71unsigned char buf[BUFSIZE]; /* push-back buffer */ 72unsigned char *bufbase = buf; /* the base for current ilevel */ 73unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 74unsigned char *bp = buf; /* first available character */ 75unsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 76stae mstack[STACKMAX+1]; /* stack of m4 machine */ 77char strspace[STRSPMAX+1]; /* string space for evaluation */ 78char *ep = strspace; /* first free char in strspace */ 79char *endest= strspace+STRSPMAX;/* end of string space */ 80int sp; /* current m4 stack pointer */ 81int fp; /* m4 call frame pointer */ 82FILE *infile[MAXINP]; /* input file stack (0=stdin) */ 83char *inname[MAXINP]; /* names of these input files */ 84int inlineno[MAXINP]; /* current number in each input*/ 85FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 86FILE *active; /* active output file pointer */ 87char *m4temp; /* filename for diversions */ 88char *m4dir; /* directory for diversions */ 89int ilevel = 0; /* input file stack pointer */ 90int oindex = 0; /* diversion index.. */ 91char *null = ""; /* as it says.. just a null.. */ 92char *m4wraps = ""; /* m4wrap string default.. */ 93char lquote = LQUOTE; /* left quote character (`) */ 94char rquote = RQUOTE; /* right quote character (') */ 95char scommt = SCOMMT; /* start character for comment */ 96char ecommt = ECOMMT; /* end character for comment */ 97int synccpp; /* Line synchronisation for C preprocessor */ 98int chscratch; /* Scratch space for gpbc() macro */ 99 100struct keyblk keywrds[] = { /* m4 keywords to be installed */ 101 "include", INCLTYPE, 102 "sinclude", SINCTYPE, 103 "define", DEFITYPE, 104 "defn", DEFNTYPE, 105 "divert", DIVRTYPE, 106 "expr", EXPRTYPE, 107 "eval", EXPRTYPE, 108 "substr", SUBSTYPE, 109 "ifelse", IFELTYPE, 110 "ifdef", IFDFTYPE, 111 "len", LENGTYPE, 112 "incr", INCRTYPE, 113 "decr", DECRTYPE, 114 "dnl", DNLNTYPE, 115 "changequote", CHNQTYPE, 116 "changecom", CHNCTYPE, 117 "index", INDXTYPE, 118#ifdef EXTENDED 119 "paste", PASTTYPE, 120 "spaste", SPASTYPE, 121#endif 122 "popdef", POPDTYPE, 123 "pushdef", PUSDTYPE, 124 "dumpdef", DUMPTYPE, 125 "shift", SHIFTYPE, 126 "translit", TRNLTYPE, 127 "undefine", UNDFTYPE, 128 "undivert", UNDVTYPE, 129 "divnum", DIVNTYPE, 130 "maketemp", MKTMTYPE, 131 "errprint", ERRPTYPE, 132 "m4wrap", M4WRTYPE, 133 "m4exit", EXITTYPE, 134 "syscmd", SYSCTYPE, 135 "sysval", SYSVTYPE, 136 137#ifdef unix 138 "unix", MACRTYPE, 139#else 140#ifdef vms 141 "vms", MACRTYPE, 142#endif 143#endif 144}; 145 146#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 147 148void macro(); 149void initkwds(); 150 151int 152main(argc,argv) 153 int argc; 154 char *argv[]; 155{ 156 register int c; 157 register int n; 158 char *p; 159 register FILE *ifp; 160 161 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 162 signal(SIGINT, onintr); 163 164 initkwds(); 165 166 while ((c = getopt(argc, argv, "D:U:s")) != -1) 167 switch(c) { 168 169 case 'D': /* define something..*/ 170 for (p = optarg; *p; p++) 171 if (*p == '=') 172 break; 173 if (*p) 174 *p++ = EOS; 175 dodefine(optarg, p); 176 break; 177 case 'U': /* undefine... */ 178 remhash(optarg, TOP); 179 break; 180 case 's': 181 synccpp = 1; 182 break; 183 case '?': 184 usage(); 185 } 186 187 argc -= optind; 188 argv += optind; 189 190 active = stdout; /* default active output */ 191 if ((p = strdup(_PATH_DIVDIRNAME)) == NULL) 192 err(1, "strdup"); 193 194 /* filename for diversions */ 195 m4dir = mkdtemp(p); 196 err_set_exit(cleanup); 197 (void) asprintf(&m4temp, "%s/%s", m4dir, _PATH_DIVNAME); 198 199 bbase[0] = bufbase; 200 if (!argc) { 201 sp = -1; /* stack pointer initialized */ 202 fp = 0; /* frame pointer initialized */ 203 infile[0] = stdin; /* default input (naturally) */ 204 if ((inname[0] = strdup("-")) == NULL) 205 err(1, NULL); 206 inlineno[0] = 1; 207 emitline(); 208 macro(); 209 } else 210 for (; argc--; ++argv) { 211 p = *argv; 212 if (p[0] == '-' && p[1] == '\0') 213 ifp = stdin; 214 else if ((ifp = fopen(p, "r")) == NULL) 215 err(1, "%s", p); 216 sp = -1; 217 fp = 0; 218 infile[0] = ifp; 219 if ((inname[0] = strdup(p)) == NULL) 220 err(1, NULL); 221 inlineno[0] = 1; 222 emitline(); 223 macro(); 224 if (ifp != stdin) 225 (void)fclose(ifp); 226 } 227 228 if (*m4wraps) { /* anything for rundown ?? */ 229 ilevel = 0; /* in case m4wrap includes.. */ 230 bufbase = bp = buf; /* use the entire buffer */ 231 putback(EOF); /* eof is a must !! */ 232 pbstr(m4wraps); /* user-defined wrapup act */ 233 macro(); /* last will and testament */ 234 } 235 236 if (active != stdout) 237 active = stdout; /* reset output just in case */ 238 for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 239 if (outfile[n] != NULL) 240 getdiv(n); 241 /* remove bitbucket if used */ 242 cleanup(0); 243 return 0; 244} 245 246ndptr inspect(); 247 248/* 249 * macro - the work horse.. 250 */ 251void 252macro() { 253 char token[MAXTOK]; 254 register char *s; 255 register int t, l; 256 register ndptr p; 257 register int nlpar; 258 259 cycle { 260 if ((t = gpbc()) == '_' || (t != EOF && isalpha(t))) { 261 putback(t); 262 if ((p = inspect(s = token)) == nil) { 263 if (sp < 0) 264 while (*s) 265 putc(*s++, active); 266 else 267 while (*s) 268 chrsave(*s++); 269 } 270 else { 271 /* 272 * real thing.. First build a call frame: 273 */ 274 pushf(fp); /* previous call frm */ 275 pushf(p->type); /* type of the call */ 276 pushf(0); /* parenthesis level */ 277 fp = sp; /* new frame pointer */ 278 /* 279 * now push the string arguments: 280 */ 281 pushs(p->defn); /* defn string */ 282 pushs(p->name); /* macro name */ 283 pushs(ep); /* start next..*/ 284 285 putback(l = gpbc()); 286 if (l != LPAREN) { /* add bracks */ 287 putback(RPAREN); 288 putback(LPAREN); 289 } 290 } 291 } 292 else if (t == EOF) { 293 if (sp > -1) 294 errx(1, "unexpected end of input"); 295 if (ilevel <= 0) 296 break; /* all done thanks.. */ 297 --ilevel; 298 (void) fclose(infile[ilevel+1]); 299 free(inname[ilevel+1]); 300 bufbase = bbase[ilevel]; 301 emitline(); 302 continue; 303 } 304 /* 305 * non-alpha single-char token seen.. 306 * [the order of else if .. stmts is important.] 307 */ 308 else if (t == lquote) { /* strip quotes */ 309 nlpar = 1; 310 do { 311 if ((l = gpbc()) == rquote) 312 nlpar--; 313 else if (l == lquote) 314 nlpar++; 315 else if (l == EOF) 316 errx(1, "missing right quote"); 317 if (nlpar > 0) { 318 if (sp < 0) 319 putc(l, active); 320 else 321 chrsave(l); 322 } 323 } 324 while (nlpar != 0); 325 } 326 327 else if (sp < 0) { /* not in a macro at all */ 328 if (t == scommt) { /* comment handling here */ 329 putc(t, active); 330 while ((t = gpbc()) != ecommt) 331 putc(t, active); 332 } 333 putc(t, active); /* output directly.. */ 334 } 335 336 else switch(t) { 337 338 case LPAREN: 339 if (PARLEV > 0) 340 chrsave(t); 341 while ((l = gpbc()) != EOF && isspace(l)) 342 ; /* skip blank, tab, nl.. */ 343 putback(l); 344 PARLEV++; 345 break; 346 347 case RPAREN: 348 if (--PARLEV > 0) 349 chrsave(t); 350 else { /* end of argument list */ 351 chrsave(EOS); 352 353 if (sp == STACKMAX) 354 errx(1, "internal stack overflow"); 355 356 if (CALTYP == MACRTYPE) 357 expand((char **) mstack+fp+1, sp-fp); 358 else 359 eval((char **) mstack+fp+1, sp-fp, CALTYP); 360 361 ep = PREVEP; /* flush strspace */ 362 sp = PREVSP; /* previous sp.. */ 363 fp = PREVFP; /* rewind stack...*/ 364 } 365 break; 366 367 case COMMA: 368 if (PARLEV == 1) { 369 chrsave(EOS); /* new argument */ 370 while ((l = gpbc()) != EOF && isspace(l)) 371 ; 372 putback(l); 373 pushs(ep); 374 } else 375 chrsave(t); 376 break; 377 378 default: 379 chrsave(t); /* stack the char */ 380 break; 381 } 382 } 383} 384 385/* 386 * build an input token.. 387 * consider only those starting with _ or A-Za-z. This is a 388 * combo with lookup to speed things up. 389 */ 390ndptr 391inspect(tp) 392register char *tp; 393{ 394 register int c; 395 register char *name = tp; 396 register char *etp = tp+MAXTOK; 397 register ndptr p; 398 register unsigned long h = 0; 399 400 while ((c = gpbc()) != EOF && (isalnum(c) || c == '_') && tp < etp) 401 h = (h << 5) + h + (*tp++ = c); 402 putback(c); 403 if (tp == etp) 404 errx(1, "token too long"); 405 406 *tp = EOS; 407 408 for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 409 if (STREQ(name, p->name)) 410 break; 411 return p; 412} 413 414/* 415 * initkwds - initialise m4 keywords as fast as possible. 416 * This very similar to install, but without certain overheads, 417 * such as calling lookup. Malloc is not used for storing the 418 * keyword strings, since we simply use the static pointers 419 * within keywrds block. 420 */ 421void 422initkwds() { 423 register int i; 424 register int h; 425 register ndptr p; 426 427 for (i = 0; i < MAXKEYS; i++) { 428 h = hash(keywrds[i].knam); 429 if ((p = malloc(sizeof(struct ndblock))) == NULL) 430 err(1, "malloc"); 431 p->nxtptr = hashtab[h]; 432 hashtab[h] = p; 433 p->name = keywrds[i].knam; 434 p->defn = null; 435 p->type = keywrds[i].ktyp | STATIC; 436 } 437} 438 439/* Emit preprocessor #line directive if -s option used. */ 440void 441emitline(void) 442{ 443 if (synccpp) 444 fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel], 445 inname[ilevel]); 446} 447