184441f85SGarrett D'Amore /*
284441f85SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
3*4e81fcfeSAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
484441f85SGarrett D'Amore * Copyright (c) 1992 Diomidis Spinellis.
584441f85SGarrett D'Amore * Copyright (c) 1992, 1993, 1994
684441f85SGarrett D'Amore * The Regents of the University of California. All rights reserved.
784441f85SGarrett D'Amore *
884441f85SGarrett D'Amore * This code is derived from software contributed to Berkeley by
984441f85SGarrett D'Amore * Diomidis Spinellis of Imperial College, University of London.
1084441f85SGarrett D'Amore *
1184441f85SGarrett D'Amore * Redistribution and use in source and binary forms, with or without
1284441f85SGarrett D'Amore * modification, are permitted provided that the following conditions
1384441f85SGarrett D'Amore * are met:
1484441f85SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright
1584441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer.
1684441f85SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright
1784441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the
1884441f85SGarrett D'Amore * documentation and/or other materials provided with the distribution.
1984441f85SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors
2084441f85SGarrett D'Amore * may be used to endorse or promote products derived from this software
2184441f85SGarrett D'Amore * without specific prior written permission.
2284441f85SGarrett D'Amore *
2384441f85SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2484441f85SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2584441f85SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2684441f85SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2784441f85SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2884441f85SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2984441f85SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3084441f85SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3184441f85SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3284441f85SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3384441f85SGarrett D'Amore * SUCH DAMAGE.
3484441f85SGarrett D'Amore */
3584441f85SGarrett D'Amore
3684441f85SGarrett D'Amore #include <sys/types.h>
3784441f85SGarrett D'Amore #include <sys/stat.h>
38*4e81fcfeSAndy Fiddaman #include <sys/ccompile.h>
3984441f85SGarrett D'Amore
4084441f85SGarrett D'Amore #include <ctype.h>
4184441f85SGarrett D'Amore #include <err.h>
4284441f85SGarrett D'Amore #include <errno.h>
4384441f85SGarrett D'Amore #include <fcntl.h>
4484441f85SGarrett D'Amore #include <limits.h>
4584441f85SGarrett D'Amore #include <regex.h>
4684441f85SGarrett D'Amore #include <stdio.h>
4784441f85SGarrett D'Amore #include <stdlib.h>
4884441f85SGarrett D'Amore #include <string.h>
4984441f85SGarrett D'Amore #include <unistd.h>
5084441f85SGarrett D'Amore #include <wchar.h>
5184441f85SGarrett D'Amore #include <wctype.h>
5284441f85SGarrett D'Amore #include <termio.h>
5384441f85SGarrett D'Amore #include <libintl.h>
5484441f85SGarrett D'Amore #include <note.h>
5584441f85SGarrett D'Amore
5684441f85SGarrett D'Amore #include "defs.h"
5784441f85SGarrett D'Amore #include "extern.h"
5884441f85SGarrett D'Amore
5984441f85SGarrett D'Amore static SPACE HS, PS, SS, YS;
6084441f85SGarrett D'Amore #define pd PS.deleted
6184441f85SGarrett D'Amore #define ps PS.space
6284441f85SGarrett D'Amore #define psl PS.len
6384441f85SGarrett D'Amore #define hs HS.space
6484441f85SGarrett D'Amore #define hsl HS.len
6584441f85SGarrett D'Amore
6684441f85SGarrett D'Amore static int applies(struct s_command *);
6784441f85SGarrett D'Amore static void do_tr(struct s_tr *);
6884441f85SGarrett D'Amore static void flush_appends(void);
6984441f85SGarrett D'Amore static void lputs(char *, size_t);
7084441f85SGarrett D'Amore static int regexec_e(regex_t *, const char *, int, int, size_t);
7184441f85SGarrett D'Amore static void regsub(SPACE *, char *, char *);
7284441f85SGarrett D'Amore static int substitute(struct s_command *);
7384441f85SGarrett D'Amore
7484441f85SGarrett D'Amore struct s_appends *appends; /* Array of pointers to strings to append. */
7584441f85SGarrett D'Amore static int appendx; /* Index into appends array. */
7684441f85SGarrett D'Amore int appendnum; /* Size of appends array. */
7784441f85SGarrett D'Amore
7884441f85SGarrett D'Amore static int lastaddr; /* Set by applies if last address of a range. */
7984441f85SGarrett D'Amore static int sdone; /* If any substitutes since last line input. */
8084441f85SGarrett D'Amore /* Iov structure for 'w' commands. */
8184441f85SGarrett D'Amore static regex_t *defpreg;
8284441f85SGarrett D'Amore size_t maxnsub;
8384441f85SGarrett D'Amore regmatch_t *match;
8484441f85SGarrett D'Amore
8584441f85SGarrett D'Amore #define OUT() do { \
8684441f85SGarrett D'Amore (void) fwrite(ps, 1, psl, outfile); \
8784441f85SGarrett D'Amore (void) fputc('\n', outfile); \
8884441f85SGarrett D'Amore _NOTE(CONSTCOND) \
8984441f85SGarrett D'Amore } while (0)
9084441f85SGarrett D'Amore
9184441f85SGarrett D'Amore void
process(void)9284441f85SGarrett D'Amore process(void)
9384441f85SGarrett D'Amore {
9484441f85SGarrett D'Amore struct s_command *cp;
9584441f85SGarrett D'Amore SPACE tspace;
9684441f85SGarrett D'Amore size_t oldpsl = 0;
9784441f85SGarrett D'Amore char *p;
9884441f85SGarrett D'Amore
9984441f85SGarrett D'Amore p = NULL;
10084441f85SGarrett D'Amore
10184441f85SGarrett D'Amore for (linenum = 0; mf_fgets(&PS, REPLACE); /* NOP */) {
10284441f85SGarrett D'Amore pd = 0;
10384441f85SGarrett D'Amore top:
10484441f85SGarrett D'Amore cp = prog;
10584441f85SGarrett D'Amore redirect:
10684441f85SGarrett D'Amore while (cp != NULL) {
10784441f85SGarrett D'Amore if (!applies(cp)) {
10884441f85SGarrett D'Amore cp = cp->next;
10984441f85SGarrett D'Amore continue;
11084441f85SGarrett D'Amore }
11184441f85SGarrett D'Amore switch (cp->code) {
11284441f85SGarrett D'Amore case '{':
11384441f85SGarrett D'Amore cp = cp->u.c;
11484441f85SGarrett D'Amore goto redirect;
11584441f85SGarrett D'Amore case 'a':
11684441f85SGarrett D'Amore if (appendx >= appendnum)
11784441f85SGarrett D'Amore if ((appends = realloc(appends,
11884441f85SGarrett D'Amore sizeof (struct s_appends) *
11984441f85SGarrett D'Amore (appendnum *= 2))) == NULL)
12084441f85SGarrett D'Amore err(1, "realloc");
12184441f85SGarrett D'Amore appends[appendx].type = AP_STRING;
12284441f85SGarrett D'Amore appends[appendx].s = cp->t;
12384441f85SGarrett D'Amore appends[appendx].len = strlen(cp->t);
12484441f85SGarrett D'Amore appendx++;
12584441f85SGarrett D'Amore break;
12684441f85SGarrett D'Amore case 'b':
12784441f85SGarrett D'Amore cp = cp->u.c;
12884441f85SGarrett D'Amore goto redirect;
12984441f85SGarrett D'Amore case 'c':
13084441f85SGarrett D'Amore pd = 1;
13184441f85SGarrett D'Amore psl = 0;
13284441f85SGarrett D'Amore if (cp->a2 == NULL || lastaddr || lastline())
13384441f85SGarrett D'Amore (void) fprintf(outfile, "%s", cp->t);
13484441f85SGarrett D'Amore break;
13584441f85SGarrett D'Amore case 'd':
13684441f85SGarrett D'Amore pd = 1;
13784441f85SGarrett D'Amore goto new;
13884441f85SGarrett D'Amore case 'D':
13984441f85SGarrett D'Amore if (pd)
14084441f85SGarrett D'Amore goto new;
14184441f85SGarrett D'Amore if (psl == 0 ||
14284441f85SGarrett D'Amore (p = memchr(ps, '\n', psl)) == NULL) {
14384441f85SGarrett D'Amore pd = 1;
14484441f85SGarrett D'Amore goto new;
14584441f85SGarrett D'Amore } else {
14684441f85SGarrett D'Amore psl -=
14784441f85SGarrett D'Amore (uintptr_t)(p + 1) - (uintptr_t)ps;
14884441f85SGarrett D'Amore (void) memmove(ps, p + 1, psl);
14984441f85SGarrett D'Amore goto top;
15084441f85SGarrett D'Amore }
15184441f85SGarrett D'Amore case 'g':
15284441f85SGarrett D'Amore cspace(&PS, hs, hsl, REPLACE);
15384441f85SGarrett D'Amore break;
15484441f85SGarrett D'Amore case 'G':
15584441f85SGarrett D'Amore cspace(&PS, "\n", 1, APPEND);
15684441f85SGarrett D'Amore cspace(&PS, hs, hsl, APPEND);
15784441f85SGarrett D'Amore break;
15884441f85SGarrett D'Amore case 'h':
15984441f85SGarrett D'Amore cspace(&HS, ps, psl, REPLACE);
16084441f85SGarrett D'Amore break;
16184441f85SGarrett D'Amore case 'H':
16284441f85SGarrett D'Amore cspace(&HS, "\n", 1, APPEND);
16384441f85SGarrett D'Amore cspace(&HS, ps, psl, APPEND);
16484441f85SGarrett D'Amore break;
16584441f85SGarrett D'Amore case 'i':
16684441f85SGarrett D'Amore (void) fprintf(outfile, "%s", cp->t);
16784441f85SGarrett D'Amore break;
16884441f85SGarrett D'Amore case 'l':
16984441f85SGarrett D'Amore lputs(ps, psl);
17084441f85SGarrett D'Amore break;
17184441f85SGarrett D'Amore case 'n':
17284441f85SGarrett D'Amore if (!nflag && !pd)
17384441f85SGarrett D'Amore OUT();
17484441f85SGarrett D'Amore flush_appends();
17584441f85SGarrett D'Amore if (!mf_fgets(&PS, REPLACE))
17684441f85SGarrett D'Amore exit(0);
17784441f85SGarrett D'Amore pd = 0;
17884441f85SGarrett D'Amore break;
17984441f85SGarrett D'Amore case 'N':
18084441f85SGarrett D'Amore flush_appends();
18184441f85SGarrett D'Amore cspace(&PS, "\n", 1, APPEND);
18284441f85SGarrett D'Amore if (!mf_fgets(&PS, APPEND))
18384441f85SGarrett D'Amore exit(0);
18484441f85SGarrett D'Amore break;
18584441f85SGarrett D'Amore case 'p':
18684441f85SGarrett D'Amore if (pd)
18784441f85SGarrett D'Amore break;
18884441f85SGarrett D'Amore OUT();
18984441f85SGarrett D'Amore break;
19084441f85SGarrett D'Amore case 'P':
19184441f85SGarrett D'Amore if (pd)
19284441f85SGarrett D'Amore break;
19384441f85SGarrett D'Amore if ((p = memchr(ps, '\n', psl)) != NULL) {
19484441f85SGarrett D'Amore oldpsl = psl;
19584441f85SGarrett D'Amore psl = (uintptr_t)p - (uintptr_t)ps;
19684441f85SGarrett D'Amore }
19784441f85SGarrett D'Amore OUT();
19884441f85SGarrett D'Amore if (p != NULL)
19984441f85SGarrett D'Amore psl = oldpsl;
20084441f85SGarrett D'Amore break;
20184441f85SGarrett D'Amore case 'q':
20284441f85SGarrett D'Amore if (!nflag && !pd)
20384441f85SGarrett D'Amore OUT();
20484441f85SGarrett D'Amore flush_appends();
20584441f85SGarrett D'Amore exit(0);
20684441f85SGarrett D'Amore /*NOTREACHED*/
20784441f85SGarrett D'Amore case 'r':
20884441f85SGarrett D'Amore if (appendx >= appendnum)
20984441f85SGarrett D'Amore if ((appends = realloc(appends,
21084441f85SGarrett D'Amore sizeof (struct s_appends) *
21184441f85SGarrett D'Amore (appendnum *= 2))) == NULL)
21284441f85SGarrett D'Amore err(1, "realloc");
21384441f85SGarrett D'Amore appends[appendx].type = AP_FILE;
21484441f85SGarrett D'Amore appends[appendx].s = cp->t;
21584441f85SGarrett D'Amore appends[appendx].len = strlen(cp->t);
21684441f85SGarrett D'Amore appendx++;
21784441f85SGarrett D'Amore break;
21884441f85SGarrett D'Amore case 's':
21984441f85SGarrett D'Amore sdone |= substitute(cp);
22084441f85SGarrett D'Amore break;
22184441f85SGarrett D'Amore case 't':
22284441f85SGarrett D'Amore if (sdone) {
22384441f85SGarrett D'Amore sdone = 0;
22484441f85SGarrett D'Amore cp = cp->u.c;
22584441f85SGarrett D'Amore goto redirect;
22684441f85SGarrett D'Amore }
22784441f85SGarrett D'Amore break;
22884441f85SGarrett D'Amore case 'w':
22984441f85SGarrett D'Amore if (pd)
23084441f85SGarrett D'Amore break;
23184441f85SGarrett D'Amore if (cp->u.fd == -1 && (cp->u.fd = open(cp->t,
23284441f85SGarrett D'Amore O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 0666))
23384441f85SGarrett D'Amore == -1)
23484441f85SGarrett D'Amore err(1, "%s", cp->t);
23584441f85SGarrett D'Amore if (write(cp->u.fd, ps, psl) != (ssize_t)psl ||
23684441f85SGarrett D'Amore write(cp->u.fd, "\n", 1) != 1)
23784441f85SGarrett D'Amore err(1, "%s", cp->t);
23884441f85SGarrett D'Amore break;
23984441f85SGarrett D'Amore case 'x':
24084441f85SGarrett D'Amore /*
24184441f85SGarrett D'Amore * If the hold space is null, make it empty
24284441f85SGarrett D'Amore * but not null. Otherwise the pattern space
24384441f85SGarrett D'Amore * will become null after the swap, which is
24484441f85SGarrett D'Amore * an abnormal condition.
24584441f85SGarrett D'Amore */
24684441f85SGarrett D'Amore if (hs == NULL)
24784441f85SGarrett D'Amore cspace(&HS, "", 0, REPLACE);
24884441f85SGarrett D'Amore tspace = PS;
24984441f85SGarrett D'Amore PS = HS;
25084441f85SGarrett D'Amore HS = tspace;
25184441f85SGarrett D'Amore break;
25284441f85SGarrett D'Amore case 'y':
25384441f85SGarrett D'Amore if (pd || psl == 0)
25484441f85SGarrett D'Amore break;
25584441f85SGarrett D'Amore do_tr(cp->u.y);
25684441f85SGarrett D'Amore break;
25784441f85SGarrett D'Amore case ':':
25884441f85SGarrett D'Amore case '}':
25984441f85SGarrett D'Amore break;
26084441f85SGarrett D'Amore case '=':
26184441f85SGarrett D'Amore (void) fprintf(outfile, "%lu\n", linenum);
26284441f85SGarrett D'Amore }
26384441f85SGarrett D'Amore cp = cp->next;
26484441f85SGarrett D'Amore } /* for all cp */
26584441f85SGarrett D'Amore
26684441f85SGarrett D'Amore new: if (!nflag && !pd)
26784441f85SGarrett D'Amore OUT();
26884441f85SGarrett D'Amore flush_appends();
26984441f85SGarrett D'Amore } /* for all lines */
27084441f85SGarrett D'Amore }
27184441f85SGarrett D'Amore
27284441f85SGarrett D'Amore /*
27384441f85SGarrett D'Amore * TRUE if the address passed matches the current program state
27484441f85SGarrett D'Amore * (lastline, linenumber, ps).
27584441f85SGarrett D'Amore */
276*4e81fcfeSAndy Fiddaman static __GNU_INLINE int
MATCH(struct s_command * cp,struct s_addr * a)277*4e81fcfeSAndy Fiddaman MATCH(struct s_command *cp, struct s_addr *a)
278*4e81fcfeSAndy Fiddaman {
279*4e81fcfeSAndy Fiddaman switch (a->type) {
280*4e81fcfeSAndy Fiddaman case AT_RE:
281*4e81fcfeSAndy Fiddaman return (regexec_e(a->u.r, ps, 0, 1, psl));
282*4e81fcfeSAndy Fiddaman case AT_LINE:
283*4e81fcfeSAndy Fiddaman return (linenum == a->u.l);
284*4e81fcfeSAndy Fiddaman case AT_RELLINE:
285*4e81fcfeSAndy Fiddaman return (linenum - cp->startline == a->u.l);
286*4e81fcfeSAndy Fiddaman case AT_LAST:
287*4e81fcfeSAndy Fiddaman return (lastline());
288*4e81fcfeSAndy Fiddaman }
289*4e81fcfeSAndy Fiddaman fatal(_("Unhandled match type"));
290*4e81fcfeSAndy Fiddaman return (0);
291*4e81fcfeSAndy Fiddaman }
29284441f85SGarrett D'Amore
29384441f85SGarrett D'Amore /*
29484441f85SGarrett D'Amore * Return TRUE if the command applies to the current line. Sets the start
29584441f85SGarrett D'Amore * line for process ranges. Interprets the non-select (``!'') flag.
29684441f85SGarrett D'Amore */
29784441f85SGarrett D'Amore static int
applies(struct s_command * cp)29884441f85SGarrett D'Amore applies(struct s_command *cp)
29984441f85SGarrett D'Amore {
30084441f85SGarrett D'Amore int r;
30184441f85SGarrett D'Amore
30284441f85SGarrett D'Amore lastaddr = 0;
30384441f85SGarrett D'Amore if (cp->a1 == NULL && cp->a2 == NULL)
30484441f85SGarrett D'Amore r = 1;
30584441f85SGarrett D'Amore else if (cp->a2)
30684441f85SGarrett D'Amore if (cp->startline > 0) {
307*4e81fcfeSAndy Fiddaman if (MATCH(cp, cp->a2)) {
30884441f85SGarrett D'Amore cp->startline = 0;
30984441f85SGarrett D'Amore lastaddr = 1;
31084441f85SGarrett D'Amore r = 1;
311*4e81fcfeSAndy Fiddaman } else if ((cp->a2->type == AT_LINE &&
31284441f85SGarrett D'Amore linenum > cp->a2->u.l) ||
31384441f85SGarrett D'Amore (cp->a2->type == AT_RELLINE &&
31484441f85SGarrett D'Amore linenum - cp->startline > cp->a2->u.l)) {
31584441f85SGarrett D'Amore /*
31684441f85SGarrett D'Amore * We missed the 2nd address due to a branch,
31784441f85SGarrett D'Amore * so just close the range and return false.
31884441f85SGarrett D'Amore */
31984441f85SGarrett D'Amore cp->startline = 0;
32084441f85SGarrett D'Amore r = 0;
321*4e81fcfeSAndy Fiddaman } else {
32284441f85SGarrett D'Amore r = 1;
323*4e81fcfeSAndy Fiddaman }
324*4e81fcfeSAndy Fiddaman } else if (MATCH(cp, cp->a1)) {
32584441f85SGarrett D'Amore /*
32684441f85SGarrett D'Amore * If the second address is a number less than or
32784441f85SGarrett D'Amore * equal to the line number first selected, only
32884441f85SGarrett D'Amore * one line shall be selected.
32984441f85SGarrett D'Amore * -- POSIX 1003.2
33084441f85SGarrett D'Amore * Likewise if the relative second line address is zero.
33184441f85SGarrett D'Amore */
33284441f85SGarrett D'Amore if ((cp->a2->type == AT_LINE &&
33384441f85SGarrett D'Amore linenum >= cp->a2->u.l) ||
33484441f85SGarrett D'Amore (cp->a2->type == AT_RELLINE && cp->a2->u.l == 0))
33584441f85SGarrett D'Amore lastaddr = 1;
33684441f85SGarrett D'Amore else {
33784441f85SGarrett D'Amore cp->startline = linenum;
33884441f85SGarrett D'Amore }
33984441f85SGarrett D'Amore r = 1;
34084441f85SGarrett D'Amore } else
34184441f85SGarrett D'Amore r = 0;
34284441f85SGarrett D'Amore else
343*4e81fcfeSAndy Fiddaman r = MATCH(cp, cp->a1);
34484441f85SGarrett D'Amore return (cp->nonsel ? ! r : r);
34584441f85SGarrett D'Amore }
34684441f85SGarrett D'Amore
34784441f85SGarrett D'Amore /*
34884441f85SGarrett D'Amore * Reset the sed processor to its initial state.
34984441f85SGarrett D'Amore */
35084441f85SGarrett D'Amore void
resetstate(void)35184441f85SGarrett D'Amore resetstate(void)
35284441f85SGarrett D'Amore {
35384441f85SGarrett D'Amore struct s_command *cp;
35484441f85SGarrett D'Amore
35584441f85SGarrett D'Amore /*
35684441f85SGarrett D'Amore * Reset all in-range markers.
35784441f85SGarrett D'Amore */
35884441f85SGarrett D'Amore for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next)
35984441f85SGarrett D'Amore if (cp->a2)
36084441f85SGarrett D'Amore cp->startline = 0;
36184441f85SGarrett D'Amore
36284441f85SGarrett D'Amore /*
36384441f85SGarrett D'Amore * Clear out the hold space.
36484441f85SGarrett D'Amore */
36584441f85SGarrett D'Amore cspace(&HS, "", 0, REPLACE);
36684441f85SGarrett D'Amore }
36784441f85SGarrett D'Amore
36884441f85SGarrett D'Amore /*
36984441f85SGarrett D'Amore * substitute --
37084441f85SGarrett D'Amore * Do substitutions in the pattern space. Currently, we build a
37184441f85SGarrett D'Amore * copy of the new pattern space in the substitute space structure
37284441f85SGarrett D'Amore * and then swap them.
37384441f85SGarrett D'Amore */
37484441f85SGarrett D'Amore static int
substitute(struct s_command * cp)37584441f85SGarrett D'Amore substitute(struct s_command *cp)
37684441f85SGarrett D'Amore {
37784441f85SGarrett D'Amore SPACE tspace;
37884441f85SGarrett D'Amore regex_t *re;
37984441f85SGarrett D'Amore regoff_t re_off, slen;
38084441f85SGarrett D'Amore int lastempty, n;
38184441f85SGarrett D'Amore char *s;
38284441f85SGarrett D'Amore
38384441f85SGarrett D'Amore s = ps;
38484441f85SGarrett D'Amore re = cp->u.s->re;
38584441f85SGarrett D'Amore if (re == NULL) {
38684441f85SGarrett D'Amore if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
38784441f85SGarrett D'Amore linenum = cp->u.s->linenum;
38884441f85SGarrett D'Amore fatal(_("\\%u not defined in the RE"),
38984441f85SGarrett D'Amore cp->u.s->maxbref);
39084441f85SGarrett D'Amore }
39184441f85SGarrett D'Amore }
39284441f85SGarrett D'Amore if (!regexec_e(re, s, 0, 0, psl))
39384441f85SGarrett D'Amore return (0);
39484441f85SGarrett D'Amore
39584441f85SGarrett D'Amore SS.len = 0; /* Clean substitute space. */
39684441f85SGarrett D'Amore slen = psl;
39784441f85SGarrett D'Amore n = cp->u.s->n;
39884441f85SGarrett D'Amore lastempty = 1;
39984441f85SGarrett D'Amore
40084441f85SGarrett D'Amore switch (n) {
40184441f85SGarrett D'Amore case 0: /* Global */
40284441f85SGarrett D'Amore do {
40384441f85SGarrett D'Amore if (lastempty || match[0].rm_so != match[0].rm_eo) {
40484441f85SGarrett D'Amore /* Locate start of replaced string. */
40584441f85SGarrett D'Amore re_off = match[0].rm_so;
40684441f85SGarrett D'Amore /* Copy leading retained string. */
40784441f85SGarrett D'Amore cspace(&SS, s, re_off, APPEND);
40884441f85SGarrett D'Amore /* Add in regular expression. */
40984441f85SGarrett D'Amore regsub(&SS, s, cp->u.s->new);
41084441f85SGarrett D'Amore }
41184441f85SGarrett D'Amore
41284441f85SGarrett D'Amore /* Move past this match. */
41384441f85SGarrett D'Amore if (match[0].rm_so != match[0].rm_eo) {
41484441f85SGarrett D'Amore s += match[0].rm_eo;
41584441f85SGarrett D'Amore slen -= match[0].rm_eo;
41684441f85SGarrett D'Amore lastempty = 0;
41784441f85SGarrett D'Amore } else {
41884441f85SGarrett D'Amore if (match[0].rm_so < slen)
41984441f85SGarrett D'Amore cspace(&SS, s + match[0].rm_so, 1,
42084441f85SGarrett D'Amore APPEND);
42184441f85SGarrett D'Amore s += match[0].rm_so + 1;
42284441f85SGarrett D'Amore slen -= match[0].rm_so + 1;
42384441f85SGarrett D'Amore lastempty = 1;
42484441f85SGarrett D'Amore }
42584441f85SGarrett D'Amore } while (slen >= 0 && regexec_e(re, s, REG_NOTBOL, 0, slen));
42684441f85SGarrett D'Amore /* Copy trailing retained string. */
42784441f85SGarrett D'Amore if (slen > 0)
42884441f85SGarrett D'Amore cspace(&SS, s, slen, APPEND);
42984441f85SGarrett D'Amore break;
43084441f85SGarrett D'Amore default: /* Nth occurrence */
43184441f85SGarrett D'Amore while (--n) {
43284441f85SGarrett D'Amore if (match[0].rm_eo == match[0].rm_so)
43384441f85SGarrett D'Amore match[0].rm_eo = match[0].rm_so + 1;
43484441f85SGarrett D'Amore s += match[0].rm_eo;
43584441f85SGarrett D'Amore slen -= match[0].rm_eo;
43684441f85SGarrett D'Amore if (slen < 0)
43784441f85SGarrett D'Amore return (0);
43884441f85SGarrett D'Amore if (!regexec_e(re, s, REG_NOTBOL, 0, slen))
43984441f85SGarrett D'Amore return (0);
44084441f85SGarrett D'Amore }
44184441f85SGarrett D'Amore /* FALLTHROUGH */
44284441f85SGarrett D'Amore case 1: /* 1st occurrence */
44384441f85SGarrett D'Amore /* Locate start of replaced string. */
44484441f85SGarrett D'Amore re_off = match[0].rm_so + ((uintptr_t)s - (uintptr_t)ps);
44584441f85SGarrett D'Amore /* Copy leading retained string. */
44684441f85SGarrett D'Amore cspace(&SS, ps, re_off, APPEND);
44784441f85SGarrett D'Amore /* Add in regular expression. */
44884441f85SGarrett D'Amore regsub(&SS, s, cp->u.s->new);
44984441f85SGarrett D'Amore /* Copy trailing retained string. */
45084441f85SGarrett D'Amore s += match[0].rm_eo;
45184441f85SGarrett D'Amore slen -= match[0].rm_eo;
45284441f85SGarrett D'Amore cspace(&SS, s, slen, APPEND);
45384441f85SGarrett D'Amore break;
45484441f85SGarrett D'Amore }
45584441f85SGarrett D'Amore
45684441f85SGarrett D'Amore /*
45784441f85SGarrett D'Amore * Swap the substitute space and the pattern space, and make sure
45884441f85SGarrett D'Amore * that any leftover pointers into stdio memory get lost.
45984441f85SGarrett D'Amore */
46084441f85SGarrett D'Amore tspace = PS;
46184441f85SGarrett D'Amore PS = SS;
46284441f85SGarrett D'Amore SS = tspace;
46384441f85SGarrett D'Amore SS.space = SS.back;
46484441f85SGarrett D'Amore
46584441f85SGarrett D'Amore /* Handle the 'p' flag. */
46684441f85SGarrett D'Amore if (cp->u.s->p)
46784441f85SGarrett D'Amore OUT();
46884441f85SGarrett D'Amore
46984441f85SGarrett D'Amore /* Handle the 'w' flag. */
47084441f85SGarrett D'Amore if (cp->u.s->wfile && !pd) {
47184441f85SGarrett D'Amore if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile,
47284441f85SGarrett D'Amore O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 0666)) == -1)
47384441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile);
47484441f85SGarrett D'Amore if (write(cp->u.s->wfd, ps, psl) != (ssize_t)psl ||
47584441f85SGarrett D'Amore write(cp->u.s->wfd, "\n", 1) != 1)
47684441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile);
47784441f85SGarrett D'Amore }
47884441f85SGarrett D'Amore return (1);
47984441f85SGarrett D'Amore }
48084441f85SGarrett D'Amore
48184441f85SGarrett D'Amore /*
48284441f85SGarrett D'Amore * do_tr --
48384441f85SGarrett D'Amore * Perform translation ('y' command) in the pattern space.
48484441f85SGarrett D'Amore */
48584441f85SGarrett D'Amore static void
do_tr(struct s_tr * y)48684441f85SGarrett D'Amore do_tr(struct s_tr *y)
48784441f85SGarrett D'Amore {
48884441f85SGarrett D'Amore SPACE tmp;
48984441f85SGarrett D'Amore char c, *p;
49084441f85SGarrett D'Amore size_t clen, left;
49184441f85SGarrett D'Amore int i;
49284441f85SGarrett D'Amore
49384441f85SGarrett D'Amore if (MB_CUR_MAX == 1) {
49484441f85SGarrett D'Amore /*
49584441f85SGarrett D'Amore * Single-byte encoding: perform in-place translation
49684441f85SGarrett D'Amore * of the pattern space.
49784441f85SGarrett D'Amore */
49884441f85SGarrett D'Amore for (p = ps; p < &ps[psl]; p++)
49984441f85SGarrett D'Amore *p = y->bytetab[(uchar_t)*p];
50084441f85SGarrett D'Amore } else {
50184441f85SGarrett D'Amore /*
50284441f85SGarrett D'Amore * Multi-byte encoding: perform translation into the
50384441f85SGarrett D'Amore * translation space, then swap the translation and
50484441f85SGarrett D'Amore * pattern spaces.
50584441f85SGarrett D'Amore */
50684441f85SGarrett D'Amore /* Clean translation space. */
50784441f85SGarrett D'Amore YS.len = 0;
50884441f85SGarrett D'Amore for (p = ps, left = psl; left > 0; p += clen, left -= clen) {
50984441f85SGarrett D'Amore if ((c = y->bytetab[(uchar_t)*p]) != '\0') {
51084441f85SGarrett D'Amore cspace(&YS, &c, 1, APPEND);
51184441f85SGarrett D'Amore clen = 1;
51284441f85SGarrett D'Amore continue;
51384441f85SGarrett D'Amore }
51484441f85SGarrett D'Amore for (i = 0; i < y->nmultis; i++)
51584441f85SGarrett D'Amore if (left >= y->multis[i].fromlen &&
51684441f85SGarrett D'Amore memcmp(p, y->multis[i].from,
51784441f85SGarrett D'Amore y->multis[i].fromlen) == 0)
51884441f85SGarrett D'Amore break;
51984441f85SGarrett D'Amore if (i < y->nmultis) {
52084441f85SGarrett D'Amore cspace(&YS, y->multis[i].to,
52184441f85SGarrett D'Amore y->multis[i].tolen, APPEND);
52284441f85SGarrett D'Amore clen = y->multis[i].fromlen;
52384441f85SGarrett D'Amore } else {
52484441f85SGarrett D'Amore cspace(&YS, p, 1, APPEND);
52584441f85SGarrett D'Amore clen = 1;
52684441f85SGarrett D'Amore }
52784441f85SGarrett D'Amore }
52884441f85SGarrett D'Amore /* Swap the translation space and the pattern space. */
52984441f85SGarrett D'Amore tmp = PS;
53084441f85SGarrett D'Amore PS = YS;
53184441f85SGarrett D'Amore YS = tmp;
53284441f85SGarrett D'Amore YS.space = YS.back;
53384441f85SGarrett D'Amore }
53484441f85SGarrett D'Amore }
53584441f85SGarrett D'Amore
53684441f85SGarrett D'Amore /*
53784441f85SGarrett D'Amore * Flush append requests. Always called before reading a line,
53884441f85SGarrett D'Amore * therefore it also resets the substitution done (sdone) flag.
53984441f85SGarrett D'Amore */
54084441f85SGarrett D'Amore static void
flush_appends(void)54184441f85SGarrett D'Amore flush_appends(void)
54284441f85SGarrett D'Amore {
54384441f85SGarrett D'Amore FILE *f;
54484441f85SGarrett D'Amore int count, i;
54584441f85SGarrett D'Amore char buf[8 * 1024];
54684441f85SGarrett D'Amore
54784441f85SGarrett D'Amore for (i = 0; i < appendx; i++)
54884441f85SGarrett D'Amore switch (appends[i].type) {
54984441f85SGarrett D'Amore case AP_STRING:
55084441f85SGarrett D'Amore (void) fwrite(appends[i].s, sizeof (char),
55184441f85SGarrett D'Amore appends[i].len, outfile);
55284441f85SGarrett D'Amore break;
55384441f85SGarrett D'Amore case AP_FILE:
55484441f85SGarrett D'Amore /*
55584441f85SGarrett D'Amore * Read files probably shouldn't be cached. Since
55684441f85SGarrett D'Amore * it's not an error to read a non-existent file,
55784441f85SGarrett D'Amore * it's possible that another program is interacting
55884441f85SGarrett D'Amore * with the sed script through the filesystem. It
55984441f85SGarrett D'Amore * would be truly bizarre, but possible. It's probably
56084441f85SGarrett D'Amore * not that big a performance win, anyhow.
56184441f85SGarrett D'Amore */
56284441f85SGarrett D'Amore if ((f = fopen(appends[i].s, "r")) == NULL)
56384441f85SGarrett D'Amore break;
56484441f85SGarrett D'Amore while ((count =
56584441f85SGarrett D'Amore fread(buf, sizeof (char), sizeof (buf), f)))
56684441f85SGarrett D'Amore (void) fwrite(buf, sizeof (char), count,
56784441f85SGarrett D'Amore outfile);
56884441f85SGarrett D'Amore (void) fclose(f);
56984441f85SGarrett D'Amore break;
57084441f85SGarrett D'Amore }
57184441f85SGarrett D'Amore if (ferror(outfile))
57284441f85SGarrett D'Amore errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
57384441f85SGarrett D'Amore appendx = sdone = 0;
57484441f85SGarrett D'Amore }
57584441f85SGarrett D'Amore
57684441f85SGarrett D'Amore static void
lputs(char * s,size_t len)57784441f85SGarrett D'Amore lputs(char *s, size_t len)
57884441f85SGarrett D'Amore {
57984441f85SGarrett D'Amore static const char escapes[] = "\\\a\b\f\r\t\v";
58084441f85SGarrett D'Amore int c, col, width;
58184441f85SGarrett D'Amore const char *p;
58284441f85SGarrett D'Amore struct winsize win;
58384441f85SGarrett D'Amore static int termwidth = -1;
58484441f85SGarrett D'Amore size_t clen, i;
58584441f85SGarrett D'Amore wchar_t wc;
58684441f85SGarrett D'Amore mbstate_t mbs;
58784441f85SGarrett D'Amore
58884441f85SGarrett D'Amore if (outfile != stdout)
58984441f85SGarrett D'Amore termwidth = 60;
59084441f85SGarrett D'Amore if (termwidth == -1) {
59184441f85SGarrett D'Amore if (((p = getenv("COLUMNS")) != NULL) && (*p != '\0'))
59284441f85SGarrett D'Amore termwidth = atoi(p);
59384441f85SGarrett D'Amore else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
59484441f85SGarrett D'Amore win.ws_col > 0)
59584441f85SGarrett D'Amore termwidth = win.ws_col;
59684441f85SGarrett D'Amore else
59784441f85SGarrett D'Amore termwidth = 60;
59884441f85SGarrett D'Amore }
59984441f85SGarrett D'Amore if (termwidth <= 0)
60084441f85SGarrett D'Amore termwidth = 1;
60184441f85SGarrett D'Amore
60284441f85SGarrett D'Amore (void) memset(&mbs, 0, sizeof (mbs));
60384441f85SGarrett D'Amore col = 0;
60484441f85SGarrett D'Amore while (len != 0) {
60584441f85SGarrett D'Amore clen = mbrtowc(&wc, s, len, &mbs);
60684441f85SGarrett D'Amore if (clen == 0)
60784441f85SGarrett D'Amore clen = 1;
60884441f85SGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) {
60984441f85SGarrett D'Amore wc = (unsigned char)*s;
61084441f85SGarrett D'Amore clen = 1;
61184441f85SGarrett D'Amore (void) memset(&mbs, 0, sizeof (mbs));
61284441f85SGarrett D'Amore }
61384441f85SGarrett D'Amore if (wc == '\n') {
61484441f85SGarrett D'Amore if (col + 1 >= termwidth)
61584441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n");
61684441f85SGarrett D'Amore (void) fputc('$', outfile);
61784441f85SGarrett D'Amore (void) fputc('\n', outfile);
61884441f85SGarrett D'Amore col = 0;
61984441f85SGarrett D'Amore } else if (iswprint(wc)) {
62084441f85SGarrett D'Amore width = wcwidth(wc);
62184441f85SGarrett D'Amore if (col + width >= termwidth) {
62284441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n");
62384441f85SGarrett D'Amore col = 0;
62484441f85SGarrett D'Amore }
62584441f85SGarrett D'Amore (void) fwrite(s, 1, clen, outfile);
62684441f85SGarrett D'Amore col += width;
62784441f85SGarrett D'Amore } else if (wc != L'\0' && (c = wctob(wc)) != EOF &&
62884441f85SGarrett D'Amore (p = strchr(escapes, c)) != NULL) {
62984441f85SGarrett D'Amore if (col + 2 >= termwidth) {
63084441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n");
63184441f85SGarrett D'Amore col = 0;
63284441f85SGarrett D'Amore }
63384441f85SGarrett D'Amore (void) fprintf(outfile, "\\%c",
63484441f85SGarrett D'Amore "\\abfrtv"[(uintptr_t)p - (uintptr_t)escapes]);
63584441f85SGarrett D'Amore col += 2;
63684441f85SGarrett D'Amore } else {
63784441f85SGarrett D'Amore if (col + 4 * clen >= (unsigned)termwidth) {
63884441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n");
63984441f85SGarrett D'Amore col = 0;
64084441f85SGarrett D'Amore }
64184441f85SGarrett D'Amore for (i = 0; i < clen; i++)
64284441f85SGarrett D'Amore (void) fprintf(outfile, "\\%03o",
64384441f85SGarrett D'Amore (int)(unsigned char)s[i]);
64484441f85SGarrett D'Amore col += 4 * clen;
64584441f85SGarrett D'Amore }
64684441f85SGarrett D'Amore s += clen;
64784441f85SGarrett D'Amore len -= clen;
64884441f85SGarrett D'Amore }
64984441f85SGarrett D'Amore if (col + 1 >= termwidth)
65084441f85SGarrett D'Amore (void) fprintf(outfile, "\\\n");
65184441f85SGarrett D'Amore (void) fputc('$', outfile);
65284441f85SGarrett D'Amore (void) fputc('\n', outfile);
65384441f85SGarrett D'Amore if (ferror(outfile))
65484441f85SGarrett D'Amore errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
65584441f85SGarrett D'Amore }
65684441f85SGarrett D'Amore
65784441f85SGarrett D'Amore static int
regexec_e(regex_t * preg,const char * string,int eflags,int nomatch,size_t slen)65884441f85SGarrett D'Amore regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
659*4e81fcfeSAndy Fiddaman size_t slen)
66084441f85SGarrett D'Amore {
66184441f85SGarrett D'Amore int eval;
66284441f85SGarrett D'Amore
66384441f85SGarrett D'Amore if (preg == NULL) {
66484441f85SGarrett D'Amore if (defpreg == NULL)
66584441f85SGarrett D'Amore fatal(_("first RE may not be empty"));
66684441f85SGarrett D'Amore } else
66784441f85SGarrett D'Amore defpreg = preg;
66884441f85SGarrett D'Amore
66984441f85SGarrett D'Amore /* Set anchors */
67084441f85SGarrett D'Amore match[0].rm_so = 0;
67184441f85SGarrett D'Amore match[0].rm_eo = slen;
67284441f85SGarrett D'Amore
67384441f85SGarrett D'Amore eval = regexec(defpreg, string,
67484441f85SGarrett D'Amore nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
67584441f85SGarrett D'Amore switch (eval) {
67684441f85SGarrett D'Amore case 0:
67784441f85SGarrett D'Amore return (1);
67884441f85SGarrett D'Amore case REG_NOMATCH:
67984441f85SGarrett D'Amore return (0);
68084441f85SGarrett D'Amore }
68184441f85SGarrett D'Amore fatal(_("RE error: %s"), strregerror(eval, defpreg));
68284441f85SGarrett D'Amore return (0);
68384441f85SGarrett D'Amore }
68484441f85SGarrett D'Amore
68584441f85SGarrett D'Amore /*
68684441f85SGarrett D'Amore * regsub - perform substitutions after a regexp match
68784441f85SGarrett D'Amore * Based on a routine by Henry Spencer
68884441f85SGarrett D'Amore */
68984441f85SGarrett D'Amore static void
regsub(SPACE * sp,char * string,char * src)69084441f85SGarrett D'Amore regsub(SPACE *sp, char *string, char *src)
69184441f85SGarrett D'Amore {
69284441f85SGarrett D'Amore int len, no;
69384441f85SGarrett D'Amore char c, *dst;
69484441f85SGarrett D'Amore
69584441f85SGarrett D'Amore #define NEEDSP(reqlen) \
69684441f85SGarrett D'Amore /* XXX What is the +1 for? */ \
69784441f85SGarrett D'Amore if (sp->len + (reqlen) + 1 >= sp->blen) { \
69884441f85SGarrett D'Amore sp->blen += (reqlen) + 1024; \
69984441f85SGarrett D'Amore if ((sp->back = realloc(sp->back, sp->blen)) == NULL) \
70084441f85SGarrett D'Amore err(1, "realloc"); \
70184441f85SGarrett D'Amore sp->space = sp->back; \
70284441f85SGarrett D'Amore dst = sp->space + sp->len; \
70384441f85SGarrett D'Amore }
70484441f85SGarrett D'Amore
70584441f85SGarrett D'Amore dst = sp->space + sp->len;
70684441f85SGarrett D'Amore while ((c = *src++) != '\0') {
70784441f85SGarrett D'Amore if (c == '&')
70884441f85SGarrett D'Amore no = 0;
70984441f85SGarrett D'Amore else if (c == '\\' && isdigit((unsigned char)*src))
71084441f85SGarrett D'Amore no = *src++ - '0';
71184441f85SGarrett D'Amore else
71284441f85SGarrett D'Amore no = -1;
71384441f85SGarrett D'Amore if (no < 0) { /* Ordinary character. */
71484441f85SGarrett D'Amore if (c == '\\' && (*src == '\\' || *src == '&'))
71584441f85SGarrett D'Amore c = *src++;
71684441f85SGarrett D'Amore NEEDSP(1);
71784441f85SGarrett D'Amore *dst++ = c;
71884441f85SGarrett D'Amore ++sp->len;
71984441f85SGarrett D'Amore } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) {
72084441f85SGarrett D'Amore len = match[no].rm_eo - match[no].rm_so;
72184441f85SGarrett D'Amore NEEDSP(len);
72284441f85SGarrett D'Amore (void) memmove(dst, string + match[no].rm_so, len);
72384441f85SGarrett D'Amore dst += len;
72484441f85SGarrett D'Amore sp->len += len;
72584441f85SGarrett D'Amore }
72684441f85SGarrett D'Amore }
72784441f85SGarrett D'Amore NEEDSP(1);
72884441f85SGarrett D'Amore *dst = '\0';
72984441f85SGarrett D'Amore }
73084441f85SGarrett D'Amore
73184441f85SGarrett D'Amore /*
73284441f85SGarrett D'Amore * cspace --
73384441f85SGarrett D'Amore * Concatenate space: append the source space to the destination space,
73484441f85SGarrett D'Amore * allocating new space as necessary.
73584441f85SGarrett D'Amore */
73684441f85SGarrett D'Amore void
cspace(SPACE * sp,const char * p,size_t len,enum e_spflag spflag)73784441f85SGarrett D'Amore cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag)
73884441f85SGarrett D'Amore {
73984441f85SGarrett D'Amore size_t tlen;
74084441f85SGarrett D'Amore
74184441f85SGarrett D'Amore /* Make sure SPACE has enough memory and ramp up quickly. */
74284441f85SGarrett D'Amore tlen = sp->len + len + 1;
74384441f85SGarrett D'Amore if (tlen > sp->blen) {
74484441f85SGarrett D'Amore sp->blen = tlen + 1024;
74584441f85SGarrett D'Amore if ((sp->space = sp->back = realloc(sp->back, sp->blen)) ==
74684441f85SGarrett D'Amore NULL)
74784441f85SGarrett D'Amore err(1, "realloc");
74884441f85SGarrett D'Amore }
74984441f85SGarrett D'Amore
75084441f85SGarrett D'Amore if (spflag == REPLACE)
75184441f85SGarrett D'Amore sp->len = 0;
75284441f85SGarrett D'Amore
75384441f85SGarrett D'Amore (void) memmove(sp->space + sp->len, p, len);
75484441f85SGarrett D'Amore
75584441f85SGarrett D'Amore sp->space[sp->len += len] = '\0';
75684441f85SGarrett D'Amore }
75784441f85SGarrett D'Amore
75884441f85SGarrett D'Amore /*
75984441f85SGarrett D'Amore * Close all cached opened files and report any errors
76084441f85SGarrett D'Amore */
76184441f85SGarrett D'Amore void
cfclose(struct s_command * cp,struct s_command * end)76284441f85SGarrett D'Amore cfclose(struct s_command *cp, struct s_command *end)
76384441f85SGarrett D'Amore {
76484441f85SGarrett D'Amore
76584441f85SGarrett D'Amore for (; cp != end; cp = cp->next)
76684441f85SGarrett D'Amore switch (cp->code) {
76784441f85SGarrett D'Amore case 's':
76884441f85SGarrett D'Amore if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
76984441f85SGarrett D'Amore err(1, "%s", cp->u.s->wfile);
77084441f85SGarrett D'Amore cp->u.s->wfd = -1;
77184441f85SGarrett D'Amore break;
77284441f85SGarrett D'Amore case 'w':
77384441f85SGarrett D'Amore if (cp->u.fd != -1 && close(cp->u.fd))
77484441f85SGarrett D'Amore err(1, "%s", cp->t);
77584441f85SGarrett D'Amore cp->u.fd = -1;
77684441f85SGarrett D'Amore break;
77784441f85SGarrett D'Amore case '{':
77884441f85SGarrett D'Amore cfclose(cp->u.c, cp->next);
77984441f85SGarrett D'Amore break;
78084441f85SGarrett D'Amore }
78184441f85SGarrett D'Amore }
782