sub.c revision 99109
159769Sgrog/* sub.c: This file contains the substitution routines for the ed 259769Sgrog line editor */ 324424Swosch/*- 424424Swosch * Copyright (c) 1993 Andrew Moore, Talke Studio. 524424Swosch * All rights reserved. 624424Swosch * 724424Swosch * Redistribution and use in source and binary forms, with or without 824424Swosch * modification, are permitted provided that the following conditions 924424Swosch * are met: 1024424Swosch * 1. Redistributions of source code must retain the above copyright 1124424Swosch * notice, this list of conditions and the following disclaimer. 1224424Swosch * 2. Redistributions in binary form must reproduce the above copyright 1324424Swosch * notice, this list of conditions and the following disclaimer in the 1424424Swosch * documentation and/or other materials provided with the distribution. 1542704Swosch * 1642704Swosch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1742704Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1824424Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1942704Swosch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2042704Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2142704Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2242704Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2342704Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2442704Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2542704Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2642704Swosch * SUCH DAMAGE. 2742704Swosch */ 2842704Swosch 2942704Swosch#include <sys/cdefs.h> 3059769Sgrog__FBSDID("$FreeBSD: head/bin/ed/sub.c 99109 2002-06-30 05:13:54Z obrien $"); 3159769Sgrog 3259769Sgrog#include "ed.h" 3359769Sgrog 3459769Sgrog 3559769Sgrogchar *rhbuf; /* rhs substitution buffer */ 3659769Sgrogint rhbufsz; /* rhs substitution buffer size */ 3759769Sgrogint rhbufi; /* rhs substitution buffer index */ 3859769Sgrog 3924424Swosch/* extract_subst_tail: extract substitution tail from the command buffer */ 4042704Swoschint 4124424Swoschextract_subst_tail(int *flagp, long *np) 4242704Swosch{ 4324424Swosch char delimiter; 4442704Swosch 4524424Swosch *flagp = *np = 0; 4624424Swosch if ((delimiter = *ibufp) == '\n') { 4724424Swosch rhbufi = 0; 4842704Swosch *flagp = GPR; 4925031Swosch return 0; 5059156Swosch } else if (extract_subst_template() == NULL) 5125031Swosch return ERR; 5225031Swosch else if (*ibufp == '\n') { 5324424Swosch *flagp = GPR; 5424424Swosch return 0; 5524424Swosch } else if (*ibufp == delimiter) 5624424Swosch ibufp++; 5771231Sitojun if ('1' <= *ibufp && *ibufp <= '9') { 5824424Swosch STRTOL(*np, ibufp); 5971231Sitojun return 0; 6025031Swosch } else if (*ibufp == 'g') { 6171231Sitojun ibufp++; 6224424Swosch *flagp = GSG; 6325031Swosch return 0; 6425031Swosch } 6571231Sitojun return 0; 6625031Swosch} 6771231Sitojun 6870110Swosch 6970110Swosch/* extract_subst_template: return pointer to copy of substitution template 7070110Swosch in the command buffer */ 7170110Swoschchar * 7270110Swoschextract_subst_template(void) 7370110Swosch{ 7470110Swosch int n = 0; 7570110Swosch int i = 0; 7670110Swosch char c; 7770110Swosch char delimiter = *ibufp++; 7870110Swosch 7980675Sasmodai if (*ibufp == '%' && *(ibufp + 1) == delimiter) { 8080675Sasmodai ibufp++; 8180675Sasmodai if (!rhbuf) 8280675Sasmodai errmsg = "no previous substitution"; 8380675Sasmodai return rhbuf; 8480675Sasmodai } 8580675Sasmodai while (*ibufp != delimiter) { 8680675Sasmodai REALLOC(rhbuf, rhbufsz, i + 2, NULL); 8780675Sasmodai if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') { 8880675Sasmodai i--, ibufp--; 8980675Sasmodai break; 9080675Sasmodai } else if (c != '\\') 9180675Sasmodai ; 9280675Sasmodai else if ((rhbuf[i++] = *ibufp++) != '\n') 9380675Sasmodai ; 9480675Sasmodai else if (!isglobal) { 9580675Sasmodai while ((n = get_tty_line()) == 0 || 9680675Sasmodai (n > 0 && ibuf[n - 1] != '\n')) 9780675Sasmodai clearerr(stdin); 9880675Sasmodai if (n < 0) 9980675Sasmodai return NULL; 10080675Sasmodai } 10180675Sasmodai } 10280675Sasmodai REALLOC(rhbuf, rhbufsz, i + 1, NULL); 10380675Sasmodai rhbuf[rhbufi = i] = '\0'; 10480675Sasmodai return rhbuf; 10580675Sasmodai} 10680675Sasmodai 10780675Sasmodai 10880675Sasmodaichar *rbuf; /* substitute_matching_text buffer */ 10980675Sasmodaiint rbufsz; /* substitute_matching_text buffer size */ 11080675Sasmodai 11180675Sasmodai/* search_and_replace: for each line in a range, change text matching a pattern 11280675Sasmodai according to a substitution template; return status */ 11380675Sasmodaiint 11480675Sasmodaisearch_and_replace(pattern_t *pat, int gflag, int kth) 11580675Sasmodai{ 11680675Sasmodai undo_t *up; 11780675Sasmodai const char *txt; 11880675Sasmodai const char *eot; 11980675Sasmodai long lc; 12080675Sasmodai long xa = current_addr; 12180675Sasmodai int nsubs = 0; 12280675Sasmodai line_t *lp; 12380675Sasmodai int len; 12480675Sasmodai 12580675Sasmodai current_addr = first_addr - 1; 12680675Sasmodai for (lc = 0; lc <= second_addr - first_addr; lc++) { 12780675Sasmodai lp = get_addressed_line_node(++current_addr); 12880675Sasmodai if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0) 12980675Sasmodai return ERR; 13080675Sasmodai else if (len) { 13180675Sasmodai up = NULL; 13280675Sasmodai if (delete_lines(current_addr, current_addr) < 0) 13380675Sasmodai return ERR; 13480675Sasmodai txt = rbuf; 13580675Sasmodai eot = rbuf + len; 13680675Sasmodai SPL1(); 13780675Sasmodai do { 138101401Swosch if ((txt = put_sbuf_line(txt)) == NULL) { 13980675Sasmodai SPL0(); 140147593Shrs return ERR; 14187200Swosch } else if (up) 142147593Shrs up->t = get_addressed_line_node(current_addr); 14380675Sasmodai else if ((up = push_undo_stack(UADD, 144104772Smaxim current_addr, current_addr)) == NULL) { 145104772Smaxim SPL0(); 146104772Smaxim return ERR; 147104772Smaxim } 148104781Sjhb } while (txt != eot); 149104781Sjhb SPL0(); 150104781Sjhb nsubs++; 151104781Sjhb xa = current_addr; 152104781Sjhb } 153104781Sjhb } 154119217Smurray current_addr = xa; 155147593Shrs if (nsubs == 0 && !(gflag & GLB)) { 156147593Shrs errmsg = "no match"; 157119217Smurray return ERR; 158119217Smurray } else if ((gflag & (GPR | GLS | GNP)) && 159119217Smurray display_lines(current_addr, current_addr, gflag) < 0) 160119217Smurray return ERR; 161132652Sosa return 0; 162132652Sosa} 163132652Sosa 164132652Sosa 165132652Sosa/* substitute_matching_text: replace text matched by a pattern according to 166132652Sosa a substitution template; return pointer to the modified text */ 167132652Sosaint 168132652Sosasubstitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth) 169132652Sosa{ 170132652Sosa int off = 0; 171140831Smaxim int changed = 0; 172140831Smaxim int matchno = 0; 173132652Sosa int i = 0; 174132652Sosa regmatch_t rm[SE_MAX]; 175132652Sosa char *txt; 176132652Sosa char *eot; 177137120Smaxim 178132652Sosa if ((txt = get_sbuf_line(lp)) == NULL) 179132652Sosa return ERR; 180132652Sosa if (isbinary) 181132652Sosa NUL_TO_NEWLINE(txt, lp->len); 182132652Sosa eot = txt + lp->len; 183132652Sosa if (!regexec(pat, txt, SE_MAX, rm, 0)) { 184132652Sosa do { 185158916Smaxim if (!kth || kth == ++matchno) { 186158916Smaxim changed++; 187158916Smaxim i = rm[0].rm_so; 188158916Smaxim REALLOC(rbuf, rbufsz, off + i, ERR); 189158916Smaxim if (isbinary) 190158916Smaxim NEWLINE_TO_NUL(txt, rm[0].rm_eo); 191158916Smaxim memcpy(rbuf + off, txt, i); 192158916Smaxim off += i; 193158916Smaxim if ((off = apply_subst_template(txt, rm, off, 194158916Smaxim pat->re_nsub)) < 0) 195158916Smaxim return ERR; 196158916Smaxim } else { 197158916Smaxim i = rm[0].rm_eo; 198158916Smaxim REALLOC(rbuf, rbufsz, off + i, ERR); 199158916Smaxim if (isbinary) 200158916Smaxim NEWLINE_TO_NUL(txt, i); 201160663Smaxim memcpy(rbuf + off, txt, i); 202160663Smaxim off += i; 203160663Smaxim } 204160663Smaxim txt += rm[0].rm_eo; 205160663Smaxim } while (*txt && 206160663Smaxim (!changed || ((gflag & GSG) && rm[0].rm_eo)) && 207160663Smaxim !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL)); 208152003Smaxim i = eot - txt; 209152003Smaxim REALLOC(rbuf, rbufsz, off + i + 2, ERR); 210132652Sosa if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) { 21124424Swosch errmsg = "infinite substitution loop"; 21224424Swosch return ERR; 21324424Swosch } 21424424Swosch if (isbinary) 21569277Sasmodai NEWLINE_TO_NUL(txt, i); 21669277Sasmodai memcpy(rbuf + off, txt, i); 21724424Swosch memcpy(rbuf + off + i, "\n", 2); 21825031Swosch } 21925031Swosch return changed ? off + i + 1 : 0; 22025031Swosch} 22180675Sasmodai 222104782Sjhb 223144864Smaxim/* apply_subst_template: modify text according to a substitution template; 22425031Swosch return offset to end of modified text */ 225104782Sjhbint 226104782Sjhbapply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub) 227104782Sjhb{ 228104797Sjhb int j = 0; 229104797Sjhb int k = 0; 23025031Swosch int n; 23125031Swosch char *sub = rhbuf; 23225031Swosch 23345349Swosch for (; sub - rhbuf < rhbufi; sub++) 23445349Swosch if (*sub == '&') { 235104782Sjhb j = rm[0].rm_so; 236104782Sjhb k = rm[0].rm_eo; 237104782Sjhb REALLOC(rbuf, rbufsz, off + k - j, ERR); 238104782Sjhb while (j < k) 23942704Swosch rbuf[off++] = boln[j++]; 24025031Swosch } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' && 24124424Swosch (n = *sub - '0') <= re_nsub) { 24259769Sgrog j = rm[n].rm_so; 24325031Swosch k = rm[n].rm_eo; 24425031Swosch REALLOC(rbuf, rbufsz, off + k - j, ERR); 24525031Swosch while (j < k) 24625031Swosch rbuf[off++] = boln[j++]; 24759769Sgrog } else { 24825031Swosch REALLOC(rbuf, rbufsz, off + 1, ERR); 24925031Swosch rbuf[off++] = *sub; 25025031Swosch } 25125031Swosch REALLOC(rbuf, rbufsz, off + 1, ERR); 25224424Swosch rbuf[off] = '\0'; 25325031Swosch return off; 25425031Swosch} 25525031Swosch