main.c revision 80289
1228753Smm/*- 2228753Smm * Copyright (c) 1989, 1993 3228753Smm * The Regents of the University of California. All rights reserved. 4228753Smm * 5228753Smm * This code is derived from software contributed to Berkeley by 6228753Smm * Ozan Yigit at York University. 7228753Smm * 8228753Smm * Redistribution and use in source and binary forms, with or without 9228753Smm * modification, are permitted provided that the following conditions 10228753Smm * are met: 11228753Smm * 1. Redistributions of source code must retain the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer. 13228753Smm * 2. Redistributions in binary form must reproduce the above copyright 14228753Smm * notice, this list of conditions and the following disclaimer in the 15228753Smm * documentation and/or other materials provided with the distribution. 16228753Smm * 3. All advertising materials mentioning features or use of this software 17228753Smm * must display the following acknowledgement: 18228753Smm * This product includes software developed by the University of 19228753Smm * California, Berkeley and its contributors. 20228753Smm * 4. Neither the name of the University nor the names of its contributors 21228753Smm * may be used to endorse or promote products derived from this software 22228753Smm * without specific prior written permission. 23228753Smm * 24228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34228753Smm * SUCH DAMAGE. 35228753Smm */ 36228753Smm 37228753Smm#ifndef lint 38228753Smmstatic const char copyright[] = 39228753Smm"@(#) Copyright (c) 1989, 1993\n\ 40228753Smm The Regents of the University of California. All rights reserved.\n"; 41228753Smm#endif /* not lint */ 42228753Smm 43228753Smm#ifndef lint 44228753Smm#if 0 45228753Smmstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 46228753Smm#endif 47228753Smmstatic const char rcsid[] = 48228753Smm "$FreeBSD: head/usr.bin/m4/main.c 80289 2001-07-24 14:09:47Z obrien $"; 49228753Smm#endif /* not lint */ 50228753Smm 51228753Smm/* 52228753Smm * main.c 53228753Smm * Facility: m4 macro processor 54228753Smm * by: oz 55228753Smm */ 56228753Smm 57228753Smm#include <sys/types.h> 58228753Smm#include <ctype.h> 59228753Smm#include <err.h> 60228753Smm#include <signal.h> 61228753Smm#include <stdio.h> 62228753Smm#include <stdlib.h> 63228753Smm#include <string.h> 64228753Smm#include <unistd.h> 65228753Smm#include "mdef.h" 66228753Smm#include "stdd.h" 67228753Smm#include "extern.h" 68228753Smm#include "pathnames.h" 69228753Smm 70228753Smmndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 71228753Smmunsigned char buf[BUFSIZE]; /* push-back buffer */ 72228753Smmunsigned char *bufbase = buf; /* the base for current ilevel */ 73228753Smmunsigned char *bbase[MAXINP]; /* the base for each ilevel */ 74228753Smmunsigned char *bp = buf; /* first available character */ 75228753Smmunsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 76228753Smmstae mstack[STACKMAX+1]; /* stack of m4 machine */ 77228753Smmchar strspace[STRSPMAX+1]; /* string space for evaluation */ 78228753Smmchar *ep = strspace; /* first free char in strspace */ 79228753Smmchar *endest= strspace+STRSPMAX;/* end of string space */ 80228753Smmint sp; /* current m4 stack pointer */ 81228753Smmint fp; /* m4 call frame pointer */ 82228753SmmFILE *infile[MAXINP]; /* input file stack (0=stdin) */ 83228753SmmFILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 84228753SmmFILE *active; /* active output file pointer */ 85228753Smmchar *m4temp; /* filename for diversions */ 86228753Smmchar *m4dir; /* directory for diversions */ 87228753Smmint ilevel = 0; /* input file stack pointer */ 88228753Smmint oindex = 0; /* diversion index.. */ 89228753Smmchar *null = ""; /* as it says.. just a null.. */ 90228753Smmchar *m4wraps = ""; /* m4wrap string default.. */ 91228753Smmchar lquote = LQUOTE; /* left quote character (`) */ 92228753Smmchar rquote = RQUOTE; /* right quote character (') */ 93228753Smmchar scommt = SCOMMT; /* start character for comment */ 94228753Smmchar ecommt = ECOMMT; /* end character for comment */ 95228753Smm 96228753Smmstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 97228753Smm "include", INCLTYPE, 98228753Smm "sinclude", SINCTYPE, 99228753Smm "define", DEFITYPE, 100228753Smm "defn", DEFNTYPE, 101228753Smm "divert", DIVRTYPE, 102228753Smm "expr", EXPRTYPE, 103228753Smm "eval", EXPRTYPE, 104228753Smm "substr", SUBSTYPE, 105228753Smm "ifelse", IFELTYPE, 106228753Smm "ifdef", IFDFTYPE, 107228753Smm "len", LENGTYPE, 108228753Smm "incr", INCRTYPE, 109228753Smm "decr", DECRTYPE, 110228753Smm "dnl", DNLNTYPE, 111228753Smm "changequote", CHNQTYPE, 112228753Smm "changecom", CHNCTYPE, 113228753Smm "index", INDXTYPE, 114228753Smm#ifdef EXTENDED 115228753Smm "paste", PASTTYPE, 116228753Smm "spaste", SPASTYPE, 117228753Smm#endif 118228753Smm "popdef", POPDTYPE, 119228753Smm "pushdef", PUSDTYPE, 120228753Smm "dumpdef", DUMPTYPE, 121228753Smm "shift", SHIFTYPE, 122228753Smm "translit", TRNLTYPE, 123228753Smm "undefine", UNDFTYPE, 124228753Smm "undivert", UNDVTYPE, 125228753Smm "divnum", DIVNTYPE, 126228753Smm "maketemp", MKTMTYPE, 127228753Smm "errprint", ERRPTYPE, 128228753Smm "m4wrap", M4WRTYPE, 129228753Smm "m4exit", EXITTYPE, 130228753Smm "syscmd", SYSCTYPE, 131228753Smm "sysval", SYSVTYPE, 132228753Smm 133228753Smm#ifdef unix 134228753Smm "unix", MACRTYPE, 135228753Smm#else 136228753Smm#ifdef vms 137228753Smm "vms", MACRTYPE, 138228753Smm#endif 139228753Smm#endif 140228753Smm}; 141228753Smm 142228753Smm#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 143228753Smm 144228753Smmvoid macro(); 145228753Smmvoid initkwds(); 146228753Smm 147228753Smmint 148228753Smmmain(argc,argv) 149228753Smm int argc; 150228753Smm char *argv[]; 151228753Smm{ 152228753Smm register int c; 153228753Smm register int n; 154228753Smm char *p; 155228753Smm register FILE *ifp; 156228753Smm 157228753Smm if (signal(SIGINT, SIG_IGN) != SIG_IGN) 158228753Smm signal(SIGINT, onintr); 159228753Smm 160228753Smm initkwds(); 161228753Smm 162228753Smm while ((c = getopt(argc, argv, "tD:U:o:")) != -1) 163228753Smm switch(c) { 164228753Smm 165228753Smm case 'D': /* define something..*/ 166228753Smm for (p = optarg; *p; p++) 167228753Smm if (*p == '=') 168228753Smm break; 169228753Smm if (*p) 170228753Smm *p++ = EOS; 171228753Smm dodefine(optarg, p); 172228753Smm break; 173228753Smm case 'U': /* undefine... */ 174228753Smm remhash(optarg, TOP); 175228753Smm break; 176228753Smm case 'o': /* specific output */ 177228753Smm case '?': 178228753Smm usage(); 179228753Smm } 180228753Smm 181228753Smm argc -= optind; 182228753Smm argv += optind; 183228753Smm 184228753Smm active = stdout; /* default active output */ 185228753Smm if ((p = strdup(_PATH_DIVDIRNAME)) == NULL) 186228753Smm err(1, "strdup"); 187228753Smm 188228753Smm /* filename for diversions */ 189228753Smm m4dir = mkdtemp(p); 190228753Smm err_set_exit(cleanup); 191228753Smm (void) asprintf(&m4temp, "%s/%s", m4dir, _PATH_DIVNAME); 192228753Smm 193228753Smm bbase[0] = bufbase; 194228753Smm if (!argc) { 195228753Smm sp = -1; /* stack pointer initialized */ 196228753Smm fp = 0; /* frame pointer initialized */ 197228753Smm infile[0] = stdin; /* default input (naturally) */ 198228753Smm macro(); 199 } else 200 for (; argc--; ++argv) { 201 p = *argv; 202 if (p[0] == '-' && p[1] == '\0') 203 ifp = stdin; 204 else if ((ifp = fopen(p, "r")) == NULL) 205 err(1, "%s", p); 206 sp = -1; 207 fp = 0; 208 infile[0] = ifp; 209 macro(); 210 if (ifp != stdin) 211 (void)fclose(ifp); 212 } 213 214 if (*m4wraps) { /* anything for rundown ?? */ 215 ilevel = 0; /* in case m4wrap includes.. */ 216 bufbase = bp = buf; /* use the entire buffer */ 217 putback(EOF); /* eof is a must !! */ 218 pbstr(m4wraps); /* user-defined wrapup act */ 219 macro(); /* last will and testament */ 220 } 221 222 if (active != stdout) 223 active = stdout; /* reset output just in case */ 224 for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 225 if (outfile[n] != NULL) 226 getdiv(n); 227 /* remove bitbucket if used */ 228 cleanup(0); 229 return 0; 230} 231 232ndptr inspect(); 233 234/* 235 * macro - the work horse.. 236 */ 237void 238macro() { 239 char token[MAXTOK]; 240 register char *s; 241 register int t, l; 242 register ndptr p; 243 register int nlpar; 244 245 cycle { 246 if ((t = gpbc()) == '_' || (t != EOF && isalpha(t))) { 247 putback(t); 248 if ((p = inspect(s = token)) == nil) { 249 if (sp < 0) 250 while (*s) 251 putc(*s++, active); 252 else 253 while (*s) 254 chrsave(*s++); 255 } 256 else { 257 /* 258 * real thing.. First build a call frame: 259 */ 260 pushf(fp); /* previous call frm */ 261 pushf(p->type); /* type of the call */ 262 pushf(0); /* parenthesis level */ 263 fp = sp; /* new frame pointer */ 264 /* 265 * now push the string arguments: 266 */ 267 pushs(p->defn); /* defn string */ 268 pushs(p->name); /* macro name */ 269 pushs(ep); /* start next..*/ 270 271 putback(l = gpbc()); 272 if (l != LPAREN) { /* add bracks */ 273 putback(RPAREN); 274 putback(LPAREN); 275 } 276 } 277 } 278 else if (t == EOF) { 279 if (sp > -1) 280 errx(1, "unexpected end of input"); 281 if (ilevel <= 0) 282 break; /* all done thanks.. */ 283 --ilevel; 284 (void) fclose(infile[ilevel+1]); 285 bufbase = bbase[ilevel]; 286 continue; 287 } 288 /* 289 * non-alpha single-char token seen.. 290 * [the order of else if .. stmts is important.] 291 */ 292 else if (t == lquote) { /* strip quotes */ 293 nlpar = 1; 294 do { 295 if ((l = gpbc()) == rquote) 296 nlpar--; 297 else if (l == lquote) 298 nlpar++; 299 else if (l == EOF) 300 errx(1, "missing right quote"); 301 if (nlpar > 0) { 302 if (sp < 0) 303 putc(l, active); 304 else 305 chrsave(l); 306 } 307 } 308 while (nlpar != 0); 309 } 310 311 else if (sp < 0) { /* not in a macro at all */ 312 if (t == scommt) { /* comment handling here */ 313 putc(t, active); 314 while ((t = gpbc()) != ecommt) 315 putc(t, active); 316 } 317 putc(t, active); /* output directly.. */ 318 } 319 320 else switch(t) { 321 322 case LPAREN: 323 if (PARLEV > 0) 324 chrsave(t); 325 while ((l = gpbc()) != EOF && isspace(l)) 326 ; /* skip blank, tab, nl.. */ 327 putback(l); 328 PARLEV++; 329 break; 330 331 case RPAREN: 332 if (--PARLEV > 0) 333 chrsave(t); 334 else { /* end of argument list */ 335 chrsave(EOS); 336 337 if (sp == STACKMAX) 338 errx(1, "internal stack overflow"); 339 340 if (CALTYP == MACRTYPE) 341 expand((char **) mstack+fp+1, sp-fp); 342 else 343 eval((char **) mstack+fp+1, sp-fp, CALTYP); 344 345 ep = PREVEP; /* flush strspace */ 346 sp = PREVSP; /* previous sp.. */ 347 fp = PREVFP; /* rewind stack...*/ 348 } 349 break; 350 351 case COMMA: 352 if (PARLEV == 1) { 353 chrsave(EOS); /* new argument */ 354 while ((l = gpbc()) != EOF && isspace(l)) 355 ; 356 putback(l); 357 pushs(ep); 358 } else 359 chrsave(t); 360 break; 361 362 default: 363 chrsave(t); /* stack the char */ 364 break; 365 } 366 } 367} 368 369/* 370 * build an input token.. 371 * consider only those starting with _ or A-Za-z. This is a 372 * combo with lookup to speed things up. 373 */ 374ndptr 375inspect(tp) 376register char *tp; 377{ 378 register int c; 379 register char *name = tp; 380 register char *etp = tp+MAXTOK; 381 register ndptr p; 382 register unsigned long h = 0; 383 384 while ((c = gpbc()) != EOF && (isalnum(c) || c == '_') && tp < etp) 385 h = (h << 5) + h + (*tp++ = c); 386 putback(c); 387 if (tp == etp) 388 errx(1, "token too long"); 389 390 *tp = EOS; 391 392 for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 393 if (STREQ(name, p->name)) 394 break; 395 return p; 396} 397 398/* 399 * initkwds - initialise m4 keywords as fast as possible. 400 * This very similar to install, but without certain overheads, 401 * such as calling lookup. Malloc is not used for storing the 402 * keyword strings, since we simply use the static pointers 403 * within keywrds block. 404 */ 405void 406initkwds() { 407 register int i; 408 register int h; 409 register ndptr p; 410 411 for (i = 0; i < MAXKEYS; i++) { 412 h = hash(keywrds[i].knam); 413 if ((p = malloc(sizeof(struct ndblock))) == NULL) 414 err(1, "malloc"); 415 p->nxtptr = hashtab[h]; 416 hashtab[h] = p; 417 p->name = keywrds[i].knam; 418 p->defn = null; 419 p->type = keywrds[i].ktyp | STATIC; 420 } 421} 422