void pbnumbase(int n, int base, int d) { static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; int num; int printed = 0; if (base > 36) m4errx(1, "base %d > 36: not supported.", base); if (base < 2) m4errx(1, "bad base %d for conversion.", base); num = (n < 0) ? -n : n; do { pushback(digits[num % base]); printed++; } while ((num /= base) > 0); if (n < 0) printed++; while (printed++ < d) pushback('0'); if (n < 0) pushback('-'); }
void doformat(const char *argv[], int argc) { const char *format = argv[2]; int pos = 3; int left_padded; long width; size_t l; const char *thisarg = NULL; char temp[2]; long extra; while (*format != 0) { if (*format != '%') { addchar(*format++); continue; } format++; if (*format == '%') { addchar(*format++); continue; } if (*format == 0) { addchar('%'); break; } if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); width = strtol(argv[pos++], NULL, 10); } else { width = strtol(format, __DECONST(char **,&format), 10); } if (width < 0) { left_padded = 1; width = -width; } else { left_padded = 0; } if (*format == '.') { format++; if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); extra = strtol(argv[pos++], NULL, 10); } else { extra = strtol(format, __DECONST(char **, &format), 10); } } else {
/* * dopushdef - install a definition in the hash table * without removing a previous definition. Since * each new entry is entered in *front* of the * hash bucket, it hides a previous definition from * lookup. */ static void dopushdef(const char *name, const char *defn) { if (!*name && !mimic_gnu) m4errx(1, "null definition."); else macro_pushdef(name, defn); }
/* * dodefine - install definition in the table */ void dodefine(const char *name, const char *defn) { if (!*name && !mimic_gnu) m4errx(1, "null definition."); else macro_define(name, defn); }
static void exit_regerror(int er, regex_t *re, const char *source) { size_t errlen; char *errbuf; errlen = regerror(er, re, NULL, 0); errbuf = xalloc(errlen, "malloc in regerror: %lu", (unsigned long)errlen); regerror(er, re, errbuf, errlen); m4errx(1, "regular expression error in %s: %s.", source, errbuf); }
void dobuiltin(const char *argv[], int argc) { ndptr p; argv[1] = NULL; p = macro_getbuiltin(argv[2]); if (p != NULL) eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p)); else m4errx(1, "unknown builtin %s.", argv[2]); }
/* * read in a diversion file, and dispose it. */ void getdiv(int n) { int c; if (active == outfile[n]) m4errx(1, "undivert: diversion still active."); rewind(outfile[n]); while ((c = getc(outfile[n])) != EOF) putc(c, active); (void) fclose(outfile[n]); outfile[n] = NULL; }
void doindir(const char *argv[], int argc) { ndptr n; struct macro_definition *p; n = lookup(argv[2]); if (n == NULL || (p = macro_getdef(n)) == NULL) m4errx(1, "indir: undefined macro %s.", argv[2]); argv[1] = p->defn; eval(argv+1, argc-1, p->type, is_traced(n)); }
/* * eval - eval all macros and builtins calls * argc - number of elements in argv. * argv - element vector : * argv[0] = definition of a user * macro or NULL if built-in. * argv[1] = name of the macro or * built-in. * argv[2] = parameters to user-defined * . macro or built-in. * . * * A call in the form of macro-or-builtin() will result in: * argv[0] = nullstr * argv[1] = macro-or-builtin * argv[2] = nullstr * * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin */ void eval(const char *argv[], int argc, int td, int is_traced) { size_t mark = SIZE_MAX; expansion_id++; if (td & RECDEF) m4errx(1, "expanding recursive definition for %s.", argv[1]); if (is_traced) mark = trace(argv, argc, infile+ilevel); if (td == MACRTYPE) expand_macro(argv, argc); else expand_builtin(argv, argc, td); if (mark != SIZE_MAX) finish_trace(mark); }
/* * 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; } }
void doformat(const char *argv[], int argc) { const char *format = argv[2]; int pos = 3; int left_padded; long width; size_t l; const char *thisarg; char temp[2]; long extra; while (*format != 0) { if (*format != '%') { addchar(*format++); continue; } format++; if (*format == '%') { addchar(*format++); continue; } if (*format == 0) { addchar('%'); break; } if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); width = strtol(argv[pos++], NULL, 10); } else { width = strtol(format, (char **)&format, 10); } if (width < 0) { left_padded = 1; width = -width; } else { left_padded = 0; } if (*format == '.') { format++; if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); extra = strtol(argv[pos++], NULL, 10); } else { extra = strtol(format, (char **)&format, 10); } } else { extra = LONG_MAX; } if (pos >= argc) m4errx(1, "Format with too many format specifiers."); switch(*format) { case 's': thisarg = argv[pos++]; break; case 'c': temp[0] = strtoul(argv[pos++], NULL, 10); temp[1] = 0; thisarg = temp; break; default: m4errx(1, "Unsupported format specification: %s.", argv[2]); } format++; l = strlen(thisarg); if (l > extra) l = extra; if (!left_padded) { while (l < width--) addchar(' '); } addchars(thisarg, l); if (left_padded) { while (l < width--) addchar(' '); } } pbstr(getstring()); }