1e3d86717SJuli Mallett /* $OpenBSD: gnum4.c,v 1.16 2002/02/16 21:27:48 millert Exp $ */ 2e3d86717SJuli Mallett 3e3d86717SJuli Mallett /* 4e3d86717SJuli Mallett * Copyright (c) 1999 Marc Espie 5e3d86717SJuli Mallett * 6e3d86717SJuli Mallett * Redistribution and use in source and binary forms, with or without 7e3d86717SJuli Mallett * modification, are permitted provided that the following conditions 8e3d86717SJuli Mallett * are met: 9e3d86717SJuli Mallett * 1. Redistributions of source code must retain the above copyright 10e3d86717SJuli Mallett * notice, this list of conditions and the following disclaimer. 11e3d86717SJuli Mallett * 2. Redistributions in binary form must reproduce the above copyright 12e3d86717SJuli Mallett * notice, this list of conditions and the following disclaimer in the 13e3d86717SJuli Mallett * documentation and/or other materials provided with the distribution. 14e3d86717SJuli Mallett * 15e3d86717SJuli Mallett * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 16e3d86717SJuli Mallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e3d86717SJuli Mallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e3d86717SJuli Mallett * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 19e3d86717SJuli Mallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e3d86717SJuli Mallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e3d86717SJuli Mallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e3d86717SJuli Mallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e3d86717SJuli Mallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e3d86717SJuli Mallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e3d86717SJuli Mallett * SUCH DAMAGE. 26e3d86717SJuli Mallett */ 27e3d86717SJuli Mallett 2856ca2b35SJuli Mallett #include <sys/cdefs.h> 2956ca2b35SJuli Mallett __FBSDID("$FreeBSD$"); 3056ca2b35SJuli Mallett 31e3d86717SJuli Mallett /* 32e3d86717SJuli Mallett * functions needed to support gnu-m4 extensions, including a fake freezing 33e3d86717SJuli Mallett */ 34e3d86717SJuli Mallett 35e3d86717SJuli Mallett #include <sys/param.h> 36e3d86717SJuli Mallett #include <sys/types.h> 37e3d86717SJuli Mallett #include <sys/wait.h> 38e3d86717SJuli Mallett #include <ctype.h> 39e3d86717SJuli Mallett #include <paths.h> 40e3d86717SJuli Mallett #include <regex.h> 41e3d86717SJuli Mallett #include <stddef.h> 42e3d86717SJuli Mallett #include <stdlib.h> 43e3d86717SJuli Mallett #include <stdio.h> 44e3d86717SJuli Mallett #include <string.h> 45e3d86717SJuli Mallett #include <err.h> 46e3d86717SJuli Mallett #include <errno.h> 47e3d86717SJuli Mallett #include <unistd.h> 48e3d86717SJuli Mallett #include "mdef.h" 49e3d86717SJuli Mallett #include "stdd.h" 50e3d86717SJuli Mallett #include "extern.h" 51e3d86717SJuli Mallett 52e3d86717SJuli Mallett 53e3d86717SJuli Mallett int mimic_gnu = 0; 54e3d86717SJuli Mallett 55e3d86717SJuli Mallett /* 56e3d86717SJuli Mallett * Support for include path search 57e3d86717SJuli Mallett * First search in the the current directory. 58e3d86717SJuli Mallett * If not found, and the path is not absolute, include path kicks in. 59e3d86717SJuli Mallett * First, -I options, in the order found on the command line. 60e3d86717SJuli Mallett * Then M4PATH env variable 61e3d86717SJuli Mallett */ 62e3d86717SJuli Mallett 63e3d86717SJuli Mallett struct path_entry { 64e3d86717SJuli Mallett char *name; 65e3d86717SJuli Mallett struct path_entry *next; 66e3d86717SJuli Mallett } *first, *last; 67e3d86717SJuli Mallett 68e3d86717SJuli Mallett static struct path_entry *new_path_entry(const char *); 69e3d86717SJuli Mallett static void ensure_m4path(void); 70e3d86717SJuli Mallett static struct input_file *dopath(struct input_file *, const char *); 71e3d86717SJuli Mallett 72e3d86717SJuli Mallett static struct path_entry * 73e3d86717SJuli Mallett new_path_entry(dirname) 74e3d86717SJuli Mallett const char *dirname; 75e3d86717SJuli Mallett { 76e3d86717SJuli Mallett struct path_entry *n; 77e3d86717SJuli Mallett 78e3d86717SJuli Mallett n = malloc(sizeof(struct path_entry)); 79e3d86717SJuli Mallett if (!n) 80e3d86717SJuli Mallett errx(1, "out of memory"); 81e3d86717SJuli Mallett n->name = strdup(dirname); 82e3d86717SJuli Mallett if (!n->name) 83e3d86717SJuli Mallett errx(1, "out of memory"); 84e3d86717SJuli Mallett n->next = 0; 85e3d86717SJuli Mallett return n; 86e3d86717SJuli Mallett } 87e3d86717SJuli Mallett 88e3d86717SJuli Mallett void 89e3d86717SJuli Mallett addtoincludepath(dirname) 90e3d86717SJuli Mallett const char *dirname; 91e3d86717SJuli Mallett { 92e3d86717SJuli Mallett struct path_entry *n; 93e3d86717SJuli Mallett 94e3d86717SJuli Mallett n = new_path_entry(dirname); 95e3d86717SJuli Mallett 96e3d86717SJuli Mallett if (last) { 97e3d86717SJuli Mallett last->next = n; 98e3d86717SJuli Mallett last = n; 99e3d86717SJuli Mallett } 100e3d86717SJuli Mallett else 101e3d86717SJuli Mallett last = first = n; 102e3d86717SJuli Mallett } 103e3d86717SJuli Mallett 104e3d86717SJuli Mallett static void 105e3d86717SJuli Mallett ensure_m4path() 106e3d86717SJuli Mallett { 107e3d86717SJuli Mallett static int envpathdone = 0; 108e3d86717SJuli Mallett char *envpath; 109e3d86717SJuli Mallett char *sweep; 110e3d86717SJuli Mallett char *path; 111e3d86717SJuli Mallett 112e3d86717SJuli Mallett if (envpathdone) 113e3d86717SJuli Mallett return; 114e3d86717SJuli Mallett envpathdone = TRUE; 115e3d86717SJuli Mallett envpath = getenv("M4PATH"); 116e3d86717SJuli Mallett if (!envpath) 117e3d86717SJuli Mallett return; 118e3d86717SJuli Mallett /* for portability: getenv result is read-only */ 119e3d86717SJuli Mallett envpath = strdup(envpath); 120e3d86717SJuli Mallett if (!envpath) 121e3d86717SJuli Mallett errx(1, "out of memory"); 122e3d86717SJuli Mallett for (sweep = envpath; 123e3d86717SJuli Mallett (path = strsep(&sweep, ":")) != NULL;) 124e3d86717SJuli Mallett addtoincludepath(path); 125e3d86717SJuli Mallett free(envpath); 126e3d86717SJuli Mallett } 127e3d86717SJuli Mallett 128e3d86717SJuli Mallett static 129e3d86717SJuli Mallett struct input_file * 130e3d86717SJuli Mallett dopath(i, filename) 131e3d86717SJuli Mallett struct input_file *i; 132e3d86717SJuli Mallett const char *filename; 133e3d86717SJuli Mallett { 134e3d86717SJuli Mallett char path[MAXPATHLEN]; 135e3d86717SJuli Mallett struct path_entry *pe; 136e3d86717SJuli Mallett FILE *f; 137e3d86717SJuli Mallett 138e3d86717SJuli Mallett for (pe = first; pe; pe = pe->next) { 139e3d86717SJuli Mallett snprintf(path, sizeof(path), "%s/%s", pe->name, filename); 140e3d86717SJuli Mallett if ((f = fopen(path, "r")) != 0) { 141e3d86717SJuli Mallett set_input(i, f, path); 142e3d86717SJuli Mallett return i; 143e3d86717SJuli Mallett } 144e3d86717SJuli Mallett } 145e3d86717SJuli Mallett return NULL; 146e3d86717SJuli Mallett } 147e3d86717SJuli Mallett 148e3d86717SJuli Mallett struct input_file * 149e3d86717SJuli Mallett fopen_trypath(i, filename) 150e3d86717SJuli Mallett struct input_file *i; 151e3d86717SJuli Mallett const char *filename; 152e3d86717SJuli Mallett { 153e3d86717SJuli Mallett FILE *f; 154e3d86717SJuli Mallett 155e3d86717SJuli Mallett f = fopen(filename, "r"); 156e3d86717SJuli Mallett if (f != NULL) { 157e3d86717SJuli Mallett set_input(i, f, filename); 158e3d86717SJuli Mallett return i; 159e3d86717SJuli Mallett } 160e3d86717SJuli Mallett if (filename[0] == '/') 161e3d86717SJuli Mallett return NULL; 162e3d86717SJuli Mallett 163e3d86717SJuli Mallett ensure_m4path(); 164e3d86717SJuli Mallett 165e3d86717SJuli Mallett return dopath(i, filename); 166e3d86717SJuli Mallett } 167e3d86717SJuli Mallett 168e3d86717SJuli Mallett void 169e3d86717SJuli Mallett doindir(argv, argc) 170e3d86717SJuli Mallett const char *argv[]; 171e3d86717SJuli Mallett int argc; 172e3d86717SJuli Mallett { 173e3d86717SJuli Mallett ndptr p; 174e3d86717SJuli Mallett 175e3d86717SJuli Mallett p = lookup(argv[2]); 176e3d86717SJuli Mallett if (p == NULL) 177e3d86717SJuli Mallett errx(1, "undefined macro %s", argv[2]); 178e3d86717SJuli Mallett argv[1] = p->defn; 179e3d86717SJuli Mallett eval(argv+1, argc-1, p->type); 180e3d86717SJuli Mallett } 181e3d86717SJuli Mallett 182e3d86717SJuli Mallett void 183e3d86717SJuli Mallett dobuiltin(argv, argc) 184e3d86717SJuli Mallett const char *argv[]; 185e3d86717SJuli Mallett int argc; 186e3d86717SJuli Mallett { 187e3d86717SJuli Mallett int n; 188e3d86717SJuli Mallett argv[1] = NULL; 189e3d86717SJuli Mallett n = builtin_type(argv[2]); 190e3d86717SJuli Mallett if (n != -1) 191e3d86717SJuli Mallett eval(argv+1, argc-1, n); 192e3d86717SJuli Mallett else 193e3d86717SJuli Mallett errx(1, "unknown builtin %s", argv[2]); 194e3d86717SJuli Mallett } 195e3d86717SJuli Mallett 196e3d86717SJuli Mallett 197e3d86717SJuli Mallett /* We need some temporary buffer space, as pb pushes BACK and substitution 198e3d86717SJuli Mallett * proceeds forward... */ 199e3d86717SJuli Mallett static char *buffer; 200e3d86717SJuli Mallett static size_t bufsize = 0; 201e3d86717SJuli Mallett static size_t current = 0; 202e3d86717SJuli Mallett 203e3d86717SJuli Mallett static void addchars(const char *, size_t); 204e3d86717SJuli Mallett static void addchar(char); 205e3d86717SJuli Mallett static char *twiddle(const char *); 206e3d86717SJuli Mallett static char *getstring(void); 207e3d86717SJuli Mallett static void exit_regerror(int, regex_t *); 208e3d86717SJuli Mallett static void do_subst(const char *, regex_t *, const char *, regmatch_t *); 209e3d86717SJuli Mallett static void do_regexpindex(const char *, regex_t *, regmatch_t *); 210e3d86717SJuli Mallett static void do_regexp(const char *, regex_t *, const char *, regmatch_t *); 211e3d86717SJuli Mallett static void add_sub(int, const char *, regex_t *, regmatch_t *); 212e3d86717SJuli Mallett static void add_replace(const char *, regex_t *, const char *, regmatch_t *); 213e3d86717SJuli Mallett #define addconstantstring(s) addchars((s), sizeof(s)-1) 214e3d86717SJuli Mallett 215e3d86717SJuli Mallett static void 216e3d86717SJuli Mallett addchars(c, n) 217e3d86717SJuli Mallett const char *c; 218e3d86717SJuli Mallett size_t n; 219e3d86717SJuli Mallett { 220e3d86717SJuli Mallett if (n == 0) 221e3d86717SJuli Mallett return; 222e3d86717SJuli Mallett while (current + n > bufsize) { 223e3d86717SJuli Mallett if (bufsize == 0) 224e3d86717SJuli Mallett bufsize = 1024; 225e3d86717SJuli Mallett else 226e3d86717SJuli Mallett bufsize *= 2; 227e3d86717SJuli Mallett buffer = realloc(buffer, bufsize); 228e3d86717SJuli Mallett if (buffer == NULL) 229e3d86717SJuli Mallett errx(1, "out of memory"); 230e3d86717SJuli Mallett } 231e3d86717SJuli Mallett memcpy(buffer+current, c, n); 232e3d86717SJuli Mallett current += n; 233e3d86717SJuli Mallett } 234e3d86717SJuli Mallett 235e3d86717SJuli Mallett static void 236e3d86717SJuli Mallett addchar(c) 237e3d86717SJuli Mallett char c; 238e3d86717SJuli Mallett { 239e3d86717SJuli Mallett if (current +1 > bufsize) { 240e3d86717SJuli Mallett if (bufsize == 0) 241e3d86717SJuli Mallett bufsize = 1024; 242e3d86717SJuli Mallett else 243e3d86717SJuli Mallett bufsize *= 2; 244e3d86717SJuli Mallett buffer = realloc(buffer, bufsize); 245e3d86717SJuli Mallett if (buffer == NULL) 246e3d86717SJuli Mallett errx(1, "out of memory"); 247e3d86717SJuli Mallett } 248e3d86717SJuli Mallett buffer[current++] = c; 249e3d86717SJuli Mallett } 250e3d86717SJuli Mallett 251e3d86717SJuli Mallett static char * 252e3d86717SJuli Mallett getstring() 253e3d86717SJuli Mallett { 254e3d86717SJuli Mallett addchar('\0'); 255e3d86717SJuli Mallett current = 0; 256e3d86717SJuli Mallett return buffer; 257e3d86717SJuli Mallett } 258e3d86717SJuli Mallett 259e3d86717SJuli Mallett 260e3d86717SJuli Mallett static void 261e3d86717SJuli Mallett exit_regerror(er, re) 262e3d86717SJuli Mallett int er; 263e3d86717SJuli Mallett regex_t *re; 264e3d86717SJuli Mallett { 265e3d86717SJuli Mallett size_t errlen; 266e3d86717SJuli Mallett char *errbuf; 267e3d86717SJuli Mallett 268e3d86717SJuli Mallett errlen = regerror(er, re, NULL, 0); 269e3d86717SJuli Mallett errbuf = xalloc(errlen); 270e3d86717SJuli Mallett regerror(er, re, errbuf, errlen); 271e3d86717SJuli Mallett errx(1, "regular expression error: %s", errbuf); 272e3d86717SJuli Mallett } 273e3d86717SJuli Mallett 274e3d86717SJuli Mallett static void 275e3d86717SJuli Mallett add_sub(n, string, re, pm) 276e3d86717SJuli Mallett int n; 277e3d86717SJuli Mallett const char *string; 278e3d86717SJuli Mallett regex_t *re; 279e3d86717SJuli Mallett regmatch_t *pm; 280e3d86717SJuli Mallett { 281e3d86717SJuli Mallett if (n > re->re_nsub) 282e3d86717SJuli Mallett warnx("No subexpression %d", n); 283e3d86717SJuli Mallett /* Subexpressions that did not match are 284e3d86717SJuli Mallett * not an error. */ 285e3d86717SJuli Mallett else if (pm[n].rm_so != -1 && 286e3d86717SJuli Mallett pm[n].rm_eo != -1) { 287e3d86717SJuli Mallett addchars(string + pm[n].rm_so, 288e3d86717SJuli Mallett pm[n].rm_eo - pm[n].rm_so); 289e3d86717SJuli Mallett } 290e3d86717SJuli Mallett } 291e3d86717SJuli Mallett 292e3d86717SJuli Mallett /* Add replacement string to the output buffer, recognizing special 293e3d86717SJuli Mallett * constructs and replacing them with substrings of the original string. 294e3d86717SJuli Mallett */ 295e3d86717SJuli Mallett static void 296e3d86717SJuli Mallett add_replace(string, re, replace, pm) 297e3d86717SJuli Mallett const char *string; 298e3d86717SJuli Mallett regex_t *re; 299e3d86717SJuli Mallett const char *replace; 300e3d86717SJuli Mallett regmatch_t *pm; 301e3d86717SJuli Mallett { 302e3d86717SJuli Mallett const char *p; 303e3d86717SJuli Mallett 304e3d86717SJuli Mallett for (p = replace; *p != '\0'; p++) { 305e3d86717SJuli Mallett if (*p == '&' && !mimic_gnu) { 306e3d86717SJuli Mallett add_sub(0, string, re, pm); 307e3d86717SJuli Mallett continue; 308e3d86717SJuli Mallett } 309e3d86717SJuli Mallett if (*p == '\\') { 310e3d86717SJuli Mallett if (p[1] == '\\') { 311e3d86717SJuli Mallett addchar(p[1]); 312e3d86717SJuli Mallett p++; 313e3d86717SJuli Mallett continue; 314e3d86717SJuli Mallett } 315e3d86717SJuli Mallett if (p[1] == '&') { 316e3d86717SJuli Mallett if (mimic_gnu) 317e3d86717SJuli Mallett add_sub(0, string, re, pm); 318e3d86717SJuli Mallett else 319e3d86717SJuli Mallett addchar(p[1]); 320e3d86717SJuli Mallett p++; 321e3d86717SJuli Mallett continue; 322e3d86717SJuli Mallett } 323e3d86717SJuli Mallett if (isdigit(p[1])) { 324e3d86717SJuli Mallett add_sub(*(++p) - '0', string, re, pm); 325e3d86717SJuli Mallett continue; 326e3d86717SJuli Mallett } 327e3d86717SJuli Mallett } 328e3d86717SJuli Mallett addchar(*p); 329e3d86717SJuli Mallett } 330e3d86717SJuli Mallett } 331e3d86717SJuli Mallett 332e3d86717SJuli Mallett static void 333e3d86717SJuli Mallett do_subst(string, re, replace, pm) 334e3d86717SJuli Mallett const char *string; 335e3d86717SJuli Mallett regex_t *re; 336e3d86717SJuli Mallett const char *replace; 337e3d86717SJuli Mallett regmatch_t *pm; 338e3d86717SJuli Mallett { 339e3d86717SJuli Mallett int error; 340e3d86717SJuli Mallett int flags = 0; 341e3d86717SJuli Mallett const char *last_match = NULL; 342e3d86717SJuli Mallett 343e3d86717SJuli Mallett while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) { 344e3d86717SJuli Mallett if (pm[0].rm_eo != 0) { 345e3d86717SJuli Mallett if (string[pm[0].rm_eo-1] == '\n') 346e3d86717SJuli Mallett flags = 0; 347e3d86717SJuli Mallett else 348e3d86717SJuli Mallett flags = REG_NOTBOL; 349e3d86717SJuli Mallett } 350e3d86717SJuli Mallett 351e3d86717SJuli Mallett /* NULL length matches are special... We use the `vi-mode' 352e3d86717SJuli Mallett * rule: don't allow a NULL-match at the last match 353e3d86717SJuli Mallett * position. 354e3d86717SJuli Mallett */ 355e3d86717SJuli Mallett if (pm[0].rm_so == pm[0].rm_eo && 356e3d86717SJuli Mallett string + pm[0].rm_so == last_match) { 357e3d86717SJuli Mallett if (*string == '\0') 358e3d86717SJuli Mallett return; 359e3d86717SJuli Mallett addchar(*string); 360e3d86717SJuli Mallett if (*string++ == '\n') 361e3d86717SJuli Mallett flags = 0; 362e3d86717SJuli Mallett else 363e3d86717SJuli Mallett flags = REG_NOTBOL; 364e3d86717SJuli Mallett continue; 365e3d86717SJuli Mallett } 366e3d86717SJuli Mallett last_match = string + pm[0].rm_so; 367e3d86717SJuli Mallett addchars(string, pm[0].rm_so); 368e3d86717SJuli Mallett add_replace(string, re, replace, pm); 369e3d86717SJuli Mallett string += pm[0].rm_eo; 370e3d86717SJuli Mallett } 371e3d86717SJuli Mallett if (error != REG_NOMATCH) 372e3d86717SJuli Mallett exit_regerror(error, re); 373e3d86717SJuli Mallett pbstr(string); 374e3d86717SJuli Mallett } 375e3d86717SJuli Mallett 376e3d86717SJuli Mallett static void 377e3d86717SJuli Mallett do_regexp(string, re, replace, pm) 378e3d86717SJuli Mallett const char *string; 379e3d86717SJuli Mallett regex_t *re; 380e3d86717SJuli Mallett const char *replace; 381e3d86717SJuli Mallett regmatch_t *pm; 382e3d86717SJuli Mallett { 383e3d86717SJuli Mallett int error; 384e3d86717SJuli Mallett 385e3d86717SJuli Mallett switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { 386e3d86717SJuli Mallett case 0: 387e3d86717SJuli Mallett add_replace(string, re, replace, pm); 388e3d86717SJuli Mallett pbstr(getstring()); 389e3d86717SJuli Mallett break; 390e3d86717SJuli Mallett case REG_NOMATCH: 391e3d86717SJuli Mallett break; 392e3d86717SJuli Mallett default: 393e3d86717SJuli Mallett exit_regerror(error, re); 394e3d86717SJuli Mallett } 395e3d86717SJuli Mallett } 396e3d86717SJuli Mallett 397e3d86717SJuli Mallett static void 398e3d86717SJuli Mallett do_regexpindex(string, re, pm) 399e3d86717SJuli Mallett const char *string; 400e3d86717SJuli Mallett regex_t *re; 401e3d86717SJuli Mallett regmatch_t *pm; 402e3d86717SJuli Mallett { 403e3d86717SJuli Mallett int error; 404e3d86717SJuli Mallett 405e3d86717SJuli Mallett switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { 406e3d86717SJuli Mallett case 0: 407e3d86717SJuli Mallett pbunsigned(pm[0].rm_so); 408e3d86717SJuli Mallett break; 409e3d86717SJuli Mallett case REG_NOMATCH: 410e3d86717SJuli Mallett pbnum(-1); 411e3d86717SJuli Mallett break; 412e3d86717SJuli Mallett default: 413e3d86717SJuli Mallett exit_regerror(error, re); 414e3d86717SJuli Mallett } 415e3d86717SJuli Mallett } 416e3d86717SJuli Mallett 417e3d86717SJuli Mallett /* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2 418e3d86717SJuli Mallett * says. So we twiddle with the regexp before passing it to regcomp. 419e3d86717SJuli Mallett */ 420e3d86717SJuli Mallett static char * 421e3d86717SJuli Mallett twiddle(p) 422e3d86717SJuli Mallett const char *p; 423e3d86717SJuli Mallett { 424e3d86717SJuli Mallett /* This could use strcspn for speed... */ 425e3d86717SJuli Mallett while (*p != '\0') { 426e3d86717SJuli Mallett if (*p == '\\') { 427e3d86717SJuli Mallett switch(p[1]) { 428e3d86717SJuli Mallett case '(': 429e3d86717SJuli Mallett case ')': 430e3d86717SJuli Mallett case '|': 431e3d86717SJuli Mallett addchar(p[1]); 432e3d86717SJuli Mallett break; 433e3d86717SJuli Mallett case 'w': 434e3d86717SJuli Mallett addconstantstring("[_a-zA-Z0-9]"); 435e3d86717SJuli Mallett break; 436e3d86717SJuli Mallett case 'W': 437e3d86717SJuli Mallett addconstantstring("[^_a-zA-Z0-9]"); 438e3d86717SJuli Mallett break; 439e3d86717SJuli Mallett case '<': 440e3d86717SJuli Mallett addconstantstring("[[:<:]]"); 441e3d86717SJuli Mallett break; 442e3d86717SJuli Mallett case '>': 443e3d86717SJuli Mallett addconstantstring("[[:>:]]"); 444e3d86717SJuli Mallett break; 445e3d86717SJuli Mallett default: 446e3d86717SJuli Mallett addchars(p, 2); 447e3d86717SJuli Mallett break; 448e3d86717SJuli Mallett } 449e3d86717SJuli Mallett p+=2; 450e3d86717SJuli Mallett continue; 451e3d86717SJuli Mallett } 452e3d86717SJuli Mallett if (*p == '(' || *p == ')' || *p == '|') 453e3d86717SJuli Mallett addchar('\\'); 454e3d86717SJuli Mallett 455e3d86717SJuli Mallett addchar(*p); 456e3d86717SJuli Mallett p++; 457e3d86717SJuli Mallett } 458e3d86717SJuli Mallett return getstring(); 459e3d86717SJuli Mallett } 460e3d86717SJuli Mallett 461e3d86717SJuli Mallett /* patsubst(string, regexp, opt replacement) */ 462e3d86717SJuli Mallett /* argv[2]: string 463e3d86717SJuli Mallett * argv[3]: regexp 464e3d86717SJuli Mallett * argv[4]: opt rep 465e3d86717SJuli Mallett */ 466e3d86717SJuli Mallett void 467e3d86717SJuli Mallett dopatsubst(argv, argc) 468e3d86717SJuli Mallett const char *argv[]; 469e3d86717SJuli Mallett int argc; 470e3d86717SJuli Mallett { 471e3d86717SJuli Mallett int error; 472e3d86717SJuli Mallett regex_t re; 473e3d86717SJuli Mallett regmatch_t *pmatch; 474e3d86717SJuli Mallett 475e3d86717SJuli Mallett if (argc <= 3) { 476e3d86717SJuli Mallett warnx("Too few arguments to patsubst"); 477e3d86717SJuli Mallett return; 478e3d86717SJuli Mallett } 479e3d86717SJuli Mallett error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], 480e3d86717SJuli Mallett REG_NEWLINE | REG_EXTENDED); 481e3d86717SJuli Mallett if (error != 0) 482e3d86717SJuli Mallett exit_regerror(error, &re); 483e3d86717SJuli Mallett 484e3d86717SJuli Mallett pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); 485e3d86717SJuli Mallett do_subst(argv[2], &re, 486e3d86717SJuli Mallett argc != 4 && argv[4] != NULL ? argv[4] : "", pmatch); 487e3d86717SJuli Mallett pbstr(getstring()); 488e3d86717SJuli Mallett free(pmatch); 489e3d86717SJuli Mallett regfree(&re); 490e3d86717SJuli Mallett } 491e3d86717SJuli Mallett 492e3d86717SJuli Mallett void 493e3d86717SJuli Mallett doregexp(argv, argc) 494e3d86717SJuli Mallett const char *argv[]; 495e3d86717SJuli Mallett int argc; 496e3d86717SJuli Mallett { 497e3d86717SJuli Mallett int error; 498e3d86717SJuli Mallett regex_t re; 499e3d86717SJuli Mallett regmatch_t *pmatch; 500e3d86717SJuli Mallett 501e3d86717SJuli Mallett if (argc <= 3) { 502e3d86717SJuli Mallett warnx("Too few arguments to regexp"); 503e3d86717SJuli Mallett return; 504e3d86717SJuli Mallett } 505e3d86717SJuli Mallett error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], 506e3d86717SJuli Mallett REG_EXTENDED); 507e3d86717SJuli Mallett if (error != 0) 508e3d86717SJuli Mallett exit_regerror(error, &re); 509e3d86717SJuli Mallett 510e3d86717SJuli Mallett pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); 511e3d86717SJuli Mallett if (argv[4] == NULL || argc == 4) 512e3d86717SJuli Mallett do_regexpindex(argv[2], &re, pmatch); 513e3d86717SJuli Mallett else 514e3d86717SJuli Mallett do_regexp(argv[2], &re, argv[4], pmatch); 515e3d86717SJuli Mallett free(pmatch); 516e3d86717SJuli Mallett regfree(&re); 517e3d86717SJuli Mallett } 518e3d86717SJuli Mallett 519e3d86717SJuli Mallett void 520e3d86717SJuli Mallett doesyscmd(cmd) 521e3d86717SJuli Mallett const char *cmd; 522e3d86717SJuli Mallett { 523e3d86717SJuli Mallett int p[2]; 524e3d86717SJuli Mallett pid_t pid, cpid; 525e3d86717SJuli Mallett char *argv[4]; 526e3d86717SJuli Mallett int cc; 527e3d86717SJuli Mallett int status; 528e3d86717SJuli Mallett 529e3d86717SJuli Mallett /* Follow gnu m4 documentation: first flush buffers. */ 530e3d86717SJuli Mallett fflush(NULL); 531e3d86717SJuli Mallett 532e3d86717SJuli Mallett argv[0] = "sh"; 533e3d86717SJuli Mallett argv[1] = "-c"; 534e3d86717SJuli Mallett argv[2] = (char *)cmd; 535e3d86717SJuli Mallett argv[3] = NULL; 536e3d86717SJuli Mallett 537e3d86717SJuli Mallett /* Just set up standard output, share stderr and stdin with m4 */ 538e3d86717SJuli Mallett if (pipe(p) == -1) 539e3d86717SJuli Mallett err(1, "bad pipe"); 540e3d86717SJuli Mallett switch(cpid = fork()) { 541e3d86717SJuli Mallett case -1: 542e3d86717SJuli Mallett err(1, "bad fork"); 543e3d86717SJuli Mallett /* NOTREACHED */ 544e3d86717SJuli Mallett case 0: 545e3d86717SJuli Mallett (void) close(p[0]); 546e3d86717SJuli Mallett (void) dup2(p[1], 1); 547e3d86717SJuli Mallett (void) close(p[1]); 548e3d86717SJuli Mallett execv(_PATH_BSHELL, argv); 549e3d86717SJuli Mallett exit(1); 550e3d86717SJuli Mallett default: 551e3d86717SJuli Mallett /* Read result in two stages, since m4's buffer is 552e3d86717SJuli Mallett * pushback-only. */ 553e3d86717SJuli Mallett (void) close(p[1]); 554e3d86717SJuli Mallett do { 555e3d86717SJuli Mallett char result[BUFSIZE]; 556e3d86717SJuli Mallett cc = read(p[0], result, sizeof result); 557e3d86717SJuli Mallett if (cc > 0) 558e3d86717SJuli Mallett addchars(result, cc); 559e3d86717SJuli Mallett } while (cc > 0 || (cc == -1 && errno == EINTR)); 560e3d86717SJuli Mallett 561e3d86717SJuli Mallett (void) close(p[0]); 562e3d86717SJuli Mallett while ((pid = wait(&status)) != cpid && pid >= 0) 563e3d86717SJuli Mallett continue; 564e3d86717SJuli Mallett pbstr(getstring()); 565e3d86717SJuli Mallett } 566e3d86717SJuli Mallett } 567