1*55997Sbostic /*- 2*55997Sbostic * Copyright (c) 1992 Diomidis Spinellis. 3*55997Sbostic * Copyright (c) 1992 The Regents of the University of California. 4*55997Sbostic * All rights reserved. 5*55997Sbostic * 6*55997Sbostic * This code is derived from software contributed to Berkeley by 7*55997Sbostic * Diomidis Spinellis of Imperial College, University of London. 8*55997Sbostic * 9*55997Sbostic * %sccs.include.redist.c% 10*55997Sbostic */ 11*55997Sbostic 12*55997Sbostic #ifndef lint 13*55997Sbostic static char sccsid[] = "@(#)process.c 5.1 (Berkeley) 08/23/92"; 14*55997Sbostic #endif /* not lint */ 15*55997Sbostic 16*55997Sbostic #include <sys/types.h> 17*55997Sbostic #include <sys/stat.h> 18*55997Sbostic #include <sys/ioctl.h> 19*55997Sbostic #include <sys/uio.h> 20*55997Sbostic 21*55997Sbostic #include <ctype.h> 22*55997Sbostic #include <errno.h> 23*55997Sbostic #include <fcntl.h> 24*55997Sbostic #include <limits.h> 25*55997Sbostic #include <regex.h> 26*55997Sbostic #include <stdio.h> 27*55997Sbostic #include <stdlib.h> 28*55997Sbostic #include <string.h> 29*55997Sbostic #include <unistd.h> 30*55997Sbostic 31*55997Sbostic #include "defs.h" 32*55997Sbostic #include "extern.h" 33*55997Sbostic 34*55997Sbostic typedef struct { 35*55997Sbostic char *space; /* Current space pointer. */ 36*55997Sbostic size_t len; /* Current length. */ 37*55997Sbostic int deleted; /* If deleted. */ 38*55997Sbostic char *back; /* Backing memory. */ 39*55997Sbostic size_t blen; /* Backing memory length. */ 40*55997Sbostic } SPACE; 41*55997Sbostic static SPACE HS, PS, SS; 42*55997Sbostic #define pd PS.deleted 43*55997Sbostic #define ps PS.space 44*55997Sbostic #define psl PS.len 45*55997Sbostic #define hs HS.space 46*55997Sbostic #define hsl HS.len 47*55997Sbostic 48*55997Sbostic static inline int applies __P((struct s_command *)); 49*55997Sbostic static void cspace __P((SPACE *, char *, size_t, int)); 50*55997Sbostic static void flush_appends __P((void)); 51*55997Sbostic static void lputs __P((char *)); 52*55997Sbostic static inline int match __P((struct s_addr *)); 53*55997Sbostic static int regexec_check __P((regex_t *, const char *, 54*55997Sbostic int, regmatch_t[], int)); 55*55997Sbostic static void regsub __P((regmatch_t *, char *, char *, SPACE *)); 56*55997Sbostic static int substitute __P((struct s_command *)); 57*55997Sbostic 58*55997Sbostic struct s_appends *appends; /* Array of pointers to strings to append. */ 59*55997Sbostic static int appendx; /* Index into appends array. */ 60*55997Sbostic int appendnum; /* Size of appends array. */ 61*55997Sbostic 62*55997Sbostic static int lastaddr; /* Set by applies if last address of a range. */ 63*55997Sbostic static int sdone; /* If any substitutes since last line input. */ 64*55997Sbostic /* Iov structure for 'w' commands. */ 65*55997Sbostic static struct iovec iov[2] = { NULL, 0, "\n", 1 }; 66*55997Sbostic 67*55997Sbostic void 68*55997Sbostic process() 69*55997Sbostic { 70*55997Sbostic struct s_command *cp; 71*55997Sbostic SPACE tspace; 72*55997Sbostic size_t len; 73*55997Sbostic char oldc, *p; 74*55997Sbostic 75*55997Sbostic for (linenum = 0; ps = mf_fgets(&psl);) { 76*55997Sbostic pd = 0; 77*55997Sbostic cp = prog; 78*55997Sbostic redirect: 79*55997Sbostic while (cp != NULL) { 80*55997Sbostic if (!applies(cp)) { 81*55997Sbostic cp = cp->next; 82*55997Sbostic continue; 83*55997Sbostic } 84*55997Sbostic switch (cp->code) { 85*55997Sbostic case '{': 86*55997Sbostic cp = cp->u.c; 87*55997Sbostic goto redirect; 88*55997Sbostic case 'a': 89*55997Sbostic if (appendx >= appendnum) 90*55997Sbostic appends = xrealloc(appends, 91*55997Sbostic sizeof(struct s_appends) * 92*55997Sbostic (appendnum *= 2)); 93*55997Sbostic appends[appendx].type = AP_STRING; 94*55997Sbostic appends[appendx].s = cp->t; 95*55997Sbostic appendx++; 96*55997Sbostic break; 97*55997Sbostic case 'b': 98*55997Sbostic cp = cp->u.c; 99*55997Sbostic goto redirect; 100*55997Sbostic case 'c': 101*55997Sbostic pd = 1; 102*55997Sbostic psl = 0; 103*55997Sbostic if (cp->a2 == NULL || lastaddr) 104*55997Sbostic (void)printf("%s", cp->t); 105*55997Sbostic break; 106*55997Sbostic case 'd': 107*55997Sbostic if (pd) 108*55997Sbostic goto new; 109*55997Sbostic psl = 0; 110*55997Sbostic ps[0] = '\0'; 111*55997Sbostic goto new; 112*55997Sbostic case 'D': 113*55997Sbostic if (pd) 114*55997Sbostic goto new; 115*55997Sbostic if ((p = strchr(ps, '\n')) == NULL) { 116*55997Sbostic psl = 0; 117*55997Sbostic ps[0] = '\0'; 118*55997Sbostic } else { 119*55997Sbostic psl -= (p - ps) - 1; 120*55997Sbostic memmove(ps, p + 1, psl); 121*55997Sbostic } 122*55997Sbostic goto new; 123*55997Sbostic case 'g': 124*55997Sbostic ps = hs; 125*55997Sbostic psl = hsl; 126*55997Sbostic break; 127*55997Sbostic case 'G': 128*55997Sbostic cspace(&PS, hs, hsl, 1); 129*55997Sbostic break; 130*55997Sbostic case 'h': 131*55997Sbostic cspace(&HS, ps, psl, 0); 132*55997Sbostic break; 133*55997Sbostic case 'H': 134*55997Sbostic cspace(&HS, ps, psl, 1); 135*55997Sbostic break; 136*55997Sbostic case 'i': 137*55997Sbostic (void)printf("%s", cp->t); 138*55997Sbostic break; 139*55997Sbostic case 'l': 140*55997Sbostic lputs(ps); 141*55997Sbostic break; 142*55997Sbostic case 'n': 143*55997Sbostic if (!nflag && !pd) 144*55997Sbostic (void)printf("%s\n", ps); 145*55997Sbostic flush_appends(); 146*55997Sbostic ps = mf_fgets(&psl); 147*55997Sbostic #ifdef HISTORIC_PRACTICE 148*55997Sbostic if (ps == NULL) 149*55997Sbostic exit(0); 150*55997Sbostic #endif 151*55997Sbostic pd = 0; 152*55997Sbostic break; 153*55997Sbostic case 'N': 154*55997Sbostic flush_appends(); 155*55997Sbostic if (ps != PS.back) 156*55997Sbostic cspace(&PS, NULL, 0, 0); 157*55997Sbostic if ((p = mf_fgets(&len)) == NULL) { 158*55997Sbostic if (!nflag && !pd) 159*55997Sbostic (void)printf("%s\n", ps); 160*55997Sbostic exit(0); 161*55997Sbostic } 162*55997Sbostic cspace(&PS, p, len, 1); 163*55997Sbostic break; 164*55997Sbostic case 'p': 165*55997Sbostic if (pd) 166*55997Sbostic break; 167*55997Sbostic (void)printf("%s\n", ps); 168*55997Sbostic break; 169*55997Sbostic case 'P': 170*55997Sbostic if (pd) 171*55997Sbostic break; 172*55997Sbostic if ((p = strchr(ps, '\n')) != NULL) { 173*55997Sbostic oldc = *p; 174*55997Sbostic *p = '\0'; 175*55997Sbostic } 176*55997Sbostic (void)printf("%s\n", ps); 177*55997Sbostic if (p != NULL) 178*55997Sbostic *p = oldc; 179*55997Sbostic break; 180*55997Sbostic case 'q': 181*55997Sbostic if (!nflag && !pd) 182*55997Sbostic (void)printf("%s\n", ps); 183*55997Sbostic flush_appends(); 184*55997Sbostic exit(0); 185*55997Sbostic case 'r': 186*55997Sbostic if (appendx >= appendnum) 187*55997Sbostic appends = xrealloc(appends, 188*55997Sbostic sizeof(struct s_appends) * 189*55997Sbostic (appendnum *= 2)); 190*55997Sbostic appends[appendx].type = AP_FILE; 191*55997Sbostic appends[appendx].s = cp->t; 192*55997Sbostic appendx++; 193*55997Sbostic break; 194*55997Sbostic case 's': 195*55997Sbostic sdone = substitute(cp); 196*55997Sbostic break; 197*55997Sbostic case 't': 198*55997Sbostic if (sdone) { 199*55997Sbostic sdone = 0; 200*55997Sbostic cp = cp->u.c; 201*55997Sbostic goto redirect; 202*55997Sbostic } 203*55997Sbostic break; 204*55997Sbostic case 'w': 205*55997Sbostic if (pd) 206*55997Sbostic break; 207*55997Sbostic if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 208*55997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 209*55997Sbostic DEFFILEMODE)) == -1) 210*55997Sbostic err(FATAL, "%s: %s\n", 211*55997Sbostic cp->t, strerror(errno)); 212*55997Sbostic iov[0].iov_base = ps; 213*55997Sbostic iov[0].iov_len = psl; 214*55997Sbostic if (writev(cp->u.fd, iov, 2) != psl + 1) 215*55997Sbostic err(FATAL, "%s: %s\n", 216*55997Sbostic cp->t, strerror(errno)); 217*55997Sbostic break; 218*55997Sbostic case 'x': 219*55997Sbostic tspace = PS; 220*55997Sbostic PS = HS; 221*55997Sbostic HS = tspace; 222*55997Sbostic break; 223*55997Sbostic case 'y': 224*55997Sbostic if (pd) 225*55997Sbostic break; 226*55997Sbostic for (p = ps, len = psl; len--; ++p) 227*55997Sbostic *p = cp->u.y[*p]; 228*55997Sbostic break; 229*55997Sbostic case ':': 230*55997Sbostic case '}': 231*55997Sbostic break; 232*55997Sbostic case '=': 233*55997Sbostic (void)printf("%lu\n", linenum); 234*55997Sbostic } 235*55997Sbostic cp = cp->next; 236*55997Sbostic } /* for all cp */ 237*55997Sbostic 238*55997Sbostic new: if (!nflag && !pd) 239*55997Sbostic (void)printf("%s\n", ps); 240*55997Sbostic flush_appends(); 241*55997Sbostic } /* for all lines */ 242*55997Sbostic } 243*55997Sbostic 244*55997Sbostic /* 245*55997Sbostic * Return TRUE if the command applies to the current line. Sets the inrange 246*55997Sbostic * flag to process ranges. Interprets the non-select (``!'') flag. 247*55997Sbostic */ 248*55997Sbostic static inline int 249*55997Sbostic applies(cp) 250*55997Sbostic struct s_command *cp; 251*55997Sbostic { 252*55997Sbostic int r; 253*55997Sbostic 254*55997Sbostic lastaddr = 0; 255*55997Sbostic if (cp->a1 == NULL && cp->a2 == NULL) 256*55997Sbostic r = 1; 257*55997Sbostic else if (cp->a2) 258*55997Sbostic if (cp->inrange) { 259*55997Sbostic if (match(cp->a2)) { 260*55997Sbostic cp->inrange = 0; 261*55997Sbostic lastaddr = 1; 262*55997Sbostic } 263*55997Sbostic r = 1; 264*55997Sbostic } else if (match(cp->a1)) { 265*55997Sbostic /* 266*55997Sbostic * If the second address is a number less than or 267*55997Sbostic * equal to the line number first selected, only 268*55997Sbostic * one line shall be selected. 269*55997Sbostic * -- POSIX 1003.2 270*55997Sbostic */ 271*55997Sbostic if (cp->a2->type == AT_LINE && 272*55997Sbostic linenum >= cp->a2->u.l) 273*55997Sbostic lastaddr = 1; 274*55997Sbostic else 275*55997Sbostic cp->inrange = 1; 276*55997Sbostic r = 1; 277*55997Sbostic } else 278*55997Sbostic r = 0; 279*55997Sbostic else 280*55997Sbostic r = match(cp->a1); 281*55997Sbostic return (cp->nonsel ? ! r : r); 282*55997Sbostic } 283*55997Sbostic 284*55997Sbostic /* 285*55997Sbostic * Return TRUE if the address passed matches the current program 286*55997Sbostic * state (linenumber, ps, lastline) 287*55997Sbostic */ 288*55997Sbostic static int inline 289*55997Sbostic match(a) 290*55997Sbostic struct s_addr *a; 291*55997Sbostic { 292*55997Sbostic int eval; 293*55997Sbostic 294*55997Sbostic switch (a->type) { 295*55997Sbostic case AT_RE: 296*55997Sbostic switch (eval = regexec(a->u.r, ps, 0, NULL, 0)) { 297*55997Sbostic case 0: 298*55997Sbostic return (1); 299*55997Sbostic case REG_NOMATCH: 300*55997Sbostic return (0); 301*55997Sbostic default: 302*55997Sbostic err(FATAL, "RE error: %s", strregerror(eval, a->u.r)); 303*55997Sbostic } 304*55997Sbostic case AT_LINE: 305*55997Sbostic return (linenum == a->u.l); 306*55997Sbostic case AT_LAST: 307*55997Sbostic return (lastline); 308*55997Sbostic } 309*55997Sbostic /* NOTREACHED */ 310*55997Sbostic } 311*55997Sbostic 312*55997Sbostic /* 313*55997Sbostic * substitute -- 314*55997Sbostic * Do substitutions in the pattern space. Currently, we build a 315*55997Sbostic * copy of the new pattern space in the substitute space structure 316*55997Sbostic * and then swap them. 317*55997Sbostic */ 318*55997Sbostic static int 319*55997Sbostic substitute(cp) 320*55997Sbostic struct s_command *cp; 321*55997Sbostic { 322*55997Sbostic SPACE tspace; 323*55997Sbostic static regex_t *re; 324*55997Sbostic int n, re_off; 325*55997Sbostic char *endp, *s; 326*55997Sbostic 327*55997Sbostic s = ps; 328*55997Sbostic re = &cp->u.s->re; 329*55997Sbostic if (regexec_check(re, 330*55997Sbostic s, re->re_nsub + 1, cp->u.s->pmatch, 0) == REG_NOMATCH) 331*55997Sbostic return (0); 332*55997Sbostic 333*55997Sbostic SS.len = 0; /* Clean substitute space. */ 334*55997Sbostic n = cp->u.s->n; 335*55997Sbostic switch (n) { 336*55997Sbostic case 0: /* Global */ 337*55997Sbostic do { 338*55997Sbostic /* Locate start of replaced string. */ 339*55997Sbostic re_off = cp->u.s->pmatch[0].rm_so; 340*55997Sbostic /* Locate end of replaced string + 1. */ 341*55997Sbostic endp = s + cp->u.s->pmatch[0].rm_eo; 342*55997Sbostic /* Copy leading retained string. */ 343*55997Sbostic cspace(&SS, s, re_off, 0); 344*55997Sbostic /* Add in regular expression. */ 345*55997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 346*55997Sbostic /* Move past this match. */ 347*55997Sbostic s += cp->u.s->pmatch[0].rm_eo; 348*55997Sbostic } while(regexec_check(re, s, re->re_nsub + 1, 349*55997Sbostic cp->u.s->pmatch, REG_NOTBOL) != REG_NOMATCH); 350*55997Sbostic /* Copy trailing retained string. */ 351*55997Sbostic cspace(&SS, s, strlen(s), 0); 352*55997Sbostic break; 353*55997Sbostic default: /* Nth occurrence */ 354*55997Sbostic while (--n) { 355*55997Sbostic s += cp->u.s->pmatch[0].rm_eo; 356*55997Sbostic if (regexec_check(re, s, re->re_nsub + 1, 357*55997Sbostic cp->u.s->pmatch, REG_NOTBOL) == REG_NOMATCH) 358*55997Sbostic return (0); 359*55997Sbostic } 360*55997Sbostic /* FALLTHROUGH */ 361*55997Sbostic case 1: /* 1st occurrence */ 362*55997Sbostic /* Locate start of replaced string. */ 363*55997Sbostic re_off = cp->u.s->pmatch[0].rm_so + s - ps; 364*55997Sbostic /* Copy leading retained string. */ 365*55997Sbostic cspace(&SS, ps, re_off, 0); 366*55997Sbostic /* Add in regular expression. */ 367*55997Sbostic regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS); 368*55997Sbostic /* Copy trailing retained string. */ 369*55997Sbostic s += cp->u.s->pmatch[0].rm_eo; 370*55997Sbostic cspace(&SS, s, strlen(s), 0); 371*55997Sbostic break; 372*55997Sbostic } 373*55997Sbostic 374*55997Sbostic /* 375*55997Sbostic * Swap the substitute space and the pattern space, and make sure 376*55997Sbostic * that any leftover pointers into stdio memory get lost. 377*55997Sbostic */ 378*55997Sbostic tspace = PS; 379*55997Sbostic PS = SS; 380*55997Sbostic SS = tspace; 381*55997Sbostic SS.space = SS.back; 382*55997Sbostic 383*55997Sbostic /* Handle the 'p' flag. */ 384*55997Sbostic if (cp->u.s->p) 385*55997Sbostic (void)printf("%s\n", ps); 386*55997Sbostic 387*55997Sbostic /* Handle the 'w' flag. */ 388*55997Sbostic if (cp->u.s->wfile && !pd) { 389*55997Sbostic if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 390*55997Sbostic O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) 391*55997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 392*55997Sbostic iov[0].iov_base = ps; 393*55997Sbostic iov[0].iov_len = psl; 394*55997Sbostic if (writev(cp->u.s->wfd, iov, 2) != psl + 1) 395*55997Sbostic err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); 396*55997Sbostic } 397*55997Sbostic return (1); 398*55997Sbostic } 399*55997Sbostic 400*55997Sbostic /* 401*55997Sbostic * Flush append requests. Always called before reading a line, 402*55997Sbostic * therefore it also resets the substitution done (sdone) flag. 403*55997Sbostic */ 404*55997Sbostic static void 405*55997Sbostic flush_appends() 406*55997Sbostic { 407*55997Sbostic FILE *f; 408*55997Sbostic int count, i; 409*55997Sbostic char buf[8 * 1024]; 410*55997Sbostic 411*55997Sbostic for (i = 0; i < appendx; i++) 412*55997Sbostic switch (appends[i].type) { 413*55997Sbostic case AP_STRING: 414*55997Sbostic (void)printf("%s", appends[i].s); 415*55997Sbostic break; 416*55997Sbostic case AP_FILE: 417*55997Sbostic /* 418*55997Sbostic * Read files probably shouldn't be cached. Since 419*55997Sbostic * it's not an error to read a non-existent file, 420*55997Sbostic * it's possible that another program is interacting 421*55997Sbostic * with the sed script through the file system. It 422*55997Sbostic * would be truly bizarre, but possible. It's probably 423*55997Sbostic * not that big a performance win, anyhow. 424*55997Sbostic */ 425*55997Sbostic if ((f = fopen(appends[i].s, "r")) == NULL) 426*55997Sbostic break; 427*55997Sbostic while (count = fread(buf, 1, sizeof(buf), f)) 428*55997Sbostic (void)fwrite(buf, 1, count, stdout); 429*55997Sbostic (void)fclose(f); 430*55997Sbostic break; 431*55997Sbostic } 432*55997Sbostic if (ferror(stdout)) 433*55997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 434*55997Sbostic appendx = 0; 435*55997Sbostic sdone = 0; 436*55997Sbostic } 437*55997Sbostic 438*55997Sbostic static void 439*55997Sbostic lputs(s) 440*55997Sbostic register char *s; 441*55997Sbostic { 442*55997Sbostic register int count; 443*55997Sbostic register char *escapes, *p; 444*55997Sbostic struct winsize win; 445*55997Sbostic static int termwidth = -1; 446*55997Sbostic 447*55997Sbostic if (termwidth == -1) 448*55997Sbostic if (p = getenv("COLUMNS")) 449*55997Sbostic termwidth = atoi(p); 450*55997Sbostic else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 451*55997Sbostic win.ws_col > 0) 452*55997Sbostic termwidth = win.ws_col; 453*55997Sbostic else 454*55997Sbostic termwidth = 60; 455*55997Sbostic 456*55997Sbostic for (count = 0; *s; ++s) { 457*55997Sbostic if (count >= termwidth) { 458*55997Sbostic (void)printf("\\\n"); 459*55997Sbostic count = 0; 460*55997Sbostic } 461*55997Sbostic if (isascii(*s) && isprint(*s) && *s != '\\') { 462*55997Sbostic (void)putchar(*s); 463*55997Sbostic count++; 464*55997Sbostic } else { 465*55997Sbostic escapes = "\\\a\b\f\n\r\t\v"; 466*55997Sbostic (void)putchar('\\'); 467*55997Sbostic if (p = strchr(escapes, *s)) { 468*55997Sbostic (void)putchar("\\abfnrtv"[p - escapes]); 469*55997Sbostic count += 2; 470*55997Sbostic } else { 471*55997Sbostic (void)printf("%03o", (u_char)*s); 472*55997Sbostic count += 4; 473*55997Sbostic } 474*55997Sbostic } 475*55997Sbostic } 476*55997Sbostic (void)putchar('$'); 477*55997Sbostic (void)putchar('\n'); 478*55997Sbostic if (ferror(stdout)) 479*55997Sbostic err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); 480*55997Sbostic } 481*55997Sbostic 482*55997Sbostic /* 483*55997Sbostic * Regexec with checking for errors 484*55997Sbostic */ 485*55997Sbostic static int 486*55997Sbostic regexec_check(preg, string, nmatch, pmatch, eflags) 487*55997Sbostic regex_t *preg; 488*55997Sbostic const char *string; 489*55997Sbostic int nmatch; 490*55997Sbostic regmatch_t pmatch[]; 491*55997Sbostic int eflags; 492*55997Sbostic { 493*55997Sbostic int eval; 494*55997Sbostic 495*55997Sbostic switch (eval = regexec(preg, string, nmatch, pmatch, eflags)) { 496*55997Sbostic case 0: 497*55997Sbostic return (0); 498*55997Sbostic case REG_NOMATCH: 499*55997Sbostic return (REG_NOMATCH); 500*55997Sbostic default: 501*55997Sbostic err(FATAL, "RE error: %s", strregerror(eval, preg)); 502*55997Sbostic } 503*55997Sbostic /* NOTREACHED */ 504*55997Sbostic } 505*55997Sbostic 506*55997Sbostic /* 507*55997Sbostic * regsub - perform substitutions after a regexp match 508*55997Sbostic * Based on a routine by Henry Spencer 509*55997Sbostic */ 510*55997Sbostic static void 511*55997Sbostic regsub(pmatch, string, src, sp) 512*55997Sbostic regmatch_t *pmatch; 513*55997Sbostic char *string, *src; 514*55997Sbostic SPACE *sp; 515*55997Sbostic { 516*55997Sbostic register int len, no; 517*55997Sbostic register char c, *dst; 518*55997Sbostic 519*55997Sbostic #define NEEDSP(reqlen) \ 520*55997Sbostic if (sp->len >= sp->blen - (reqlen) - 1) { \ 521*55997Sbostic sp->blen += (reqlen) + 1024; \ 522*55997Sbostic sp->space = sp->back = xrealloc(sp->back, sp->blen); \ 523*55997Sbostic dst = sp->space + sp->len; \ 524*55997Sbostic } 525*55997Sbostic 526*55997Sbostic dst = sp->space + sp->len; 527*55997Sbostic while ((c = *src++) != '\0') { 528*55997Sbostic if (c == '&') 529*55997Sbostic no = 0; 530*55997Sbostic else if (c == '\\' && isdigit(*src)) 531*55997Sbostic no = *src++ - '0'; 532*55997Sbostic else 533*55997Sbostic no = -1; 534*55997Sbostic if (no < 0) { /* Ordinary character. */ 535*55997Sbostic if (c == '\\' && (*src == '\\' || *src == '&')) 536*55997Sbostic c = *src++; 537*55997Sbostic NEEDSP(1); 538*55997Sbostic *dst++ = c; 539*55997Sbostic ++sp->len; 540*55997Sbostic } else if (pmatch[no].rm_so != -1 && pmatch[no].rm_eo != -1) { 541*55997Sbostic len = pmatch[no].rm_eo - pmatch[no].rm_so; 542*55997Sbostic NEEDSP(len); 543*55997Sbostic memmove(dst, string + pmatch[no].rm_so, len); 544*55997Sbostic dst += len; 545*55997Sbostic sp->len += len; 546*55997Sbostic } 547*55997Sbostic } 548*55997Sbostic NEEDSP(1); 549*55997Sbostic *dst = '\0'; 550*55997Sbostic } 551*55997Sbostic 552*55997Sbostic /* 553*55997Sbostic * aspace -- 554*55997Sbostic * Append the source space to the destination space, allocating new 555*55997Sbostic * space as necessary. 556*55997Sbostic */ 557*55997Sbostic static void 558*55997Sbostic cspace(sp, p, len, append) 559*55997Sbostic SPACE *sp; 560*55997Sbostic char *p; 561*55997Sbostic size_t len; 562*55997Sbostic int append; 563*55997Sbostic { 564*55997Sbostic size_t tlen; 565*55997Sbostic int needcopy; 566*55997Sbostic 567*55997Sbostic /* Current pointer may point to something else at the moment. */ 568*55997Sbostic needcopy = sp->space != sp->back; 569*55997Sbostic 570*55997Sbostic /* 571*55997Sbostic * Make sure SPACE has enough memory and ramp up quickly. 572*55997Sbostic * Add in two extra bytes, one for the newline, one for a 573*55997Sbostic * terminating NULL. 574*55997Sbostic */ 575*55997Sbostic tlen = sp->len + len + 2; 576*55997Sbostic if (tlen > sp->blen) { 577*55997Sbostic sp->blen = tlen + 1024; 578*55997Sbostic sp->back = xrealloc(sp->back, sp->blen); 579*55997Sbostic } 580*55997Sbostic 581*55997Sbostic if (needcopy) 582*55997Sbostic memmove(sp->back, sp->space, sp->len + 1); 583*55997Sbostic sp->space = sp->back; 584*55997Sbostic 585*55997Sbostic /* May just be copying out of a stdio buffer. */ 586*55997Sbostic if (len == NULL) 587*55997Sbostic return; 588*55997Sbostic 589*55997Sbostic /* Append a separating newline. */ 590*55997Sbostic if (append) 591*55997Sbostic sp->space[sp->len++] = '\n'; 592*55997Sbostic 593*55997Sbostic /* Append the new stuff, plus its terminating NULL. */ 594*55997Sbostic memmove(sp->space + sp->len, p, len + 1); 595*55997Sbostic sp->len += len; 596*55997Sbostic } 597*55997Sbostic 598*55997Sbostic /* 599*55997Sbostic * Close all cached opened files and report any errors 600*55997Sbostic */ 601*55997Sbostic void 602*55997Sbostic cfclose(cp) 603*55997Sbostic register struct s_command *cp; 604*55997Sbostic { 605*55997Sbostic 606*55997Sbostic for (; cp != NULL; cp = cp->next) 607*55997Sbostic switch(cp->code) { 608*55997Sbostic case 's': 609*55997Sbostic if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 610*55997Sbostic err(FATAL, 611*55997Sbostic "%s: %s", cp->u.s->wfile, strerror(errno)); 612*55997Sbostic break; 613*55997Sbostic case 'w': 614*55997Sbostic if (cp->u.fd != -1 && close(cp->u.fd)) 615*55997Sbostic err(FATAL, "%s: %s", cp->t, strerror(errno)); 616*55997Sbostic break; 617*55997Sbostic case '{': 618*55997Sbostic cfclose(cp->u.c); 619*55997Sbostic break; 620*55997Sbostic } 621*55997Sbostic } 622