sub.c revision 1297
178189Sbrian/* sub.c: This file contains the substitution routines for the ed 278189Sbrian line editor */ 378189Sbrian/*- 478189Sbrian * Copyright (c) 1993 Andrew Moore, Talke Studio. 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai */ 2850479Speter 296059Samurai#ifndef lint 3078189Sbrianstatic char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp"; 3143313Sbrian#endif /* not lint */ 3230715Sbrian 3330715Sbrian#include "ed.h" 3430715Sbrian 3581634Sbrian 3636285Sbrianchar *rhbuf; /* rhs substitution buffer */ 3730715Sbrianint rhbufsz; /* rhs substitution buffer size */ 3831061Sbrianint rhbufi; /* rhs substitution buffer index */ 3949472Sbrian 4046686Sbrian/* extract_subst_tail: extract substitution tail from the command buffer */ 4130715Sbrianint 4246686Sbrianextract_subst_tail(flagp, np) 4330715Sbrian int *flagp; 4430715Sbrian int *np; 4530715Sbrian{ 466059Samurai char delimiter; 4746686Sbrian 486059Samurai *flagp = *np = 0; 4936285Sbrian if ((delimiter = *ibufp) == '\n') { 506059Samurai rhbufi = 0; 5136285Sbrian *flagp = GPR; 5236285Sbrian return 0; 5336285Sbrian } else if (extract_subst_template() == NULL) 5481634Sbrian return ERR; 5581634Sbrian else if (*ibufp == '\n') { 566059Samurai *flagp = GPR; 5736285Sbrian return 0; 5836285Sbrian } else if (*ibufp == delimiter) 5936285Sbrian ibufp++; 6036285Sbrian if ('1' <= *ibufp && *ibufp <= '9') { 6136285Sbrian STRTOL(*np, ibufp); 6236285Sbrian return 0; 6343313Sbrian } else if (*ibufp == 'g') { 6443313Sbrian ibufp++; 6543313Sbrian *flagp = GSG; 6681634Sbrian return 0; 6781634Sbrian } 6836285Sbrian return 0; 6930715Sbrian} 706059Samurai 7128679Sbrian 726059Samurai/* extract_subst_template: return pointer to copy of substitution template 7346686Sbrian in the command buffer */ 7446686Sbrianchar * 7546686Sbrianextract_subst_template() 766059Samurai{ 776059Samurai int n = 0; 7845103Sbrian int i = 0; 7936285Sbrian char c; 806059Samurai char delimiter = *ibufp++; 8154912Sbrian 8245103Sbrian if (*ibufp == '%' && *(ibufp + 1) == delimiter) { 8346686Sbrian ibufp++; 8446686Sbrian if (!rhbuf) sprintf(errmsg, "no previous substitution"); 8545103Sbrian return rhbuf; 8636285Sbrian } 8736285Sbrian while (*ibufp != delimiter) { 8846686Sbrian REALLOC(rhbuf, rhbufsz, i + 2, NULL); 896059Samurai if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') { 906059Samurai i--, ibufp--; 916059Samurai break; 9246686Sbrian } else if (c != '\\') 936059Samurai ; 9446686Sbrian else if ((rhbuf[i++] = *ibufp++) != '\n') 9547061Sbrian ; 9654912Sbrian else if (!isglobal) { 976059Samurai while ((n = get_tty_line()) == 0 || 9846686Sbrian n > 0 && ibuf[n - 1] != '\n') 996059Samurai clearerr(stdin); 10046686Sbrian if (n < 0) 10147061Sbrian return NULL; 10254912Sbrian } 1036059Samurai } 10446686Sbrian REALLOC(rhbuf, rhbufsz, i + 1, NULL); 1056059Samurai rhbuf[rhbufi = i] = '\0'; 10647061Sbrian return rhbuf; 10754912Sbrian} 10846686Sbrian 1096059Samurai 11046686Sbrianchar *rbuf; /* substitute_matching_text buffer */ 11136285Sbrianint rbufsz; /* substitute_matching_text buffer size */ 11246686Sbrian 1136059Samurai/* search_and_replace: for each line in a range, change text matching a pattern 1146059Samurai according to a substitution template; return status */ 1156059Samuraiint 11646828Sbriansearch_and_replace(pat, gflag, kth) 1176059Samurai pattern_t *pat; 1186059Samurai int gflag; 1196059Samurai int kth; 12028679Sbrian{ 1216059Samurai undo_t *up; 12254912Sbrian char *txt; 12354912Sbrian char *eot; 1246059Samurai long lc; 1256059Samurai int nsubs = 0; 12628679Sbrian line_t *lp; 12728679Sbrian int len; 1286059Samurai 1296059Samurai current_addr = first_addr - 1; 13036960Sbrian for (lc = 0; lc <= second_addr - first_addr; lc++) { 13136960Sbrian lp = get_addressed_line_node(++current_addr); 1326735Samurai if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0) 13354912Sbrian return ERR; 13432663Sbrian else if (len) { 13547695Sbrian up = NULL; 13654912Sbrian if (delete_lines(current_addr, current_addr) < 0) 13746686Sbrian return ERR; 1386059Samurai txt = rbuf; 13928679Sbrian eot = rbuf + len; 1406059Samurai SPL1(); 14128679Sbrian do { 14293465Sbrian if ((txt = put_sbuf_line(txt)) == NULL) { 14328679Sbrian SPL0(); 1446059Samurai return ERR; 14528679Sbrian } else if (up) 14628679Sbrian up->t = get_addressed_line_node(current_addr); 1476059Samurai else if ((up = push_undo_stack(UADD, 1486059Samurai current_addr, current_addr)) == NULL) { 14936285Sbrian SPL0(); 15036960Sbrian return ERR; 15136960Sbrian } 1526735Samurai } while (txt != eot); 15354912Sbrian SPL0(); 15432663Sbrian nsubs++; 1556735Samurai } 1566059Samurai } 1576059Samurai if (nsubs == 0 && !(gflag & GLB)) { 15854913Sbrian sprintf(errmsg, "no match"); 15954913Sbrian return ERR; 16054912Sbrian } else if ((gflag & (GPR | GLS | GNP)) && 16154913Sbrian display_lines(current_addr, current_addr, gflag) < 0) 16254913Sbrian return ERR; 1636059Samurai return 0; 1646059Samurai} 16546686Sbrian 16646686Sbrian 16746686Sbrian/* substitute_matching_text: replace text matched by a pattern according to 1686059Samurai a substitution template; return pointer to the modified text */ 1696059Samuraiint 1706059Samuraisubstitute_matching_text(pat, lp, gflag, kth) 17146686Sbrian pattern_t *pat; 1726059Samurai line_t *lp; 1736059Samurai int gflag; 17447061Sbrian int kth; 1756059Samurai{ 1766059Samurai int off = 0; 1776059Samurai int changed = 0; 17847061Sbrian int matchno = 0; 1796059Samurai int i = 0; 1806059Samurai regmatch_t rm[SE_MAX]; 18146686Sbrian char *txt; 1826059Samurai char *eot; 18346686Sbrian 18446686Sbrian if ((txt = get_sbuf_line(lp)) == NULL) 18546686Sbrian return ERR; 1866059Samurai if (isbinary) 18731514Sbrian NUL_TO_NEWLINE(txt, lp->len); 18831514Sbrian eot = txt + lp->len; 18932439Sbrian if (!regexec(pat, txt, SE_MAX, rm, 0)) { 19031514Sbrian do { 19137010Sbrian if (!kth || kth == ++matchno) { 19231514Sbrian changed++; 19336285Sbrian i = rm[0].rm_so; 19446686Sbrian REALLOC(rbuf, rbufsz, off + i, ERR); 19546686Sbrian if (isbinary) 19636285Sbrian NEWLINE_TO_NUL(txt, rm[0].rm_eo); 19736285Sbrian memcpy(rbuf + off, txt, i); 19831514Sbrian off += i; 19931514Sbrian if ((off = apply_subst_template(txt, rm, off, 20046686Sbrian pat->re_nsub)) < 0) 20146686Sbrian return ERR; 202 } else { 203 i = rm[0].rm_eo; 204 REALLOC(rbuf, rbufsz, off + i, ERR); 205 if (isbinary) 206 NEWLINE_TO_NUL(txt, i); 207 memcpy(rbuf + off, txt, i); 208 off += i; 209 } 210 txt += rm[0].rm_eo; 211 } while (*txt && (!changed || (gflag & GSG) && rm[0].rm_eo) && 212 !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL)); 213 i = eot - txt; 214 REALLOC(rbuf, rbufsz, off + i + 2, ERR); 215 if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) { 216 sprintf(errmsg, "infinite substitution loop"); 217 return ERR; 218 } 219 if (isbinary) 220 NEWLINE_TO_NUL(txt, i); 221 memcpy(rbuf + off, txt, i); 222 memcpy(rbuf + off + i, "\n", 2); 223 } 224 return changed ? off + i + 1 : 0; 225} 226 227 228/* apply_subst_template: modify text according to a substitution template; 229 return offset to end of modified text */ 230int 231apply_subst_template(boln, rm, off, re_nsub) 232 char *boln; 233 regmatch_t *rm; 234 int off; 235 int re_nsub; 236{ 237 int j = 0; 238 int k = 0; 239 int n; 240 char *sub = rhbuf; 241 242 for (; sub - rhbuf < rhbufi; sub++) 243 if (*sub == '&') { 244 j = rm[0].rm_so; 245 k = rm[0].rm_eo; 246 REALLOC(rbuf, rbufsz, off + k - j, ERR); 247 while (j < k) 248 rbuf[off++] = boln[j++]; 249 } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' && 250 (n = *sub - '0') <= re_nsub) { 251 j = rm[n].rm_so; 252 k = rm[n].rm_eo; 253 REALLOC(rbuf, rbufsz, off + k - j, ERR); 254 while (j < k) 255 rbuf[off++] = boln[j++]; 256 } else { 257 REALLOC(rbuf, rbufsz, off + 1, ERR); 258 rbuf[off++] = *sub; 259 } 260 REALLOC(rbuf, rbufsz, off + 1, ERR); 261 rbuf[off] = '\0'; 262 return off; 263} 264