process.c revision 80286
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1992 Diomidis Spinellis. 31590Srgrimes * Copyright (c) 1992, 1993, 1994 41590Srgrimes * The Regents of the University of California. All rights reserved. 51590Srgrimes * 61590Srgrimes * This code is derived from software contributed to Berkeley by 71590Srgrimes * Diomidis Spinellis of Imperial College, University of London. 81590Srgrimes * 91590Srgrimes * Redistribution and use in source and binary forms, with or without 101590Srgrimes * modification, are permitted provided that the following conditions 111590Srgrimes * are met: 121590Srgrimes * 1. Redistributions of source code must retain the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer. 141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer in the 161590Srgrimes * documentation and/or other materials provided with the distribution. 171590Srgrimes * 3. All advertising materials mentioning features or use of this software 181590Srgrimes * must display the following acknowledgement: 191590Srgrimes * This product includes software developed by the University of 201590Srgrimes * California, Berkeley and its contributors. 211590Srgrimes * 4. Neither the name of the University nor the names of its contributors 221590Srgrimes * may be used to endorse or promote products derived from this software 231590Srgrimes * without specific prior written permission. 241590Srgrimes * 251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351590Srgrimes * SUCH DAMAGE. 361590Srgrimes */ 371590Srgrimes 381590Srgrimes#ifndef lint 3928066Scharnier#if 0 401590Srgrimesstatic char sccsid[] = "@(#)process.c 8.6 (Berkeley) 4/20/94"; 4128066Scharnier#endif 4228066Scharnierstatic const char rcsid[] = 4350477Speter "$FreeBSD: head/usr.bin/sed/process.c 80286 2001-07-24 14:05:21Z obrien $"; 441590Srgrimes#endif /* not lint */ 451590Srgrimes 461590Srgrimes#include <sys/types.h> 471590Srgrimes#include <sys/stat.h> 481590Srgrimes#include <sys/ioctl.h> 491590Srgrimes#include <sys/uio.h> 501590Srgrimes 511590Srgrimes#include <ctype.h> 5228066Scharnier#include <err.h> 531590Srgrimes#include <errno.h> 541590Srgrimes#include <fcntl.h> 551590Srgrimes#include <limits.h> 561590Srgrimes#include <regex.h> 571590Srgrimes#include <stdio.h> 581590Srgrimes#include <stdlib.h> 591590Srgrimes#include <string.h> 601590Srgrimes#include <unistd.h> 611590Srgrimes 621590Srgrimes#include "defs.h" 631590Srgrimes#include "extern.h" 641590Srgrimes 651590Srgrimesstatic SPACE HS, PS, SS; 661590Srgrimes#define pd PS.deleted 671590Srgrimes#define ps PS.space 681590Srgrimes#define psl PS.len 691590Srgrimes#define hs HS.space 701590Srgrimes#define hsl HS.len 711590Srgrimes 721590Srgrimesstatic inline int applies __P((struct s_command *)); 731590Srgrimesstatic void flush_appends __P((void)); 741590Srgrimesstatic void lputs __P((char *)); 751590Srgrimesstatic inline int regexec_e __P((regex_t *, const char *, int, int, size_t)); 761590Srgrimesstatic void regsub __P((SPACE *, char *, char *)); 771590Srgrimesstatic int substitute __P((struct s_command *)); 781590Srgrimes 791590Srgrimesstruct s_appends *appends; /* Array of pointers to strings to append. */ 801590Srgrimesstatic int appendx; /* Index into appends array. */ 811590Srgrimesint appendnum; /* Size of appends array. */ 821590Srgrimes 831590Srgrimesstatic int lastaddr; /* Set by applies if last address of a range. */ 841590Srgrimesstatic int sdone; /* If any substitutes since last line input. */ 851590Srgrimes /* Iov structure for 'w' commands. */ 861590Srgrimesstatic regex_t *defpreg; 871590Srgrimessize_t maxnsub; 881590Srgrimesregmatch_t *match; 891590Srgrimes 901590Srgrimes#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); } 911590Srgrimes 921590Srgrimesvoid 931590Srgrimesprocess() 941590Srgrimes{ 951590Srgrimes struct s_command *cp; 961590Srgrimes SPACE tspace; 9741572Sarchie size_t len, oldpsl = 0; 9810075Sjkh char *p; 991590Srgrimes 1001590Srgrimes for (linenum = 0; mf_fgets(&PS, REPLACE);) { 1011590Srgrimes pd = 0; 10210075Sjkhtop: 1031590Srgrimes cp = prog; 1041590Srgrimesredirect: 1051590Srgrimes while (cp != NULL) { 1061590Srgrimes if (!applies(cp)) { 1071590Srgrimes cp = cp->next; 1081590Srgrimes continue; 1091590Srgrimes } 1101590Srgrimes switch (cp->code) { 1111590Srgrimes case '{': 1121590Srgrimes cp = cp->u.c; 1131590Srgrimes goto redirect; 1141590Srgrimes case 'a': 1151590Srgrimes if (appendx >= appendnum) 11680286Sobrien if ((appends = realloc(appends, 1171590Srgrimes sizeof(struct s_appends) * 11880286Sobrien (appendnum *= 2))) == NULL) 11980286Sobrien err(1, "realloc"); 1201590Srgrimes appends[appendx].type = AP_STRING; 1211590Srgrimes appends[appendx].s = cp->t; 1221590Srgrimes appends[appendx].len = strlen(cp->t); 1231590Srgrimes appendx++; 1241590Srgrimes break; 1251590Srgrimes case 'b': 1261590Srgrimes cp = cp->u.c; 1271590Srgrimes goto redirect; 1281590Srgrimes case 'c': 1291590Srgrimes pd = 1; 1301590Srgrimes psl = 0; 1311590Srgrimes if (cp->a2 == NULL || lastaddr) 1321590Srgrimes (void)printf("%s", cp->t); 1331590Srgrimes break; 1341590Srgrimes case 'd': 1351590Srgrimes pd = 1; 1361590Srgrimes goto new; 1371590Srgrimes case 'D': 1381590Srgrimes if (pd) 1391590Srgrimes goto new; 14010075Sjkh if ((p = memchr(ps, '\n', psl - 1)) == NULL) { 1411590Srgrimes pd = 1; 14210075Sjkh goto new; 14310075Sjkh } else { 14410075Sjkh psl -= (p + 1) - ps; 1451590Srgrimes memmove(ps, p + 1, psl); 14610075Sjkh goto top; 1471590Srgrimes } 1481590Srgrimes case 'g': 1491590Srgrimes cspace(&PS, hs, hsl, REPLACE); 1501590Srgrimes break; 1511590Srgrimes case 'G': 1521590Srgrimes cspace(&PS, hs, hsl, 0); 1531590Srgrimes break; 1541590Srgrimes case 'h': 1551590Srgrimes cspace(&HS, ps, psl, REPLACE); 1561590Srgrimes break; 1571590Srgrimes case 'H': 1581590Srgrimes cspace(&HS, ps, psl, 0); 1591590Srgrimes break; 1601590Srgrimes case 'i': 1611590Srgrimes (void)printf("%s", cp->t); 1621590Srgrimes break; 1631590Srgrimes case 'l': 1641590Srgrimes lputs(ps); 1651590Srgrimes break; 1661590Srgrimes case 'n': 1671590Srgrimes if (!nflag && !pd) 1681590Srgrimes OUT(ps) 1691590Srgrimes flush_appends(); 1701590Srgrimes if (!mf_fgets(&PS, REPLACE)) 1711590Srgrimes exit(0); 1721590Srgrimes pd = 0; 1731590Srgrimes break; 1741590Srgrimes case 'N': 1751590Srgrimes flush_appends(); 1761590Srgrimes if (!mf_fgets(&PS, 0)) { 1771590Srgrimes if (!nflag && !pd) 1781590Srgrimes OUT(ps) 1791590Srgrimes exit(0); 1801590Srgrimes } 1811590Srgrimes break; 1821590Srgrimes case 'p': 1831590Srgrimes if (pd) 1841590Srgrimes break; 1851590Srgrimes OUT(ps) 1861590Srgrimes break; 1871590Srgrimes case 'P': 1881590Srgrimes if (pd) 1891590Srgrimes break; 19010075Sjkh if ((p = memchr(ps, '\n', psl - 1)) != NULL) { 19110075Sjkh oldpsl = psl; 19210075Sjkh psl = (p + 1) - ps; 1931590Srgrimes } 1941590Srgrimes OUT(ps) 1951590Srgrimes if (p != NULL) 19610075Sjkh psl = oldpsl; 1971590Srgrimes break; 1981590Srgrimes case 'q': 1991590Srgrimes if (!nflag && !pd) 2001590Srgrimes OUT(ps) 2011590Srgrimes flush_appends(); 2021590Srgrimes exit(0); 2031590Srgrimes case 'r': 2041590Srgrimes if (appendx >= appendnum) 20580286Sobrien if ((appends = realloc(appends, 2061590Srgrimes sizeof(struct s_appends) * 20780286Sobrien (appendnum *= 2))) == NULL) 20880286Sobrien err(1, "realloc"); 2091590Srgrimes appends[appendx].type = AP_FILE; 2101590Srgrimes appends[appendx].s = cp->t; 2111590Srgrimes appends[appendx].len = strlen(cp->t); 2121590Srgrimes appendx++; 2131590Srgrimes break; 2141590Srgrimes case 's': 2151590Srgrimes sdone |= substitute(cp); 2161590Srgrimes break; 2171590Srgrimes case 't': 2181590Srgrimes if (sdone) { 2191590Srgrimes sdone = 0; 2201590Srgrimes cp = cp->u.c; 2211590Srgrimes goto redirect; 2221590Srgrimes } 2231590Srgrimes break; 2241590Srgrimes case 'w': 2251590Srgrimes if (pd) 2261590Srgrimes break; 2271590Srgrimes if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 2281590Srgrimes O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 2291590Srgrimes DEFFILEMODE)) == -1) 23028066Scharnier err(1, "%s", cp->t); 2311590Srgrimes if (write(cp->u.fd, ps, psl) != psl) 23228066Scharnier err(1, "%s", cp->t); 2331590Srgrimes break; 2341590Srgrimes case 'x': 2351590Srgrimes if (hs == NULL) 23610075Sjkh cspace(&HS, "\n", 1, REPLACE); 2371590Srgrimes tspace = PS; 2381590Srgrimes PS = HS; 2391590Srgrimes HS = tspace; 2401590Srgrimes break; 2411590Srgrimes case 'y': 2421590Srgrimes if (pd) 2431590Srgrimes break; 2441590Srgrimes for (p = ps, len = psl; --len; ++p) 24535520Sache *p = cp->u.y[(unsigned char)*p]; 2461590Srgrimes break; 2471590Srgrimes case ':': 2481590Srgrimes case '}': 2491590Srgrimes break; 2501590Srgrimes case '=': 2511590Srgrimes (void)printf("%lu\n", linenum); 2521590Srgrimes } 2531590Srgrimes cp = cp->next; 2541590Srgrimes } /* for all cp */ 2551590Srgrimes 2561590Srgrimesnew: if (!nflag && !pd) 2571590Srgrimes OUT(ps) 2581590Srgrimes flush_appends(); 2591590Srgrimes } /* for all lines */ 2601590Srgrimes} 2611590Srgrimes 2621590Srgrimes/* 2631590Srgrimes * TRUE if the address passed matches the current program state 2641590Srgrimes * (lastline, linenumber, ps). 2651590Srgrimes */ 2661590Srgrimes#define MATCH(a) \ 2671590Srgrimes (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \ 2681590Srgrimes (a)->type == AT_LINE ? linenum == (a)->u.l : lastline 2691590Srgrimes 2701590Srgrimes/* 2711590Srgrimes * Return TRUE if the command applies to the current line. Sets the inrange 2721590Srgrimes * flag to process ranges. Interprets the non-select (``!'') flag. 2731590Srgrimes */ 2741590Srgrimesstatic inline int 2751590Srgrimesapplies(cp) 2761590Srgrimes struct s_command *cp; 2771590Srgrimes{ 2781590Srgrimes int r; 2791590Srgrimes 2801590Srgrimes lastaddr = 0; 2811590Srgrimes if (cp->a1 == NULL && cp->a2 == NULL) 2821590Srgrimes r = 1; 2831590Srgrimes else if (cp->a2) 2841590Srgrimes if (cp->inrange) { 2851590Srgrimes if (MATCH(cp->a2)) { 2861590Srgrimes cp->inrange = 0; 2871590Srgrimes lastaddr = 1; 2881590Srgrimes } 2891590Srgrimes r = 1; 2901590Srgrimes } else if (MATCH(cp->a1)) { 2911590Srgrimes /* 2921590Srgrimes * If the second address is a number less than or 2931590Srgrimes * equal to the line number first selected, only 2941590Srgrimes * one line shall be selected. 2951590Srgrimes * -- POSIX 1003.2 2961590Srgrimes */ 2971590Srgrimes if (cp->a2->type == AT_LINE && 2981590Srgrimes linenum >= cp->a2->u.l) 2991590Srgrimes lastaddr = 1; 3001590Srgrimes else 3011590Srgrimes cp->inrange = 1; 3021590Srgrimes r = 1; 3031590Srgrimes } else 3041590Srgrimes r = 0; 3051590Srgrimes else 3061590Srgrimes r = MATCH(cp->a1); 3071590Srgrimes return (cp->nonsel ? ! r : r); 3081590Srgrimes} 3091590Srgrimes 3101590Srgrimes/* 3111590Srgrimes * substitute -- 3121590Srgrimes * Do substitutions in the pattern space. Currently, we build a 3131590Srgrimes * copy of the new pattern space in the substitute space structure 3141590Srgrimes * and then swap them. 3151590Srgrimes */ 3161590Srgrimesstatic int 3171590Srgrimessubstitute(cp) 3181590Srgrimes struct s_command *cp; 3191590Srgrimes{ 3201590Srgrimes SPACE tspace; 3211590Srgrimes regex_t *re; 3221590Srgrimes size_t re_off, slen; 3231590Srgrimes int lastempty, n; 3241590Srgrimes char *s; 3251590Srgrimes 3261590Srgrimes s = ps; 3271590Srgrimes re = cp->u.s->re; 3281590Srgrimes if (re == NULL) { 3291590Srgrimes if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { 3301590Srgrimes linenum = cp->u.s->linenum; 33128066Scharnier errx(1, "%lu: %s: \\%d not defined in the RE", 33228066Scharnier linenum, fname, cp->u.s->maxbref); 3331590Srgrimes } 3341590Srgrimes } 3351590Srgrimes if (!regexec_e(re, s, 0, 0, psl)) 3361590Srgrimes return (0); 3371590Srgrimes 3381590Srgrimes SS.len = 0; /* Clean substitute space. */ 3391590Srgrimes slen = psl; 3401590Srgrimes n = cp->u.s->n; 3411590Srgrimes lastempty = 1; 3421590Srgrimes 3431590Srgrimes switch (n) { 3441590Srgrimes case 0: /* Global */ 3451590Srgrimes do { 3461590Srgrimes if (lastempty || match[0].rm_so != match[0].rm_eo) { 3471590Srgrimes /* Locate start of replaced string. */ 3481590Srgrimes re_off = match[0].rm_so; 3491590Srgrimes /* Copy leading retained string. */ 3501590Srgrimes cspace(&SS, s, re_off, APPEND); 3511590Srgrimes /* Add in regular expression. */ 3521590Srgrimes regsub(&SS, s, cp->u.s->new); 3531590Srgrimes } 3541590Srgrimes 35510075Sjkh /* Move past this match. */ 3561590Srgrimes if (match[0].rm_so != match[0].rm_eo) { 3571590Srgrimes s += match[0].rm_eo; 3581590Srgrimes slen -= match[0].rm_eo; 3591590Srgrimes lastempty = 0; 3601590Srgrimes } else { 3611590Srgrimes if (match[0].rm_so == 0) 36210075Sjkh cspace(&SS, s, match[0].rm_so + 1, 36310075Sjkh APPEND); 3641590Srgrimes else 36510075Sjkh cspace(&SS, s + match[0].rm_so, 1, 36610075Sjkh APPEND); 3671590Srgrimes s += match[0].rm_so + 1; 3681590Srgrimes slen -= match[0].rm_so + 1; 3691590Srgrimes lastempty = 1; 3701590Srgrimes } 3711590Srgrimes } while (slen > 0 && regexec_e(re, s, REG_NOTBOL, 0, slen)); 3721590Srgrimes /* Copy trailing retained string. */ 3731590Srgrimes if (slen > 0) 3741590Srgrimes cspace(&SS, s, slen, APPEND); 3751590Srgrimes break; 3761590Srgrimes default: /* Nth occurrence */ 3771590Srgrimes while (--n) { 3781590Srgrimes s += match[0].rm_eo; 3791590Srgrimes slen -= match[0].rm_eo; 3801590Srgrimes if (!regexec_e(re, s, REG_NOTBOL, 0, slen)) 3811590Srgrimes return (0); 3821590Srgrimes } 3831590Srgrimes /* FALLTHROUGH */ 3841590Srgrimes case 1: /* 1st occurrence */ 3851590Srgrimes /* Locate start of replaced string. */ 3861590Srgrimes re_off = match[0].rm_so + (s - ps); 3871590Srgrimes /* Copy leading retained string. */ 3881590Srgrimes cspace(&SS, ps, re_off, APPEND); 3891590Srgrimes /* Add in regular expression. */ 3901590Srgrimes regsub(&SS, s, cp->u.s->new); 3911590Srgrimes /* Copy trailing retained string. */ 3921590Srgrimes s += match[0].rm_eo; 3931590Srgrimes slen -= match[0].rm_eo; 3941590Srgrimes cspace(&SS, s, slen, APPEND); 3951590Srgrimes break; 3961590Srgrimes } 3971590Srgrimes 3981590Srgrimes /* 3991590Srgrimes * Swap the substitute space and the pattern space, and make sure 4001590Srgrimes * that any leftover pointers into stdio memory get lost. 4011590Srgrimes */ 4021590Srgrimes tspace = PS; 4031590Srgrimes PS = SS; 4041590Srgrimes SS = tspace; 4051590Srgrimes SS.space = SS.back; 4061590Srgrimes 4071590Srgrimes /* Handle the 'p' flag. */ 4081590Srgrimes if (cp->u.s->p) 4091590Srgrimes OUT(ps) 4101590Srgrimes 4111590Srgrimes /* Handle the 'w' flag. */ 4121590Srgrimes if (cp->u.s->wfile && !pd) { 4131590Srgrimes if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 4141590Srgrimes O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) 41528066Scharnier err(1, "%s", cp->u.s->wfile); 4161590Srgrimes if (write(cp->u.s->wfd, ps, psl) != psl) 41728066Scharnier err(1, "%s", cp->u.s->wfile); 4181590Srgrimes } 4191590Srgrimes return (1); 4201590Srgrimes} 4211590Srgrimes 4221590Srgrimes/* 4231590Srgrimes * Flush append requests. Always called before reading a line, 4241590Srgrimes * therefore it also resets the substitution done (sdone) flag. 4251590Srgrimes */ 4261590Srgrimesstatic void 4271590Srgrimesflush_appends() 4281590Srgrimes{ 4291590Srgrimes FILE *f; 4301590Srgrimes int count, i; 4311590Srgrimes char buf[8 * 1024]; 4321590Srgrimes 4338874Srgrimes for (i = 0; i < appendx; i++) 4341590Srgrimes switch (appends[i].type) { 4351590Srgrimes case AP_STRING: 4368874Srgrimes fwrite(appends[i].s, sizeof(char), appends[i].len, 4371590Srgrimes stdout); 4381590Srgrimes break; 4391590Srgrimes case AP_FILE: 4401590Srgrimes /* 4411590Srgrimes * Read files probably shouldn't be cached. Since 4421590Srgrimes * it's not an error to read a non-existent file, 4431590Srgrimes * it's possible that another program is interacting 4441590Srgrimes * with the sed script through the file system. It 4451590Srgrimes * would be truly bizarre, but possible. It's probably 4461590Srgrimes * not that big a performance win, anyhow. 4471590Srgrimes */ 4481590Srgrimes if ((f = fopen(appends[i].s, "r")) == NULL) 4491590Srgrimes break; 45028066Scharnier while ((count = fread(buf, sizeof(char), sizeof(buf), f))) 4511590Srgrimes (void)fwrite(buf, sizeof(char), count, stdout); 4521590Srgrimes (void)fclose(f); 4531590Srgrimes break; 4541590Srgrimes } 4551590Srgrimes if (ferror(stdout)) 45628066Scharnier errx(1, "stdout: %s", strerror(errno ? errno : EIO)); 4571590Srgrimes appendx = sdone = 0; 4581590Srgrimes} 4591590Srgrimes 4601590Srgrimesstatic void 4611590Srgrimeslputs(s) 4621590Srgrimes register char *s; 4631590Srgrimes{ 4641590Srgrimes register int count; 4651590Srgrimes register char *escapes, *p; 4661590Srgrimes struct winsize win; 4671590Srgrimes static int termwidth = -1; 4681590Srgrimes 46946081Simp if (termwidth == -1) { 47028066Scharnier if ((p = getenv("COLUMNS"))) 4711590Srgrimes termwidth = atoi(p); 4721590Srgrimes else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 4731590Srgrimes win.ws_col > 0) 4741590Srgrimes termwidth = win.ws_col; 4751590Srgrimes else 4761590Srgrimes termwidth = 60; 47746081Simp } 4781590Srgrimes 4798874Srgrimes for (count = 0; *s; ++s) { 4801590Srgrimes if (count >= termwidth) { 4811590Srgrimes (void)printf("\\\n"); 4821590Srgrimes count = 0; 4831590Srgrimes } 48417522Sache if (isprint((unsigned char)*s) && *s != '\\') { 4851590Srgrimes (void)putchar(*s); 4861590Srgrimes count++; 4871590Srgrimes } else { 4881590Srgrimes escapes = "\\\a\b\f\n\r\t\v"; 4891590Srgrimes (void)putchar('\\'); 49028066Scharnier if ((p = strchr(escapes, *s))) { 4911590Srgrimes (void)putchar("\\abfnrtv"[p - escapes]); 4921590Srgrimes count += 2; 4931590Srgrimes } else { 4941590Srgrimes (void)printf("%03o", *(u_char *)s); 4951590Srgrimes count += 4; 4961590Srgrimes } 4971590Srgrimes } 4981590Srgrimes } 4991590Srgrimes (void)putchar('$'); 5001590Srgrimes (void)putchar('\n'); 5011590Srgrimes if (ferror(stdout)) 50228066Scharnier errx(1, "stdout: %s", strerror(errno ? errno : EIO)); 5031590Srgrimes} 5041590Srgrimes 5051590Srgrimesstatic inline int 5061590Srgrimesregexec_e(preg, string, eflags, nomatch, slen) 5071590Srgrimes regex_t *preg; 5081590Srgrimes const char *string; 5091590Srgrimes int eflags, nomatch; 5101590Srgrimes size_t slen; 5111590Srgrimes{ 5121590Srgrimes int eval; 5138874Srgrimes 5141590Srgrimes if (preg == NULL) { 5151590Srgrimes if (defpreg == NULL) 51628066Scharnier errx(1, "first RE may not be empty"); 5171590Srgrimes } else 5181590Srgrimes defpreg = preg; 5191590Srgrimes 5201590Srgrimes /* Set anchors, discounting trailing newline (if any). */ 5211590Srgrimes if (slen > 0 && string[slen - 1] == '\n') 5221590Srgrimes slen--; 5231590Srgrimes match[0].rm_so = 0; 5241590Srgrimes match[0].rm_eo = slen; 5258874Srgrimes 5261590Srgrimes eval = regexec(defpreg, string, 5271590Srgrimes nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND); 5281590Srgrimes switch(eval) { 5291590Srgrimes case 0: 5301590Srgrimes return (1); 5311590Srgrimes case REG_NOMATCH: 5321590Srgrimes return (0); 5331590Srgrimes } 53428066Scharnier errx(1, "RE error: %s", strregerror(eval, defpreg)); 5351590Srgrimes /* NOTREACHED */ 5361590Srgrimes} 5371590Srgrimes 5381590Srgrimes/* 5391590Srgrimes * regsub - perform substitutions after a regexp match 5401590Srgrimes * Based on a routine by Henry Spencer 5411590Srgrimes */ 5421590Srgrimesstatic void 5431590Srgrimesregsub(sp, string, src) 5441590Srgrimes SPACE *sp; 5451590Srgrimes char *string, *src; 5461590Srgrimes{ 5471590Srgrimes register int len, no; 5481590Srgrimes register char c, *dst; 5491590Srgrimes 5501590Srgrimes#define NEEDSP(reqlen) \ 5511590Srgrimes if (sp->len >= sp->blen - (reqlen) - 1) { \ 5521590Srgrimes sp->blen += (reqlen) + 1024; \ 55380286Sobrien if ((sp->space = sp->back = realloc(sp->back, sp->blen)) \ 55480286Sobrien == NULL) \ 55580286Sobrien err(1, "realloc"); \ 5561590Srgrimes dst = sp->space + sp->len; \ 5571590Srgrimes } 5581590Srgrimes 5591590Srgrimes dst = sp->space + sp->len; 5601590Srgrimes while ((c = *src++) != '\0') { 5611590Srgrimes if (c == '&') 5621590Srgrimes no = 0; 56317522Sache else if (c == '\\' && isdigit((unsigned char)*src)) 5641590Srgrimes no = *src++ - '0'; 5651590Srgrimes else 5661590Srgrimes no = -1; 5671590Srgrimes if (no < 0) { /* Ordinary character. */ 5681590Srgrimes if (c == '\\' && (*src == '\\' || *src == '&')) 5691590Srgrimes c = *src++; 5701590Srgrimes NEEDSP(1); 5711590Srgrimes *dst++ = c; 5721590Srgrimes ++sp->len; 5731590Srgrimes } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) { 5741590Srgrimes len = match[no].rm_eo - match[no].rm_so; 5751590Srgrimes NEEDSP(len); 5761590Srgrimes memmove(dst, string + match[no].rm_so, len); 5771590Srgrimes dst += len; 5781590Srgrimes sp->len += len; 5791590Srgrimes } 5801590Srgrimes } 5811590Srgrimes NEEDSP(1); 5821590Srgrimes *dst = '\0'; 5831590Srgrimes} 5841590Srgrimes 5851590Srgrimes/* 5861590Srgrimes * aspace -- 5871590Srgrimes * Append the source space to the destination space, allocating new 5881590Srgrimes * space as necessary. 5891590Srgrimes */ 5901590Srgrimesvoid 5911590Srgrimescspace(sp, p, len, spflag) 5921590Srgrimes SPACE *sp; 5931590Srgrimes char *p; 5941590Srgrimes size_t len; 5951590Srgrimes enum e_spflag spflag; 5961590Srgrimes{ 5971590Srgrimes size_t tlen; 5981590Srgrimes 5991590Srgrimes /* Make sure SPACE has enough memory and ramp up quickly. */ 6001590Srgrimes tlen = sp->len + len + 1; 6011590Srgrimes if (tlen > sp->blen) { 6021590Srgrimes sp->blen = tlen + 1024; 60380286Sobrien if ((sp->space = sp->back = realloc(sp->back, sp->blen)) == 60480286Sobrien NULL) 60580286Sobrien err(1, "realloc"); 6061590Srgrimes } 6071590Srgrimes 6081590Srgrimes if (spflag == REPLACE) 6091590Srgrimes sp->len = 0; 6101590Srgrimes 6111590Srgrimes memmove(sp->space + sp->len, p, len); 6121590Srgrimes 6131590Srgrimes sp->space[sp->len += len] = '\0'; 6141590Srgrimes} 6151590Srgrimes 6161590Srgrimes/* 6171590Srgrimes * Close all cached opened files and report any errors 6181590Srgrimes */ 6191590Srgrimesvoid 6201590Srgrimescfclose(cp, end) 6211590Srgrimes register struct s_command *cp, *end; 6221590Srgrimes{ 6231590Srgrimes 6241590Srgrimes for (; cp != end; cp = cp->next) 6251590Srgrimes switch(cp->code) { 6261590Srgrimes case 's': 6271590Srgrimes if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 62828066Scharnier err(1, "%s", cp->u.s->wfile); 6291590Srgrimes cp->u.s->wfd = -1; 6301590Srgrimes break; 6311590Srgrimes case 'w': 6321590Srgrimes if (cp->u.fd != -1 && close(cp->u.fd)) 63328066Scharnier err(1, "%s", cp->t); 6341590Srgrimes cp->u.fd = -1; 6351590Srgrimes break; 6361590Srgrimes case '{': 6371590Srgrimes cfclose(cp->u.c, cp->next); 6381590Srgrimes break; 6391590Srgrimes } 6401590Srgrimes} 641