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