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*56005Sbostic static char sccsid[] = "@(#)process.c 5.2 (Berkeley) 08/24/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 *)); 5255997Sbostic static inline int match __P((struct s_addr *)); 5355997Sbostic static int regexec_check __P((regex_t *, const char *, 5455997Sbostic int, regmatch_t[], int)); 5555997Sbostic static void regsub __P((regmatch_t *, char *, char *, SPACE *)); 5655997Sbostic static int substitute __P((struct s_command *)); 5755997Sbostic 5855997Sbostic struct s_appends *appends; /* Array of pointers to strings to append. */ 5955997Sbostic static int appendx; /* Index into appends array. */ 6055997Sbostic int appendnum; /* Size of appends array. */ 6155997Sbostic 6255997Sbostic static int lastaddr; /* Set by applies if last address of a range. */ 6355997Sbostic static int sdone; /* If any substitutes since last line input. */ 6455997Sbostic /* Iov structure for 'w' commands. */ 6555997Sbostic static struct iovec iov[2] = { NULL, 0, "\n", 1 }; 6655997Sbostic 6755997Sbostic void 6855997Sbostic process() 6955997Sbostic { 7055997Sbostic struct s_command *cp; 7155997Sbostic SPACE tspace; 7255997Sbostic size_t len; 7355997Sbostic char oldc, *p; 7455997Sbostic 7555997Sbostic for (linenum = 0; ps = mf_fgets(&psl);) { 7655997Sbostic pd = 0; 7755997Sbostic cp = prog; 7855997Sbostic redirect: 7955997Sbostic while (cp != NULL) { 8055997Sbostic if (!applies(cp)) { 8155997Sbostic cp = cp->next; 8255997Sbostic continue; 8355997Sbostic } 8455997Sbostic switch (cp->code) { 8555997Sbostic case '{': 8655997Sbostic cp = cp->u.c; 8755997Sbostic goto redirect; 8855997Sbostic case 'a': 8955997Sbostic if (appendx >= appendnum) 9055997Sbostic appends = xrealloc(appends, 9155997Sbostic sizeof(struct s_appends) * 9255997Sbostic (appendnum *= 2)); 9355997Sbostic appends[appendx].type = AP_STRING; 9455997Sbostic appends[appendx].s = cp->t; 9555997Sbostic appendx++; 9655997Sbostic break; 9755997Sbostic case 'b': 9855997Sbostic cp = cp->u.c; 9955997Sbostic goto redirect; 10055997Sbostic case 'c': 10155997Sbostic pd = 1; 10255997Sbostic psl = 0; 10355997Sbostic if (cp->a2 == NULL || lastaddr) 10455997Sbostic (void)printf("%s", cp->t); 10555997Sbostic break; 10655997Sbostic case 'd': 10755997Sbostic if (pd) 10855997Sbostic goto new; 109*56005Sbostic pd = 1; 11055997Sbostic goto new; 11155997Sbostic case 'D': 11255997Sbostic if (pd) 11355997Sbostic goto new; 114*56005Sbostic if ((p = strchr(ps, '\n')) == NULL) 115*56005Sbostic pd = 1; 116*56005Sbostic else { 11755997Sbostic psl -= (p - ps) - 1; 11855997Sbostic memmove(ps, p + 1, psl); 11955997Sbostic } 12055997Sbostic goto new; 12155997Sbostic case 'g': 12255997Sbostic ps = hs; 12355997Sbostic psl = hsl; 12455997Sbostic break; 12555997Sbostic case 'G': 12655997Sbostic cspace(&PS, hs, hsl, 1); 12755997Sbostic break; 12855997Sbostic case 'h': 12955997Sbostic cspace(&HS, ps, psl, 0); 13055997Sbostic break; 13155997Sbostic case 'H': 13255997Sbostic cspace(&HS, ps, psl, 1); 13355997Sbostic break; 13455997Sbostic case 'i': 13555997Sbostic (void)printf("%s", cp->t); 13655997Sbostic break; 13755997Sbostic case 'l': 13855997Sbostic lputs(ps); 13955997Sbostic break; 14055997Sbostic case 'n': 14155997Sbostic if (!nflag && !pd) 14255997Sbostic (void)printf("%s\n", ps); 14355997Sbostic flush_appends(); 14455997Sbostic ps = mf_fgets(&psl); 14555997Sbostic #ifdef HISTORIC_PRACTICE 14655997Sbostic if (ps == NULL) 14755997Sbostic exit(0); 14855997Sbostic #endif 14955997Sbostic pd = 0; 15055997Sbostic break; 15155997Sbostic case 'N': 15255997Sbostic flush_appends(); 15355997Sbostic if (ps != PS.back) 15455997Sbostic cspace(&PS, NULL, 0, 0); 15555997Sbostic if ((p = mf_fgets(&len)) == NULL) { 15655997Sbostic if (!nflag && !pd) 15755997Sbostic (void)printf("%s\n", ps); 15855997Sbostic exit(0); 15955997Sbostic } 16055997Sbostic cspace(&PS, p, len, 1); 16155997Sbostic break; 16255997Sbostic case 'p': 16355997Sbostic if (pd) 16455997Sbostic break; 16555997Sbostic (void)printf("%s\n", ps); 16655997Sbostic break; 16755997Sbostic case 'P': 16855997Sbostic if (pd) 16955997Sbostic break; 17055997Sbostic if ((p = strchr(ps, '\n')) != NULL) { 17155997Sbostic oldc = *p; 17255997Sbostic *p = '\0'; 17355997Sbostic } 17455997Sbostic (void)printf("%s\n", ps); 17555997Sbostic if (p != NULL) 17655997Sbostic *p = oldc; 17755997Sbostic break; 17855997Sbostic case 'q': 17955997Sbostic if (!nflag && !pd) 18055997Sbostic (void)printf("%s\n", ps); 18155997Sbostic flush_appends(); 18255997Sbostic exit(0); 18355997Sbostic case 'r': 18455997Sbostic if (appendx >= appendnum) 18555997Sbostic appends = xrealloc(appends, 18655997Sbostic sizeof(struct s_appends) * 18755997Sbostic (appendnum *= 2)); 18855997Sbostic appends[appendx].type = AP_FILE; 18955997Sbostic appends[appendx].s = cp->t; 19055997Sbostic appendx++; 19155997Sbostic break; 19255997Sbostic case 's': 19355997Sbostic sdone = substitute(cp); 19455997Sbostic break; 19555997Sbostic case 't': 19655997Sbostic if (sdone) { 19755997Sbostic sdone = 0; 19855997Sbostic cp = cp->u.c; 19955997Sbostic goto redirect; 20055997Sbostic } 20155997Sbostic break; 20255997Sbostic case 'w': 20355997Sbostic if (pd) 20455997Sbostic break; 20555997Sbostic if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 20655997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 20755997Sbostic DEFFILEMODE)) == -1) 20855997Sbostic err(FATAL, "%s: %s\n", 20955997Sbostic cp->t, strerror(errno)); 21055997Sbostic iov[0].iov_base = ps; 21155997Sbostic iov[0].iov_len = psl; 21255997Sbostic if (writev(cp->u.fd, iov, 2) != psl + 1) 21355997Sbostic err(FATAL, "%s: %s\n", 21455997Sbostic cp->t, strerror(errno)); 21555997Sbostic break; 21655997Sbostic case 'x': 21755997Sbostic tspace = PS; 21855997Sbostic PS = HS; 21955997Sbostic HS = tspace; 22055997Sbostic break; 22155997Sbostic case 'y': 22255997Sbostic if (pd) 22355997Sbostic break; 22455997Sbostic for (p = ps, len = psl; len--; ++p) 22555997Sbostic *p = cp->u.y[*p]; 22655997Sbostic break; 22755997Sbostic case ':': 22855997Sbostic case '}': 22955997Sbostic break; 23055997Sbostic case '=': 23155997Sbostic (void)printf("%lu\n", linenum); 23255997Sbostic } 23355997Sbostic cp = cp->next; 23455997Sbostic } /* for all cp */ 23555997Sbostic 23655997Sbostic new: if (!nflag && !pd) 23755997Sbostic (void)printf("%s\n", ps); 23855997Sbostic flush_appends(); 23955997Sbostic } /* for all lines */ 24055997Sbostic } 24155997Sbostic 24255997Sbostic /* 24355997Sbostic * Return TRUE if the command applies to the current line. Sets the inrange 24455997Sbostic * flag to process ranges. Interprets the non-select (``!'') flag. 24555997Sbostic */ 24655997Sbostic static inline int 24755997Sbostic applies(cp) 24855997Sbostic struct s_command *cp; 24955997Sbostic { 25055997Sbostic int r; 25155997Sbostic 25255997Sbostic lastaddr = 0; 25355997Sbostic if (cp->a1 == NULL && cp->a2 == NULL) 25455997Sbostic r = 1; 25555997Sbostic else if (cp->a2) 25655997Sbostic if (cp->inrange) { 25755997Sbostic if (match(cp->a2)) { 25855997Sbostic cp->inrange = 0; 25955997Sbostic lastaddr = 1; 26055997Sbostic } 26155997Sbostic r = 1; 26255997Sbostic } else if (match(cp->a1)) { 26355997Sbostic /* 26455997Sbostic * If the second address is a number less than or 26555997Sbostic * equal to the line number first selected, only 26655997Sbostic * one line shall be selected. 26755997Sbostic * -- POSIX 1003.2 26855997Sbostic */ 26955997Sbostic if (cp->a2->type == AT_LINE && 27055997Sbostic linenum >= cp->a2->u.l) 27155997Sbostic lastaddr = 1; 27255997Sbostic else 27355997Sbostic cp->inrange = 1; 27455997Sbostic r = 1; 27555997Sbostic } else 27655997Sbostic r = 0; 27755997Sbostic else 27855997Sbostic r = match(cp->a1); 27955997Sbostic return (cp->nonsel ? ! r : r); 28055997Sbostic } 28155997Sbostic 28255997Sbostic /* 28355997Sbostic * Return TRUE if the address passed matches the current program 28455997Sbostic * state (linenumber, ps, lastline) 28555997Sbostic */ 28655997Sbostic static int inline 28755997Sbostic match(a) 28855997Sbostic struct s_addr *a; 28955997Sbostic { 29055997Sbostic int eval; 29155997Sbostic 29255997Sbostic switch (a->type) { 29355997Sbostic case AT_RE: 29455997Sbostic switch (eval = regexec(a->u.r, ps, 0, NULL, 0)) { 29555997Sbostic case 0: 29655997Sbostic return (1); 29755997Sbostic case REG_NOMATCH: 29855997Sbostic return (0); 29955997Sbostic default: 30055997Sbostic err(FATAL, "RE error: %s", strregerror(eval, a->u.r)); 30155997Sbostic } 30255997Sbostic case AT_LINE: 30355997Sbostic return (linenum == a->u.l); 30455997Sbostic case AT_LAST: 30555997Sbostic return (lastline); 30655997Sbostic } 30755997Sbostic /* NOTREACHED */ 30855997Sbostic } 30955997Sbostic 31055997Sbostic /* 31155997Sbostic * substitute -- 31255997Sbostic * Do substitutions in the pattern space. Currently, we build a 31355997Sbostic * copy of the new pattern space in the substitute space structure 31455997Sbostic * and then swap them. 31555997Sbostic */ 31655997Sbostic static int 31755997Sbostic substitute(cp) 31855997Sbostic struct s_command *cp; 31955997Sbostic { 32055997Sbostic SPACE tspace; 32155997Sbostic static regex_t *re; 32255997Sbostic int n, re_off; 32355997Sbostic char *endp, *s; 32455997Sbostic 32555997Sbostic s = ps; 32655997Sbostic re = &cp->u.s->re; 32755997Sbostic if (regexec_check(re, 32855997Sbostic s, re->re_nsub + 1, cp->u.s->pmatch, 0) == REG_NOMATCH) 32955997Sbostic return (0); 33055997Sbostic 33155997Sbostic SS.len = 0; /* Clean substitute space. */ 33255997Sbostic n = cp->u.s->n; 33355997Sbostic switch (n) { 33455997Sbostic case 0: /* Global */ 33555997Sbostic do { 33655997Sbostic /* Locate start of replaced string. */ 33755997Sbostic re_off = cp->u.s->pmatch[0].rm_so; 33855997Sbostic /* Locate end of replaced string + 1. */ 33955997Sbostic endp = s + cp->u.s->pmatch[0].rm_eo; 34055997Sbostic /* Copy leading retained string. */ 34155997Sbostic cspace(&SS, s, re_off, 0); 34255997Sbostic /* Add in regular expression. */ 34355997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 34455997Sbostic /* Move past this match. */ 34555997Sbostic s += cp->u.s->pmatch[0].rm_eo; 34655997Sbostic } while(regexec_check(re, s, re->re_nsub + 1, 34755997Sbostic cp->u.s->pmatch, REG_NOTBOL) != REG_NOMATCH); 34855997Sbostic /* Copy trailing retained string. */ 34955997Sbostic cspace(&SS, s, strlen(s), 0); 35055997Sbostic break; 35155997Sbostic default: /* Nth occurrence */ 35255997Sbostic while (--n) { 35355997Sbostic s += cp->u.s->pmatch[0].rm_eo; 35455997Sbostic if (regexec_check(re, s, re->re_nsub + 1, 35555997Sbostic cp->u.s->pmatch, REG_NOTBOL) == REG_NOMATCH) 35655997Sbostic return (0); 35755997Sbostic } 35855997Sbostic /* FALLTHROUGH */ 35955997Sbostic case 1: /* 1st occurrence */ 36055997Sbostic /* Locate start of replaced string. */ 36155997Sbostic re_off = cp->u.s->pmatch[0].rm_so + s - ps; 36255997Sbostic /* Copy leading retained string. */ 36355997Sbostic cspace(&SS, ps, re_off, 0); 36455997Sbostic /* Add in regular expression. */ 36555997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 36655997Sbostic /* Copy trailing retained string. */ 36755997Sbostic s += cp->u.s->pmatch[0].rm_eo; 36855997Sbostic cspace(&SS, s, strlen(s), 0); 36955997Sbostic break; 37055997Sbostic } 37155997Sbostic 37255997Sbostic /* 37355997Sbostic * Swap the substitute space and the pattern space, and make sure 37455997Sbostic * that any leftover pointers into stdio memory get lost. 37555997Sbostic */ 37655997Sbostic tspace = PS; 37755997Sbostic PS = SS; 37855997Sbostic SS = tspace; 37955997Sbostic SS.space = SS.back; 38055997Sbostic 38155997Sbostic /* Handle the 'p' flag. */ 38255997Sbostic if (cp->u.s->p) 38355997Sbostic (void)printf("%s\n", ps); 38455997Sbostic 38555997Sbostic /* Handle the 'w' flag. */ 38655997Sbostic if (cp->u.s->wfile && !pd) { 38755997Sbostic if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 38855997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) 38955997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 39055997Sbostic iov[0].iov_base = ps; 39155997Sbostic iov[0].iov_len = psl; 39255997Sbostic if (writev(cp->u.s->wfd, iov, 2) != psl + 1) 39355997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 39455997Sbostic } 39555997Sbostic return (1); 39655997Sbostic } 39755997Sbostic 39855997Sbostic /* 39955997Sbostic * Flush append requests. Always called before reading a line, 40055997Sbostic * therefore it also resets the substitution done (sdone) flag. 40155997Sbostic */ 40255997Sbostic static void 40355997Sbostic flush_appends() 40455997Sbostic { 40555997Sbostic FILE *f; 40655997Sbostic int count, i; 40755997Sbostic char buf[8 * 1024]; 40855997Sbostic 40955997Sbostic for (i = 0; i < appendx; i++) 41055997Sbostic switch (appends[i].type) { 41155997Sbostic case AP_STRING: 41255997Sbostic (void)printf("%s", appends[i].s); 41355997Sbostic break; 41455997Sbostic case AP_FILE: 41555997Sbostic /* 41655997Sbostic * Read files probably shouldn't be cached. Since 41755997Sbostic * it's not an error to read a non-existent file, 41855997Sbostic * it's possible that another program is interacting 41955997Sbostic * with the sed script through the file system. It 42055997Sbostic * would be truly bizarre, but possible. It's probably 42155997Sbostic * not that big a performance win, anyhow. 42255997Sbostic */ 42355997Sbostic if ((f = fopen(appends[i].s, "r")) == NULL) 42455997Sbostic break; 42555997Sbostic while (count = fread(buf, 1, sizeof(buf), f)) 42655997Sbostic (void)fwrite(buf, 1, count, stdout); 42755997Sbostic (void)fclose(f); 42855997Sbostic break; 42955997Sbostic } 43055997Sbostic if (ferror(stdout)) 43155997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 43255997Sbostic appendx = 0; 43355997Sbostic sdone = 0; 43455997Sbostic } 43555997Sbostic 43655997Sbostic static void 43755997Sbostic lputs(s) 43855997Sbostic register char *s; 43955997Sbostic { 44055997Sbostic register int count; 44155997Sbostic register char *escapes, *p; 44255997Sbostic struct winsize win; 44355997Sbostic static int termwidth = -1; 44455997Sbostic 44555997Sbostic if (termwidth == -1) 44655997Sbostic if (p = getenv("COLUMNS")) 44755997Sbostic termwidth = atoi(p); 44855997Sbostic else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 44955997Sbostic win.ws_col > 0) 45055997Sbostic termwidth = win.ws_col; 45155997Sbostic else 45255997Sbostic termwidth = 60; 45355997Sbostic 45455997Sbostic for (count = 0; *s; ++s) { 45555997Sbostic if (count >= termwidth) { 45655997Sbostic (void)printf("\\\n"); 45755997Sbostic count = 0; 45855997Sbostic } 45955997Sbostic if (isascii(*s) && isprint(*s) && *s != '\\') { 46055997Sbostic (void)putchar(*s); 46155997Sbostic count++; 46255997Sbostic } else { 46355997Sbostic escapes = "\\\a\b\f\n\r\t\v"; 46455997Sbostic (void)putchar('\\'); 46555997Sbostic if (p = strchr(escapes, *s)) { 46655997Sbostic (void)putchar("\\abfnrtv"[p - escapes]); 46755997Sbostic count += 2; 46855997Sbostic } else { 46955997Sbostic (void)printf("%03o", (u_char)*s); 47055997Sbostic count += 4; 47155997Sbostic } 47255997Sbostic } 47355997Sbostic } 47455997Sbostic (void)putchar('$'); 47555997Sbostic (void)putchar('\n'); 47655997Sbostic if (ferror(stdout)) 47755997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 47855997Sbostic } 47955997Sbostic 48055997Sbostic /* 48155997Sbostic * Regexec with checking for errors 48255997Sbostic */ 48355997Sbostic static int 48455997Sbostic regexec_check(preg, string, nmatch, pmatch, eflags) 48555997Sbostic regex_t *preg; 48655997Sbostic const char *string; 48755997Sbostic int nmatch; 48855997Sbostic regmatch_t pmatch[]; 48955997Sbostic int eflags; 49055997Sbostic { 49155997Sbostic int eval; 49255997Sbostic 49355997Sbostic switch (eval = regexec(preg, string, nmatch, pmatch, eflags)) { 49455997Sbostic case 0: 49555997Sbostic return (0); 49655997Sbostic case REG_NOMATCH: 49755997Sbostic return (REG_NOMATCH); 49855997Sbostic default: 49955997Sbostic err(FATAL, "RE error: %s", strregerror(eval, preg)); 50055997Sbostic } 50155997Sbostic /* NOTREACHED */ 50255997Sbostic } 50355997Sbostic 50455997Sbostic /* 50555997Sbostic * regsub - perform substitutions after a regexp match 50655997Sbostic * Based on a routine by Henry Spencer 50755997Sbostic */ 50855997Sbostic static void 50955997Sbostic regsub(pmatch, string, src, sp) 51055997Sbostic regmatch_t *pmatch; 51155997Sbostic char *string, *src; 51255997Sbostic SPACE *sp; 51355997Sbostic { 51455997Sbostic register int len, no; 51555997Sbostic register char c, *dst; 51655997Sbostic 51755997Sbostic #define NEEDSP(reqlen) \ 51855997Sbostic if (sp->len >= sp->blen - (reqlen) - 1) { \ 51955997Sbostic sp->blen += (reqlen) + 1024; \ 52055997Sbostic sp->space = sp->back = xrealloc(sp->back, sp->blen); \ 52155997Sbostic dst = sp->space + sp->len; \ 52255997Sbostic } 52355997Sbostic 52455997Sbostic dst = sp->space + sp->len; 52555997Sbostic while ((c = *src++) != '\0') { 52655997Sbostic if (c == '&') 52755997Sbostic no = 0; 52855997Sbostic else if (c == '\\' && isdigit(*src)) 52955997Sbostic no = *src++ - '0'; 53055997Sbostic else 53155997Sbostic no = -1; 53255997Sbostic if (no < 0) { /* Ordinary character. */ 53355997Sbostic if (c == '\\' && (*src == '\\' || *src == '&')) 53455997Sbostic c = *src++; 53555997Sbostic NEEDSP(1); 53655997Sbostic *dst++ = c; 53755997Sbostic ++sp->len; 53855997Sbostic } else if (pmatch[no].rm_so != -1 && pmatch[no].rm_eo != -1) { 53955997Sbostic len = pmatch[no].rm_eo - pmatch[no].rm_so; 54055997Sbostic NEEDSP(len); 54155997Sbostic memmove(dst, string + pmatch[no].rm_so, len); 54255997Sbostic dst += len; 54355997Sbostic sp->len += len; 54455997Sbostic } 54555997Sbostic } 54655997Sbostic NEEDSP(1); 54755997Sbostic *dst = '\0'; 54855997Sbostic } 54955997Sbostic 55055997Sbostic /* 55155997Sbostic * aspace -- 55255997Sbostic * Append the source space to the destination space, allocating new 55355997Sbostic * space as necessary. 55455997Sbostic */ 55555997Sbostic static void 55655997Sbostic cspace(sp, p, len, append) 55755997Sbostic SPACE *sp; 55855997Sbostic char *p; 55955997Sbostic size_t len; 56055997Sbostic int append; 56155997Sbostic { 56255997Sbostic size_t tlen; 56355997Sbostic int needcopy; 56455997Sbostic 56555997Sbostic /* Current pointer may point to something else at the moment. */ 56655997Sbostic needcopy = sp->space != sp->back; 56755997Sbostic 56855997Sbostic /* 56955997Sbostic * Make sure SPACE has enough memory and ramp up quickly. 57055997Sbostic * Add in two extra bytes, one for the newline, one for a 57155997Sbostic * terminating NULL. 57255997Sbostic */ 57355997Sbostic tlen = sp->len + len + 2; 57455997Sbostic if (tlen > sp->blen) { 57555997Sbostic sp->blen = tlen + 1024; 57655997Sbostic sp->back = xrealloc(sp->back, sp->blen); 57755997Sbostic } 57855997Sbostic 57955997Sbostic if (needcopy) 58055997Sbostic memmove(sp->back, sp->space, sp->len + 1); 58155997Sbostic sp->space = sp->back; 58255997Sbostic 58355997Sbostic /* May just be copying out of a stdio buffer. */ 58455997Sbostic if (len == NULL) 58555997Sbostic return; 58655997Sbostic 58755997Sbostic /* Append a separating newline. */ 58855997Sbostic if (append) 58955997Sbostic sp->space[sp->len++] = '\n'; 59055997Sbostic 59155997Sbostic /* Append the new stuff, plus its terminating NULL. */ 59255997Sbostic memmove(sp->space + sp->len, p, len + 1); 59355997Sbostic sp->len += len; 59455997Sbostic } 59555997Sbostic 59655997Sbostic /* 59755997Sbostic * Close all cached opened files and report any errors 59855997Sbostic */ 59955997Sbostic void 60055997Sbostic cfclose(cp) 60155997Sbostic register struct s_command *cp; 60255997Sbostic { 60355997Sbostic 60455997Sbostic for (; cp != NULL; cp = cp->next) 60555997Sbostic switch(cp->code) { 60655997Sbostic case 's': 60755997Sbostic if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 60855997Sbostic err(FATAL, 60955997Sbostic "%s: %s", cp->u.s->wfile, strerror(errno)); 61055997Sbostic break; 61155997Sbostic case 'w': 61255997Sbostic if (cp->u.fd != -1 && close(cp->u.fd)) 61355997Sbostic err(FATAL, "%s: %s", cp->t, strerror(errno)); 61455997Sbostic break; 61555997Sbostic case '{': 61655997Sbostic cfclose(cp->u.c); 61755997Sbostic break; 61855997Sbostic } 61955997Sbostic } 620