sub.c revision 1057
1/* sub.c: This file contains the substitution routines for the ed 2 line editor */ 3/*- 4 * Copyright (c) 1993 Andrew Moore, Talke Studio. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#ifndef lint 30static char *rcsid = "@(#)$Id: sub.c,v 1.3 1993/12/15 15:22:02 alm Exp alm $"; 31#endif /* not lint */ 32 33#include "ed.h" 34 35 36char *rhbuf; /* rhs substitution buffer */ 37int rhbufsz; /* rhs substitution buffer size */ 38int rhbufi; /* rhs substitution buffer index */ 39 40/* extract_subst_tail: extract substitution tail from the command buffer */ 41int 42extract_subst_tail(flagp, np) 43 int *flagp; 44 int *np; 45{ 46 char delimiter; 47 48 *flagp = *np = 0; 49 if ((delimiter = *ibufp) == '\n') { 50 rhbufi = 0; 51 *flagp = GPR; 52 return 0; 53 } else if (extract_subst_template() == NULL) 54 return ERR; 55 else if (*ibufp == '\n') { 56 *flagp = GPR; 57 return 0; 58 } else if (*ibufp == delimiter) 59 ibufp++; 60 if ('1' <= *ibufp && *ibufp <= '9') { 61 STRTOL(*np, ibufp); 62 return 0; 63 } else if (*ibufp == 'g') { 64 ibufp++; 65 *flagp = GSG; 66 return 0; 67 } 68 return 0; 69} 70 71 72/* extract_subst_template: return pointer to copy of substitution template 73 in the command buffer */ 74char * 75extract_subst_template() 76{ 77 int n = 0; 78 int i = 0; 79 char c; 80 char delimiter = *ibufp++; 81 82 if (*ibufp == '%' && *(ibufp + 1) == delimiter) { 83 ibufp++; 84 if (!rhbuf) sprintf(errmsg, "no previous substitution"); 85 return rhbuf; 86 } 87 while (*ibufp != delimiter) { 88 REALLOC(rhbuf, rhbufsz, i + 2, NULL); 89 if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') { 90 i--, ibufp--; 91 break; 92 } else if (c != '\\') 93 ; 94 else if ((rhbuf[i++] = *ibufp++) != '\n') 95 ; 96 else if (!isglobal) { 97 while ((n = get_tty_line()) == 0 || 98 n > 0 && ibuf[n - 1] != '\n') 99 clearerr(stdin); 100 if (n < 0) 101 return NULL; 102 } 103 } 104 REALLOC(rhbuf, rhbufsz, i + 1, NULL); 105 rhbuf[rhbufi = i] = '\0'; 106 return rhbuf; 107} 108 109 110char *rbuf; /* substitute_matching_text buffer */ 111int rbufsz; /* substitute_matching_text buffer size */ 112 113/* search_and_replace: for each line in a range, change text matching a pattern 114 according to a substitution template; return status */ 115int 116search_and_replace(pat, gflag, kth) 117 pattern_t *pat; 118 int gflag; 119 int kth; 120{ 121 undo_t *up; 122 char *txt; 123 char *eot; 124 long lc; 125 int nsubs = 0; 126 line_t *lp; 127 int len; 128 129 current_addr = first_addr - 1; 130 for (lc = 0; lc <= second_addr - first_addr; lc++) { 131 lp = get_addressed_line_node(++current_addr); 132 if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0) 133 return ERR; 134 else if (len) { 135 up = NULL; 136 if (delete_lines(current_addr, current_addr) < 0) 137 return ERR; 138 txt = rbuf; 139 eot = rbuf + len; 140 SPL1(); 141 do { 142 if ((txt = put_sbuf_line(txt)) == NULL) { 143 SPL0(); 144 return ERR; 145 } else if (up) 146 up->t = get_addressed_line_node(current_addr); 147 else if ((up = push_undo_stack(UADD, 148 current_addr, current_addr)) == NULL) { 149 SPL0(); 150 return ERR; 151 } 152 } while (txt != eot); 153 SPL0(); 154 nsubs++; 155 } 156 } 157 if (nsubs == 0 && !(gflag & GLB)) { 158 sprintf(errmsg, "no match"); 159 return ERR; 160 } else if ((gflag & (GPR | GLS | GNP)) && 161 display_lines(current_addr, current_addr, gflag) < 0) 162 return ERR; 163 return 0; 164} 165 166 167/* substitute_matching_text: replace text matched by a pattern according to 168 a substitution template; return pointer to the modified text */ 169int 170substitute_matching_text(pat, lp, gflag, kth) 171 pattern_t *pat; 172 line_t *lp; 173 int gflag; 174 int kth; 175{ 176 int off = 0; 177 int changed = 0; 178 int matchno = 0; 179 int i = 0; 180 regmatch_t rm[SE_MAX]; 181 char *txt; 182 char *eot; 183 184 if ((txt = get_sbuf_line(lp)) == NULL) 185 return ERR; 186 if (isbinary) 187 NUL_TO_NEWLINE(txt, lp->len); 188 eot = txt + lp->len; 189 if (!regexec(pat, txt, SE_MAX, rm, 0)) { 190 do { 191 if (!kth || kth == ++matchno) { 192 changed++; 193 i = rm[0].rm_so; 194 REALLOC(rbuf, rbufsz, off + i, ERR); 195 if (isbinary) 196 NEWLINE_TO_NUL(txt, rm[0].rm_eo); 197 memcpy(rbuf + off, txt, i); 198 off += i; 199 if ((off = apply_subst_template(txt, rm, off, 200 pat->re_nsub)) < 0) 201 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