18855Srgrimes/* sub.c: This file contains the substitution routines for the ed 21057Salm line editor */ 31057Salm/*- 41057Salm * Copyright (c) 1993 Andrew Moore, Talke Studio. 51057Salm * All rights reserved. 61057Salm * 71057Salm * Redistribution and use in source and binary forms, with or without 81057Salm * modification, are permitted provided that the following conditions 91057Salm * are met: 101057Salm * 1. Redistributions of source code must retain the above copyright 111057Salm * notice, this list of conditions and the following disclaimer. 121057Salm * 2. Redistributions in binary form must reproduce the above copyright 131057Salm * notice, this list of conditions and the following disclaimer in the 141057Salm * documentation and/or other materials provided with the distribution. 151057Salm * 161057Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171057Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181057Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191057Salm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201057Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211057Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221057Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231057Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241057Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251057Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261057Salm * SUCH DAMAGE. 271057Salm */ 281057Salm 2999109Sobrien#include <sys/cdefs.h> 3099109Sobrien__FBSDID("$FreeBSD$"); 311057Salm 321057Salm#include "ed.h" 331057Salm 341057Salm 35241720Sedstatic char *rhbuf; /* rhs substitution buffer */ 36241720Sedstatic int rhbufsz; /* rhs substitution buffer size */ 37241720Sedstatic int rhbufi; /* rhs substitution buffer index */ 381057Salm 391057Salm/* extract_subst_tail: extract substitution tail from the command buffer */ 401057Salmint 4190109Simpextract_subst_tail(int *flagp, long *np) 421057Salm{ 431057Salm char delimiter; 441057Salm 451057Salm *flagp = *np = 0; 461057Salm if ((delimiter = *ibufp) == '\n') { 471057Salm rhbufi = 0; 481057Salm *flagp = GPR; 491057Salm return 0; 501057Salm } else if (extract_subst_template() == NULL) 511057Salm return ERR; 521057Salm else if (*ibufp == '\n') { 531057Salm *flagp = GPR; 541057Salm return 0; 551057Salm } else if (*ibufp == delimiter) 561057Salm ibufp++; 571057Salm if ('1' <= *ibufp && *ibufp <= '9') { 581057Salm STRTOL(*np, ibufp); 591057Salm return 0; 601057Salm } else if (*ibufp == 'g') { 611057Salm ibufp++; 621057Salm *flagp = GSG; 631057Salm return 0; 641057Salm } 651057Salm return 0; 661057Salm} 671057Salm 681057Salm 691057Salm/* extract_subst_template: return pointer to copy of substitution template 701057Salm in the command buffer */ 711057Salmchar * 7290109Simpextract_subst_template(void) 731057Salm{ 741057Salm int n = 0; 751057Salm int i = 0; 761057Salm char c; 771057Salm char delimiter = *ibufp++; 781057Salm 791057Salm if (*ibufp == '%' && *(ibufp + 1) == delimiter) { 801057Salm ibufp++; 8181220Smike if (!rhbuf) 8281220Smike errmsg = "no previous substitution"; 831057Salm return rhbuf; 841057Salm } 851057Salm while (*ibufp != delimiter) { 861057Salm REALLOC(rhbuf, rhbufsz, i + 2, NULL); 871057Salm if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') { 881057Salm i--, ibufp--; 891057Salm break; 901057Salm } else if (c != '\\') 911057Salm ; 921057Salm else if ((rhbuf[i++] = *ibufp++) != '\n') 931057Salm ; 941057Salm else if (!isglobal) { 951057Salm while ((n = get_tty_line()) == 0 || 967165Sjoerg (n > 0 && ibuf[n - 1] != '\n')) 971057Salm clearerr(stdin); 981057Salm if (n < 0) 991057Salm return NULL; 1001057Salm } 1011057Salm } 1021057Salm REALLOC(rhbuf, rhbufsz, i + 1, NULL); 1031057Salm rhbuf[rhbufi = i] = '\0'; 1041057Salm return rhbuf; 1051057Salm} 1061057Salm 1071057Salm 108241720Sedstatic char *rbuf; /* substitute_matching_text buffer */ 109241720Sedstatic int rbufsz; /* substitute_matching_text buffer size */ 1101057Salm 1111057Salm/* search_and_replace: for each line in a range, change text matching a pattern 1121057Salm according to a substitution template; return status */ 1131057Salmint 11490109Simpsearch_and_replace(pattern_t *pat, int gflag, int kth) 1151057Salm{ 1161057Salm undo_t *up; 11781220Smike const char *txt; 11881220Smike const char *eot; 1191057Salm long lc; 1205598Salm long xa = current_addr; 1211057Salm int nsubs = 0; 1221057Salm line_t *lp; 1231057Salm int len; 1241057Salm 1251057Salm current_addr = first_addr - 1; 1261057Salm for (lc = 0; lc <= second_addr - first_addr; lc++) { 1271057Salm lp = get_addressed_line_node(++current_addr); 1281057Salm if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0) 1291057Salm return ERR; 1301057Salm else if (len) { 1311057Salm up = NULL; 1321057Salm if (delete_lines(current_addr, current_addr) < 0) 1331057Salm return ERR; 1341057Salm txt = rbuf; 1351057Salm eot = rbuf + len; 1361057Salm SPL1(); 1371057Salm do { 1381057Salm if ((txt = put_sbuf_line(txt)) == NULL) { 1391057Salm SPL0(); 1401057Salm return ERR; 1411057Salm } else if (up) 1421057Salm up->t = get_addressed_line_node(current_addr); 1431057Salm else if ((up = push_undo_stack(UADD, 1441057Salm current_addr, current_addr)) == NULL) { 1451057Salm SPL0(); 1461057Salm return ERR; 1471057Salm } 1481057Salm } while (txt != eot); 1491057Salm SPL0(); 1501057Salm nsubs++; 1515598Salm xa = current_addr; 1521057Salm } 1531057Salm } 1545598Salm current_addr = xa; 1551057Salm if (nsubs == 0 && !(gflag & GLB)) { 15681220Smike errmsg = "no match"; 1571057Salm return ERR; 1581057Salm } else if ((gflag & (GPR | GLS | GNP)) && 1591057Salm display_lines(current_addr, current_addr, gflag) < 0) 1601057Salm return ERR; 1611057Salm return 0; 1621057Salm} 1631057Salm 1641057Salm 1651057Salm/* substitute_matching_text: replace text matched by a pattern according to 1661057Salm a substitution template; return pointer to the modified text */ 1671057Salmint 16890109Simpsubstitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth) 1691057Salm{ 1701057Salm int off = 0; 1711057Salm int changed = 0; 1721057Salm int matchno = 0; 1731057Salm int i = 0; 1741057Salm regmatch_t rm[SE_MAX]; 1751057Salm char *txt; 1761057Salm char *eot; 1771057Salm 1781057Salm if ((txt = get_sbuf_line(lp)) == NULL) 1791057Salm return ERR; 1808855Srgrimes if (isbinary) 1811057Salm NUL_TO_NEWLINE(txt, lp->len); 1821057Salm eot = txt + lp->len; 1831057Salm if (!regexec(pat, txt, SE_MAX, rm, 0)) { 1841057Salm do { 1851057Salm if (!kth || kth == ++matchno) { 1861057Salm changed++; 1871057Salm i = rm[0].rm_so; 1881057Salm REALLOC(rbuf, rbufsz, off + i, ERR); 1891057Salm if (isbinary) 1901057Salm NEWLINE_TO_NUL(txt, rm[0].rm_eo); 1911057Salm memcpy(rbuf + off, txt, i); 1921057Salm off += i; 1931057Salm if ((off = apply_subst_template(txt, rm, off, 1941057Salm pat->re_nsub)) < 0) 1951057Salm return ERR; 1961057Salm } else { 1971057Salm i = rm[0].rm_eo; 1981057Salm REALLOC(rbuf, rbufsz, off + i, ERR); 1991057Salm if (isbinary) 2001057Salm NEWLINE_TO_NUL(txt, i); 2011057Salm memcpy(rbuf + off, txt, i); 2021057Salm off += i; 2031057Salm } 2041057Salm txt += rm[0].rm_eo; 2058855Srgrimes } while (*txt && 2067165Sjoerg (!changed || ((gflag & GSG) && rm[0].rm_eo)) && 2077165Sjoerg !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL)); 2081057Salm i = eot - txt; 2091057Salm REALLOC(rbuf, rbufsz, off + i + 2, ERR); 2101057Salm if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) { 21181220Smike errmsg = "infinite substitution loop"; 2121057Salm return ERR; 2131057Salm } 2141057Salm if (isbinary) 2151057Salm NEWLINE_TO_NUL(txt, i); 2161057Salm memcpy(rbuf + off, txt, i); 2171057Salm memcpy(rbuf + off + i, "\n", 2); 2181057Salm } 2191057Salm return changed ? off + i + 1 : 0; 2201057Salm} 2211057Salm 2221057Salm 2231057Salm/* apply_subst_template: modify text according to a substitution template; 2241057Salm return offset to end of modified text */ 2251057Salmint 22690109Simpapply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub) 2271057Salm{ 2281057Salm int j = 0; 2291057Salm int k = 0; 2301057Salm int n; 2311057Salm char *sub = rhbuf; 2321057Salm 2331057Salm for (; sub - rhbuf < rhbufi; sub++) 2341057Salm if (*sub == '&') { 2351057Salm j = rm[0].rm_so; 2361057Salm k = rm[0].rm_eo; 2371057Salm REALLOC(rbuf, rbufsz, off + k - j, ERR); 2381057Salm while (j < k) 2391057Salm rbuf[off++] = boln[j++]; 2401057Salm } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' && 2411057Salm (n = *sub - '0') <= re_nsub) { 2421057Salm j = rm[n].rm_so; 2431057Salm k = rm[n].rm_eo; 2441057Salm REALLOC(rbuf, rbufsz, off + k - j, ERR); 2451057Salm while (j < k) 2461057Salm rbuf[off++] = boln[j++]; 2471057Salm } else { 2481057Salm REALLOC(rbuf, rbufsz, off + 1, ERR); 2491057Salm rbuf[off++] = *sub; 2501057Salm } 2511057Salm REALLOC(rbuf, rbufsz, off + 1, ERR); 2521057Salm rbuf[off] = '\0'; 2531057Salm return off; 2541057Salm} 255