/* * expand_builtin - evaluate built-in macros. */ void expand_builtin(const char *argv[], int argc, int td) { int c, n; int ac; static int sysval = 0; #ifdef DEBUG printf("argc = %d\n", argc); for (n = 0; n < argc; n++) printf("argv[%d] = %s\n", n, argv[n]); fflush(stdout); #endif /* * if argc == 3 and argv[2] is null, then we * have macro-or-builtin() type call. We adjust * argc to avoid further checking.. */ /* we keep the initial value for those built-ins that differentiate * between builtin() and builtin. */ ac = argc; if (argc == 3 && !*(argv[2]) && !mimic_gnu) argc--; switch (td & TYPEMASK) { case DEFITYPE: if (argc > 2) dodefine(argv[2], (argc > 3) ? argv[3] : null); break; case PUSDTYPE: if (argc > 2) dopushdef(argv[2], (argc > 3) ? argv[3] : null); break; case DUMPTYPE: dodump(argv, argc); break; case TRACEONTYPE: dotrace(argv, argc, 1); break; case TRACEOFFTYPE: dotrace(argv, argc, 0); break; case EXPRTYPE: /* * doexpr - evaluate arithmetic * expression */ { int base = 10; int maxdigits = 0; const char *errstr; if (argc > 3) { base = strtonum(argv[3], 2, 36, &errstr); if (errstr) { m4errx(1, "expr: base %s invalid.", argv[3]); } } if (argc > 4) { maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); if (errstr) { m4errx(1, "expr: maxdigits %s invalid.", argv[4]); } } if (argc > 2) pbnumbase(expr(argv[2]), base, maxdigits); break; } case IFELTYPE: if (argc > 4) doifelse(argv, argc); break; case IFDFTYPE: /* * doifdef - select one of two * alternatives based on the existence of * another definition */ if (argc > 3) { if (lookup_macro_definition(argv[2]) != NULL) pbstr(argv[3]); else if (argc > 4) pbstr(argv[4]); } break; case LENGTYPE: /* * dolen - find the length of the * argument */ pbnum((argc > 2) ? strlen(argv[2]) : 0); break; case INCRTYPE: /* * doincr - increment the value of the * argument */ if (argc > 2) pbnum(atoi(argv[2]) + 1); break; case DECRTYPE: /* * dodecr - decrement the value of the * argument */ if (argc > 2) pbnum(atoi(argv[2]) - 1); break; case SYSCTYPE: /* * dosys - execute system command */ if (argc > 2) { fflush(stdout); sysval = system(argv[2]); } break; case SYSVTYPE: /* * dosysval - return value of the last * system call. * */ pbnum(sysval); break; case ESYSCMDTYPE: if (argc > 2) doesyscmd(argv[2]); break; case INCLTYPE: if (argc > 2) if (!doincl(argv[2])) { if (mimic_gnu) { warn("%s at line %lu: include(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); exit_code = 1; } else err(1, "%s at line %lu: include(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); } break; case SINCTYPE: if (argc > 2) (void) doincl(argv[2]); break; #ifdef EXTENDED case PASTTYPE: if (argc > 2) if (!dopaste(argv[2])) err(1, "%s at line %lu: paste(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); break; case SPASTYPE: if (argc > 2) (void) dopaste(argv[2]); break; case FORMATTYPE: doformat(argv, argc); break; #endif case CHNQTYPE: dochq(argv, ac); break; case CHNCTYPE: dochc(argv, argc); break; case SUBSTYPE: /* * dosub - select substring * */ if (argc > 3) dosub(argv, argc); break; case SHIFTYPE: /* * doshift - push back all arguments * except the first one (i.e. skip * argv[2]) */ if (argc > 3) { for (n = argc - 1; n > 3; n--) { pbstr(rquote); pbstr(argv[n]); pbstr(lquote); pushback(COMMA); } pbstr(rquote); pbstr(argv[3]); pbstr(lquote); } break; case DIVRTYPE: if (argc > 2 && (n = atoi(argv[2])) != 0) dodiv(n); else { active = stdout; oindex = 0; } break; case UNDVTYPE: doundiv(argv, argc); break; case DIVNTYPE: /* * dodivnum - return the number of * current output diversion */ pbnum(oindex); break; case UNDFTYPE: /* * doundefine - undefine a previously * defined macro(s) or m4 keyword(s). */ if (argc > 2) for (n = 2; n < argc; n++) macro_undefine(argv[n]); break; case POPDTYPE: /* * dopopdef - remove the topmost * definitions of macro(s) or m4 * keyword(s). */ if (argc > 2) for (n = 2; n < argc; n++) macro_popdef(argv[n]); break; case MKTMTYPE: /* * dotemp - create a temporary file */ if (argc > 2) { int fd; char *temp; temp = xstrdup(argv[2]); fd = mkstemp(temp); if (fd == -1) err(1, "%s at line %lu: couldn't make temp file %s", CURRENT_NAME, CURRENT_LINE, argv[2]); close(fd); pbstr(temp); free(temp); } break; case TRNLTYPE: /* * dotranslit - replace all characters in * the source string that appears in the * "from" string with the corresponding * characters in the "to" string. */ if (argc > 3) { char *temp; temp = xalloc(strlen(argv[2])+1, NULL); if (argc > 4) map(temp, argv[2], argv[3], argv[4]); else map(temp, argv[2], argv[3], null); pbstr(temp); free(temp); } else if (argc > 2) pbstr(argv[2]); break; case INDXTYPE: /* * doindex - find the index of the second * argument string in the first argument * string. -1 if not present. */ pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); break; case ERRPTYPE: /* * doerrp - print the arguments to stderr * file */ if (argc > 2) { for (n = 2; n < argc; n++) fprintf(stderr, "%s ", argv[n]); fprintf(stderr, "\n"); } break; case DNLNTYPE: /* * dodnl - eat-up-to and including * newline */ while ((c = gpbc()) != '\n' && c != EOF) ; break; case M4WRTYPE: /* * dom4wrap - set up for * wrap-up/wind-down activity */ if (argc > 2) dom4wrap(argv[2]); break; case EXITTYPE: /* * doexit - immediate exit from m4. */ killdiv(); exit((argc > 2) ? atoi(argv[2]) : 0); break; case DEFNTYPE: if (argc > 2) for (n = 2; n < argc; n++) dodefn(argv[n]); break; case INDIRTYPE: /* Indirect call */ if (argc > 2) doindir(argv, argc); break; case BUILTINTYPE: /* Builtins only */ if (argc > 2) dobuiltin(argv, argc); break; case PATSTYPE: if (argc > 2) dopatsubst(argv, argc); break; case REGEXPTYPE: if (argc > 2) doregexp(argv, argc); break; case LINETYPE: doprintlineno(infile+ilevel); break; case FILENAMETYPE: doprintfilename(infile+ilevel); break; case SELFTYPE: pbstr(rquote); pbstr(argv[1]); pbstr(lquote); break; default: m4errx(1, "eval: major botch."); break; } }
int main(int argc, char *argv[]) { int c; int n; char *p; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); init_macros(); initspaces(); STACKMAX = INITSTACKMAX; mstack = xreallocarray(NULL, STACKMAX, sizeof(stae), NULL); sstack = xalloc(STACKMAX, NULL); maxout = 0; outfile = NULL; resizedivs(MAXOUT); while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -1) switch(c) { case 'D': /* define something..*/ for (p = optarg; *p; p++) if (*p == '=') break; if (*p) *p++ = EOS; dodefine(optarg, p); break; case 'I': addtoincludepath(optarg); break; case 'P': prefix_builtins = 1; break; case 'U': /* undefine... */ macro_popdef(optarg); break; case 'g': mimic_gnu = 1; break; case 'd': set_trace_flags(optarg); break; case 's': synch_lines = 1; break; case 't': mark_traced(optarg, 1); break; case 'o': trace_file(optarg); break; case '?': usage(); } argc -= optind; argv += optind; initkwds(); if (mimic_gnu) setup_builtin("format", FORMATTYPE); active = stdout; /* default active output */ bbase[0] = bufbase; if (!argc) { sp = -1; /* stack pointer initialized */ fp = 0; /* frame pointer initialized */ set_input(infile+0, stdin, "stdin"); /* default input (naturally) */ macro(); } else for (; argc--; ++argv) { p = *argv; if (p[0] == '-' && p[1] == EOS) set_input(infile, stdin, "stdin"); else if (fopen_trypath(infile, p) == NULL) err(1, "%s", p); sp = -1; fp = 0; macro(); release_input(infile); } if (wrapindex) { int i; ilevel = 0; /* in case m4wrap includes.. */ bufbase = bp = buf; /* use the entire buffer */ if (mimic_gnu) { while (wrapindex != 0) { for (i = 0; i < wrapindex; i++) pbstr(m4wraps[i]); wrapindex =0; macro(); } } else { for (i = 0; i < wrapindex; i++) { pbstr(m4wraps[i]); macro(); } } } if (active != stdout) active = stdout; /* reset output just in case */ for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ if (outfile[n] != NULL) getdiv(n); /* remove bitbucket if used */ if (outfile[0] != NULL) { (void) fclose(outfile[0]); } return exit_code; }