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