1*84441f85SGarrett D'Amore /* 2*84441f85SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 3*84441f85SGarrett D'Amore * Copyright (c) 1992 Diomidis Spinellis. 4*84441f85SGarrett D'Amore * Copyright (c) 1992, 1993, 1994 5*84441f85SGarrett D'Amore * The Regents of the University of California. All rights reserved. 6*84441f85SGarrett D'Amore * 7*84441f85SGarrett D'Amore * This code is derived from software contributed to Berkeley by 8*84441f85SGarrett D'Amore * Diomidis Spinellis of Imperial College, University of London. 9*84441f85SGarrett D'Amore * 10*84441f85SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 11*84441f85SGarrett D'Amore * modification, are permitted provided that the following conditions 12*84441f85SGarrett D'Amore * are met: 13*84441f85SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 14*84441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 15*84441f85SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 16*84441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 17*84441f85SGarrett D'Amore * documentation and/or other materials provided with the distribution. 18*84441f85SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 19*84441f85SGarrett D'Amore * may be used to endorse or promote products derived from this software 20*84441f85SGarrett D'Amore * without specific prior written permission. 21*84441f85SGarrett D'Amore * 22*84441f85SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23*84441f85SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24*84441f85SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25*84441f85SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26*84441f85SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27*84441f85SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28*84441f85SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29*84441f85SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30*84441f85SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31*84441f85SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*84441f85SGarrett D'Amore * SUCH DAMAGE. 33*84441f85SGarrett D'Amore */ 34*84441f85SGarrett D'Amore 35*84441f85SGarrett D'Amore #include <sys/types.h> 36*84441f85SGarrett D'Amore #include <sys/stat.h> 37*84441f85SGarrett D'Amore 38*84441f85SGarrett D'Amore #include <ctype.h> 39*84441f85SGarrett D'Amore #include <err.h> 40*84441f85SGarrett D'Amore #include <errno.h> 41*84441f85SGarrett D'Amore #include <fcntl.h> 42*84441f85SGarrett D'Amore #include <limits.h> 43*84441f85SGarrett D'Amore #include <regex.h> 44*84441f85SGarrett D'Amore #include <stdio.h> 45*84441f85SGarrett D'Amore #include <stdlib.h> 46*84441f85SGarrett D'Amore #include <string.h> 47*84441f85SGarrett D'Amore #include <unistd.h> 48*84441f85SGarrett D'Amore #include <wchar.h> 49*84441f85SGarrett D'Amore #include <wctype.h> 50*84441f85SGarrett D'Amore #include <termio.h> 51*84441f85SGarrett D'Amore #include <libintl.h> 52*84441f85SGarrett D'Amore #include <note.h> 53*84441f85SGarrett D'Amore 54*84441f85SGarrett D'Amore #include "defs.h" 55*84441f85SGarrett D'Amore #include "extern.h" 56*84441f85SGarrett D'Amore 57*84441f85SGarrett D'Amore static SPACE HS, PS, SS, YS; 58*84441f85SGarrett D'Amore #define pd PS.deleted 59*84441f85SGarrett D'Amore #define ps PS.space 60*84441f85SGarrett D'Amore #define psl PS.len 61*84441f85SGarrett D'Amore #define hs HS.space 62*84441f85SGarrett D'Amore #define hsl HS.len 63*84441f85SGarrett D'Amore 64*84441f85SGarrett D'Amore static int applies(struct s_command *); 65*84441f85SGarrett D'Amore static void do_tr(struct s_tr *); 66*84441f85SGarrett D'Amore static void flush_appends(void); 67*84441f85SGarrett D'Amore static void lputs(char *, size_t); 68*84441f85SGarrett D'Amore static int regexec_e(regex_t *, const char *, int, int, size_t); 69*84441f85SGarrett D'Amore static void regsub(SPACE *, char *, char *); 70*84441f85SGarrett D'Amore static int substitute(struct s_command *); 71*84441f85SGarrett D'Amore 72*84441f85SGarrett D'Amore struct s_appends *appends; /* Array of pointers to strings to append. */ 73*84441f85SGarrett D'Amore static int appendx; /* Index into appends array. */ 74*84441f85SGarrett D'Amore int appendnum; /* Size of appends array. */ 75*84441f85SGarrett D'Amore 76*84441f85SGarrett D'Amore static int lastaddr; /* Set by applies if last address of a range. */ 77*84441f85SGarrett D'Amore static int sdone; /* If any substitutes since last line input. */ 78*84441f85SGarrett D'Amore /* Iov structure for 'w' commands. */ 79*84441f85SGarrett D'Amore static regex_t *defpreg; 80*84441f85SGarrett D'Amore size_t maxnsub; 81*84441f85SGarrett D'Amore regmatch_t *match; 82*84441f85SGarrett D'Amore 83*84441f85SGarrett D'Amore #define OUT() do { \ 84*84441f85SGarrett D'Amore (void) fwrite(ps, 1, psl, outfile); \ 85*84441f85SGarrett D'Amore (void) fputc('\n', outfile); \ 86*84441f85SGarrett D'Amore _NOTE(CONSTCOND) \ 87*84441f85SGarrett D'Amore } while (0) 88*84441f85SGarrett D'Amore 89*84441f85SGarrett D'Amore void 90*84441f85SGarrett D'Amore process(void) 91*84441f85SGarrett D'Amore { 92*84441f85SGarrett D'Amore struct s_command *cp; 93*84441f85SGarrett D'Amore SPACE tspace; 94*84441f85SGarrett D'Amore size_t oldpsl = 0; 95*84441f85SGarrett D'Amore char *p; 96*84441f85SGarrett D'Amore 97*84441f85SGarrett D'Amore p = NULL; 98*84441f85SGarrett D'Amore 99*84441f85SGarrett D'Amore for (linenum = 0; mf_fgets(&PS, REPLACE); /* NOP */) { 100*84441f85SGarrett D'Amore pd = 0; 101*84441f85SGarrett D'Amore top: 102*84441f85SGarrett D'Amore cp = prog; 103*84441f85SGarrett D'Amore redirect: 104*84441f85SGarrett D'Amore while (cp != NULL) { 105*84441f85SGarrett D'Amore if (!applies(cp)) { 106*84441f85SGarrett D'Amore cp = cp->next; 107*84441f85SGarrett D'Amore continue; 108*84441f85SGarrett D'Amore } 109*84441f85SGarrett D'Amore switch (cp->code) { 110*84441f85SGarrett D'Amore case '{': 111*84441f85SGarrett D'Amore cp = cp->u.c; 112*84441f85SGarrett D'Amore goto redirect; 113*84441f85SGarrett D'Amore case 'a': 114*84441f85SGarrett D'Amore if (appendx >= appendnum) 115*84441f85SGarrett D'Amore if ((appends = realloc(appends, 116*84441f85SGarrett D'Amore sizeof (struct s_appends) * 117*84441f85SGarrett D'Amore (appendnum *= 2))) == NULL) 118*84441f85SGarrett D'Amore err(1, "realloc"); 119*84441f85SGarrett D'Amore appends[appendx].type = AP_STRING; 120*84441f85SGarrett D'Amore appends[appendx].s = cp->t; 121*84441f85SGarrett D'Amore appends[appendx].len = strlen(cp->t); 122*84441f85SGarrett D'Amore appendx++; 123*84441f85SGarrett D'Amore break; 124*84441f85SGarrett D'Amore case 'b': 125*84441f85SGarrett D'Amore cp = cp->u.c; 126*84441f85SGarrett D'Amore goto redirect; 127*84441f85SGarrett D'Amore case 'c': 128*84441f85SGarrett D'Amore pd = 1; 129*84441f85SGarrett D'Amore psl = 0; 130*84441f85SGarrett D'Amore if (cp->a2 == NULL || lastaddr || lastline()) 131*84441f85SGarrett D'Amore (void) fprintf(outfile, "%s", cp->t); 132*84441f85SGarrett D'Amore break; 133*84441f85SGarrett D'Amore case 'd': 134*84441f85SGarrett D'Amore pd = 1; 135*84441f85SGarrett D'Amore goto new; 136*84441f85SGarrett D'Amore case 'D': 137*84441f85SGarrett D'Amore if (pd) 138*84441f85SGarrett D'Amore goto new; 139*84441f85SGarrett D'Amore if (psl == 0 || 140*84441f85SGarrett D'Amore (p = memchr(ps, '\n', psl)) == NULL) { 141*84441f85SGarrett D'Amore pd = 1; 142*84441f85SGarrett D'Amore goto new; 143*84441f85SGarrett D'Amore } else { 144*84441f85SGarrett D'Amore psl -= 145*84441f85SGarrett D'Amore (uintptr_t)(p + 1) - (uintptr_t)ps; 146*84441f85SGarrett D'Amore (void) memmove(ps, p + 1, psl); 147*84441f85SGarrett D'Amore goto top; 148*84441f85SGarrett D'Amore } 149*84441f85SGarrett D'Amore case 'g': 150*84441f85SGarrett D'Amore cspace(&PS, hs, hsl, REPLACE); 151*84441f85SGarrett D'Amore break; 152*84441f85SGarrett D'Amore case 'G': 153*84441f85SGarrett D'Amore cspace(&PS, "\n", 1, APPEND); 154*84441f85SGarrett D'Amore cspace(&PS, hs, hsl, APPEND); 155*84441f85SGarrett D'Amore break; 156*84441f85SGarrett D'Amore case 'h': 157*84441f85SGarrett D'Amore cspace(&HS, ps, psl, REPLACE); 158*84441f85SGarrett D'Amore break; 159*84441f85SGarrett D'Amore case 'H': 160*84441f85SGarrett D'Amore cspace(&HS, "\n", 1, APPEND); 161*84441f85SGarrett D'Amore cspace(&HS, ps, psl, APPEND); 162*84441f85SGarrett D'Amore break; 163*84441f85SGarrett D'Amore case 'i': 164*84441f85SGarrett D'Amore (void) fprintf(outfile, "%s", cp->t); 165*84441f85SGarrett D'Amore break; 166*84441f85SGarrett D'Amore case 'l': 167*84441f85SGarrett D'Amore lputs(ps, psl); 168*84441f85SGarrett D'Amore break; 169*84441f85SGarrett D'Amore case 'n': 170*84441f85SGarrett D'Amore if (!nflag && !pd) 171*84441f85SGarrett D'Amore OUT(); 172*84441f85SGarrett D'Amore flush_appends(); 173*84441f85SGarrett D'Amore if (!mf_fgets(&PS, REPLACE)) 174*84441f85SGarrett D'Amore exit(0); 175*84441f85SGarrett D'Amore pd = 0; 176*84441f85SGarrett D'Amore break; 177*84441f85SGarrett D'Amore case 'N': 178*84441f85SGarrett D'Amore flush_appends(); 179*84441f85SGarrett D'Amore cspace(&PS, "\n", 1, APPEND); 180*84441f85SGarrett D'Amore if (!mf_fgets(&PS, APPEND)) 181*84441f85SGarrett D'Amore exit(0); 182*84441f85SGarrett D'Amore break; 183*84441f85SGarrett D'Amore case 'p': 184*84441f85SGarrett D'Amore if (pd) 185*84441f85SGarrett D'Amore break; 186*84441f85SGarrett D'Amore OUT(); 187*84441f85SGarrett D'Amore break; 188*84441f85SGarrett D'Amore case 'P': 189*84441f85SGarrett D'Amore if (pd) 190*84441f85SGarrett D'Amore break; 191*84441f85SGarrett D'Amore if ((p = memchr(ps, '\n', psl)) != NULL) { 192*84441f85SGarrett D'Amore oldpsl = psl; 193*84441f85SGarrett D'Amore psl = (uintptr_t)p - (uintptr_t)ps; 194*84441f85SGarrett D'Amore } 195*84441f85SGarrett D'Amore OUT(); 196*84441f85SGarrett D'Amore if (p != NULL) 197*84441f85SGarrett D'Amore psl = oldpsl; 198*84441f85SGarrett D'Amore break; 199*84441f85SGarrett D'Amore case 'q': 200*84441f85SGarrett D'Amore if (!nflag && !pd) 201*84441f85SGarrett D'Amore OUT(); 202*84441f85SGarrett D'Amore flush_appends(); 203*84441f85SGarrett D'Amore exit(0); 204*84441f85SGarrett D'Amore /*NOTREACHED*/ 205*84441f85SGarrett D'Amore case 'r': 206*84441f85SGarrett D'Amore if (appendx >= appendnum) 207*84441f85SGarrett D'Amore if ((appends = realloc(appends, 208*84441f85SGarrett D'Amore sizeof (struct s_appends) * 209*84441f85SGarrett D'Amore (appendnum *= 2))) == NULL) 210*84441f85SGarrett D'Amore err(1, "realloc"); 211*84441f85SGarrett D'Amore appends[appendx].type = AP_FILE; 212*84441f85SGarrett D'Amore appends[appendx].s = cp->t; 213*84441f85SGarrett D'Amore appends[appendx].len = strlen(cp->t); 214*84441f85SGarrett D'Amore appendx++; 215*84441f85SGarrett D'Amore break; 216*84441f85SGarrett D'Amore case 's': 217*84441f85SGarrett D'Amore sdone |= substitute(cp); 218*84441f85SGarrett D'Amore break; 219*84441f85SGarrett D'Amore case 't': 220*84441f85SGarrett D'Amore if (sdone) { 221*84441f85SGarrett D'Amore sdone = 0; 222*84441f85SGarrett D'Amore cp = cp->u.c; 223*84441f85SGarrett D'Amore goto redirect; 224*84441f85SGarrett D'Amore } 225*84441f85SGarrett D'Amore break; 226*84441f85SGarrett D'Amore case 'w': 227*84441f85SGarrett D'Amore if (pd) 228*84441f85SGarrett D'Amore break; 229*84441f85SGarrett D'Amore if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 230*84441f85SGarrett D'Amore O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 0666)) 231*84441f85SGarrett D'Amore == -1) 232*84441f85SGarrett D'Amore err(1, "%s", cp->t); 233*84441f85SGarrett D'Amore if (write(cp->u.fd, ps, psl) != (ssize_t)psl || 234*84441f85SGarrett D'Amore write(cp->u.fd, "\n", 1) != 1) 235*84441f85SGarrett D'Amore err(1, "%s", cp->t); 236*84441f85SGarrett D'Amore break; 237*84441f85SGarrett D'Amore case 'x': 238*84441f85SGarrett D'Amore /* 239*84441f85SGarrett D'Amore * If the hold space is null, make it empty 240*84441f85SGarrett D'Amore * but not null. Otherwise the pattern space 241*84441f85SGarrett D'Amore * will become null after the swap, which is 242*84441f85SGarrett D'Amore * an abnormal condition. 243*84441f85SGarrett D'Amore */ 244*84441f85SGarrett D'Amore if (hs == NULL) 245*84441f85SGarrett D'Amore cspace(&HS, "", 0, REPLACE); 246*84441f85SGarrett D'Amore tspace = PS; 247*84441f85SGarrett D'Amore PS = HS; 248*84441f85SGarrett D'Amore HS = tspace; 249*84441f85SGarrett D'Amore break; 250*84441f85SGarrett D'Amore case 'y': 251*84441f85SGarrett D'Amore if (pd || psl == 0) 252*84441f85SGarrett D'Amore break; 253*84441f85SGarrett D'Amore do_tr(cp->u.y); 254*84441f85SGarrett D'Amore break; 255*84441f85SGarrett D'Amore case ':': 256*84441f85SGarrett D'Amore case '}': 257*84441f85SGarrett D'Amore break; 258*84441f85SGarrett D'Amore case '=': 259*84441f85SGarrett D'Amore (void) fprintf(outfile, "%lu\n", linenum); 260*84441f85SGarrett D'Amore } 261*84441f85SGarrett D'Amore cp = cp->next; 262*84441f85SGarrett D'Amore } /* for all cp */ 263*84441f85SGarrett D'Amore 264*84441f85SGarrett D'Amore new: if (!nflag && !pd) 265*84441f85SGarrett D'Amore OUT(); 266*84441f85SGarrett D'Amore flush_appends(); 267*84441f85SGarrett D'Amore } /* for all lines */ 268*84441f85SGarrett D'Amore } 269*84441f85SGarrett D'Amore 270*84441f85SGarrett D'Amore /* 271*84441f85SGarrett D'Amore * TRUE if the address passed matches the current program state 272*84441f85SGarrett D'Amore * (lastline, linenumber, ps). 273*84441f85SGarrett D'Amore */ 274*84441f85SGarrett D'Amore #define MATCH(a) \ 275*84441f85SGarrett D'Amore ((a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \ 276*84441f85SGarrett D'Amore (a)->type == AT_LINE ? linenum == (a)->u.l : lastline()) 277*84441f85SGarrett D'Amore 278*84441f85SGarrett D'Amore /* 279*84441f85SGarrett D'Amore * Return TRUE if the command applies to the current line. Sets the start 280*84441f85SGarrett D'Amore * line for process ranges. Interprets the non-select (``!'') flag. 281*84441f85SGarrett D'Amore */ 282*84441f85SGarrett D'Amore static int 283*84441f85SGarrett D'Amore applies(struct s_command *cp) 284*84441f85SGarrett D'Amore { 285*84441f85SGarrett D'Amore int r; 286*84441f85SGarrett D'Amore 287*84441f85SGarrett D'Amore lastaddr = 0; 288*84441f85SGarrett D'Amore if (cp->a1 == NULL && cp->a2 == NULL) 289*84441f85SGarrett D'Amore r = 1; 290*84441f85SGarrett D'Amore else if (cp->a2) 291*84441f85SGarrett D'Amore if (cp->startline > 0) { 292*84441f85SGarrett D'Amore if (MATCH(cp->a2)) { 293*84441f85SGarrett D'Amore cp->startline = 0; 294*84441f85SGarrett D'Amore lastaddr = 1; 295*84441f85SGarrett D'Amore r = 1; 296*84441f85SGarrett D'Amore } else if (linenum - cp->startline <= cp->a2->u.l) 297*84441f85SGarrett D'Amore r = 1; 298*84441f85SGarrett D'Amore else if ((cp->a2->type == AT_LINE && 299*84441f85SGarrett D'Amore linenum > cp->a2->u.l) || 300*84441f85SGarrett D'Amore (cp->a2->type == AT_RELLINE && 301*84441f85SGarrett D'Amore linenum - cp->startline > cp->a2->u.l)) { 302*84441f85SGarrett D'Amore /* 303*84441f85SGarrett D'Amore * We missed the 2nd address due to a branch, 304*84441f85SGarrett D'Amore * so just close the range and return false. 305*84441f85SGarrett D'Amore */ 306*84441f85SGarrett D'Amore cp->startline = 0; 307*84441f85SGarrett D'Amore r = 0; 308*84441f85SGarrett D'Amore } else 309*84441f85SGarrett D'Amore r = 1; 310*84441f85SGarrett D'Amore } else if (MATCH(cp->a1)) { 311*84441f85SGarrett D'Amore /* 312*84441f85SGarrett D'Amore * If the second address is a number less than or 313*84441f85SGarrett D'Amore * equal to the line number first selected, only 314*84441f85SGarrett D'Amore * one line shall be selected. 315*84441f85SGarrett D'Amore * -- POSIX 1003.2 316*84441f85SGarrett D'Amore * Likewise if the relative second line address is zero. 317*84441f85SGarrett D'Amore */ 318*84441f85SGarrett D'Amore if ((cp->a2->type == AT_LINE && 319*84441f85SGarrett D'Amore linenum >= cp->a2->u.l) || 320*84441f85SGarrett D'Amore (cp->a2->type == AT_RELLINE && cp->a2->u.l == 0)) 321*84441f85SGarrett D'Amore lastaddr = 1; 322*84441f85SGarrett D'Amore else { 323*84441f85SGarrett D'Amore cp->startline = linenum; 324*84441f85SGarrett D'Amore } 325*84441f85SGarrett D'Amore r = 1; 326*84441f85SGarrett D'Amore } else 327*84441f85SGarrett D'Amore r = 0; 328*84441f85SGarrett D'Amore else 329*84441f85SGarrett D'Amore r = MATCH(cp->a1); 330*84441f85SGarrett D'Amore return (cp->nonsel ? ! r : r); 331*84441f85SGarrett D'Amore } 332*84441f85SGarrett D'Amore 333*84441f85SGarrett D'Amore /* 334*84441f85SGarrett D'Amore * Reset the sed processor to its initial state. 335*84441f85SGarrett D'Amore */ 336*84441f85SGarrett D'Amore void 337*84441f85SGarrett D'Amore resetstate(void) 338*84441f85SGarrett D'Amore { 339*84441f85SGarrett D'Amore struct s_command *cp; 340*84441f85SGarrett D'Amore 341*84441f85SGarrett D'Amore /* 342*84441f85SGarrett D'Amore * Reset all in-range markers. 343*84441f85SGarrett D'Amore */ 344*84441f85SGarrett D'Amore for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next) 345*84441f85SGarrett D'Amore if (cp->a2) 346*84441f85SGarrett D'Amore cp->startline = 0; 347*84441f85SGarrett D'Amore 348*84441f85SGarrett D'Amore /* 349*84441f85SGarrett D'Amore * Clear out the hold space. 350*84441f85SGarrett D'Amore */ 351*84441f85SGarrett D'Amore cspace(&HS, "", 0, REPLACE); 352*84441f85SGarrett D'Amore } 353*84441f85SGarrett D'Amore 354*84441f85SGarrett D'Amore /* 355*84441f85SGarrett D'Amore * substitute -- 356*84441f85SGarrett D'Amore * Do substitutions in the pattern space. Currently, we build a 357*84441f85SGarrett D'Amore * copy of the new pattern space in the substitute space structure 358*84441f85SGarrett D'Amore * and then swap them. 359*84441f85SGarrett D'Amore */ 360*84441f85SGarrett D'Amore static int 361*84441f85SGarrett D'Amore substitute(struct s_command *cp) 362*84441f85SGarrett D'Amore { 363*84441f85SGarrett D'Amore SPACE tspace; 364*84441f85SGarrett D'Amore regex_t *re; 365*84441f85SGarrett D'Amore regoff_t re_off, slen; 366*84441f85SGarrett D'Amore int lastempty, n; 367*84441f85SGarrett D'Amore char *s; 368*84441f85SGarrett D'Amore 369*84441f85SGarrett D'Amore s = ps; 370*84441f85SGarrett D'Amore re = cp->u.s->re; 371*84441f85SGarrett D'Amore if (re == NULL) { 372*84441f85SGarrett D'Amore if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { 373*84441f85SGarrett D'Amore linenum = cp->u.s->linenum; 374*84441f85SGarrett D'Amore fatal(_("\\%u not defined in the RE"), 375*84441f85SGarrett D'Amore cp->u.s->maxbref); 376*84441f85SGarrett D'Amore } 377*84441f85SGarrett D'Amore } 378*84441f85SGarrett D'Amore if (!regexec_e(re, s, 0, 0, psl)) 379*84441f85SGarrett D'Amore return (0); 380*84441f85SGarrett D'Amore 381*84441f85SGarrett D'Amore SS.len = 0; /* Clean substitute space. */ 382*84441f85SGarrett D'Amore slen = psl; 383*84441f85SGarrett D'Amore n = cp->u.s->n; 384*84441f85SGarrett D'Amore lastempty = 1; 385*84441f85SGarrett D'Amore 386*84441f85SGarrett D'Amore switch (n) { 387*84441f85SGarrett D'Amore case 0: /* Global */ 388*84441f85SGarrett D'Amore do { 389*84441f85SGarrett D'Amore if (lastempty || match[0].rm_so != match[0].rm_eo) { 390*84441f85SGarrett D'Amore /* Locate start of replaced string. */ 391*84441f85SGarrett D'Amore re_off = match[0].rm_so; 392*84441f85SGarrett D'Amore /* Copy leading retained string. */ 393*84441f85SGarrett D'Amore cspace(&SS, s, re_off, APPEND); 394*84441f85SGarrett D'Amore /* Add in regular expression. */ 395*84441f85SGarrett D'Amore regsub(&SS, s, cp->u.s->new); 396*84441f85SGarrett D'Amore } 397*84441f85SGarrett D'Amore 398*84441f85SGarrett D'Amore /* Move past this match. */ 399*84441f85SGarrett D'Amore if (match[0].rm_so != match[0].rm_eo) { 400*84441f85SGarrett D'Amore s += match[0].rm_eo; 401*84441f85SGarrett D'Amore slen -= match[0].rm_eo; 402*84441f85SGarrett D'Amore lastempty = 0; 403*84441f85SGarrett D'Amore } else { 404*84441f85SGarrett D'Amore if (match[0].rm_so < slen) 405*84441f85SGarrett D'Amore cspace(&SS, s + match[0].rm_so, 1, 406*84441f85SGarrett D'Amore APPEND); 407*84441f85SGarrett D'Amore s += match[0].rm_so + 1; 408*84441f85SGarrett D'Amore slen -= match[0].rm_so + 1; 409*84441f85SGarrett D'Amore lastempty = 1; 410*84441f85SGarrett D'Amore } 411*84441f85SGarrett D'Amore } while (slen >= 0 && regexec_e(re, s, REG_NOTBOL, 0, slen)); 412*84441f85SGarrett D'Amore /* Copy trailing retained string. */ 413*84441f85SGarrett D'Amore if (slen > 0) 414*84441f85SGarrett D'Amore cspace(&SS, s, slen, APPEND); 415*84441f85SGarrett D'Amore break; 416*84441f85SGarrett D'Amore default: /* Nth occurrence */ 417*84441f85SGarrett D'Amore while (--n) { 418*84441f85SGarrett D'Amore if (match[0].rm_eo == match[0].rm_so) 419*84441f85SGarrett D'Amore match[0].rm_eo = match[0].rm_so + 1; 420*84441f85SGarrett D'Amore s += match[0].rm_eo; 421*84441f85SGarrett D'Amore slen -= match[0].rm_eo; 422*84441f85SGarrett D'Amore if (slen < 0) 423*84441f85SGarrett D'Amore return (0); 424*84441f85SGarrett D'Amore if (!regexec_e(re, s, REG_NOTBOL, 0, slen)) 425*84441f85SGarrett D'Amore return (0); 426*84441f85SGarrett D'Amore } 427*84441f85SGarrett D'Amore /* FALLTHROUGH */ 428*84441f85SGarrett D'Amore case 1: /* 1st occurrence */ 429*84441f85SGarrett D'Amore /* Locate start of replaced string. */ 430*84441f85SGarrett D'Amore re_off = match[0].rm_so + ((uintptr_t)s - (uintptr_t)ps); 431*84441f85SGarrett D'Amore /* Copy leading retained string. */ 432*84441f85SGarrett D'Amore cspace(&SS, ps, re_off, APPEND); 433*84441f85SGarrett D'Amore /* Add in regular expression. */ 434*84441f85SGarrett D'Amore regsub(&SS, s, cp->u.s->new); 435*84441f85SGarrett D'Amore /* Copy trailing retained string. */ 436*84441f85SGarrett D'Amore s += match[0].rm_eo; 437*84441f85SGarrett D'Amore slen -= match[0].rm_eo; 438*84441f85SGarrett D'Amore cspace(&SS, s, slen, APPEND); 439*84441f85SGarrett D'Amore break; 440*84441f85SGarrett D'Amore } 441*84441f85SGarrett D'Amore 442*84441f85SGarrett D'Amore /* 443*84441f85SGarrett D'Amore * Swap the substitute space and the pattern space, and make sure 444*84441f85SGarrett D'Amore * that any leftover pointers into stdio memory get lost. 445*84441f85SGarrett D'Amore */ 446*84441f85SGarrett D'Amore tspace = PS; 447*84441f85SGarrett D'Amore PS = SS; 448*84441f85SGarrett D'Amore SS = tspace; 449*84441f85SGarrett D'Amore SS.space = SS.back; 450*84441f85SGarrett D'Amore 451*84441f85SGarrett D'Amore /* Handle the 'p' flag. */ 452*84441f85SGarrett D'Amore if (cp->u.s->p) 453*84441f85SGarrett D'Amore OUT(); 454*84441f85SGarrett D'Amore 455*84441f85SGarrett D'Amore /* Handle the 'w' flag. */ 456*84441f85SGarrett D'Amore if (cp->u.s->wfile && !pd) { 457*84441f85SGarrett D'Amore if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 458*84441f85SGarrett D'Amore O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 0666)) == -1) 459*84441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile); 460*84441f85SGarrett D'Amore if (write(cp->u.s->wfd, ps, psl) != (ssize_t)psl || 461*84441f85SGarrett D'Amore write(cp->u.s->wfd, "\n", 1) != 1) 462*84441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile); 463*84441f85SGarrett D'Amore } 464*84441f85SGarrett D'Amore return (1); 465*84441f85SGarrett D'Amore } 466*84441f85SGarrett D'Amore 467*84441f85SGarrett D'Amore /* 468*84441f85SGarrett D'Amore * do_tr -- 469*84441f85SGarrett D'Amore * Perform translation ('y' command) in the pattern space. 470*84441f85SGarrett D'Amore */ 471*84441f85SGarrett D'Amore static void 472*84441f85SGarrett D'Amore do_tr(struct s_tr *y) 473*84441f85SGarrett D'Amore { 474*84441f85SGarrett D'Amore SPACE tmp; 475*84441f85SGarrett D'Amore char c, *p; 476*84441f85SGarrett D'Amore size_t clen, left; 477*84441f85SGarrett D'Amore int i; 478*84441f85SGarrett D'Amore 479*84441f85SGarrett D'Amore if (MB_CUR_MAX == 1) { 480*84441f85SGarrett D'Amore /* 481*84441f85SGarrett D'Amore * Single-byte encoding: perform in-place translation 482*84441f85SGarrett D'Amore * of the pattern space. 483*84441f85SGarrett D'Amore */ 484*84441f85SGarrett D'Amore for (p = ps; p < &ps[psl]; p++) 485*84441f85SGarrett D'Amore *p = y->bytetab[(uchar_t)*p]; 486*84441f85SGarrett D'Amore } else { 487*84441f85SGarrett D'Amore /* 488*84441f85SGarrett D'Amore * Multi-byte encoding: perform translation into the 489*84441f85SGarrett D'Amore * translation space, then swap the translation and 490*84441f85SGarrett D'Amore * pattern spaces. 491*84441f85SGarrett D'Amore */ 492*84441f85SGarrett D'Amore /* Clean translation space. */ 493*84441f85SGarrett D'Amore YS.len = 0; 494*84441f85SGarrett D'Amore for (p = ps, left = psl; left > 0; p += clen, left -= clen) { 495*84441f85SGarrett D'Amore if ((c = y->bytetab[(uchar_t)*p]) != '\0') { 496*84441f85SGarrett D'Amore cspace(&YS, &c, 1, APPEND); 497*84441f85SGarrett D'Amore clen = 1; 498*84441f85SGarrett D'Amore continue; 499*84441f85SGarrett D'Amore } 500*84441f85SGarrett D'Amore for (i = 0; i < y->nmultis; i++) 501*84441f85SGarrett D'Amore if (left >= y->multis[i].fromlen && 502*84441f85SGarrett D'Amore memcmp(p, y->multis[i].from, 503*84441f85SGarrett D'Amore y->multis[i].fromlen) == 0) 504*84441f85SGarrett D'Amore break; 505*84441f85SGarrett D'Amore if (i < y->nmultis) { 506*84441f85SGarrett D'Amore cspace(&YS, y->multis[i].to, 507*84441f85SGarrett D'Amore y->multis[i].tolen, APPEND); 508*84441f85SGarrett D'Amore clen = y->multis[i].fromlen; 509*84441f85SGarrett D'Amore } else { 510*84441f85SGarrett D'Amore cspace(&YS, p, 1, APPEND); 511*84441f85SGarrett D'Amore clen = 1; 512*84441f85SGarrett D'Amore } 513*84441f85SGarrett D'Amore } 514*84441f85SGarrett D'Amore /* Swap the translation space and the pattern space. */ 515*84441f85SGarrett D'Amore tmp = PS; 516*84441f85SGarrett D'Amore PS = YS; 517*84441f85SGarrett D'Amore YS = tmp; 518*84441f85SGarrett D'Amore YS.space = YS.back; 519*84441f85SGarrett D'Amore } 520*84441f85SGarrett D'Amore } 521*84441f85SGarrett D'Amore 522*84441f85SGarrett D'Amore /* 523*84441f85SGarrett D'Amore * Flush append requests. Always called before reading a line, 524*84441f85SGarrett D'Amore * therefore it also resets the substitution done (sdone) flag. 525*84441f85SGarrett D'Amore */ 526*84441f85SGarrett D'Amore static void 527*84441f85SGarrett D'Amore flush_appends(void) 528*84441f85SGarrett D'Amore { 529*84441f85SGarrett D'Amore FILE *f; 530*84441f85SGarrett D'Amore int count, i; 531*84441f85SGarrett D'Amore char buf[8 * 1024]; 532*84441f85SGarrett D'Amore 533*84441f85SGarrett D'Amore for (i = 0; i < appendx; i++) 534*84441f85SGarrett D'Amore switch (appends[i].type) { 535*84441f85SGarrett D'Amore case AP_STRING: 536*84441f85SGarrett D'Amore (void) fwrite(appends[i].s, sizeof (char), 537*84441f85SGarrett D'Amore appends[i].len, outfile); 538*84441f85SGarrett D'Amore break; 539*84441f85SGarrett D'Amore case AP_FILE: 540*84441f85SGarrett D'Amore /* 541*84441f85SGarrett D'Amore * Read files probably shouldn't be cached. Since 542*84441f85SGarrett D'Amore * it's not an error to read a non-existent file, 543*84441f85SGarrett D'Amore * it's possible that another program is interacting 544*84441f85SGarrett D'Amore * with the sed script through the filesystem. It 545*84441f85SGarrett D'Amore * would be truly bizarre, but possible. It's probably 546*84441f85SGarrett D'Amore * not that big a performance win, anyhow. 547*84441f85SGarrett D'Amore */ 548*84441f85SGarrett D'Amore if ((f = fopen(appends[i].s, "r")) == NULL) 549*84441f85SGarrett D'Amore break; 550*84441f85SGarrett D'Amore while ((count = 551*84441f85SGarrett D'Amore fread(buf, sizeof (char), sizeof (buf), f))) 552*84441f85SGarrett D'Amore (void) fwrite(buf, sizeof (char), count, 553*84441f85SGarrett D'Amore outfile); 554*84441f85SGarrett D'Amore (void) fclose(f); 555*84441f85SGarrett D'Amore break; 556*84441f85SGarrett D'Amore } 557*84441f85SGarrett D'Amore if (ferror(outfile)) 558*84441f85SGarrett D'Amore errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO)); 559*84441f85SGarrett D'Amore appendx = sdone = 0; 560*84441f85SGarrett D'Amore } 561*84441f85SGarrett D'Amore 562*84441f85SGarrett D'Amore static void 563*84441f85SGarrett D'Amore lputs(char *s, size_t len) 564*84441f85SGarrett D'Amore { 565*84441f85SGarrett D'Amore static const char escapes[] = "\\\a\b\f\r\t\v"; 566*84441f85SGarrett D'Amore int c, col, width; 567*84441f85SGarrett D'Amore const char *p; 568*84441f85SGarrett D'Amore struct winsize win; 569*84441f85SGarrett D'Amore static int termwidth = -1; 570*84441f85SGarrett D'Amore size_t clen, i; 571*84441f85SGarrett D'Amore wchar_t wc; 572*84441f85SGarrett D'Amore mbstate_t mbs; 573*84441f85SGarrett D'Amore 574*84441f85SGarrett D'Amore if (outfile != stdout) 575*84441f85SGarrett D'Amore termwidth = 60; 576*84441f85SGarrett D'Amore if (termwidth == -1) { 577*84441f85SGarrett D'Amore if (((p = getenv("COLUMNS")) != NULL) && (*p != '\0')) 578*84441f85SGarrett D'Amore termwidth = atoi(p); 579*84441f85SGarrett D'Amore else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 580*84441f85SGarrett D'Amore win.ws_col > 0) 581*84441f85SGarrett D'Amore termwidth = win.ws_col; 582*84441f85SGarrett D'Amore else 583*84441f85SGarrett D'Amore termwidth = 60; 584*84441f85SGarrett D'Amore } 585*84441f85SGarrett D'Amore if (termwidth <= 0) 586*84441f85SGarrett D'Amore termwidth = 1; 587*84441f85SGarrett D'Amore 588*84441f85SGarrett D'Amore (void) memset(&mbs, 0, sizeof (mbs)); 589*84441f85SGarrett D'Amore col = 0; 590*84441f85SGarrett D'Amore while (len != 0) { 591*84441f85SGarrett D'Amore clen = mbrtowc(&wc, s, len, &mbs); 592*84441f85SGarrett D'Amore if (clen == 0) 593*84441f85SGarrett D'Amore clen = 1; 594*84441f85SGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) { 595*84441f85SGarrett D'Amore wc = (unsigned char)*s; 596*84441f85SGarrett D'Amore clen = 1; 597*84441f85SGarrett D'Amore (void) memset(&mbs, 0, sizeof (mbs)); 598*84441f85SGarrett D'Amore } 599*84441f85SGarrett D'Amore if (wc == '\n') { 600*84441f85SGarrett D'Amore if (col + 1 >= termwidth) 601*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n"); 602*84441f85SGarrett D'Amore (void) fputc('$', outfile); 603*84441f85SGarrett D'Amore (void) fputc('\n', outfile); 604*84441f85SGarrett D'Amore col = 0; 605*84441f85SGarrett D'Amore } else if (iswprint(wc)) { 606*84441f85SGarrett D'Amore width = wcwidth(wc); 607*84441f85SGarrett D'Amore if (col + width >= termwidth) { 608*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n"); 609*84441f85SGarrett D'Amore col = 0; 610*84441f85SGarrett D'Amore } 611*84441f85SGarrett D'Amore (void) fwrite(s, 1, clen, outfile); 612*84441f85SGarrett D'Amore col += width; 613*84441f85SGarrett D'Amore } else if (wc != L'\0' && (c = wctob(wc)) != EOF && 614*84441f85SGarrett D'Amore (p = strchr(escapes, c)) != NULL) { 615*84441f85SGarrett D'Amore if (col + 2 >= termwidth) { 616*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n"); 617*84441f85SGarrett D'Amore col = 0; 618*84441f85SGarrett D'Amore } 619*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\%c", 620*84441f85SGarrett D'Amore "\\abfrtv"[(uintptr_t)p - (uintptr_t)escapes]); 621*84441f85SGarrett D'Amore col += 2; 622*84441f85SGarrett D'Amore } else { 623*84441f85SGarrett D'Amore if (col + 4 * clen >= (unsigned)termwidth) { 624*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n"); 625*84441f85SGarrett D'Amore col = 0; 626*84441f85SGarrett D'Amore } 627*84441f85SGarrett D'Amore for (i = 0; i < clen; i++) 628*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\%03o", 629*84441f85SGarrett D'Amore (int)(unsigned char)s[i]); 630*84441f85SGarrett D'Amore col += 4 * clen; 631*84441f85SGarrett D'Amore } 632*84441f85SGarrett D'Amore s += clen; 633*84441f85SGarrett D'Amore len -= clen; 634*84441f85SGarrett D'Amore } 635*84441f85SGarrett D'Amore if (col + 1 >= termwidth) 636*84441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n"); 637*84441f85SGarrett D'Amore (void) fputc('$', outfile); 638*84441f85SGarrett D'Amore (void) fputc('\n', outfile); 639*84441f85SGarrett D'Amore if (ferror(outfile)) 640*84441f85SGarrett D'Amore errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO)); 641*84441f85SGarrett D'Amore } 642*84441f85SGarrett D'Amore 643*84441f85SGarrett D'Amore static int 644*84441f85SGarrett D'Amore regexec_e(regex_t *preg, const char *string, int eflags, int nomatch, 645*84441f85SGarrett D'Amore size_t slen) 646*84441f85SGarrett D'Amore { 647*84441f85SGarrett D'Amore int eval; 648*84441f85SGarrett D'Amore 649*84441f85SGarrett D'Amore if (preg == NULL) { 650*84441f85SGarrett D'Amore if (defpreg == NULL) 651*84441f85SGarrett D'Amore fatal(_("first RE may not be empty")); 652*84441f85SGarrett D'Amore } else 653*84441f85SGarrett D'Amore defpreg = preg; 654*84441f85SGarrett D'Amore 655*84441f85SGarrett D'Amore /* Set anchors */ 656*84441f85SGarrett D'Amore match[0].rm_so = 0; 657*84441f85SGarrett D'Amore match[0].rm_eo = slen; 658*84441f85SGarrett D'Amore 659*84441f85SGarrett D'Amore eval = regexec(defpreg, string, 660*84441f85SGarrett D'Amore nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND); 661*84441f85SGarrett D'Amore switch (eval) { 662*84441f85SGarrett D'Amore case 0: 663*84441f85SGarrett D'Amore return (1); 664*84441f85SGarrett D'Amore case REG_NOMATCH: 665*84441f85SGarrett D'Amore return (0); 666*84441f85SGarrett D'Amore } 667*84441f85SGarrett D'Amore fatal(_("RE error: %s"), strregerror(eval, defpreg)); 668*84441f85SGarrett D'Amore return (0); 669*84441f85SGarrett D'Amore } 670*84441f85SGarrett D'Amore 671*84441f85SGarrett D'Amore /* 672*84441f85SGarrett D'Amore * regsub - perform substitutions after a regexp match 673*84441f85SGarrett D'Amore * Based on a routine by Henry Spencer 674*84441f85SGarrett D'Amore */ 675*84441f85SGarrett D'Amore static void 676*84441f85SGarrett D'Amore regsub(SPACE *sp, char *string, char *src) 677*84441f85SGarrett D'Amore { 678*84441f85SGarrett D'Amore int len, no; 679*84441f85SGarrett D'Amore char c, *dst; 680*84441f85SGarrett D'Amore 681*84441f85SGarrett D'Amore #define NEEDSP(reqlen) \ 682*84441f85SGarrett D'Amore /* XXX What is the +1 for? */ \ 683*84441f85SGarrett D'Amore if (sp->len + (reqlen) + 1 >= sp->blen) { \ 684*84441f85SGarrett D'Amore sp->blen += (reqlen) + 1024; \ 685*84441f85SGarrett D'Amore if ((sp->back = realloc(sp->back, sp->blen)) == NULL) \ 686*84441f85SGarrett D'Amore err(1, "realloc"); \ 687*84441f85SGarrett D'Amore sp->space = sp->back; \ 688*84441f85SGarrett D'Amore dst = sp->space + sp->len; \ 689*84441f85SGarrett D'Amore } 690*84441f85SGarrett D'Amore 691*84441f85SGarrett D'Amore dst = sp->space + sp->len; 692*84441f85SGarrett D'Amore while ((c = *src++) != '\0') { 693*84441f85SGarrett D'Amore if (c == '&') 694*84441f85SGarrett D'Amore no = 0; 695*84441f85SGarrett D'Amore else if (c == '\\' && isdigit((unsigned char)*src)) 696*84441f85SGarrett D'Amore no = *src++ - '0'; 697*84441f85SGarrett D'Amore else 698*84441f85SGarrett D'Amore no = -1; 699*84441f85SGarrett D'Amore if (no < 0) { /* Ordinary character. */ 700*84441f85SGarrett D'Amore if (c == '\\' && (*src == '\\' || *src == '&')) 701*84441f85SGarrett D'Amore c = *src++; 702*84441f85SGarrett D'Amore NEEDSP(1); 703*84441f85SGarrett D'Amore *dst++ = c; 704*84441f85SGarrett D'Amore ++sp->len; 705*84441f85SGarrett D'Amore } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) { 706*84441f85SGarrett D'Amore len = match[no].rm_eo - match[no].rm_so; 707*84441f85SGarrett D'Amore NEEDSP(len); 708*84441f85SGarrett D'Amore (void) memmove(dst, string + match[no].rm_so, len); 709*84441f85SGarrett D'Amore dst += len; 710*84441f85SGarrett D'Amore sp->len += len; 711*84441f85SGarrett D'Amore } 712*84441f85SGarrett D'Amore } 713*84441f85SGarrett D'Amore NEEDSP(1); 714*84441f85SGarrett D'Amore *dst = '\0'; 715*84441f85SGarrett D'Amore } 716*84441f85SGarrett D'Amore 717*84441f85SGarrett D'Amore /* 718*84441f85SGarrett D'Amore * cspace -- 719*84441f85SGarrett D'Amore * Concatenate space: append the source space to the destination space, 720*84441f85SGarrett D'Amore * allocating new space as necessary. 721*84441f85SGarrett D'Amore */ 722*84441f85SGarrett D'Amore void 723*84441f85SGarrett D'Amore cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag) 724*84441f85SGarrett D'Amore { 725*84441f85SGarrett D'Amore size_t tlen; 726*84441f85SGarrett D'Amore 727*84441f85SGarrett D'Amore /* Make sure SPACE has enough memory and ramp up quickly. */ 728*84441f85SGarrett D'Amore tlen = sp->len + len + 1; 729*84441f85SGarrett D'Amore if (tlen > sp->blen) { 730*84441f85SGarrett D'Amore sp->blen = tlen + 1024; 731*84441f85SGarrett D'Amore if ((sp->space = sp->back = realloc(sp->back, sp->blen)) == 732*84441f85SGarrett D'Amore NULL) 733*84441f85SGarrett D'Amore err(1, "realloc"); 734*84441f85SGarrett D'Amore } 735*84441f85SGarrett D'Amore 736*84441f85SGarrett D'Amore if (spflag == REPLACE) 737*84441f85SGarrett D'Amore sp->len = 0; 738*84441f85SGarrett D'Amore 739*84441f85SGarrett D'Amore (void) memmove(sp->space + sp->len, p, len); 740*84441f85SGarrett D'Amore 741*84441f85SGarrett D'Amore sp->space[sp->len += len] = '\0'; 742*84441f85SGarrett D'Amore } 743*84441f85SGarrett D'Amore 744*84441f85SGarrett D'Amore /* 745*84441f85SGarrett D'Amore * Close all cached opened files and report any errors 746*84441f85SGarrett D'Amore */ 747*84441f85SGarrett D'Amore void 748*84441f85SGarrett D'Amore cfclose(struct s_command *cp, struct s_command *end) 749*84441f85SGarrett D'Amore { 750*84441f85SGarrett D'Amore 751*84441f85SGarrett D'Amore for (; cp != end; cp = cp->next) 752*84441f85SGarrett D'Amore switch (cp->code) { 753*84441f85SGarrett D'Amore case 's': 754*84441f85SGarrett D'Amore if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 755*84441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile); 756*84441f85SGarrett D'Amore cp->u.s->wfd = -1; 757*84441f85SGarrett D'Amore break; 758*84441f85SGarrett D'Amore case 'w': 759*84441f85SGarrett D'Amore if (cp->u.fd != -1 && close(cp->u.fd)) 760*84441f85SGarrett D'Amore err(1, "%s", cp->t); 761*84441f85SGarrett D'Amore cp->u.fd = -1; 762*84441f85SGarrett D'Amore break; 763*84441f85SGarrett D'Amore case '{': 764*84441f85SGarrett D'Amore cfclose(cp->u.c, cp->next); 765*84441f85SGarrett D'Amore break; 766*84441f85SGarrett D'Amore } 767*84441f85SGarrett D'Amore } 768