155997Sbostic /*- 255997Sbostic * Copyright (c) 1992 Diomidis Spinellis. 355997Sbostic * Copyright (c) 1992 The Regents of the University of California. 455997Sbostic * All rights reserved. 555997Sbostic * 655997Sbostic * This code is derived from software contributed to Berkeley by 755997Sbostic * Diomidis Spinellis of Imperial College, University of London. 855997Sbostic * 955997Sbostic * %sccs.include.redist.c% 1055997Sbostic */ 1155997Sbostic 1255997Sbostic #ifndef lint 13*56064Sbostic static char sccsid[] = "@(#)process.c 5.4 (Berkeley) 08/27/92"; 1455997Sbostic #endif /* not lint */ 1555997Sbostic 1655997Sbostic #include <sys/types.h> 1755997Sbostic #include <sys/stat.h> 1855997Sbostic #include <sys/ioctl.h> 1955997Sbostic #include <sys/uio.h> 2055997Sbostic 2155997Sbostic #include <ctype.h> 2255997Sbostic #include <errno.h> 2355997Sbostic #include <fcntl.h> 2455997Sbostic #include <limits.h> 2555997Sbostic #include <regex.h> 2655997Sbostic #include <stdio.h> 2755997Sbostic #include <stdlib.h> 2855997Sbostic #include <string.h> 2955997Sbostic #include <unistd.h> 3055997Sbostic 3155997Sbostic #include "defs.h" 3255997Sbostic #include "extern.h" 3355997Sbostic 3455997Sbostic typedef struct { 3555997Sbostic char *space; /* Current space pointer. */ 3655997Sbostic size_t len; /* Current length. */ 3755997Sbostic int deleted; /* If deleted. */ 3855997Sbostic char *back; /* Backing memory. */ 3955997Sbostic size_t blen; /* Backing memory length. */ 4055997Sbostic } SPACE; 4155997Sbostic static SPACE HS, PS, SS; 4255997Sbostic #define pd PS.deleted 4355997Sbostic #define ps PS.space 4455997Sbostic #define psl PS.len 4555997Sbostic #define hs HS.space 4655997Sbostic #define hsl HS.len 4755997Sbostic 4855997Sbostic static inline int applies __P((struct s_command *)); 4955997Sbostic static void cspace __P((SPACE *, char *, size_t, int)); 5055997Sbostic static void flush_appends __P((void)); 5155997Sbostic static void lputs __P((char *)); 5256019Sbostic static inline int regexec_e __P((regex_t *, const char *, 5356019Sbostic size_t, regmatch_t [], int)); 5455997Sbostic static void regsub __P((regmatch_t *, char *, char *, SPACE *)); 5555997Sbostic static int substitute __P((struct s_command *)); 5655997Sbostic 5755997Sbostic struct s_appends *appends; /* Array of pointers to strings to append. */ 5855997Sbostic static int appendx; /* Index into appends array. */ 5955997Sbostic int appendnum; /* Size of appends array. */ 6055997Sbostic 6155997Sbostic static int lastaddr; /* Set by applies if last address of a range. */ 6255997Sbostic static int sdone; /* If any substitutes since last line input. */ 6355997Sbostic /* Iov structure for 'w' commands. */ 6455997Sbostic static struct iovec iov[2] = { NULL, 0, "\n", 1 }; 6555997Sbostic 6656019Sbostic static regex_t *defpreg; 6756019Sbostic static size_t defnmatch; 6856019Sbostic 6955997Sbostic void 7055997Sbostic process() 7155997Sbostic { 7255997Sbostic struct s_command *cp; 7355997Sbostic SPACE tspace; 7455997Sbostic size_t len; 7555997Sbostic char oldc, *p; 7655997Sbostic 7755997Sbostic for (linenum = 0; ps = mf_fgets(&psl);) { 7855997Sbostic pd = 0; 7955997Sbostic cp = prog; 8055997Sbostic redirect: 8155997Sbostic while (cp != NULL) { 8255997Sbostic if (!applies(cp)) { 8355997Sbostic cp = cp->next; 8455997Sbostic continue; 8555997Sbostic } 8655997Sbostic switch (cp->code) { 8755997Sbostic case '{': 8855997Sbostic cp = cp->u.c; 8955997Sbostic goto redirect; 9055997Sbostic case 'a': 9155997Sbostic if (appendx >= appendnum) 9255997Sbostic appends = xrealloc(appends, 9355997Sbostic sizeof(struct s_appends) * 9455997Sbostic (appendnum *= 2)); 9555997Sbostic appends[appendx].type = AP_STRING; 9655997Sbostic appends[appendx].s = cp->t; 9755997Sbostic appendx++; 9855997Sbostic break; 9955997Sbostic case 'b': 10055997Sbostic cp = cp->u.c; 10155997Sbostic goto redirect; 10255997Sbostic case 'c': 10355997Sbostic pd = 1; 10455997Sbostic psl = 0; 10555997Sbostic if (cp->a2 == NULL || lastaddr) 10655997Sbostic (void)printf("%s", cp->t); 10755997Sbostic break; 10855997Sbostic case 'd': 10955997Sbostic if (pd) 11055997Sbostic goto new; 11156005Sbostic pd = 1; 11255997Sbostic goto new; 11355997Sbostic case 'D': 11455997Sbostic if (pd) 11555997Sbostic goto new; 11656005Sbostic if ((p = strchr(ps, '\n')) == NULL) 11756005Sbostic pd = 1; 11856005Sbostic else { 11955997Sbostic psl -= (p - ps) - 1; 12055997Sbostic memmove(ps, p + 1, psl); 12155997Sbostic } 12255997Sbostic goto new; 12355997Sbostic case 'g': 12455997Sbostic ps = hs; 12555997Sbostic psl = hsl; 12655997Sbostic break; 12755997Sbostic case 'G': 12855997Sbostic cspace(&PS, hs, hsl, 1); 12955997Sbostic break; 13055997Sbostic case 'h': 13155997Sbostic cspace(&HS, ps, psl, 0); 13255997Sbostic break; 13355997Sbostic case 'H': 13455997Sbostic cspace(&HS, ps, psl, 1); 13555997Sbostic break; 13655997Sbostic case 'i': 13755997Sbostic (void)printf("%s", cp->t); 13855997Sbostic break; 13955997Sbostic case 'l': 14055997Sbostic lputs(ps); 14155997Sbostic break; 14255997Sbostic case 'n': 14355997Sbostic if (!nflag && !pd) 14455997Sbostic (void)printf("%s\n", ps); 14555997Sbostic flush_appends(); 14655997Sbostic ps = mf_fgets(&psl); 14755997Sbostic #ifdef HISTORIC_PRACTICE 14855997Sbostic if (ps == NULL) 14955997Sbostic exit(0); 15055997Sbostic #endif 15155997Sbostic pd = 0; 15255997Sbostic break; 15355997Sbostic case 'N': 15455997Sbostic flush_appends(); 15555997Sbostic if (ps != PS.back) 15655997Sbostic cspace(&PS, NULL, 0, 0); 15755997Sbostic if ((p = mf_fgets(&len)) == NULL) { 15855997Sbostic if (!nflag && !pd) 15955997Sbostic (void)printf("%s\n", ps); 16055997Sbostic exit(0); 16155997Sbostic } 16255997Sbostic cspace(&PS, p, len, 1); 16355997Sbostic break; 16455997Sbostic case 'p': 16555997Sbostic if (pd) 16655997Sbostic break; 16755997Sbostic (void)printf("%s\n", ps); 16855997Sbostic break; 16955997Sbostic case 'P': 17055997Sbostic if (pd) 17155997Sbostic break; 17255997Sbostic if ((p = strchr(ps, '\n')) != NULL) { 17355997Sbostic oldc = *p; 17455997Sbostic *p = '\0'; 17555997Sbostic } 17655997Sbostic (void)printf("%s\n", ps); 17755997Sbostic if (p != NULL) 17855997Sbostic *p = oldc; 17955997Sbostic break; 18055997Sbostic case 'q': 18155997Sbostic if (!nflag && !pd) 18255997Sbostic (void)printf("%s\n", ps); 18355997Sbostic flush_appends(); 18455997Sbostic exit(0); 18555997Sbostic case 'r': 18655997Sbostic if (appendx >= appendnum) 18755997Sbostic appends = xrealloc(appends, 18855997Sbostic sizeof(struct s_appends) * 18955997Sbostic (appendnum *= 2)); 19055997Sbostic appends[appendx].type = AP_FILE; 19155997Sbostic appends[appendx].s = cp->t; 19255997Sbostic appendx++; 19355997Sbostic break; 19455997Sbostic case 's': 19555997Sbostic sdone = substitute(cp); 19655997Sbostic break; 19755997Sbostic case 't': 19855997Sbostic if (sdone) { 19955997Sbostic sdone = 0; 20055997Sbostic cp = cp->u.c; 20155997Sbostic goto redirect; 20255997Sbostic } 20355997Sbostic break; 20455997Sbostic case 'w': 20555997Sbostic if (pd) 20655997Sbostic break; 20755997Sbostic if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 20855997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 20955997Sbostic DEFFILEMODE)) == -1) 21055997Sbostic err(FATAL, "%s: %s\n", 21155997Sbostic cp->t, strerror(errno)); 21255997Sbostic iov[0].iov_base = ps; 21355997Sbostic iov[0].iov_len = psl; 21455997Sbostic if (writev(cp->u.fd, iov, 2) != psl + 1) 21555997Sbostic err(FATAL, "%s: %s\n", 21655997Sbostic cp->t, strerror(errno)); 21755997Sbostic break; 21855997Sbostic case 'x': 21955997Sbostic tspace = PS; 22055997Sbostic PS = HS; 22155997Sbostic HS = tspace; 22255997Sbostic break; 22355997Sbostic case 'y': 22455997Sbostic if (pd) 22555997Sbostic break; 22655997Sbostic for (p = ps, len = psl; len--; ++p) 22755997Sbostic *p = cp->u.y[*p]; 22855997Sbostic break; 22955997Sbostic case ':': 23055997Sbostic case '}': 23155997Sbostic break; 23255997Sbostic case '=': 23355997Sbostic (void)printf("%lu\n", linenum); 23455997Sbostic } 23555997Sbostic cp = cp->next; 23655997Sbostic } /* for all cp */ 23755997Sbostic 23855997Sbostic new: if (!nflag && !pd) 23955997Sbostic (void)printf("%s\n", ps); 24055997Sbostic flush_appends(); 24155997Sbostic } /* for all lines */ 24255997Sbostic } 24355997Sbostic 24455997Sbostic /* 24556019Sbostic * TRUE if the address passed matches the current program state 24656019Sbostic * (lastline, linenumber, ps). 24756019Sbostic */ 24856019Sbostic #define MATCH(a) \ 24956019Sbostic (a)->type == AT_RE ? \ 25056019Sbostic regexec_e((a)->u.r, ps, 0, NULL, 0) : \ 25156019Sbostic (a)->type == AT_LINE ? linenum == (a)->u.l : lastline 25256019Sbostic 25356019Sbostic /* 25455997Sbostic * Return TRUE if the command applies to the current line. Sets the inrange 25555997Sbostic * flag to process ranges. Interprets the non-select (``!'') flag. 25655997Sbostic */ 25755997Sbostic static inline int 25855997Sbostic applies(cp) 25955997Sbostic struct s_command *cp; 26055997Sbostic { 26155997Sbostic int r; 26255997Sbostic 26355997Sbostic lastaddr = 0; 26455997Sbostic if (cp->a1 == NULL && cp->a2 == NULL) 26555997Sbostic r = 1; 26655997Sbostic else if (cp->a2) 26755997Sbostic if (cp->inrange) { 26856019Sbostic if (MATCH(cp->a2)) { 26955997Sbostic cp->inrange = 0; 27055997Sbostic lastaddr = 1; 27155997Sbostic } 27255997Sbostic r = 1; 27356019Sbostic } else if (MATCH(cp->a1)) { 27455997Sbostic /* 27555997Sbostic * If the second address is a number less than or 27655997Sbostic * equal to the line number first selected, only 27755997Sbostic * one line shall be selected. 27855997Sbostic * -- POSIX 1003.2 27955997Sbostic */ 28055997Sbostic if (cp->a2->type == AT_LINE && 28155997Sbostic linenum >= cp->a2->u.l) 28255997Sbostic lastaddr = 1; 28355997Sbostic else 28455997Sbostic cp->inrange = 1; 28555997Sbostic r = 1; 28655997Sbostic } else 28755997Sbostic r = 0; 28855997Sbostic else 28956019Sbostic r = MATCH(cp->a1); 29055997Sbostic return (cp->nonsel ? ! r : r); 29155997Sbostic } 29255997Sbostic 29355997Sbostic /* 29455997Sbostic * substitute -- 29555997Sbostic * Do substitutions in the pattern space. Currently, we build a 29655997Sbostic * copy of the new pattern space in the substitute space structure 29755997Sbostic * and then swap them. 29855997Sbostic */ 29955997Sbostic static int 30055997Sbostic substitute(cp) 30155997Sbostic struct s_command *cp; 30255997Sbostic { 30355997Sbostic SPACE tspace; 30456019Sbostic regex_t *re; 30556019Sbostic size_t nsub; 30655997Sbostic int n, re_off; 30755997Sbostic char *endp, *s; 30855997Sbostic 30955997Sbostic s = ps; 31056019Sbostic re = cp->u.s->re; 31156019Sbostic if (re == NULL) { 31256019Sbostic nsub = 1; 31356019Sbostic if (defpreg != NULL && cp->u.s->maxbref > defnmatch) { 31456019Sbostic linenum = cp->u.s->linenum; 31556019Sbostic err(COMPILE, "\\%d not defined in the RE", 31656019Sbostic cp->u.s->maxbref); 31756019Sbostic } 31856019Sbostic } else 31956019Sbostic nsub = re->re_nsub + 1; 32056019Sbostic if (!regexec_e(re, s, nsub, cp->u.s->pmatch, 0)) 32155997Sbostic return (0); 32255997Sbostic 32355997Sbostic SS.len = 0; /* Clean substitute space. */ 32455997Sbostic n = cp->u.s->n; 32555997Sbostic switch (n) { 32655997Sbostic case 0: /* Global */ 32755997Sbostic do { 32855997Sbostic /* Locate start of replaced string. */ 32955997Sbostic re_off = cp->u.s->pmatch[0].rm_so; 33055997Sbostic /* Locate end of replaced string + 1. */ 33155997Sbostic endp = s + cp->u.s->pmatch[0].rm_eo; 33255997Sbostic /* Copy leading retained string. */ 33355997Sbostic cspace(&SS, s, re_off, 0); 33455997Sbostic /* Add in regular expression. */ 33555997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 33655997Sbostic /* Move past this match. */ 33755997Sbostic s += cp->u.s->pmatch[0].rm_eo; 33856019Sbostic } while(regexec_e(re, s, nsub, cp->u.s->pmatch, REG_NOTBOL)); 33955997Sbostic /* Copy trailing retained string. */ 34055997Sbostic cspace(&SS, s, strlen(s), 0); 34155997Sbostic break; 34255997Sbostic default: /* Nth occurrence */ 34355997Sbostic while (--n) { 34455997Sbostic s += cp->u.s->pmatch[0].rm_eo; 34556019Sbostic if (!regexec_e(re, 34656019Sbostic s, nsub, cp->u.s->pmatch, REG_NOTBOL)) 34755997Sbostic return (0); 34855997Sbostic } 34955997Sbostic /* FALLTHROUGH */ 35055997Sbostic case 1: /* 1st occurrence */ 35155997Sbostic /* Locate start of replaced string. */ 35255997Sbostic re_off = cp->u.s->pmatch[0].rm_so + s - ps; 35355997Sbostic /* Copy leading retained string. */ 35455997Sbostic cspace(&SS, ps, re_off, 0); 35555997Sbostic /* Add in regular expression. */ 35655997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 35755997Sbostic /* Copy trailing retained string. */ 35855997Sbostic s += cp->u.s->pmatch[0].rm_eo; 35955997Sbostic cspace(&SS, s, strlen(s), 0); 36055997Sbostic break; 36155997Sbostic } 36255997Sbostic 36355997Sbostic /* 36455997Sbostic * Swap the substitute space and the pattern space, and make sure 36555997Sbostic * that any leftover pointers into stdio memory get lost. 36655997Sbostic */ 36755997Sbostic tspace = PS; 36855997Sbostic PS = SS; 36955997Sbostic SS = tspace; 37055997Sbostic SS.space = SS.back; 37155997Sbostic 37255997Sbostic /* Handle the 'p' flag. */ 37355997Sbostic if (cp->u.s->p) 37455997Sbostic (void)printf("%s\n", ps); 37555997Sbostic 37655997Sbostic /* Handle the 'w' flag. */ 37755997Sbostic if (cp->u.s->wfile && !pd) { 37855997Sbostic if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 37955997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) 38055997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 38155997Sbostic iov[0].iov_base = ps; 38255997Sbostic iov[0].iov_len = psl; 38355997Sbostic if (writev(cp->u.s->wfd, iov, 2) != psl + 1) 38455997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 38555997Sbostic } 38655997Sbostic return (1); 38755997Sbostic } 38855997Sbostic 38955997Sbostic /* 39055997Sbostic * Flush append requests. Always called before reading a line, 39155997Sbostic * therefore it also resets the substitution done (sdone) flag. 39255997Sbostic */ 39355997Sbostic static void 39455997Sbostic flush_appends() 39555997Sbostic { 39655997Sbostic FILE *f; 39755997Sbostic int count, i; 39855997Sbostic char buf[8 * 1024]; 39955997Sbostic 40055997Sbostic for (i = 0; i < appendx; i++) 40155997Sbostic switch (appends[i].type) { 40255997Sbostic case AP_STRING: 40355997Sbostic (void)printf("%s", appends[i].s); 40455997Sbostic break; 40555997Sbostic case AP_FILE: 40655997Sbostic /* 40755997Sbostic * Read files probably shouldn't be cached. Since 40855997Sbostic * it's not an error to read a non-existent file, 40955997Sbostic * it's possible that another program is interacting 41055997Sbostic * with the sed script through the file system. It 41155997Sbostic * would be truly bizarre, but possible. It's probably 41255997Sbostic * not that big a performance win, anyhow. 41355997Sbostic */ 41455997Sbostic if ((f = fopen(appends[i].s, "r")) == NULL) 41555997Sbostic break; 41655997Sbostic while (count = fread(buf, 1, sizeof(buf), f)) 41755997Sbostic (void)fwrite(buf, 1, count, stdout); 41855997Sbostic (void)fclose(f); 41955997Sbostic break; 42055997Sbostic } 42155997Sbostic if (ferror(stdout)) 42255997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 42355997Sbostic appendx = 0; 42455997Sbostic sdone = 0; 42555997Sbostic } 42655997Sbostic 42755997Sbostic static void 42855997Sbostic lputs(s) 42955997Sbostic register char *s; 43055997Sbostic { 43155997Sbostic register int count; 43255997Sbostic register char *escapes, *p; 43355997Sbostic struct winsize win; 43455997Sbostic static int termwidth = -1; 43555997Sbostic 43655997Sbostic if (termwidth == -1) 43755997Sbostic if (p = getenv("COLUMNS")) 43855997Sbostic termwidth = atoi(p); 43955997Sbostic else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 44055997Sbostic win.ws_col > 0) 44155997Sbostic termwidth = win.ws_col; 44255997Sbostic else 44355997Sbostic termwidth = 60; 44455997Sbostic 44555997Sbostic for (count = 0; *s; ++s) { 44655997Sbostic if (count >= termwidth) { 44755997Sbostic (void)printf("\\\n"); 44855997Sbostic count = 0; 44955997Sbostic } 45055997Sbostic if (isascii(*s) && isprint(*s) && *s != '\\') { 45155997Sbostic (void)putchar(*s); 45255997Sbostic count++; 45355997Sbostic } else { 45455997Sbostic escapes = "\\\a\b\f\n\r\t\v"; 45555997Sbostic (void)putchar('\\'); 45655997Sbostic if (p = strchr(escapes, *s)) { 45755997Sbostic (void)putchar("\\abfnrtv"[p - escapes]); 45855997Sbostic count += 2; 45955997Sbostic } else { 46055997Sbostic (void)printf("%03o", (u_char)*s); 46155997Sbostic count += 4; 46255997Sbostic } 46355997Sbostic } 46455997Sbostic } 46555997Sbostic (void)putchar('$'); 46655997Sbostic (void)putchar('\n'); 46755997Sbostic if (ferror(stdout)) 46855997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 46955997Sbostic } 47055997Sbostic 47156019Sbostic static inline int 47256019Sbostic regexec_e(preg, string, nmatch, pmatch, eflags) 47355997Sbostic regex_t *preg; 47455997Sbostic const char *string; 47556019Sbostic size_t nmatch; 47655997Sbostic regmatch_t pmatch[]; 47755997Sbostic int eflags; 47855997Sbostic { 47955997Sbostic int eval; 48055997Sbostic 48156019Sbostic if (preg == NULL) { 48256019Sbostic if (defpreg == NULL) 48356019Sbostic err(FATAL, "first RE may not be empty"); 48456019Sbostic } else { 48556019Sbostic defpreg = preg; 48656019Sbostic defnmatch = nmatch; 48756019Sbostic } 48856019Sbostic 48956019Sbostic eval = regexec(defpreg, 49056019Sbostic string, pmatch == NULL ? 0 : defnmatch, pmatch, eflags); 49156019Sbostic switch(eval) { 49255997Sbostic case 0: 49356019Sbostic return (1); 49456019Sbostic case REG_NOMATCH: 49555997Sbostic return (0); 49655997Sbostic } 49756019Sbostic err(FATAL, "RE error: %s", strregerror(eval, defpreg)); 49855997Sbostic /* NOTREACHED */ 49955997Sbostic } 50055997Sbostic 50155997Sbostic /* 50255997Sbostic * regsub - perform substitutions after a regexp match 50355997Sbostic * Based on a routine by Henry Spencer 50455997Sbostic */ 50555997Sbostic static void 50655997Sbostic regsub(pmatch, string, src, sp) 50755997Sbostic regmatch_t *pmatch; 50855997Sbostic char *string, *src; 50955997Sbostic SPACE *sp; 51055997Sbostic { 51155997Sbostic register int len, no; 51255997Sbostic register char c, *dst; 51355997Sbostic 51455997Sbostic #define NEEDSP(reqlen) \ 51555997Sbostic if (sp->len >= sp->blen - (reqlen) - 1) { \ 51655997Sbostic sp->blen += (reqlen) + 1024; \ 51755997Sbostic sp->space = sp->back = xrealloc(sp->back, sp->blen); \ 51855997Sbostic dst = sp->space + sp->len; \ 51955997Sbostic } 52055997Sbostic 52155997Sbostic dst = sp->space + sp->len; 52255997Sbostic while ((c = *src++) != '\0') { 52355997Sbostic if (c == '&') 52455997Sbostic no = 0; 52555997Sbostic else if (c == '\\' && isdigit(*src)) 52655997Sbostic no = *src++ - '0'; 52755997Sbostic else 52855997Sbostic no = -1; 52955997Sbostic if (no < 0) { /* Ordinary character. */ 53055997Sbostic if (c == '\\' && (*src == '\\' || *src == '&')) 53155997Sbostic c = *src++; 53255997Sbostic NEEDSP(1); 53355997Sbostic *dst++ = c; 53455997Sbostic ++sp->len; 53555997Sbostic } else if (pmatch[no].rm_so != -1 && pmatch[no].rm_eo != -1) { 53655997Sbostic len = pmatch[no].rm_eo - pmatch[no].rm_so; 53755997Sbostic NEEDSP(len); 53855997Sbostic memmove(dst, string + pmatch[no].rm_so, len); 53955997Sbostic dst += len; 54055997Sbostic sp->len += len; 54155997Sbostic } 54255997Sbostic } 54355997Sbostic NEEDSP(1); 54455997Sbostic *dst = '\0'; 54555997Sbostic } 54655997Sbostic 54755997Sbostic /* 54855997Sbostic * aspace -- 54955997Sbostic * Append the source space to the destination space, allocating new 55055997Sbostic * space as necessary. 55155997Sbostic */ 55255997Sbostic static void 55355997Sbostic cspace(sp, p, len, append) 55455997Sbostic SPACE *sp; 55555997Sbostic char *p; 55655997Sbostic size_t len; 55755997Sbostic int append; 55855997Sbostic { 55955997Sbostic size_t tlen; 56055997Sbostic int needcopy; 56155997Sbostic 56255997Sbostic /* Current pointer may point to something else at the moment. */ 56355997Sbostic needcopy = sp->space != sp->back; 56455997Sbostic 56555997Sbostic /* 56655997Sbostic * Make sure SPACE has enough memory and ramp up quickly. 56755997Sbostic * Add in two extra bytes, one for the newline, one for a 56855997Sbostic * terminating NULL. 56955997Sbostic */ 57055997Sbostic tlen = sp->len + len + 2; 57155997Sbostic if (tlen > sp->blen) { 57255997Sbostic sp->blen = tlen + 1024; 57355997Sbostic sp->back = xrealloc(sp->back, sp->blen); 57455997Sbostic } 57555997Sbostic 57655997Sbostic if (needcopy) 57755997Sbostic memmove(sp->back, sp->space, sp->len + 1); 57855997Sbostic sp->space = sp->back; 57955997Sbostic 58055997Sbostic /* May just be copying out of a stdio buffer. */ 58155997Sbostic if (len == NULL) 58255997Sbostic return; 58355997Sbostic 58455997Sbostic /* Append a separating newline. */ 58555997Sbostic if (append) 58655997Sbostic sp->space[sp->len++] = '\n'; 58755997Sbostic 58855997Sbostic /* Append the new stuff, plus its terminating NULL. */ 58955997Sbostic memmove(sp->space + sp->len, p, len + 1); 59055997Sbostic sp->len += len; 59155997Sbostic } 59255997Sbostic 59355997Sbostic /* 59455997Sbostic * Close all cached opened files and report any errors 59555997Sbostic */ 59655997Sbostic void 59755997Sbostic cfclose(cp) 59855997Sbostic register struct s_command *cp; 59955997Sbostic { 60055997Sbostic 60155997Sbostic for (; cp != NULL; cp = cp->next) 60255997Sbostic switch(cp->code) { 60355997Sbostic case 's': 60455997Sbostic if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 60555997Sbostic err(FATAL, 60655997Sbostic "%s: %s", cp->u.s->wfile, strerror(errno)); 607*56064Sbostic cp->u.s->wfd = -1; 60855997Sbostic break; 60955997Sbostic case 'w': 61055997Sbostic if (cp->u.fd != -1 && close(cp->u.fd)) 61155997Sbostic err(FATAL, "%s: %s", cp->t, strerror(errno)); 612*56064Sbostic cp->u.fd = -1; 61355997Sbostic break; 61455997Sbostic case '{': 61555997Sbostic cfclose(cp->u.c); 61655997Sbostic break; 61755997Sbostic } 61855997Sbostic } 619