Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / bin / ed / sub.c
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  * @(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp
29  * $FreeBSD: src/bin/ed/sub.c,v 1.12 1999/08/27 23:14:15 peter Exp $
30  * $DragonFly: src/bin/ed/sub.c,v 1.2 2003/06/17 04:22:50 dillon Exp $
31  */
32
33 #include "ed.h"
34
35
36 char *rhbuf;                    /* rhs substitution buffer */
37 int rhbufsz;                    /* rhs substitution buffer size */
38 int rhbufi;                     /* rhs substitution buffer index */
39
40 /* extract_subst_tail: extract substitution tail from the command buffer */
41 int
42 extract_subst_tail(flagp, np)
43         int *flagp;
44         long *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 */
74 char *
75 extract_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
110 char *rbuf;                     /* substitute_matching_text buffer */
111 int 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  */
115 int
116 search_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         long xa = current_addr;
126         int nsubs = 0;
127         line_t *lp;
128         int len;
129
130         current_addr = first_addr - 1;
131         for (lc = 0; lc <= second_addr - first_addr; lc++) {
132                 lp = get_addressed_line_node(++current_addr);
133                 if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
134                         return ERR;
135                 else if (len) {
136                         up = NULL;
137                         if (delete_lines(current_addr, current_addr) < 0)
138                                 return ERR;
139                         txt = rbuf;
140                         eot = rbuf + len;
141                         SPL1();
142                         do {
143                                 if ((txt = put_sbuf_line(txt)) == NULL) {
144                                         SPL0();
145                                         return ERR;
146                                 } else if (up)
147                                         up->t = get_addressed_line_node(current_addr);
148                                 else if ((up = push_undo_stack(UADD,
149                                     current_addr, current_addr)) == NULL) {
150                                         SPL0();
151                                         return ERR;
152                                 }
153                         } while (txt != eot);
154                         SPL0();
155                         nsubs++;
156                         xa = current_addr;
157                 }
158         }
159         current_addr = xa;
160         if  (nsubs == 0 && !(gflag & GLB)) {
161                 sprintf(errmsg, "no match");
162                 return ERR;
163         } else if ((gflag & (GPR | GLS | GNP)) &&
164             display_lines(current_addr, current_addr, gflag) < 0)
165                 return ERR;
166         return 0;
167 }
168
169
170 /* substitute_matching_text: replace text matched by a pattern according to
171    a substitution template; return pointer to the modified text */
172 int
173 substitute_matching_text(pat, lp, gflag, kth)
174         pattern_t *pat;
175         line_t *lp;
176         int gflag;
177         int kth;
178 {
179         int off = 0;
180         int changed = 0;
181         int matchno = 0;
182         int i = 0;
183         regmatch_t rm[SE_MAX];
184         char *txt;
185         char *eot;
186
187         if ((txt = get_sbuf_line(lp)) == NULL)
188                 return ERR;
189         if (isbinary)
190                 NUL_TO_NEWLINE(txt, lp->len);
191         eot = txt + lp->len;
192         if (!regexec(pat, txt, SE_MAX, rm, 0)) {
193                 do {
194                         if (!kth || kth == ++matchno) {
195                                 changed++;
196                                 i = rm[0].rm_so;
197                                 REALLOC(rbuf, rbufsz, off + i, ERR);
198                                 if (isbinary)
199                                         NEWLINE_TO_NUL(txt, rm[0].rm_eo);
200                                 memcpy(rbuf + off, txt, i);
201                                 off += i;
202                                 if ((off = apply_subst_template(txt, rm, off,
203                                     pat->re_nsub)) < 0)
204                                         return ERR;
205                         } else {
206                                 i = rm[0].rm_eo;
207                                 REALLOC(rbuf, rbufsz, off + i, ERR);
208                                 if (isbinary)
209                                         NEWLINE_TO_NUL(txt, i);
210                                 memcpy(rbuf + off, txt, i);
211                                 off += i;
212                         }
213                         txt += rm[0].rm_eo;
214                 } while (*txt &&
215                         (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
216                         !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
217                 i = eot - txt;
218                 REALLOC(rbuf, rbufsz, off + i + 2, ERR);
219                 if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
220                         sprintf(errmsg, "infinite substitution loop");
221                         return  ERR;
222                 }
223                 if (isbinary)
224                         NEWLINE_TO_NUL(txt, i);
225                 memcpy(rbuf + off, txt, i);
226                 memcpy(rbuf + off + i, "\n", 2);
227         }
228         return changed ? off + i + 1 : 0;
229 }
230
231
232 /* apply_subst_template: modify text according to a substitution template;
233    return offset to end of modified text */
234 int
235 apply_subst_template(boln, rm, off, re_nsub)
236         char *boln;
237         regmatch_t *rm;
238         int off;
239         int re_nsub;
240 {
241         int j = 0;
242         int k = 0;
243         int n;
244         char *sub = rhbuf;
245
246         for (; sub - rhbuf < rhbufi; sub++)
247                 if (*sub == '&') {
248                         j = rm[0].rm_so;
249                         k = rm[0].rm_eo;
250                         REALLOC(rbuf, rbufsz, off + k - j, ERR);
251                         while (j < k)
252                                 rbuf[off++] = boln[j++];
253                 } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
254                     (n = *sub - '0') <= re_nsub) {
255                         j = rm[n].rm_so;
256                         k = rm[n].rm_eo;
257                         REALLOC(rbuf, rbufsz, off + k - j, ERR);
258                         while (j < k)
259                                 rbuf[off++] = boln[j++];
260                 } else {
261                         REALLOC(rbuf, rbufsz, off + 1, ERR);
262                         rbuf[off++] = *sub;
263                 }
264         REALLOC(rbuf, rbufsz, off + 1, ERR);
265         rbuf[off] = '\0';
266         return off;
267 }