gnum4.c revision 90744
190744Sjmallett/* $OpenBSD: gnum4.c,v 1.16 2002/02/16 21:27:48 millert Exp $ */ 290744Sjmallett 390744Sjmallett/* 490744Sjmallett * Copyright (c) 1999 Marc Espie 590744Sjmallett * 690744Sjmallett * Redistribution and use in source and binary forms, with or without 790744Sjmallett * modification, are permitted provided that the following conditions 890744Sjmallett * are met: 990744Sjmallett * 1. Redistributions of source code must retain the above copyright 1090744Sjmallett * notice, this list of conditions and the following disclaimer. 1190744Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 1290744Sjmallett * notice, this list of conditions and the following disclaimer in the 1390744Sjmallett * documentation and/or other materials provided with the distribution. 1490744Sjmallett * 1590744Sjmallett * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1690744Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1790744Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1890744Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1990744Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2090744Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2190744Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2290744Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2390744Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2490744Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2590744Sjmallett * SUCH DAMAGE. 2690744Sjmallett */ 2790744Sjmallett 2890744Sjmallett/* 2990744Sjmallett * functions needed to support gnu-m4 extensions, including a fake freezing 3090744Sjmallett */ 3190744Sjmallett 3290744Sjmallett#include <sys/param.h> 3390744Sjmallett#include <sys/types.h> 3490744Sjmallett#include <sys/wait.h> 3590744Sjmallett#include <ctype.h> 3690744Sjmallett#include <paths.h> 3790744Sjmallett#include <regex.h> 3890744Sjmallett#include <stddef.h> 3990744Sjmallett#include <stdlib.h> 4090744Sjmallett#include <stdio.h> 4190744Sjmallett#include <string.h> 4290744Sjmallett#include <err.h> 4390744Sjmallett#include <errno.h> 4490744Sjmallett#include <unistd.h> 4590744Sjmallett#include "mdef.h" 4690744Sjmallett#include "stdd.h" 4790744Sjmallett#include "extern.h" 4890744Sjmallett 4990744Sjmallett 5090744Sjmallettint mimic_gnu = 0; 5190744Sjmallett 5290744Sjmallett/* 5390744Sjmallett * Support for include path search 5490744Sjmallett * First search in the the current directory. 5590744Sjmallett * If not found, and the path is not absolute, include path kicks in. 5690744Sjmallett * First, -I options, in the order found on the command line. 5790744Sjmallett * Then M4PATH env variable 5890744Sjmallett */ 5990744Sjmallett 6090744Sjmallettstruct path_entry { 6190744Sjmallett char *name; 6290744Sjmallett struct path_entry *next; 6390744Sjmallett} *first, *last; 6490744Sjmallett 6590744Sjmallettstatic struct path_entry *new_path_entry(const char *); 6690744Sjmallettstatic void ensure_m4path(void); 6790744Sjmallettstatic struct input_file *dopath(struct input_file *, const char *); 6890744Sjmallett 6990744Sjmallettstatic struct path_entry * 7090744Sjmallettnew_path_entry(dirname) 7190744Sjmallett const char *dirname; 7290744Sjmallett{ 7390744Sjmallett struct path_entry *n; 7490744Sjmallett 7590744Sjmallett n = malloc(sizeof(struct path_entry)); 7690744Sjmallett if (!n) 7790744Sjmallett errx(1, "out of memory"); 7890744Sjmallett n->name = strdup(dirname); 7990744Sjmallett if (!n->name) 8090744Sjmallett errx(1, "out of memory"); 8190744Sjmallett n->next = 0; 8290744Sjmallett return n; 8390744Sjmallett} 8490744Sjmallett 8590744Sjmallettvoid 8690744Sjmallettaddtoincludepath(dirname) 8790744Sjmallett const char *dirname; 8890744Sjmallett{ 8990744Sjmallett struct path_entry *n; 9090744Sjmallett 9190744Sjmallett n = new_path_entry(dirname); 9290744Sjmallett 9390744Sjmallett if (last) { 9490744Sjmallett last->next = n; 9590744Sjmallett last = n; 9690744Sjmallett } 9790744Sjmallett else 9890744Sjmallett last = first = n; 9990744Sjmallett} 10090744Sjmallett 10190744Sjmallettstatic void 10290744Sjmallettensure_m4path() 10390744Sjmallett{ 10490744Sjmallett static int envpathdone = 0; 10590744Sjmallett char *envpath; 10690744Sjmallett char *sweep; 10790744Sjmallett char *path; 10890744Sjmallett 10990744Sjmallett if (envpathdone) 11090744Sjmallett return; 11190744Sjmallett envpathdone = TRUE; 11290744Sjmallett envpath = getenv("M4PATH"); 11390744Sjmallett if (!envpath) 11490744Sjmallett return; 11590744Sjmallett /* for portability: getenv result is read-only */ 11690744Sjmallett envpath = strdup(envpath); 11790744Sjmallett if (!envpath) 11890744Sjmallett errx(1, "out of memory"); 11990744Sjmallett for (sweep = envpath; 12090744Sjmallett (path = strsep(&sweep, ":")) != NULL;) 12190744Sjmallett addtoincludepath(path); 12290744Sjmallett free(envpath); 12390744Sjmallett} 12490744Sjmallett 12590744Sjmallettstatic 12690744Sjmallettstruct input_file * 12790744Sjmallettdopath(i, filename) 12890744Sjmallett struct input_file *i; 12990744Sjmallett const char *filename; 13090744Sjmallett{ 13190744Sjmallett char path[MAXPATHLEN]; 13290744Sjmallett struct path_entry *pe; 13390744Sjmallett FILE *f; 13490744Sjmallett 13590744Sjmallett for (pe = first; pe; pe = pe->next) { 13690744Sjmallett snprintf(path, sizeof(path), "%s/%s", pe->name, filename); 13790744Sjmallett if ((f = fopen(path, "r")) != 0) { 13890744Sjmallett set_input(i, f, path); 13990744Sjmallett return i; 14090744Sjmallett } 14190744Sjmallett } 14290744Sjmallett return NULL; 14390744Sjmallett} 14490744Sjmallett 14590744Sjmallettstruct input_file * 14690744Sjmallettfopen_trypath(i, filename) 14790744Sjmallett struct input_file *i; 14890744Sjmallett const char *filename; 14990744Sjmallett{ 15090744Sjmallett FILE *f; 15190744Sjmallett 15290744Sjmallett f = fopen(filename, "r"); 15390744Sjmallett if (f != NULL) { 15490744Sjmallett set_input(i, f, filename); 15590744Sjmallett return i; 15690744Sjmallett } 15790744Sjmallett if (filename[0] == '/') 15890744Sjmallett return NULL; 15990744Sjmallett 16090744Sjmallett ensure_m4path(); 16190744Sjmallett 16290744Sjmallett return dopath(i, filename); 16390744Sjmallett} 16490744Sjmallett 16590744Sjmallettvoid 16690744Sjmallettdoindir(argv, argc) 16790744Sjmallett const char *argv[]; 16890744Sjmallett int argc; 16990744Sjmallett{ 17090744Sjmallett ndptr p; 17190744Sjmallett 17290744Sjmallett p = lookup(argv[2]); 17390744Sjmallett if (p == NULL) 17490744Sjmallett errx(1, "undefined macro %s", argv[2]); 17590744Sjmallett argv[1] = p->defn; 17690744Sjmallett eval(argv+1, argc-1, p->type); 17790744Sjmallett} 17890744Sjmallett 17990744Sjmallettvoid 18090744Sjmallettdobuiltin(argv, argc) 18190744Sjmallett const char *argv[]; 18290744Sjmallett int argc; 18390744Sjmallett{ 18490744Sjmallett int n; 18590744Sjmallett argv[1] = NULL; 18690744Sjmallett n = builtin_type(argv[2]); 18790744Sjmallett if (n != -1) 18890744Sjmallett eval(argv+1, argc-1, n); 18990744Sjmallett else 19090744Sjmallett errx(1, "unknown builtin %s", argv[2]); 19190744Sjmallett} 19290744Sjmallett 19390744Sjmallett 19490744Sjmallett/* We need some temporary buffer space, as pb pushes BACK and substitution 19590744Sjmallett * proceeds forward... */ 19690744Sjmallettstatic char *buffer; 19790744Sjmallettstatic size_t bufsize = 0; 19890744Sjmallettstatic size_t current = 0; 19990744Sjmallett 20090744Sjmallettstatic void addchars(const char *, size_t); 20190744Sjmallettstatic void addchar(char); 20290744Sjmallettstatic char *twiddle(const char *); 20390744Sjmallettstatic char *getstring(void); 20490744Sjmallettstatic void exit_regerror(int, regex_t *); 20590744Sjmallettstatic void do_subst(const char *, regex_t *, const char *, regmatch_t *); 20690744Sjmallettstatic void do_regexpindex(const char *, regex_t *, regmatch_t *); 20790744Sjmallettstatic void do_regexp(const char *, regex_t *, const char *, regmatch_t *); 20890744Sjmallettstatic void add_sub(int, const char *, regex_t *, regmatch_t *); 20990744Sjmallettstatic void add_replace(const char *, regex_t *, const char *, regmatch_t *); 21090744Sjmallett#define addconstantstring(s) addchars((s), sizeof(s)-1) 21190744Sjmallett 21290744Sjmallettstatic void 21390744Sjmallettaddchars(c, n) 21490744Sjmallett const char *c; 21590744Sjmallett size_t n; 21690744Sjmallett{ 21790744Sjmallett if (n == 0) 21890744Sjmallett return; 21990744Sjmallett while (current + n > bufsize) { 22090744Sjmallett if (bufsize == 0) 22190744Sjmallett bufsize = 1024; 22290744Sjmallett else 22390744Sjmallett bufsize *= 2; 22490744Sjmallett buffer = realloc(buffer, bufsize); 22590744Sjmallett if (buffer == NULL) 22690744Sjmallett errx(1, "out of memory"); 22790744Sjmallett } 22890744Sjmallett memcpy(buffer+current, c, n); 22990744Sjmallett current += n; 23090744Sjmallett} 23190744Sjmallett 23290744Sjmallettstatic void 23390744Sjmallettaddchar(c) 23490744Sjmallett char c; 23590744Sjmallett{ 23690744Sjmallett if (current +1 > bufsize) { 23790744Sjmallett if (bufsize == 0) 23890744Sjmallett bufsize = 1024; 23990744Sjmallett else 24090744Sjmallett bufsize *= 2; 24190744Sjmallett buffer = realloc(buffer, bufsize); 24290744Sjmallett if (buffer == NULL) 24390744Sjmallett errx(1, "out of memory"); 24490744Sjmallett } 24590744Sjmallett buffer[current++] = c; 24690744Sjmallett} 24790744Sjmallett 24890744Sjmallettstatic char * 24990744Sjmallettgetstring() 25090744Sjmallett{ 25190744Sjmallett addchar('\0'); 25290744Sjmallett current = 0; 25390744Sjmallett return buffer; 25490744Sjmallett} 25590744Sjmallett 25690744Sjmallett 25790744Sjmallettstatic void 25890744Sjmallettexit_regerror(er, re) 25990744Sjmallett int er; 26090744Sjmallett regex_t *re; 26190744Sjmallett{ 26290744Sjmallett size_t errlen; 26390744Sjmallett char *errbuf; 26490744Sjmallett 26590744Sjmallett errlen = regerror(er, re, NULL, 0); 26690744Sjmallett errbuf = xalloc(errlen); 26790744Sjmallett regerror(er, re, errbuf, errlen); 26890744Sjmallett errx(1, "regular expression error: %s", errbuf); 26990744Sjmallett} 27090744Sjmallett 27190744Sjmallettstatic void 27290744Sjmallettadd_sub(n, string, re, pm) 27390744Sjmallett int n; 27490744Sjmallett const char *string; 27590744Sjmallett regex_t *re; 27690744Sjmallett regmatch_t *pm; 27790744Sjmallett{ 27890744Sjmallett if (n > re->re_nsub) 27990744Sjmallett warnx("No subexpression %d", n); 28090744Sjmallett /* Subexpressions that did not match are 28190744Sjmallett * not an error. */ 28290744Sjmallett else if (pm[n].rm_so != -1 && 28390744Sjmallett pm[n].rm_eo != -1) { 28490744Sjmallett addchars(string + pm[n].rm_so, 28590744Sjmallett pm[n].rm_eo - pm[n].rm_so); 28690744Sjmallett } 28790744Sjmallett} 28890744Sjmallett 28990744Sjmallett/* Add replacement string to the output buffer, recognizing special 29090744Sjmallett * constructs and replacing them with substrings of the original string. 29190744Sjmallett */ 29290744Sjmallettstatic void 29390744Sjmallettadd_replace(string, re, replace, pm) 29490744Sjmallett const char *string; 29590744Sjmallett regex_t *re; 29690744Sjmallett const char *replace; 29790744Sjmallett regmatch_t *pm; 29890744Sjmallett{ 29990744Sjmallett const char *p; 30090744Sjmallett 30190744Sjmallett for (p = replace; *p != '\0'; p++) { 30290744Sjmallett if (*p == '&' && !mimic_gnu) { 30390744Sjmallett add_sub(0, string, re, pm); 30490744Sjmallett continue; 30590744Sjmallett } 30690744Sjmallett if (*p == '\\') { 30790744Sjmallett if (p[1] == '\\') { 30890744Sjmallett addchar(p[1]); 30990744Sjmallett p++; 31090744Sjmallett continue; 31190744Sjmallett } 31290744Sjmallett if (p[1] == '&') { 31390744Sjmallett if (mimic_gnu) 31490744Sjmallett add_sub(0, string, re, pm); 31590744Sjmallett else 31690744Sjmallett addchar(p[1]); 31790744Sjmallett p++; 31890744Sjmallett continue; 31990744Sjmallett } 32090744Sjmallett if (isdigit(p[1])) { 32190744Sjmallett add_sub(*(++p) - '0', string, re, pm); 32290744Sjmallett continue; 32390744Sjmallett } 32490744Sjmallett } 32590744Sjmallett addchar(*p); 32690744Sjmallett } 32790744Sjmallett} 32890744Sjmallett 32990744Sjmallettstatic void 33090744Sjmallettdo_subst(string, re, replace, pm) 33190744Sjmallett const char *string; 33290744Sjmallett regex_t *re; 33390744Sjmallett const char *replace; 33490744Sjmallett regmatch_t *pm; 33590744Sjmallett{ 33690744Sjmallett int error; 33790744Sjmallett int flags = 0; 33890744Sjmallett const char *last_match = NULL; 33990744Sjmallett 34090744Sjmallett while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) { 34190744Sjmallett if (pm[0].rm_eo != 0) { 34290744Sjmallett if (string[pm[0].rm_eo-1] == '\n') 34390744Sjmallett flags = 0; 34490744Sjmallett else 34590744Sjmallett flags = REG_NOTBOL; 34690744Sjmallett } 34790744Sjmallett 34890744Sjmallett /* NULL length matches are special... We use the `vi-mode' 34990744Sjmallett * rule: don't allow a NULL-match at the last match 35090744Sjmallett * position. 35190744Sjmallett */ 35290744Sjmallett if (pm[0].rm_so == pm[0].rm_eo && 35390744Sjmallett string + pm[0].rm_so == last_match) { 35490744Sjmallett if (*string == '\0') 35590744Sjmallett return; 35690744Sjmallett addchar(*string); 35790744Sjmallett if (*string++ == '\n') 35890744Sjmallett flags = 0; 35990744Sjmallett else 36090744Sjmallett flags = REG_NOTBOL; 36190744Sjmallett continue; 36290744Sjmallett } 36390744Sjmallett last_match = string + pm[0].rm_so; 36490744Sjmallett addchars(string, pm[0].rm_so); 36590744Sjmallett add_replace(string, re, replace, pm); 36690744Sjmallett string += pm[0].rm_eo; 36790744Sjmallett } 36890744Sjmallett if (error != REG_NOMATCH) 36990744Sjmallett exit_regerror(error, re); 37090744Sjmallett pbstr(string); 37190744Sjmallett} 37290744Sjmallett 37390744Sjmallettstatic void 37490744Sjmallettdo_regexp(string, re, replace, pm) 37590744Sjmallett const char *string; 37690744Sjmallett regex_t *re; 37790744Sjmallett const char *replace; 37890744Sjmallett regmatch_t *pm; 37990744Sjmallett{ 38090744Sjmallett int error; 38190744Sjmallett 38290744Sjmallett switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { 38390744Sjmallett case 0: 38490744Sjmallett add_replace(string, re, replace, pm); 38590744Sjmallett pbstr(getstring()); 38690744Sjmallett break; 38790744Sjmallett case REG_NOMATCH: 38890744Sjmallett break; 38990744Sjmallett default: 39090744Sjmallett exit_regerror(error, re); 39190744Sjmallett } 39290744Sjmallett} 39390744Sjmallett 39490744Sjmallettstatic void 39590744Sjmallettdo_regexpindex(string, re, pm) 39690744Sjmallett const char *string; 39790744Sjmallett regex_t *re; 39890744Sjmallett regmatch_t *pm; 39990744Sjmallett{ 40090744Sjmallett int error; 40190744Sjmallett 40290744Sjmallett switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { 40390744Sjmallett case 0: 40490744Sjmallett pbunsigned(pm[0].rm_so); 40590744Sjmallett break; 40690744Sjmallett case REG_NOMATCH: 40790744Sjmallett pbnum(-1); 40890744Sjmallett break; 40990744Sjmallett default: 41090744Sjmallett exit_regerror(error, re); 41190744Sjmallett } 41290744Sjmallett} 41390744Sjmallett 41490744Sjmallett/* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2 41590744Sjmallett * says. So we twiddle with the regexp before passing it to regcomp. 41690744Sjmallett */ 41790744Sjmallettstatic char * 41890744Sjmalletttwiddle(p) 41990744Sjmallett const char *p; 42090744Sjmallett{ 42190744Sjmallett /* This could use strcspn for speed... */ 42290744Sjmallett while (*p != '\0') { 42390744Sjmallett if (*p == '\\') { 42490744Sjmallett switch(p[1]) { 42590744Sjmallett case '(': 42690744Sjmallett case ')': 42790744Sjmallett case '|': 42890744Sjmallett addchar(p[1]); 42990744Sjmallett break; 43090744Sjmallett case 'w': 43190744Sjmallett addconstantstring("[_a-zA-Z0-9]"); 43290744Sjmallett break; 43390744Sjmallett case 'W': 43490744Sjmallett addconstantstring("[^_a-zA-Z0-9]"); 43590744Sjmallett break; 43690744Sjmallett case '<': 43790744Sjmallett addconstantstring("[[:<:]]"); 43890744Sjmallett break; 43990744Sjmallett case '>': 44090744Sjmallett addconstantstring("[[:>:]]"); 44190744Sjmallett break; 44290744Sjmallett default: 44390744Sjmallett addchars(p, 2); 44490744Sjmallett break; 44590744Sjmallett } 44690744Sjmallett p+=2; 44790744Sjmallett continue; 44890744Sjmallett } 44990744Sjmallett if (*p == '(' || *p == ')' || *p == '|') 45090744Sjmallett addchar('\\'); 45190744Sjmallett 45290744Sjmallett addchar(*p); 45390744Sjmallett p++; 45490744Sjmallett } 45590744Sjmallett return getstring(); 45690744Sjmallett} 45790744Sjmallett 45890744Sjmallett/* patsubst(string, regexp, opt replacement) */ 45990744Sjmallett/* argv[2]: string 46090744Sjmallett * argv[3]: regexp 46190744Sjmallett * argv[4]: opt rep 46290744Sjmallett */ 46390744Sjmallettvoid 46490744Sjmallettdopatsubst(argv, argc) 46590744Sjmallett const char *argv[]; 46690744Sjmallett int argc; 46790744Sjmallett{ 46890744Sjmallett int error; 46990744Sjmallett regex_t re; 47090744Sjmallett regmatch_t *pmatch; 47190744Sjmallett 47290744Sjmallett if (argc <= 3) { 47390744Sjmallett warnx("Too few arguments to patsubst"); 47490744Sjmallett return; 47590744Sjmallett } 47690744Sjmallett error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], 47790744Sjmallett REG_NEWLINE | REG_EXTENDED); 47890744Sjmallett if (error != 0) 47990744Sjmallett exit_regerror(error, &re); 48090744Sjmallett 48190744Sjmallett pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); 48290744Sjmallett do_subst(argv[2], &re, 48390744Sjmallett argc != 4 && argv[4] != NULL ? argv[4] : "", pmatch); 48490744Sjmallett pbstr(getstring()); 48590744Sjmallett free(pmatch); 48690744Sjmallett regfree(&re); 48790744Sjmallett} 48890744Sjmallett 48990744Sjmallettvoid 49090744Sjmallettdoregexp(argv, argc) 49190744Sjmallett const char *argv[]; 49290744Sjmallett int argc; 49390744Sjmallett{ 49490744Sjmallett int error; 49590744Sjmallett regex_t re; 49690744Sjmallett regmatch_t *pmatch; 49790744Sjmallett 49890744Sjmallett if (argc <= 3) { 49990744Sjmallett warnx("Too few arguments to regexp"); 50090744Sjmallett return; 50190744Sjmallett } 50290744Sjmallett error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], 50390744Sjmallett REG_EXTENDED); 50490744Sjmallett if (error != 0) 50590744Sjmallett exit_regerror(error, &re); 50690744Sjmallett 50790744Sjmallett pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); 50890744Sjmallett if (argv[4] == NULL || argc == 4) 50990744Sjmallett do_regexpindex(argv[2], &re, pmatch); 51090744Sjmallett else 51190744Sjmallett do_regexp(argv[2], &re, argv[4], pmatch); 51290744Sjmallett free(pmatch); 51390744Sjmallett regfree(&re); 51490744Sjmallett} 51590744Sjmallett 51690744Sjmallettvoid 51790744Sjmallettdoesyscmd(cmd) 51890744Sjmallett const char *cmd; 51990744Sjmallett{ 52090744Sjmallett int p[2]; 52190744Sjmallett pid_t pid, cpid; 52290744Sjmallett char *argv[4]; 52390744Sjmallett int cc; 52490744Sjmallett int status; 52590744Sjmallett 52690744Sjmallett /* Follow gnu m4 documentation: first flush buffers. */ 52790744Sjmallett fflush(NULL); 52890744Sjmallett 52990744Sjmallett argv[0] = "sh"; 53090744Sjmallett argv[1] = "-c"; 53190744Sjmallett argv[2] = (char *)cmd; 53290744Sjmallett argv[3] = NULL; 53390744Sjmallett 53490744Sjmallett /* Just set up standard output, share stderr and stdin with m4 */ 53590744Sjmallett if (pipe(p) == -1) 53690744Sjmallett err(1, "bad pipe"); 53790744Sjmallett switch(cpid = fork()) { 53890744Sjmallett case -1: 53990744Sjmallett err(1, "bad fork"); 54090744Sjmallett /* NOTREACHED */ 54190744Sjmallett case 0: 54290744Sjmallett (void) close(p[0]); 54390744Sjmallett (void) dup2(p[1], 1); 54490744Sjmallett (void) close(p[1]); 54590744Sjmallett execv(_PATH_BSHELL, argv); 54690744Sjmallett exit(1); 54790744Sjmallett default: 54890744Sjmallett /* Read result in two stages, since m4's buffer is 54990744Sjmallett * pushback-only. */ 55090744Sjmallett (void) close(p[1]); 55190744Sjmallett do { 55290744Sjmallett char result[BUFSIZE]; 55390744Sjmallett cc = read(p[0], result, sizeof result); 55490744Sjmallett if (cc > 0) 55590744Sjmallett addchars(result, cc); 55690744Sjmallett } while (cc > 0 || (cc == -1 && errno == EINTR)); 55790744Sjmallett 55890744Sjmallett (void) close(p[0]); 55990744Sjmallett while ((pid = wait(&status)) != cpid && pid >= 0) 56090744Sjmallett continue; 56190744Sjmallett pbstr(getstring()); 56290744Sjmallett } 56390744Sjmallett} 564