process.c revision 122045
1189747Ssam/*- 2189747Ssam * Copyright (c) 1992 Diomidis Spinellis. 3189747Ssam * Copyright (c) 1992, 1993, 1994 4189747Ssam * The Regents of the University of California. All rights reserved. 5189747Ssam * 6189747Ssam * This code is derived from software contributed to Berkeley by 7189747Ssam * Diomidis Spinellis of Imperial College, University of London. 8189747Ssam * 9189747Ssam * Redistribution and use in source and binary forms, with or without 10189747Ssam * modification, are permitted provided that the following conditions 11189747Ssam * are met: 12189747Ssam * 1. Redistributions of source code must retain the above copyright 13189747Ssam * notice, this list of conditions and the following disclaimer. 14189747Ssam * 2. Redistributions in binary form must reproduce the above copyright 15189747Ssam * notice, this list of conditions and the following disclaimer in the 16189747Ssam * documentation and/or other materials provided with the distribution. 17189747Ssam * 3. All advertising materials mentioning features or use of this software 18189747Ssam * must display the following acknowledgement: 19189747Ssam * This product includes software developed by the University of 20189747Ssam * California, Berkeley and its contributors. 21189747Ssam * 4. Neither the name of the University nor the names of its contributors 22189747Ssam * may be used to endorse or promote products derived from this software 23189747Ssam * without specific prior written permission. 24189747Ssam * 25189747Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26189747Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27217631Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28189747Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29189747Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30189747Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31217631Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32217631Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33189747Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34189747Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35189747Ssam * SUCH DAMAGE. 36189747Ssam */ 37189747Ssam 38189747Ssam#include <sys/cdefs.h> 39189747Ssam__FBSDID("$FreeBSD: head/usr.bin/sed/process.c 122045 2003-11-04 12:16:47Z des $"); 40189747Ssam 41189747Ssam#ifndef lint 42189747Ssamstatic const char sccsid[] = "@(#)process.c 8.6 (Berkeley) 4/20/94"; 43189747Ssam#endif 44189747Ssam 45189747Ssam#include <sys/types.h> 46189747Ssam#include <sys/stat.h> 47189747Ssam#include <sys/ioctl.h> 48189747Ssam#include <sys/uio.h> 49189747Ssam 50189747Ssam#include <ctype.h> 51189747Ssam#include <err.h> 52189747Ssam#include <errno.h> 53189747Ssam#include <fcntl.h> 54189747Ssam#include <limits.h> 55189747Ssam#include <regex.h> 56189747Ssam#include <stdio.h> 57189747Ssam#include <stdlib.h> 58189747Ssam#include <string.h> 59189747Ssam#include <unistd.h> 60189747Ssam 61189747Ssam#include "defs.h" 62189747Ssam#include "extern.h" 63189747Ssam 64189747Ssamstatic SPACE HS, PS, SS; 65189747Ssam#define pd PS.deleted 66189747Ssam#define ps PS.space 67189747Ssam#define psl PS.len 68189747Ssam#define hs HS.space 69189747Ssam#define hsl HS.len 70189747Ssam 71189747Ssamstatic __inline int applies(struct s_command *); 72218183Sadrianstatic void flush_appends(void); 73189747Ssamstatic void lputs(char *); 74189747Ssamstatic __inline int regexec_e(regex_t *, const char *, int, int, size_t); 75189747Ssamstatic void regsub(SPACE *, char *, char *); 76189747Ssamstatic int substitute(struct s_command *); 77189747Ssam 78189747Ssamstruct s_appends *appends; /* Array of pointers to strings to append. */ 79189747Ssamstatic int appendx; /* Index into appends array. */ 80217624Sadrianint appendnum; /* Size of appends array. */ 81217624Sadrian 82189747Ssamstatic int lastaddr; /* Set by applies if last address of a range. */ 83189747Ssamstatic int sdone; /* If any substitutes since last line input. */ 84189747Ssam /* Iov structure for 'w' commands. */ 85189747Ssamstatic regex_t *defpreg; 86189747Ssamsize_t maxnsub; 87189747Ssamregmatch_t *match; 88189747Ssam 89189747Ssam#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); putchar('\n'); } 90189747Ssam 91189747Ssamvoid 92189747Ssamprocess(void) 93189747Ssam{ 94189747Ssam struct s_command *cp; 95189747Ssam SPACE tspace; 96189747Ssam size_t len, oldpsl = 0; 97189747Ssam char *p; 98189747Ssam 99189747Ssam p = NULL; 100189747Ssam 101189747Ssam for (linenum = 0; mf_fgets(&PS, REPLACE);) { 102189747Ssam pd = 0; 103189747Ssamtop: 104189747Ssam cp = prog; 105189747Ssamredirect: 106189747Ssam while (cp != NULL) { 107189747Ssam if (!applies(cp)) { 108189747Ssam cp = cp->next; 109189747Ssam continue; 110189747Ssam } 111189747Ssam switch (cp->code) { 112189747Ssam case '{': 113189747Ssam cp = cp->u.c; 114189747Ssam goto redirect; 115189747Ssam case 'a': 116189747Ssam if (appendx >= appendnum) 117189747Ssam if ((appends = realloc(appends, 118189747Ssam sizeof(struct s_appends) * 119189747Ssam (appendnum *= 2))) == NULL) 120189747Ssam err(1, "realloc"); 121189747Ssam appends[appendx].type = AP_STRING; 122189747Ssam appends[appendx].s = cp->t; 123189747Ssam appends[appendx].len = strlen(cp->t); 124189747Ssam appendx++; 125189747Ssam break; 126189747Ssam case 'b': 127189747Ssam cp = cp->u.c; 128189747Ssam goto redirect; 129189747Ssam case 'c': 130189747Ssam pd = 1; 131189747Ssam psl = 0; 132189747Ssam if (cp->a2 == NULL || lastaddr) 133189747Ssam (void)printf("%s", cp->t); 134189747Ssam break; 135189747Ssam case 'd': 136189747Ssam pd = 1; 137189747Ssam goto new; 138189747Ssam case 'D': 139189747Ssam if (pd) 140189747Ssam goto new; 141189747Ssam if (psl == 0 || 142189747Ssam (p = memchr(ps, '\n', psl)) == NULL) { 143189747Ssam pd = 1; 144189747Ssam goto new; 145189747Ssam } else { 146189747Ssam psl -= (p + 1) - ps; 147189747Ssam memmove(ps, p + 1, psl); 148189747Ssam goto top; 149203882Srpaulo } 150189747Ssam case 'g': 151189747Ssam cspace(&PS, hs, hsl, REPLACE); 152189747Ssam break; 153189747Ssam case 'G': 154189747Ssam cspace(&PS, "\n", 1, 0); 155189747Ssam cspace(&PS, hs, hsl, 0); 156189747Ssam break; 157189747Ssam case 'h': 158189747Ssam cspace(&HS, ps, psl, REPLACE); 159189747Ssam break; 160189747Ssam case 'H': 161189747Ssam cspace(&HS, "\n", 1, 0); 162189747Ssam cspace(&HS, ps, psl, 0); 163189747Ssam break; 164203882Srpaulo case 'i': 165189747Ssam (void)printf("%s", cp->t); 166189747Ssam break; 167189747Ssam case 'l': 168189747Ssam lputs(ps); 169189747Ssam break; 170189747Ssam case 'n': 171189747Ssam if (!nflag && !pd) 172189747Ssam OUT(ps) 173189747Ssam flush_appends(); 174189747Ssam if (!mf_fgets(&PS, REPLACE)) 175189747Ssam exit(0); 176189747Ssam pd = 0; 177189747Ssam break; 178189747Ssam case 'N': 179189747Ssam flush_appends(); 180189747Ssam cspace(&PS, "\n", 1, 0); 181189747Ssam if (!mf_fgets(&PS, 0)) 182189747Ssam exit(0); 183189747Ssam break; 184189747Ssam case 'p': 185189747Ssam if (pd) 186189747Ssam break; 187189747Ssam OUT(ps) 188189747Ssam break; 189189747Ssam case 'P': 190189747Ssam if (pd) 191189747Ssam break; 192189747Ssam if (psl != 0 && 193189747Ssam (p = memchr(ps, '\n', psl)) != NULL) { 194189747Ssam oldpsl = psl; 195189747Ssam psl = p - ps; 196189747Ssam } 197189747Ssam OUT(ps) 198189747Ssam if (p != NULL) 199189747Ssam psl = oldpsl; 200189747Ssam break; 201189747Ssam case 'q': 202189747Ssam if (!nflag && !pd) 203189747Ssam OUT(ps) 204189747Ssam flush_appends(); 205189747Ssam exit(0); 206189747Ssam case 'r': 207189747Ssam if (appendx >= appendnum) 208189747Ssam if ((appends = realloc(appends, 209189747Ssam sizeof(struct s_appends) * 210189747Ssam (appendnum *= 2))) == NULL) 211189747Ssam err(1, "realloc"); 212189747Ssam appends[appendx].type = AP_FILE; 213189747Ssam appends[appendx].s = cp->t; 214189747Ssam appends[appendx].len = strlen(cp->t); 215189747Ssam appendx++; 216189747Ssam break; 217189747Ssam case 's': 218189747Ssam sdone |= substitute(cp); 219189747Ssam break; 220189747Ssam case 't': 221189747Ssam if (sdone) { 222189747Ssam sdone = 0; 223189747Ssam cp = cp->u.c; 224189747Ssam goto redirect; 225189747Ssam } 226189747Ssam break; 227189747Ssam case 'w': 228189747Ssam if (pd) 229189747Ssam break; 230189747Ssam if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, 231189747Ssam O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 232189747Ssam DEFFILEMODE)) == -1) 233189747Ssam err(1, "%s", cp->t); 234189747Ssam if (write(cp->u.fd, ps, psl) != psl || 235189747Ssam write(cp->u.fd, "\n", 1) != 1) 236189747Ssam err(1, "%s", cp->t); 237203882Srpaulo break; 238189747Ssam case 'x': 239189747Ssam if (hs == NULL) 240189747Ssam cspace(&HS, "", 0, REPLACE); 241189747Ssam tspace = PS; 242189747Ssam PS = HS; 243189747Ssam HS = tspace; 244189747Ssam break; 245189747Ssam case 'y': 246189747Ssam if (pd || psl == 0) 247189747Ssam break; 248189747Ssam for (p = ps, len = psl; len--; ++p) 249189747Ssam *p = cp->u.y[(unsigned char)*p]; 250189747Ssam break; 251189747Ssam case ':': 252189747Ssam case '}': 253189747Ssam break; 254189747Ssam case '=': 255189747Ssam (void)printf("%lu\n", linenum); 256189747Ssam } 257189747Ssam cp = cp->next; 258189747Ssam } /* for all cp */ 259189747Ssam 260189747Ssamnew: if (!nflag && !pd) 261189747Ssam OUT(ps) 262189747Ssam flush_appends(); 263189747Ssam } /* for all lines */ 264189747Ssam} 265189747Ssam 266189747Ssam/* 267189747Ssam * TRUE if the address passed matches the current program state 268189747Ssam * (lastline, linenumber, ps). 269189747Ssam */ 270189747Ssam#define MATCH(a) \ 271189747Ssam (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \ 272189747Ssam (a)->type == AT_LINE ? linenum == (a)->u.l : lastline() 273189747Ssam 274189747Ssam/* 275189747Ssam * Return TRUE if the command applies to the current line. Sets the inrange 276189747Ssam * flag to process ranges. Interprets the non-select (``!'') flag. 277189747Ssam */ 278189747Ssamstatic __inline int 279189747Ssamapplies(struct s_command *cp) 280189747Ssam{ 281189747Ssam int r; 282189747Ssam 283218068Sadrian lastaddr = 0; 284218068Sadrian if (cp->a1 == NULL && cp->a2 == NULL) 285218068Sadrian r = 1; 286218068Sadrian else if (cp->a2) 287218068Sadrian if (cp->inrange) { 288218068Sadrian if (MATCH(cp->a2)) { 289218068Sadrian cp->inrange = 0; 290218068Sadrian lastaddr = 1; 291218068Sadrian } 292203882Srpaulo r = 1; 293189747Ssam } else if (MATCH(cp->a1)) { 294189747Ssam /* 295189747Ssam * If the second address is a number less than or 296189747Ssam * equal to the line number first selected, only 297189747Ssam * one line shall be selected. 298189747Ssam * -- POSIX 1003.2 299189747Ssam */ 300189747Ssam if (cp->a2->type == AT_LINE && 301189747Ssam linenum >= cp->a2->u.l) 302189747Ssam lastaddr = 1; 303189747Ssam else 304189747Ssam cp->inrange = 1; 305189747Ssam r = 1; 306189747Ssam } else 307189747Ssam r = 0; 308189747Ssam else 309189747Ssam r = MATCH(cp->a1); 310189747Ssam return (cp->nonsel ? ! r : r); 311189747Ssam} 312203882Srpaulo 313189747Ssam/* 314189747Ssam * substitute -- 315189747Ssam * Do substitutions in the pattern space. Currently, we build a 316189747Ssam * copy of the new pattern space in the substitute space structure 317189747Ssam * and then swap them. 318189747Ssam */ 319189747Ssamstatic int 320189747Ssamsubstitute(struct s_command *cp) 321189747Ssam{ 322189747Ssam SPACE tspace; 323189747Ssam regex_t *re; 324189747Ssam regoff_t re_off, slen; 325189747Ssam int lastempty, n; 326189747Ssam char *s; 327189747Ssam 328189747Ssam s = ps; 329189747Ssam re = cp->u.s->re; 330189747Ssam if (re == NULL) { 331189747Ssam if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { 332189747Ssam linenum = cp->u.s->linenum; 333189747Ssam errx(1, "%lu: %s: \\%d not defined in the RE", 334189747Ssam linenum, fname, cp->u.s->maxbref); 335189747Ssam } 336189747Ssam } 337189747Ssam if (!regexec_e(re, s, 0, 0, psl)) 338189747Ssam return (0); 339189747Ssam 340189747Ssam SS.len = 0; /* Clean substitute space. */ 341189747Ssam slen = psl; 342189747Ssam n = cp->u.s->n; 343189747Ssam lastempty = 1; 344189747Ssam 345189747Ssam switch (n) { 346189747Ssam case 0: /* Global */ 347189747Ssam do { 348189747Ssam if (lastempty || match[0].rm_so != match[0].rm_eo) { 349189747Ssam /* Locate start of replaced string. */ 350189747Ssam re_off = match[0].rm_so; 351189747Ssam /* Copy leading retained string. */ 352189747Ssam cspace(&SS, s, re_off, APPEND); 353189747Ssam /* Add in regular expression. */ 354189747Ssam regsub(&SS, s, cp->u.s->new); 355189747Ssam } 356189747Ssam 357189747Ssam /* Move past this match. */ 358189747Ssam if (match[0].rm_so != match[0].rm_eo) { 359189747Ssam s += match[0].rm_eo; 360189747Ssam slen -= match[0].rm_eo; 361189747Ssam lastempty = 0; 362189747Ssam } else { 363189747Ssam if (match[0].rm_so < slen) 364189747Ssam cspace(&SS, s + match[0].rm_so, 1, 365189747Ssam APPEND); 366189747Ssam s += match[0].rm_so + 1; 367189747Ssam slen -= match[0].rm_so + 1; 368189747Ssam lastempty = 1; 369189747Ssam } 370189747Ssam } while (slen >= 0 && regexec_e(re, s, REG_NOTBOL, 0, slen)); 371203930Srpaulo /* Copy trailing retained string. */ 372189747Ssam if (slen > 0) 373189747Ssam cspace(&SS, s, slen, APPEND); 374189747Ssam break; 375189747Ssam default: /* Nth occurrence */ 376189747Ssam while (--n) { 377189747Ssam if (match[0].rm_eo == match[0].rm_so) 378189747Ssam match[0].rm_eo = match[0].rm_so + 1; 379189747Ssam s += match[0].rm_eo; 380189747Ssam slen -= match[0].rm_eo; 381189747Ssam if (slen < 0) 382189747Ssam return (0); 383189747Ssam if (!regexec_e(re, s, REG_NOTBOL, 0, slen)) 384189747Ssam return (0); 385189747Ssam } 386189747Ssam /* FALLTHROUGH */ 387189747Ssam case 1: /* 1st occurrence */ 388189747Ssam /* Locate start of replaced string. */ 389189747Ssam re_off = match[0].rm_so + (s - ps); 390189747Ssam /* Copy leading retained string. */ 391189747Ssam cspace(&SS, ps, re_off, APPEND); 392189747Ssam /* Add in regular expression. */ 393189747Ssam regsub(&SS, s, cp->u.s->new); 394189747Ssam /* Copy trailing retained string. */ 395189747Ssam s += match[0].rm_eo; 396189747Ssam slen -= match[0].rm_eo; 397189747Ssam cspace(&SS, s, slen, APPEND); 398189747Ssam break; 399189747Ssam } 400189747Ssam 401189747Ssam /* 402189747Ssam * Swap the substitute space and the pattern space, and make sure 403189747Ssam * that any leftover pointers into stdio memory get lost. 404189747Ssam */ 405189747Ssam tspace = PS; 406189747Ssam PS = SS; 407189747Ssam SS = tspace; 408189747Ssam SS.space = SS.back; 409189747Ssam 410189747Ssam /* Handle the 'p' flag. */ 411189747Ssam if (cp->u.s->p) 412189747Ssam OUT(ps) 413189747Ssam 414189747Ssam /* Handle the 'w' flag. */ 415189747Ssam if (cp->u.s->wfile && !pd) { 416189747Ssam if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, 417189747Ssam O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) 418189747Ssam err(1, "%s", cp->u.s->wfile); 419189747Ssam if (write(cp->u.s->wfd, ps, psl) != psl || 420189747Ssam write(cp->u.s->wfd, "\n", 1) != 1) 421189747Ssam err(1, "%s", cp->u.s->wfile); 422189747Ssam } 423189747Ssam return (1); 424189747Ssam} 425189747Ssam 426189747Ssam/* 427189747Ssam * Flush append requests. Always called before reading a line, 428189747Ssam * therefore it also resets the substitution done (sdone) flag. 429189747Ssam */ 430189747Ssamstatic void 431189747Ssamflush_appends(void) 432189747Ssam{ 433189747Ssam FILE *f; 434189747Ssam int count, i; 435189747Ssam char buf[8 * 1024]; 436189747Ssam 437189747Ssam for (i = 0; i < appendx; i++) 438189747Ssam switch (appends[i].type) { 439189747Ssam case AP_STRING: 440189747Ssam fwrite(appends[i].s, sizeof(char), appends[i].len, 441189747Ssam stdout); 442189747Ssam break; 443189747Ssam case AP_FILE: 444189747Ssam /* 445189747Ssam * Read files probably shouldn't be cached. Since 446189747Ssam * it's not an error to read a non-existent file, 447189747Ssam * it's possible that another program is interacting 448189747Ssam * with the sed script through the filesystem. It 449189747Ssam * would be truly bizarre, but possible. It's probably 450189747Ssam * not that big a performance win, anyhow. 451189747Ssam */ 452189747Ssam if ((f = fopen(appends[i].s, "r")) == NULL) 453189747Ssam break; 454189747Ssam while ((count = fread(buf, sizeof(char), sizeof(buf), f))) 455189747Ssam (void)fwrite(buf, sizeof(char), count, stdout); 456189747Ssam (void)fclose(f); 457189747Ssam break; 458189747Ssam } 459189747Ssam if (ferror(stdout)) 460189747Ssam errx(1, "stdout: %s", strerror(errno ? errno : EIO)); 461189747Ssam appendx = sdone = 0; 462189747Ssam} 463189747Ssam 464189747Ssamstatic void 465189747Ssamlputs(char *s) 466189747Ssam{ 467189747Ssam int count; 468189747Ssam const char *escapes; 469189747Ssam char *p; 470189747Ssam struct winsize win; 471189747Ssam static int termwidth = -1; 472189747Ssam 473189747Ssam if (termwidth == -1) { 474189747Ssam if ((p = getenv("COLUMNS")) && *p != '\0') 475189747Ssam termwidth = atoi(p); 476189747Ssam else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && 477189747Ssam win.ws_col > 0) 478189747Ssam termwidth = win.ws_col; 479189747Ssam else 480189747Ssam termwidth = 60; 481189747Ssam } 482189747Ssam 483189747Ssam for (count = 0; *s; ++s) { 484189747Ssam if (count + 5 >= termwidth) { 485189747Ssam (void)printf("\\\n"); 486189747Ssam count = 0; 487189747Ssam } 488189747Ssam if (isprint((unsigned char)*s) && *s != '\\') { 489189747Ssam (void)putchar(*s); 490189747Ssam count++; 491189747Ssam } else if (*s == '\n') { 492189747Ssam (void)putchar('$'); 493189747Ssam (void)putchar('\n'); 494189747Ssam count = 0; 495189747Ssam } else { 496189747Ssam escapes = "\\\a\b\f\r\t\v"; 497189747Ssam (void)putchar('\\'); 498189747Ssam if ((p = strchr(escapes, *s))) { 499189747Ssam (void)putchar("\\abfrtv"[p - escapes]); 500189747Ssam count += 2; 501189747Ssam } else { 502189747Ssam (void)printf("%03o", *(u_char *)s); 503189747Ssam count += 4; 504189747Ssam } 505189747Ssam } 506189747Ssam } 507189747Ssam (void)putchar('$'); 508189747Ssam (void)putchar('\n'); 509189747Ssam if (ferror(stdout)) 510189747Ssam errx(1, "stdout: %s", strerror(errno ? errno : EIO)); 511189747Ssam} 512189747Ssam 513189747Ssamstatic __inline int 514189747Ssamregexec_e(regex_t *preg, const char *string, int eflags, int nomatch, 515189747Ssam size_t slen) 516189747Ssam{ 517189747Ssam int eval; 518189747Ssam 519189747Ssam if (preg == NULL) { 520189747Ssam if (defpreg == NULL) 521189747Ssam errx(1, "first RE may not be empty"); 522189747Ssam } else 523189747Ssam defpreg = preg; 524189747Ssam 525189747Ssam /* Set anchors */ 526189747Ssam match[0].rm_so = 0; 527189747Ssam match[0].rm_eo = slen; 528189747Ssam 529189747Ssam eval = regexec(defpreg, string, 530189747Ssam nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND); 531189747Ssam switch(eval) { 532189747Ssam case 0: 533189747Ssam return (1); 534189747Ssam case REG_NOMATCH: 535189747Ssam return (0); 536189747Ssam } 537189747Ssam errx(1, "RE error: %s", strregerror(eval, defpreg)); 538189747Ssam /* NOTREACHED */ 539189747Ssam} 540189747Ssam 541189747Ssam/* 542189747Ssam * regsub - perform substitutions after a regexp match 543189747Ssam * Based on a routine by Henry Spencer 544189747Ssam */ 545189747Ssamstatic void 546189747Ssamregsub(SPACE *sp, char *string, char *src) 547189747Ssam{ 548189747Ssam int len, no; 549189747Ssam char c, *dst; 550189747Ssam 551189747Ssam#define NEEDSP(reqlen) \ 552189747Ssam /* XXX What is the +1 for? */ \ 553189747Ssam if (sp->len + (reqlen) + 1 >= sp->blen) { \ 554189747Ssam sp->blen += (reqlen) + 1024; \ 555189747Ssam if ((sp->space = sp->back = realloc(sp->back, sp->blen)) \ 556189747Ssam == NULL) \ 557189747Ssam err(1, "realloc"); \ 558189747Ssam dst = sp->space + sp->len; \ 559189747Ssam } 560189747Ssam 561189747Ssam dst = sp->space + sp->len; 562189747Ssam while ((c = *src++) != '\0') { 563189747Ssam if (c == '&') 564189747Ssam no = 0; 565189747Ssam else if (c == '\\' && isdigit((unsigned char)*src)) 566189747Ssam no = *src++ - '0'; 567189747Ssam else 568189747Ssam no = -1; 569189747Ssam if (no < 0) { /* Ordinary character. */ 570189747Ssam if (c == '\\' && (*src == '\\' || *src == '&')) 571189747Ssam c = *src++; 572189747Ssam NEEDSP(1); 573189747Ssam *dst++ = c; 574189747Ssam ++sp->len; 575189747Ssam } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) { 576189747Ssam len = match[no].rm_eo - match[no].rm_so; 577189747Ssam NEEDSP(len); 578189747Ssam memmove(dst, string + match[no].rm_so, len); 579189747Ssam dst += len; 580189747Ssam sp->len += len; 581189747Ssam } 582189747Ssam } 583189747Ssam NEEDSP(1); 584189747Ssam *dst = '\0'; 585189747Ssam} 586189747Ssam 587189747Ssam/* 588189747Ssam * aspace -- 589189747Ssam * Append the source space to the destination space, allocating new 590189747Ssam * space as necessary. 591189747Ssam */ 592189747Ssamvoid 593189747Ssamcspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag) 594189747Ssam{ 595189747Ssam size_t tlen; 596189747Ssam 597189747Ssam /* Make sure SPACE has enough memory and ramp up quickly. */ 598189747Ssam tlen = sp->len + len + 1; 599189747Ssam if (tlen > sp->blen) { 600189747Ssam sp->blen = tlen + 1024; 601189747Ssam if ((sp->space = sp->back = realloc(sp->back, sp->blen)) == 602189747Ssam NULL) 603189747Ssam err(1, "realloc"); 604189747Ssam } 605189747Ssam 606189747Ssam if (spflag == REPLACE) 607189747Ssam sp->len = 0; 608189747Ssam 609189747Ssam memmove(sp->space + sp->len, p, len); 610189747Ssam 611189747Ssam sp->space[sp->len += len] = '\0'; 612189747Ssam} 613189747Ssam 614189747Ssam/* 615189747Ssam * Close all cached opened files and report any errors 616189747Ssam */ 617189747Ssamvoid 618189747Ssamcfclose(struct s_command *cp, struct s_command *end) 619189747Ssam{ 620189747Ssam 621189747Ssam for (; cp != end; cp = cp->next) 622189747Ssam switch(cp->code) { 623189747Ssam case 's': 624189747Ssam if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) 625189747Ssam err(1, "%s", cp->u.s->wfile); 626189747Ssam cp->u.s->wfd = -1; 627189747Ssam break; 628189747Ssam case 'w': 629189747Ssam if (cp->u.fd != -1 && close(cp->u.fd)) 630189747Ssam err(1, "%s", cp->t); 631189747Ssam cp->u.fd = -1; 632189747Ssam break; 633189747Ssam case '{': 634189747Ssam cfclose(cp->u.c, cp->next); 635189747Ssam break; 636189747Ssam } 637189747Ssam} 638189747Ssam