Bug Summary

File:src/usr.bin/vi/build/../ex/ex_subst.c
Warning:line 211, column 11
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ex_subst.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/vi/build/../ex/ex_subst.c
1/* $OpenBSD: ex_subst.c,v 1.30 2017/04/18 01:45:35 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12#include "config.h"
13
14#include <sys/queue.h>
15#include <sys/time.h>
16
17#include <bitstring.h>
18#include <ctype.h>
19#include <errno(*__errno()).h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "../common/common.h"
27#include "../vi/vi.h"
28
29#define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
30
31#define SUB_FIRST0x01 0x01 /* The 'r' flag isn't reasonable. */
32#define SUB_MUSTSETR0x02 0x02 /* The 'r' flag is required. */
33
34static int re_conv(SCR *, char **, size_t *, int *);
35static int re_sub(SCR *, char *, char **, size_t *, size_t *, regmatch_t [10]);
36static int re_tag_conv(SCR *, char **, size_t *, int *);
37static int s(SCR *, EXCMD *, char *, regex_t *, u_int);
38
39/*
40 * ex_s --
41 * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
42 *
43 * Substitute on lines matching a pattern.
44 *
45 * PUBLIC: int ex_s(SCR *, EXCMD *);
46 */
47int
48ex_s(SCR *sp, EXCMD *cmdp)
49{
50 regex_t *re;
51 size_t blen, len;
52 u_int flags;
53 int delim;
54 char *bp, *ptrn, *rep, *p, *t;
55
56 /*
57 * Skip leading white space.
58 *
59 * !!!
60 * Historic vi allowed any non-alphanumeric to serve as the
61 * substitution command delimiter.
62 *
63 * !!!
64 * If the arguments are empty, it's the same as &, i.e. we
65 * repeat the last substitution.
66 */
67 if (cmdp->argc == 0)
1
Assuming field 'argc' is not equal to 0
2
Taking false branch
68 goto subagain;
69 for (p = cmdp->argv[0]->bp,
4
Loop condition is true. Entering loop body
70 len = cmdp->argv[0]->len; len > 0; --len, ++p) {
3
Assuming 'len' is > 0
71 if (!isblank(*p))
5
Taking true branch
72 break;
6
Execution continues on line 74
73 }
74 if (len
6.1
'len' is not equal to 0
== 0)
7
Taking false branch
75subagain: return (ex_subagain(sp, cmdp));
76
77 delim = *p++;
78 if (isalnum(delim) || delim == '\\')
8
Assuming the condition is false
9
Taking false branch
79 return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR0x02));
80
81 /*
82 * !!!
83 * The full-blown substitute command reset the remembered
84 * state of the 'c' and 'g' suffices.
85 */
86 sp->c_suffix = sp->g_suffix = 0;
87
88 /*
89 * Get the pattern string, toss escaping characters.
90 *
91 * !!!
92 * Historic vi accepted any of the following forms:
93 *
94 * :s/abc/def/ change "abc" to "def"
95 * :s/abc/def change "abc" to "def"
96 * :s/abc/ delete "abc"
97 * :s/abc delete "abc"
98 *
99 * QUOTING NOTE:
100 *
101 * Only toss an escaping character if it escapes a delimiter.
102 * This means that "s/A/\\\\f" replaces "A" with "\\f". It
103 * would be nice to be more regular, i.e. for each layer of
104 * escaping a single escaping character is removed, but that's
105 * not how the historic vi worked.
106 */
107 for (ptrn = t = p;;) {
10
Loop condition is true. Entering loop body
108 if (p[0] == '\0' || p[0] == delim) {
11
Assuming the condition is false
12
Assuming the condition is true
13
Taking true branch
109 if (p[0] == delim)
14
Taking true branch
110 ++p;
111 /*
112 * !!!
113 * Nul terminate the pattern string -- it's passed
114 * to regcomp which doesn't understand anything else.
115 */
116 *t = '\0';
117 break;
15
Execution continues on line 132
118 }
119 if (p[0] == '\\') {
120 if (p[1] == delim)
121 ++p;
122 else if (p[1] == '\\')
123 *t++ = *p++;
124 }
125 *t++ = *p++;
126 }
127
128 /*
129 * If the pattern string is empty, use the last RE (not just the
130 * last substitution RE).
131 */
132 if (*ptrn == '\0') {
16
Taking true branch
133 if (sp->re == NULL((void *)0)) {
17
Assuming field 're' is not equal to NULL
18
Taking false branch
134 ex_emsg(sp, NULL((void *)0), EXM_NOPREVRE);
135 return (1);
136 }
137
138 /* Re-compile the RE if necessary. */
139 if (!F_ISSET(sp, SC_RE_SEARCH)(((sp)->flags) & ((0x00400000))) && re_compile(sp,
19
Assuming the condition is false
140 sp->re, sp->re_len, NULL((void *)0), NULL((void *)0), &sp->re_c, RE_C_SEARCH0x0002))
141 return (1);
142 flags = 0;
143 } else {
144 /*
145 * !!!
146 * Compile the RE. Historic practice is that substitutes set
147 * the search direction as well as both substitute and search
148 * RE's. We compile the RE twice, as we don't want to bother
149 * ref counting the pattern string and (opaque) structure.
150 */
151 if (re_compile(sp, ptrn, t - ptrn,
152 &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH0x0002))
153 return (1);
154 if (re_compile(sp, ptrn, t - ptrn,
155 &sp->subre, &sp->subre_len, &sp->subre_c, RE_C_SUBST0x0008))
156 return (1);
157
158 flags = SUB_FIRST0x01;
159 sp->searchdir = FORWARD;
160 }
161 re = &sp->re_c;
162
163 /*
164 * Get the replacement string.
165 *
166 * The special character & (\& if O_MAGIC not set) matches the
167 * entire RE. No handling of & is required here, it's done by
168 * re_sub().
169 *
170 * The special character ~ (\~ if O_MAGIC not set) inserts the
171 * previous replacement string into this replacement string.
172 * Count ~'s to figure out how much space we need. We could
173 * special case nonexistent last patterns or whether or not
174 * O_MAGIC is set, but it's probably not worth the effort.
175 *
176 * QUOTING NOTE:
177 *
178 * Only toss an escaping character if it escapes a delimiter or
179 * if O_MAGIC is set and it escapes a tilde.
180 *
181 * !!!
182 * If the entire replacement pattern is "%", then use the last
183 * replacement pattern. This semantic was added to vi in System
184 * V and then percolated elsewhere, presumably around the time
185 * that it was added to their version of ed(1).
186 */
187 if (p[0] == '\0' || p[0] == delim) {
20
Assuming the condition is false
21
Assuming the condition is false
22
Taking false branch
188 if (p[0] == delim)
189 ++p;
190 free(sp->repl);
191 sp->repl = NULL((void *)0);
192 sp->repl_len = 0;
193 } else if (p[0] == '%' && (p[1] == '\0' || p[1] == delim))
23
Assuming the condition is false
194 p += p[1] == delim ? 2 : 1;
195 else {
196 for (rep = p, len = 0;
24
Loop condition is true. Entering loop body
29
Loop condition is true. Entering loop body
34
Loop condition is true. Entering loop body
197 p[0] != '\0' && p[0] != delim; ++p, ++len)
27
Assuming the condition is true
28
Assuming the condition is true
32
Assuming the condition is true
33
Assuming the condition is true
37
Assuming the condition is false
198 if (p[0] == '~')
25
Assuming the condition is false
26
Taking false branch
30
Assuming the condition is false
31
Taking false branch
35
Assuming the condition is true
36
Taking true branch
199 len += sp->repl_len;
200 GET_SPACE_RET(sp, bp, blen, len){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((len)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp)),
&((blen)), ((len)))) == ((void *)0)) return (1); ((bp)) =
L__bincp; } }; } else { { void *L__bincp; if (((len)) > (
L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp->
tmp_bp), &(L__gp->tmp_blen), ((len)))) == ((void *)0))
return (1); (L__gp->tmp_bp) = L__bincp; } }; (bp) = L__gp
->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp)->flags
) |= ((0x0100))); } }
;
38
'?' condition is false
39
Assuming 'L__gp' is equal to null
40
Assuming 'len' is <= 'blen'
41
Taking false branch
201 for (t = bp, len = 0, p = rep;;) {
42
Loop condition is true. Entering loop body
202 if (p[0] == '\0' || p[0] == delim) {
43
Taking false branch
203 if (p[0] == delim)
204 ++p;
205 break;
206 }
207 if (p[0] == '\\') {
44
Assuming the condition is true
45
Taking true branch
208 if (p[1] == delim)
46
Taking false branch
209 ++p;
210 else if (p[1] == '\\') {
47
Assuming the condition is true
48
Taking true branch
211 *t++ = *p++;
49
Null pointer value stored to 't'
50
Dereference of null pointer
212 ++len;
213 } else if (p[1] == '~') {
214 ++p;
215 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
)
216 goto tilde;
217 }
218 } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
219tilde: ++p;
220 memcpy(t, sp->repl, sp->repl_len);
221 t += sp->repl_len;
222 len += sp->repl_len;
223 continue;
224 }
225 *t++ = *p++;
226 ++len;
227 }
228 if ((sp->repl_len = len) != 0) {
229 free(sp->repl);
230 if ((sp->repl = malloc(len)) == NULL((void *)0)) {
231 msgq(sp, M_SYSERR, NULL((void *)0));
232 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
233 return (1);
234 }
235 memcpy(sp->repl, bp, len);
236 }
237 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
238 }
239 return (s(sp, cmdp, p, re, flags));
240}
241
242/*
243 * ex_subagain --
244 * [line [,line]] & [cgr] [count] [#lp]]
245 *
246 * Substitute using the last substitute RE and replacement pattern.
247 *
248 * PUBLIC: int ex_subagain(SCR *, EXCMD *);
249 */
250int
251ex_subagain(SCR *sp, EXCMD *cmdp)
252{
253 if (sp->subre == NULL((void *)0)) {
254 ex_emsg(sp, NULL((void *)0), EXM_NOPREVRE);
255 return (1);
256 }
257 if (!F_ISSET(sp, SC_RE_SUBST)(((sp)->flags) & ((0x00800000))) && re_compile(sp,
258 sp->subre, sp->subre_len, NULL((void *)0), NULL((void *)0), &sp->subre_c, RE_C_SUBST0x0008))
259 return (1);
260 return (s(sp,
261 cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL((void *)0), &sp->subre_c, 0));
262}
263
264/*
265 * ex_subtilde --
266 * [line [,line]] ~ [cgr] [count] [#lp]]
267 *
268 * Substitute using the last RE and last substitute replacement pattern.
269 *
270 * PUBLIC: int ex_subtilde(SCR *, EXCMD *);
271 */
272int
273ex_subtilde(SCR *sp, EXCMD *cmdp)
274{
275 if (sp->re == NULL((void *)0)) {
276 ex_emsg(sp, NULL((void *)0), EXM_NOPREVRE);
277 return (1);
278 }
279 if (!F_ISSET(sp, SC_RE_SEARCH)(((sp)->flags) & ((0x00400000))) && re_compile(sp,
280 sp->re, sp->re_len, NULL((void *)0), NULL((void *)0), &sp->re_c, RE_C_SEARCH0x0002))
281 return (1);
282 return (s(sp,
283 cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL((void *)0), &sp->re_c, 0));
284}
285
286/*
287 * s --
288 * Do the substitution. This stuff is *really* tricky. There are lots of
289 * special cases, and general nastiness. Don't mess with it unless you're
290 * pretty confident.
291 *
292 * The nasty part of the substitution is what happens when the replacement
293 * string contains newlines. It's a bit tricky -- consider the information
294 * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is
295 * to build a set of newline offsets which we use to break the line up later,
296 * when the replacement is done. Don't change it unless you're *damned*
297 * confident.
298 */
299#define NEEDNEWLINE(sp){ if ((sp)->newl_len == (sp)->newl_cnt) { (sp)->newl_len
+= 25; { void *tmpp; if (((tmpp) = (reallocarray(((sp)->newl
), ((sp)->newl_len), (sizeof(size_t))))) == ((void *)0)) {
msgq(((sp)), M_SYSERR, ((void *)0)); free((sp)->newl); } (
sp)->newl = tmpp; }; if ((sp)->newl == ((void *)0)) { (
sp)->newl_len = 0; return (1); } } }
{ \
300 if ((sp)->newl_len == (sp)->newl_cnt) { \
301 (sp)->newl_len += 25; \
302 REALLOCARRAY((sp), (sp)->newl, \{ void *tmpp; if (((tmpp) = (reallocarray(((sp)->newl), ((
sp)->newl_len), (sizeof(size_t))))) == ((void *)0)) { msgq
(((sp)), M_SYSERR, ((void *)0)); free((sp)->newl); } (sp)->
newl = tmpp; }
303 (sp)->newl_len, sizeof(size_t)){ void *tmpp; if (((tmpp) = (reallocarray(((sp)->newl), ((
sp)->newl_len), (sizeof(size_t))))) == ((void *)0)) { msgq
(((sp)), M_SYSERR, ((void *)0)); free((sp)->newl); } (sp)->
newl = tmpp; }
; \
304 if ((sp)->newl == NULL((void *)0)) { \
305 (sp)->newl_len = 0; \
306 return (1); \
307 } \
308 } \
309}
310
311#define BUILD(sp, l, len){ if (lbclen + (len) > lblen) { lblen += (((lbclen + (len)
) > (256)) ? (lbclen + (len)) : (256)); { void *tmpp; if (
((tmpp) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((
sp)), M_SYSERR, ((void *)0)); free(lb); } lb = tmpp; }; if (lb
== ((void *)0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen
, (l), (len)); lbclen += (len); }
{ \
312 if (lbclen + (len) > lblen) { \
313 lblen += MAXIMUM(lbclen + (len), 256)(((lbclen + (len)) > (256)) ? (lbclen + (len)) : (256)); \
314 REALLOC((sp), lb, lblen){ void *tmpp; if (((tmpp) = (realloc((lb), (lblen)))) == ((void
*)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free(lb); } lb =
tmpp; }
; \
315 if (lb == NULL((void *)0)) { \
316 lbclen = 0; \
317 return (1); \
318 } \
319 } \
320 memcpy(lb + lbclen, (l), (len)); \
321 lbclen += (len); \
322}
323
324#define NEEDSP(sp, len, pnt){ if (lbclen + (len) > lblen) { lblen += (((lbclen + (len)
) > (256)) ? (lbclen + (len)) : (256)); { void *tmpp; if (
((tmpp) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((
sp)), M_SYSERR, ((void *)0)); free(lb); } lb = tmpp; }; if (lb
== ((void *)0)) { lbclen = 0; return (1); } (pnt) = lb + lbclen
; } }
{ \
325 if (lbclen + (len) > lblen) { \
326 lblen += MAXIMUM(lbclen + (len), 256)(((lbclen + (len)) > (256)) ? (lbclen + (len)) : (256)); \
327 REALLOC((sp), lb, lblen){ void *tmpp; if (((tmpp) = (realloc((lb), (lblen)))) == ((void
*)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free(lb); } lb =
tmpp; }
; \
328 if (lb == NULL((void *)0)) { \
329 lbclen = 0; \
330 return (1); \
331 } \
332 (pnt) = lb + lbclen; \
333 } \
334}
335
336static int
337s(SCR *sp, EXCMD *cmdp, char *s, regex_t *re, u_int flags)
338{
339 EVENT ev;
340 MARK from, to;
341 TEXTH tiq;
342 recno_t elno, lno, slno;
343 regmatch_t match[10];
344 size_t blen, cnt, last, lbclen, lblen, len, llen;
345 size_t offset, saved_offset, scno;
346 int lflag, nflag, pflag, rflag;
347 int didsub, do_eol_match, eflags, nempty, eval;
348 int linechanged, matched, quit, rval;
349 unsigned long ul;
350 char *bp, *lb;
351
352 NEEDFILE(sp, cmdp){ if ((sp)->ep == ((void *)0)) { ex_emsg((sp), (cmdp)->
cmd->name, EXM_NOFILEYET); return (1); } }
;
353
354 slno = sp->lno;
355 scno = sp->cno;
356
357 /*
358 * !!!
359 * Historically, the 'g' and 'c' suffices were always toggled as flags,
360 * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was
361 * not set, they were initialized to 0 for all substitute commands. If
362 * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user
363 * specified substitute/replacement patterns (see ex_s()).
364 */
365 if (!O_ISSET(sp, O_EDCOMPATIBLE)((((&(((sp)))->opts[(((O_EDCOMPATIBLE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_EDCOMPATIBLE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_EDCOMPATIBLE
)))].o_cur.val)
)
366 sp->c_suffix = sp->g_suffix = 0;
367
368 /*
369 * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
370 * it only displayed the last change. I'd disallow them, but they are
371 * useful in combination with the [v]global commands. In the current
372 * model the problem is combining them with the 'c' flag -- the screen
373 * would have to flip back and forth between the confirm screen and the
374 * ex print screen, which would be pretty awful. We do display all
375 * changes, though, for what that's worth.
376 *
377 * !!!
378 * Historic vi was fairly strict about the order of "options", the
379 * count, and "flags". I'm somewhat fuzzy on the difference between
380 * options and flags, anyway, so this is a simpler approach, and we
381 * just take it them in whatever order the user gives them. (The ex
382 * usage statement doesn't reflect this.)
383 */
384 lflag = nflag = pflag = rflag = 0;
385 if (s == NULL((void *)0))
386 goto noargs;
387 for (lno = OOBLNO0; *s != '\0'; ++s)
388 switch (*s) {
389 case ' ':
390 case '\t':
391 continue;
392 case '+':
393 ++cmdp->flagoff;
394 break;
395 case '-':
396 --cmdp->flagoff;
397 break;
398 case '0': case '1': case '2': case '3': case '4':
399 case '5': case '6': case '7': case '8': case '9':
400 if (lno != OOBLNO0)
401 goto usage;
402 errno(*__errno()) = 0;
403 if ((ul = strtoul(s, &s, 10)) >= UINT_MAX(2147483647 *2U +1U))
404 errno(*__errno()) = ERANGE34;
405 if (*s == '\0') /* Loop increment correction. */
406 --s;
407 if (errno(*__errno()) == ERANGE34) {
408 if (ul >= UINT_MAX(2147483647 *2U +1U))
409 msgq(sp, M_ERR, "Count overflow");
410 else
411 msgq(sp, M_SYSERR, NULL((void *)0));
412 return (1);
413 }
414 lno = (recno_t)ul;
415 /*
416 * In historic vi, the count was inclusive from the
417 * second address.
418 */
419 cmdp->addr1.lno = cmdp->addr2.lno;
420 cmdp->addr2.lno += lno - 1;
421 if (!db_exist(sp, cmdp->addr2.lno) &&
422 db_last(sp, &cmdp->addr2.lno))
423 return (1);
424 break;
425 case '#':
426 nflag = 1;
427 break;
428 case 'c':
429 sp->c_suffix = !sp->c_suffix;
430
431 /* Ex text structure initialization. */
432 if (F_ISSET(sp, SC_EX)(((sp)->flags) & ((0x00000001)))) {
433 memset(&tiq, 0, sizeof(TEXTH));
434 TAILQ_INIT(&tiq)do { (&tiq)->tqh_first = ((void *)0); (&tiq)->tqh_last
= &(&tiq)->tqh_first; } while (0)
;
435 }
436 break;
437 case 'g':
438 sp->g_suffix = !sp->g_suffix;
439 break;
440 case 'l':
441 lflag = 1;
442 break;
443 case 'p':
444 pflag = 1;
445 break;
446 case 'r':
447 if (LF_ISSET(SUB_FIRST)((flags) & ((0x01)))) {
448 msgq(sp, M_ERR,
449 "Regular expression specified; r flag meaningless");
450 return (1);
451 }
452 if (!F_ISSET(sp, SC_RE_SEARCH)(((sp)->flags) & ((0x00400000)))) {
453 ex_emsg(sp, NULL((void *)0), EXM_NOPREVRE);
454 return (1);
455 }
456 rflag = 1;
457 re = &sp->re_c;
458 break;
459 default:
460 goto usage;
461 }
462
463 if (*s != '\0' || (!rflag && LF_ISSET(SUB_MUSTSETR)((flags) & ((0x02))))) {
464usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
465 return (1);
466 }
467
468noargs: if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002))) && sp->c_suffix && (lflag || nflag || pflag)) {
469 msgq(sp, M_ERR,
470"The #, l and p flags may not be combined with the c flag in vi mode");
471 return (1);
472 }
473
474 /*
475 * bp: if interactive, line cache
476 * blen: if interactive, line cache length
477 * lb: build buffer pointer.
478 * lbclen: current length of built buffer.
479 * lblen; length of build buffer.
480 */
481 bp = lb = NULL((void *)0);
482 blen = lbclen = lblen = 0;
483
484 /* For each line... */
485 for (matched = quit = 0, lno = cmdp->addr1.lno,
486 elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
487
488 /* Someone's unhappy, time to stop. */
489 if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get
((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)->
flags) & ((0x0004)))))
)
490 break;
491
492 /* Get the line. */
493 if (db_get(sp, lno, DBG_FATAL0x001, &s, &llen))
494 goto err;
495
496 /*
497 * Make a local copy if doing confirmation -- when calling
498 * the confirm routine we're likely to lose the cached copy.
499 */
500 if (sp->c_suffix) {
501 if (bp == NULL((void *)0)) {
502 GET_SPACE_RET(sp, bp, blen, llen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((llen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp))
, &((blen)), ((llen)))) == ((void *)0)) return (1); ((bp)
) = L__bincp; } }; } else { { void *L__bincp; if (((llen)) >
(L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp->
tmp_bp), &(L__gp->tmp_blen), ((llen)))) == ((void *)0)
) return (1); (L__gp->tmp_bp) = L__bincp; } }; (bp) = L__gp
->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp)->flags
) |= ((0x0100))); } }
;
503 } else
504 ADD_SPACE_RET(sp, bp, blen, llen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) { (((L__gp)->flags) &= ~((0x0100))); { void *L__bincp
; if (((llen)) > (L__gp->tmp_blen)) { if ((L__bincp = binc
(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen), ((llen
)))) == ((void *)0)) return (1); (L__gp->tmp_bp) = L__bincp
; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (
((L__gp)->flags) |= ((0x0100))); } else { void *L__bincp; if
(((llen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp
)), &((blen)), ((llen)))) == ((void *)0)) return (1); ((bp
)) = L__bincp; } }; }
;
505 memcpy(bp, s, llen);
506 s = bp;
507 }
508
509 /* Start searching from the beginning. */
510 offset = 0;
511 len = llen;
512
513 /* Reset the build buffer offset. */
514 lbclen = 0;
515
516 /* Reset empty match test variable. */
517 nempty = -1;
518
519 /*
520 * We don't want to have to do a setline if the line didn't
521 * change -- keep track of whether or not this line changed.
522 * If doing confirmations, don't want to keep setting the
523 * line if change is refused -- keep track of substitutions.
524 */
525 didsub = linechanged = 0;
526
527 /* New line, do an EOL match. */
528 do_eol_match = 1;
529
530 /* It's not nul terminated, but we pretend it is. */
531 eflags = REG_STARTEND00004;
532
533 /* The search area is from s + offset to the EOL. */
534nextmatch: match[0].rm_so = offset;
535 match[0].rm_eo = llen;
536
537 /* Get the next match. */
538 eval = regexec(re, (char *)s, 10, match, eflags);
539
540 /*
541 * There wasn't a match or if there was an error, deal with
542 * it. If there was a previous match in this line, resolve
543 * the changes into the database. Otherwise, just move on.
544 */
545 if (eval == REG_NOMATCH1)
546 goto endmatch;
547 if (eval != 0) {
548 re_error(sp, eval, re);
549 goto err;
550 }
551 matched = 1;
552
553 /* Only the first search can match an anchored expression. */
554 eflags |= REG_NOTBOL00001;
555
556 /*
557 * !!!
558 * It's possible to match 0-length strings -- for example, the
559 * command s;a*;X;, when matched against the string "aabb" will
560 * result in "XbXbX", i.e. the matches are "aa", the space
561 * between the b's and the space between the b's and the end of
562 * the string. There is a similar space between the beginning
563 * of the string and the a's. The rule that we use (because vi
564 * historically used it) is that any 0-length match, occurring
565 * immediately after a match, is ignored. Otherwise, the above
566 * example would have resulted in "XXbXbX". Another example is
567 * incorrectly using " *" to replace groups of spaces with one
568 * space.
569 *
570 * If the match is empty and at the same place as the end of the
571 * previous match, ignore the match and move forward. If
572 * there's no more characters in the string, we were
573 * attempting to match after the last character, so quit.
574 */
575 if (match[0].rm_so == nempty && match[0].rm_eo == nempty) {
576 nempty = -1;
577 if (len == 0)
578 goto endmatch;
579 BUILD(sp, s + offset, 1){ if (lbclen + (1) > lblen) { lblen += (((lbclen + (1)) >
(256)) ? (lbclen + (1)) : (256)); { void *tmpp; if (((tmpp) =
(realloc((lb), (lblen)))) == ((void *)0)) { msgq(((sp)), M_SYSERR
, ((void *)0)); free(lb); } lb = tmpp; }; if (lb == ((void *)
0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen, (s + offset
), (1)); lbclen += (1); }
580 ++offset;
581 --len;
582 goto nextmatch;
583 }
584
585 /* Confirm change. */
586 if (sp->c_suffix) {
587 /*
588 * Set the cursor position for confirmation. Note,
589 * if we matched on a '$', the cursor may be past
590 * the end of line.
591 */
592 from.lno = to.lno = lno;
593 from.cno = match[0].rm_so;
594 to.cno = match[0].rm_eo;
595 /*
596 * Both ex and vi have to correct for a change before
597 * the first character in the line.
598 */
599 if (llen == 0)
600 from.cno = to.cno = 0;
601 if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
602 /*
603 * Only vi has to correct for a change after
604 * the last character in the line.
605 *
606 * XXX
607 * It would be nice to change the vi code so
608 * that we could display a cursor past EOL.
609 */
610 if (to.cno >= llen)
611 to.cno = llen - 1;
612 if (from.cno >= llen)
613 from.cno = llen - 1;
614
615 sp->lno = from.lno;
616 sp->cno = from.cno;
617 if (vs_refresh(sp, 1))
618 goto err;
619
620 vs_update(sp, "Confirm change? [n]", NULL((void *)0));
621
622 if (v_event_get(sp, &ev, 0, 0))
623 goto err;
624 switch (ev.e_event) {
625 case E_CHARACTER:
626 break;
627 case E_EOF:
628 case E_ERR:
629 case E_INTERRUPT:
630 goto lquit;
631 default:
632 v_event_err(sp, &ev);
633 goto lquit;
634 }
635 } else {
636 if (ex_print(sp, cmdp, &from, &to, 0) ||
637 ex_scprint(sp, &from, &to))
638 goto lquit;
639 if (ex_txt(sp, &tiq, 0, TXT_CR0x00000800))
640 goto err;
641 ev.e_c_u_event._e_ch.c = TAILQ_FIRST(&tiq)((&tiq)->tqh_first)->lb[0];
642 }
643
644 switch (ev.e_c_u_event._e_ch.c) {
645 case CH_YES'y':
646 break;
647 default:
648 case CH_NO'n':
649 didsub = 0;
650 BUILD(sp, s + offset, match[0].rm_eo - offset){ if (lbclen + (match[0].rm_eo - offset) > lblen) { lblen +=
(((lbclen + (match[0].rm_eo - offset)) > (256)) ? (lbclen
+ (match[0].rm_eo - offset)) : (256)); { void *tmpp; if (((tmpp
) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((sp)), M_SYSERR
, ((void *)0)); free(lb); } lb = tmpp; }; if (lb == ((void *)
0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen, (s + offset
), (match[0].rm_eo - offset)); lbclen += (match[0].rm_eo - offset
); }
;
651 goto skip;
652 case CH_QUIT'q':
653 /* Set the quit/interrupted flags. */
654lquit: quit = 1;
655 F_SET(sp->gp, G_INTERRUPTED)(((sp->gp)->flags) |= ((0x0004)));
656
657 /*
658 * Resolve any changes, then return to (and
659 * exit from) the main loop.
660 */
661 goto endmatch;
662 }
663 }
664
665 /*
666 * Set the cursor to the last position changed, converting
667 * from 1-based to 0-based.
668 */
669 sp->lno = lno;
670 sp->cno = match[0].rm_so;
671
672 /* Copy the bytes before the match into the build buffer. */
673 BUILD(sp, s + offset, match[0].rm_so - offset){ if (lbclen + (match[0].rm_so - offset) > lblen) { lblen +=
(((lbclen + (match[0].rm_so - offset)) > (256)) ? (lbclen
+ (match[0].rm_so - offset)) : (256)); { void *tmpp; if (((tmpp
) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((sp)), M_SYSERR
, ((void *)0)); free(lb); } lb = tmpp; }; if (lb == ((void *)
0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen, (s + offset
), (match[0].rm_so - offset)); lbclen += (match[0].rm_so - offset
); }
;
674
675 /* Substitute the matching bytes. */
676 didsub = 1;
677 if (re_sub(sp, s, &lb, &lbclen, &lblen, match))
678 goto err;
679
680 /* Set the change flag so we know this line was modified. */
681 linechanged = 1;
682
683 /* Move past the matched bytes. */
684skip: offset = match[0].rm_eo;
685 len = llen - match[0].rm_eo;
686
687 /* A match cannot be followed by an empty pattern. */
688 nempty = match[0].rm_eo;
689
690 /*
691 * If doing a global change with confirmation, we have to
692 * update the screen. The basic idea is to store the line
693 * so the screen update routines can find it, and restart.
694 */
695 if (didsub && sp->c_suffix && sp->g_suffix) {
696 /*
697 * The new search offset will be the end of the
698 * modified line.
699 */
700 saved_offset = lbclen;
701
702 /* Copy the rest of the line. */
703 if (len)
704 BUILD(sp, s + offset, len){ if (lbclen + (len) > lblen) { lblen += (((lbclen + (len)
) > (256)) ? (lbclen + (len)) : (256)); { void *tmpp; if (
((tmpp) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((
sp)), M_SYSERR, ((void *)0)); free(lb); } lb = tmpp; }; if (lb
== ((void *)0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen
, (s + offset), (len)); lbclen += (len); }
705
706 /* Set the new offset. */
707 offset = saved_offset;
708
709 /* Store inserted lines, adjusting the build buffer. */
710 last = 0;
711 if (sp->newl_cnt) {
712 for (cnt = 0;
713 cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
714 if (db_insert(sp, lno,
715 lb + last, sp->newl[cnt] - last))
716 goto err;
717 last = sp->newl[cnt] + 1;
718 ++sp->rptlines[L_ADDED0];
719 }
720 lbclen -= last;
721 offset -= last;
722 sp->newl_cnt = 0;
723 }
724
725 /* Store and retrieve the line. */
726 if (db_set(sp, lno, lb + last, lbclen))
727 goto err;
728 if (db_get(sp, lno, DBG_FATAL0x001, &s, &llen))
729 goto err;
730 ADD_SPACE_RET(sp, bp, blen, llen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) { (((L__gp)->flags) &= ~((0x0100))); { void *L__bincp
; if (((llen)) > (L__gp->tmp_blen)) { if ((L__bincp = binc
(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen), ((llen
)))) == ((void *)0)) return (1); (L__gp->tmp_bp) = L__bincp
; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (
((L__gp)->flags) |= ((0x0100))); } else { void *L__bincp; if
(((llen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp
)), &((blen)), ((llen)))) == ((void *)0)) return (1); ((bp
)) = L__bincp; } }; }
731 memcpy(bp, s, llen);
732 s = bp;
733 len = llen - offset;
734
735 /* Restart the build. */
736 lbclen = 0;
737 BUILD(sp, s, offset){ if (lbclen + (offset) > lblen) { lblen += (((lbclen + (offset
)) > (256)) ? (lbclen + (offset)) : (256)); { void *tmpp; if
(((tmpp) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(
((sp)), M_SYSERR, ((void *)0)); free(lb); } lb = tmpp; }; if (
lb == ((void *)0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen
, (s), (offset)); lbclen += (offset); }
;
738
739 /*
740 * If we haven't already done the after-the-string
741 * match, do one. Set REG_NOTEOL so the '$' pattern
742 * only matches once.
743 */
744 if (!do_eol_match)
745 goto endmatch;
746 if (offset == len) {
747 do_eol_match = 0;
748 eflags |= REG_NOTEOL00002;
749 }
750 goto nextmatch;
751 }
752
753 /*
754 * If it's a global:
755 *
756 * If at the end of the string, do a test for the after
757 * the string match. Set REG_NOTEOL so the '$' pattern
758 * only matches once.
759 */
760 if (sp->g_suffix && do_eol_match) {
761 if (len == 0) {
762 do_eol_match = 0;
763 eflags |= REG_NOTEOL00002;
764 }
765 goto nextmatch;
766 }
767
768endmatch: if (!linechanged)
769 continue;
770
771 /* Copy any remaining bytes into the build buffer. */
772 if (len)
773 BUILD(sp, s + offset, len){ if (lbclen + (len) > lblen) { lblen += (((lbclen + (len)
) > (256)) ? (lbclen + (len)) : (256)); { void *tmpp; if (
((tmpp) = (realloc((lb), (lblen)))) == ((void *)0)) { msgq(((
sp)), M_SYSERR, ((void *)0)); free(lb); } lb = tmpp; }; if (lb
== ((void *)0)) { lbclen = 0; return (1); } } memcpy(lb + lbclen
, (s + offset), (len)); lbclen += (len); }
774
775 /* Store inserted lines, adjusting the build buffer. */
776 last = 0;
777 if (sp->newl_cnt) {
778 for (cnt = 0;
779 cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
780 if (db_insert(sp,
781 lno, lb + last, sp->newl[cnt] - last))
782 goto err;
783 last = sp->newl[cnt] + 1;
784 ++sp->rptlines[L_ADDED0];
785 }
786 lbclen -= last;
787 sp->newl_cnt = 0;
788 }
789
790 /* Store the changed line. */
791 if (db_set(sp, lno, lb + last, lbclen))
792 goto err;
793
794 /* Update changed line counter. */
795 if (sp->rptlchange != lno) {
796 sp->rptlchange = lno;
797 ++sp->rptlines[L_CHANGED1];
798 }
799
800 /*
801 * !!!
802 * Display as necessary. Historic practice is to only
803 * display the last line of a line split into multiple
804 * lines.
805 */
806 if (lflag || nflag || pflag) {
807 from.lno = to.lno = lno;
808 from.cno = to.cno = 0;
809 if (lflag)
810 (void)ex_print(sp, cmdp, &from, &to, E_C_LIST0x00400);
811 if (nflag)
812 (void)ex_print(sp, cmdp, &from, &to, E_C_HASH0x00200);
813 if (pflag)
814 (void)ex_print(sp, cmdp, &from, &to, E_C_PRINT0x01000);
815 }
816 }
817
818 /*
819 * !!!
820 * Historically, vi attempted to leave the cursor at the same place if
821 * the substitution was done at the current cursor position. Otherwise
822 * it moved it to the first non-blank of the last line changed. There
823 * were some problems: for example, :s/$/foo/ with the cursor on the
824 * last character of the line left the cursor on the last character, or
825 * the & command with multiple occurrences of the matching string in the
826 * line usually left the cursor in a fairly random position.
827 *
828 * We try to do the same thing, with the exception that if the user is
829 * doing substitution with confirmation, we move to the last line about
830 * which the user was consulted, as opposed to the last line that they
831 * actually changed. This prevents a screen flash if the user doesn't
832 * change many of the possible lines.
833 */
834 if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) {
835 sp->cno = 0;
836 (void)nonblank(sp, sp->lno, &sp->cno);
837 }
838
839 /*
840 * If not in a global command, and nothing matched, say so.
841 * Else, if none of the lines displayed, put something up.
842 */
843 rval = 0;
844 if (!matched) {
845 if (!F_ISSET(sp, SC_EX_GLOBAL)(((sp)->flags) & ((0x00020000)))) {
846 msgq(sp, M_ERR, "No match found");
847 goto err;
848 }
849 } else if (!lflag && !nflag && !pflag)
850 F_SET(cmdp, E_AUTOPRINT)(((cmdp)->flags) |= ((0x00000040)));
851
852 if (0) {
853err: rval = 1;
854 }
855
856 if (bp != NULL((void *)0))
857 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
858 free(lb);
859 return (rval);
860}
861
862/*
863 * re_compile --
864 * Compile the RE.
865 *
866 * PUBLIC: int re_compile(SCR *,
867 * PUBLIC: char *, size_t, char **, size_t *, regex_t *, u_int);
868 */
869int
870re_compile(SCR *sp, char *ptrn, size_t plen, char **ptrnp, size_t *lenp,
871 regex_t *rep, u_int flags)
872{
873 size_t len;
874 int reflags, replaced, rval;
875 char *p;
876
877 /* Set RE flags. */
878 reflags = 0;
879 if (!LF_ISSET(RE_C_TAG)((flags) & ((0x0010)))) {
880 if (O_ISSET(sp, O_EXTENDED)((((&(((sp)))->opts[(((O_EXTENDED)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_EXTENDED
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_EXTENDED))
)].o_cur.val)
)
881 reflags |= REG_EXTENDED0001;
882 if (O_ISSET(sp, O_IGNORECASE)((((&(((sp)))->opts[(((O_IGNORECASE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_IGNORECASE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_IGNORECASE
)))].o_cur.val)
)
883 reflags |= REG_ICASE0002;
884 if (O_ISSET(sp, O_ICLOWER)((((&(((sp)))->opts[(((O_ICLOWER)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_ICLOWER
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_ICLOWER)))
].o_cur.val)
) {
885 for (p = ptrn, len = plen; len > 0; ++p, --len)
886 if (isupper(*p))
887 break;
888 if (len == 0)
889 reflags |= REG_ICASE0002;
890 }
891 }
892
893 /* If we're replacing a saved value, clear the old one. */
894 if (LF_ISSET(RE_C_SEARCH)((flags) & ((0x0002))) && F_ISSET(sp, SC_RE_SEARCH)(((sp)->flags) & ((0x00400000)))) {
895 regfree(&sp->re_c);
896 F_CLR(sp, SC_RE_SEARCH)(((sp)->flags) &= ~((0x00400000)));
897 }
898 if (LF_ISSET(RE_C_SUBST)((flags) & ((0x0008))) && F_ISSET(sp, SC_RE_SUBST)(((sp)->flags) & ((0x00800000)))) {
899 regfree(&sp->subre_c);
900 F_CLR(sp, SC_RE_SUBST)(((sp)->flags) &= ~((0x00800000)));
901 }
902
903 /*
904 * If we're saving the string, it's a pattern we haven't seen before,
905 * so convert the vi-style RE's to POSIX 1003.2 RE's. Save a copy for
906 * later recompilation. Free any previously saved value.
907 */
908 if (ptrnp != NULL((void *)0)) {
909 if (LF_ISSET(RE_C_TAG)((flags) & ((0x0010)))) {
910 if (re_tag_conv(sp, &ptrn, &plen, &replaced))
911 return (1);
912 } else
913 if (re_conv(sp, &ptrn, &plen, &replaced))
914 return (1);
915
916 /* Discard previous pattern. */
917 free(*ptrnp);
918 *ptrnp = NULL((void *)0);
919 if (lenp != NULL((void *)0))
920 *lenp = plen;
921
922 /*
923 * Copy the string into allocated memory.
924 *
925 * XXX
926 * Regcomp isn't 8-bit clean, so the pattern is nul-terminated
927 * for now. There's just no other solution.
928 */
929 MALLOC(sp, *ptrnp, plen + 1){ if (((*ptrnp) = malloc(plen + 1)) == ((void *)0)) msgq((sp)
, M_SYSERR, ((void *)0)); }
;
930 if (*ptrnp != NULL((void *)0)) {
931 memcpy(*ptrnp, ptrn, plen);
932 (*ptrnp)[plen] = '\0';
933 }
934
935 /* Free up conversion-routine-allocated memory. */
936 if (replaced)
937 FREE_SPACE(sp, ptrn, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (ptrn) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(ptrn); }
;
938
939 if (*ptrnp == NULL((void *)0))
940 return (1);
941
942 ptrn = *ptrnp;
943 }
944
945 /*
946 * XXX
947 * Regcomp isn't 8-bit clean, so we just lost if the pattern
948 * contained a nul. Bummer!
949 */
950 if ((rval = regcomp(rep, ptrn, /* plen, */ reflags)) != 0) {
951 if (!LF_ISSET(RE_C_SILENT)((flags) & ((0x0004))))
952 re_error(sp, rval, rep);
953 return (1);
954 }
955
956 if (LF_ISSET(RE_C_SEARCH)((flags) & ((0x0002))))
957 F_SET(sp, SC_RE_SEARCH)(((sp)->flags) |= ((0x00400000)));
958 if (LF_ISSET(RE_C_SUBST)((flags) & ((0x0008))))
959 F_SET(sp, SC_RE_SUBST)(((sp)->flags) |= ((0x00800000)));
960
961 return (0);
962}
963
964/*
965 * re_conv --
966 * Convert vi's regular expressions into something that the
967 * the POSIX 1003.2 RE functions can handle.
968 *
969 * There are two conversions we make to make vi's RE's (specifically
970 * the global, search, and substitute patterns) work with POSIX RE's.
971 * We assume that \<ptrn\> does "word" searches, which is non-standard
972 * but supported by most regexp libraries..
973 *
974 * 1: If O_MAGIC is not set, strip backslashes from the magic character
975 * set (.[*~) that have them, and add them to the ones that don't.
976 * 2: If O_MAGIC is not set, the string "\~" is replaced with the text
977 * from the last substitute command's replacement string. If O_MAGIC
978 * is set, it's the string "~".
979 *
980 * !!!/XXX
981 * This doesn't exactly match the historic behavior of vi because we do
982 * the ~ substitution before calling the RE engine, so magic characters
983 * in the replacement string will be expanded by the RE engine, and they
984 * weren't historically. It's a bug.
985 */
986static int
987re_conv(SCR *sp, char **ptrnp, size_t *plenp, int *replacedp)
988{
989 size_t blen, len, needlen;
990 int magic;
991 char *bp, *p, *t;
992
993 /*
994 * First pass through, we figure out how much space we'll need.
995 * We do it in two passes, on the grounds that most of the time
996 * the user is doing a search and won't have magic characters.
997 * That way we can skip most of the memory allocation and copies.
998 */
999 magic = 0;
1000 for (p = *ptrnp, len = *plenp, needlen = 0; len > 0; ++p, --len)
1001 switch (*p) {
1002 case '\\':
1003 if (len > 1) {
1004 --len;
1005 switch (*++p) {
1006 case '~':
1007 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1008 magic = 1;
1009 needlen += sp->repl_len;
1010 }
1011 break;
1012 case '.':
1013 case '[':
1014 case '*':
1015 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1016 magic = 1;
1017 needlen += 1;
1018 }
1019 break;
1020 default:
1021 needlen += 2;
1022 }
1023 } else
1024 needlen += 1;
1025 break;
1026 case '~':
1027 if (O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1028 magic = 1;
1029 needlen += sp->repl_len;
1030 }
1031 break;
1032 case '.':
1033 case '[':
1034 case '*':
1035 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1036 magic = 1;
1037 needlen += 2;
1038 }
1039 break;
1040 default:
1041 needlen += 1;
1042 break;
1043 }
1044
1045 if (!magic) {
1046 *replacedp = 0;
1047 return (0);
1048 }
1049
1050 /* Get enough memory to hold the final pattern. */
1051 *replacedp = 1;
1052 GET_SPACE_RET(sp, bp, blen, needlen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((needlen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp
)), &((blen)), ((needlen)))) == ((void *)0)) return (1); (
(bp)) = L__bincp; } }; } else { { void *L__bincp; if (((needlen
)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (
L__gp->tmp_bp), &(L__gp->tmp_blen), ((needlen)))) ==
((void *)0)) return (1); (L__gp->tmp_bp) = L__bincp; } };
(bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp
)->flags) |= ((0x0100))); } }
;
1053
1054 for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len)
1055 switch (*p) {
1056 case '\\':
1057 if (len > 1) {
1058 --len;
1059 switch (*++p) {
1060 case '~':
1061 if (O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
)
1062 *t++ = '~';
1063 else {
1064 memcpy(t,
1065 sp->repl, sp->repl_len);
1066 t += sp->repl_len;
1067 }
1068 break;
1069 case '.':
1070 case '[':
1071 case '*':
1072 if (O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
)
1073 *t++ = '\\';
1074 *t++ = *p;
1075 break;
1076 default:
1077 *t++ = '\\';
1078 *t++ = *p;
1079 }
1080 } else
1081 *t++ = '\\';
1082 break;
1083 case '~':
1084 if (O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1085 memcpy(t, sp->repl, sp->repl_len);
1086 t += sp->repl_len;
1087 } else
1088 *t++ = '~';
1089 break;
1090 case '.':
1091 case '[':
1092 case '*':
1093 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
)
1094 *t++ = '\\';
1095 *t++ = *p;
1096 break;
1097 default:
1098 *t++ = *p;
1099 break;
1100 }
1101
1102 *ptrnp = bp;
1103 *plenp = t - bp;
1104 return (0);
1105}
1106
1107/*
1108 * re_tag_conv --
1109 * Convert a tags search path into something that the POSIX
1110 * 1003.2 RE functions can handle.
1111 */
1112static int
1113re_tag_conv(SCR *sp, char **ptrnp, size_t *plenp, int *replacedp)
1114{
1115 size_t blen, len;
1116 int lastdollar;
1117 char *bp, *p, *t;
1118
1119 len = *plenp;
1120
1121 /* Max memory usage is 2 times the length of the string. */
1122 *replacedp = 1;
1123 GET_SPACE_RET(sp, bp, blen, len * 2){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((len * 2)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp
)), &((blen)), ((len * 2)))) == ((void *)0)) return (1); (
(bp)) = L__bincp; } }; } else { { void *L__bincp; if (((len *
2)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp))
, (L__gp->tmp_bp), &(L__gp->tmp_blen), ((len * 2)))
) == ((void *)0)) return (1); (L__gp->tmp_bp) = L__bincp; }
}; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (((
L__gp)->flags) |= ((0x0100))); } }
;
1124
1125 p = *ptrnp;
1126 t = bp;
1127
1128 /* If the last character is a '/' or '?', we just strip it. */
1129 if (len > 0 && (p[len - 1] == '/' || p[len - 1] == '?'))
1130 --len;
1131
1132 /* If the next-to-last or last character is a '$', it's magic. */
1133 if (len > 0 && p[len - 1] == '$') {
1134 --len;
1135 lastdollar = 1;
1136 } else
1137 lastdollar = 0;
1138
1139 /* If the first character is a '/' or '?', we just strip it. */
1140 if (len > 0 && (p[0] == '/' || p[0] == '?')) {
1141 ++p;
1142 --len;
1143 }
1144
1145 /* If the first or second character is a '^', it's magic. */
1146 if (p[0] == '^') {
1147 *t++ = *p++;
1148 --len;
1149 }
1150
1151 /*
1152 * Escape every other magic character we can find, meanwhile stripping
1153 * the backslashes ctags inserts when escaping the search delimiter
1154 * characters.
1155 */
1156 for (; len > 0; --len) {
1157 if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) {
1158 ++p;
1159 --len;
1160 } else if (strchr("^.[]$*", p[0]))
1161 *t++ = '\\';
1162 *t++ = *p++;
1163 if (len == 0)
1164 break;
1165 }
1166 if (lastdollar)
1167 *t++ = '$';
1168
1169 *ptrnp = bp;
1170 *plenp = t - bp;
1171 return (0);
1172}
1173
1174/*
1175 * re_error --
1176 * Report a regular expression error.
1177 *
1178 * PUBLIC: void re_error(SCR *, int, regex_t *);
1179 */
1180void
1181re_error(SCR *sp, int errcode, regex_t *preg)
1182{
1183 size_t s;
1184 char *oe;
1185
1186 s = regerror(errcode, preg, "", 0);
1187 if ((oe = malloc(s)) == NULL((void *)0))
1188 msgq(sp, M_SYSERR, NULL((void *)0));
1189 else {
1190 (void)regerror(errcode, preg, oe, s);
1191 msgq(sp, M_ERR, "RE error: %s", oe);
1192 free(oe);
1193 }
1194}
1195
1196/*
1197 * re_sub --
1198 * Do the substitution for a regular expression.
1199 */
1200static int
1201re_sub(SCR *sp, char *ip, char **lbp, size_t *lbclenp, size_t *lblenp,
1202 regmatch_t match[10])
1203{
1204 enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv;
1205 size_t lbclen, lblen; /* Local copies. */
1206 size_t mlen; /* Match length. */
1207 size_t rpl; /* Remaining replacement length. */
1208 char *rp; /* Replacement pointer. */
1209 int ch;
1210 int no; /* Match replacement offset. */
1211 char *p, *t; /* Buffer pointers. */
1212 char *lb; /* Local copies. */
1213
1214 lb = *lbp; /* Get local copies. */
1215 lbclen = *lbclenp;
1216 lblen = *lblenp;
1217
1218 /*
1219 * QUOTING NOTE:
1220 *
1221 * There are some special sequences that vi provides in the
1222 * replacement patterns.
1223 * & string the RE matched (\& if nomagic set)
1224 * \# n-th regular subexpression
1225 * \E end \U, \L conversion
1226 * \e end \U, \L conversion
1227 * \l convert the next character to lower-case
1228 * \L convert to lower-case, until \E, \e, or end of replacement
1229 * \u convert the next character to upper-case
1230 * \U convert to upper-case, until \E, \e, or end of replacement
1231 *
1232 * Otherwise, since this is the lowest level of replacement, discard
1233 * all escaping characters. This (hopefully) matches historic practice.
1234 */
1235#define OUTCH(ch, nltrans){ CHAR_T __ch = (ch); u_int __value = ((unsigned char)(__ch) <=
254 ? (sp)->gp->special_key[(unsigned char)(__ch)] : (
unsigned char)(__ch) > (sp)->gp->max_special ? 0 : v_key_val
((sp),(__ch))); if ((nltrans) && (__value == K_CR || __value
== K_NL)) { { if ((sp)->newl_len == (sp)->newl_cnt) { (
sp)->newl_len += 25; { void *tmpp; if (((tmpp) = (reallocarray
(((sp)->newl), ((sp)->newl_len), (sizeof(size_t))))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free((sp
)->newl); } (sp)->newl = tmpp; }; if ((sp)->newl == (
(void *)0)) { (sp)->newl_len = 0; return (1); } } }; sp->
newl[sp->newl_cnt++] = lbclen; } else if (conv != C_NOTSET
) { switch (conv) { case C_ONELOWER: conv = C_NOTSET; case C_LOWER
: if (isupper(__ch)) __ch = tolower(__ch); break; case C_ONEUPPER
: conv = C_NOTSET; case C_UPPER: if (islower(__ch)) __ch = toupper
(__ch); break; default: abort(); } } { if (lbclen + (1) > lblen
) { lblen += (((lbclen + (1)) > (256)) ? (lbclen + (1)) : (
256)); { void *tmpp; if (((tmpp) = (realloc((lb), (lblen)))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free(lb)
; } lb = tmpp; }; if (lb == ((void *)0)) { lbclen = 0; return
(1); } (p) = lb + lbclen; } }; *p++ = __ch; ++lbclen; }
{ \
1236 CHAR_T __ch = (ch); \
1237 u_int __value = KEY_VAL(sp, __ch)((unsigned char)(__ch) <= 254 ? (sp)->gp->special_key
[(unsigned char)(__ch)] : (unsigned char)(__ch) > (sp)->
gp->max_special ? 0 : v_key_val((sp),(__ch)))
; \
1238 if ((nltrans) && (__value == K_CR || __value == K_NL)) { \
1239 NEEDNEWLINE(sp){ if ((sp)->newl_len == (sp)->newl_cnt) { (sp)->newl_len
+= 25; { void *tmpp; if (((tmpp) = (reallocarray(((sp)->newl
), ((sp)->newl_len), (sizeof(size_t))))) == ((void *)0)) {
msgq(((sp)), M_SYSERR, ((void *)0)); free((sp)->newl); } (
sp)->newl = tmpp; }; if ((sp)->newl == ((void *)0)) { (
sp)->newl_len = 0; return (1); } } }
; \
1240 sp->newl[sp->newl_cnt++] = lbclen; \
1241 } else if (conv != C_NOTSET) { \
1242 switch (conv) { \
1243 case C_ONELOWER: \
1244 conv = C_NOTSET; \
1245 /* FALLTHROUGH */ \
1246 case C_LOWER: \
1247 if (isupper(__ch)) \
1248 __ch = tolower(__ch); \
1249 break; \
1250 case C_ONEUPPER: \
1251 conv = C_NOTSET; \
1252 /* FALLTHROUGH */ \
1253 case C_UPPER: \
1254 if (islower(__ch)) \
1255 __ch = toupper(__ch); \
1256 break; \
1257 default: \
1258 abort(); \
1259 } \
1260 } \
1261 NEEDSP(sp, 1, p){ if (lbclen + (1) > lblen) { lblen += (((lbclen + (1)) >
(256)) ? (lbclen + (1)) : (256)); { void *tmpp; if (((tmpp) =
(realloc((lb), (lblen)))) == ((void *)0)) { msgq(((sp)), M_SYSERR
, ((void *)0)); free(lb); } lb = tmpp; }; if (lb == ((void *)
0)) { lbclen = 0; return (1); } (p) = lb + lbclen; } }
; \
1262 *p++ = __ch; \
1263 ++lbclen; \
1264}
1265 conv = C_NOTSET;
1266 for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
1267 switch (ch = *rp++) {
1268 case '&':
1269 if (O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1270 no = 0;
1271 goto subzero;
1272 }
1273 break;
1274 case '\\':
1275 if (rpl == 0)
1276 break;
1277 --rpl;
1278 switch (ch = *rp) {
1279 case '&':
1280 ++rp;
1281 if (!O_ISSET(sp, O_MAGIC)((((&(((sp)))->opts[(((O_MAGIC)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_MAGIC
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_MAGIC)))].
o_cur.val)
) {
1282 no = 0;
1283 goto subzero;
1284 }
1285 break;
1286 case '0': case '1': case '2': case '3': case '4':
1287 case '5': case '6': case '7': case '8': case '9':
1288 no = *rp++ - '0';
1289subzero: if (match[no].rm_so == -1 ||
1290 match[no].rm_eo == -1)
1291 break;
1292 mlen = match[no].rm_eo - match[no].rm_so;
1293 for (t = ip + match[no].rm_so; mlen--; ++t)
1294 OUTCH(*t, 0){ CHAR_T __ch = (*t); u_int __value = ((unsigned char)(__ch) <=
254 ? (sp)->gp->special_key[(unsigned char)(__ch)] : (
unsigned char)(__ch) > (sp)->gp->max_special ? 0 : v_key_val
((sp),(__ch))); if ((0) && (__value == K_CR || __value
== K_NL)) { { if ((sp)->newl_len == (sp)->newl_cnt) { (
sp)->newl_len += 25; { void *tmpp; if (((tmpp) = (reallocarray
(((sp)->newl), ((sp)->newl_len), (sizeof(size_t))))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free((sp
)->newl); } (sp)->newl = tmpp; }; if ((sp)->newl == (
(void *)0)) { (sp)->newl_len = 0; return (1); } } }; sp->
newl[sp->newl_cnt++] = lbclen; } else if (conv != C_NOTSET
) { switch (conv) { case C_ONELOWER: conv = C_NOTSET; case C_LOWER
: if (isupper(__ch)) __ch = tolower(__ch); break; case C_ONEUPPER
: conv = C_NOTSET; case C_UPPER: if (islower(__ch)) __ch = toupper
(__ch); break; default: abort(); } } { if (lbclen + (1) > lblen
) { lblen += (((lbclen + (1)) > (256)) ? (lbclen + (1)) : (
256)); { void *tmpp; if (((tmpp) = (realloc((lb), (lblen)))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free(lb)
; } lb = tmpp; }; if (lb == ((void *)0)) { lbclen = 0; return
(1); } (p) = lb + lbclen; } }; *p++ = __ch; ++lbclen; }
;
1295 continue;
1296 case 'e':
1297 case 'E':
1298 ++rp;
1299 conv = C_NOTSET;
1300 continue;
1301 case 'l':
1302 ++rp;
1303 conv = C_ONELOWER;
1304 continue;
1305 case 'L':
1306 ++rp;
1307 conv = C_LOWER;
1308 continue;
1309 case 'u':
1310 ++rp;
1311 conv = C_ONEUPPER;
1312 continue;
1313 case 'U':
1314 ++rp;
1315 conv = C_UPPER;
1316 continue;
1317 default:
1318 ++rp;
1319 break;
1320 }
1321 }
1322 OUTCH(ch, 1){ CHAR_T __ch = (ch); u_int __value = ((unsigned char)(__ch) <=
254 ? (sp)->gp->special_key[(unsigned char)(__ch)] : (
unsigned char)(__ch) > (sp)->gp->max_special ? 0 : v_key_val
((sp),(__ch))); if ((1) && (__value == K_CR || __value
== K_NL)) { { if ((sp)->newl_len == (sp)->newl_cnt) { (
sp)->newl_len += 25; { void *tmpp; if (((tmpp) = (reallocarray
(((sp)->newl), ((sp)->newl_len), (sizeof(size_t))))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free((sp
)->newl); } (sp)->newl = tmpp; }; if ((sp)->newl == (
(void *)0)) { (sp)->newl_len = 0; return (1); } } }; sp->
newl[sp->newl_cnt++] = lbclen; } else if (conv != C_NOTSET
) { switch (conv) { case C_ONELOWER: conv = C_NOTSET; case C_LOWER
: if (isupper(__ch)) __ch = tolower(__ch); break; case C_ONEUPPER
: conv = C_NOTSET; case C_UPPER: if (islower(__ch)) __ch = toupper
(__ch); break; default: abort(); } } { if (lbclen + (1) > lblen
) { lblen += (((lbclen + (1)) > (256)) ? (lbclen + (1)) : (
256)); { void *tmpp; if (((tmpp) = (realloc((lb), (lblen)))) ==
((void *)0)) { msgq(((sp)), M_SYSERR, ((void *)0)); free(lb)
; } lb = tmpp; }; if (lb == ((void *)0)) { lbclen = 0; return
(1); } (p) = lb + lbclen; } }; *p++ = __ch; ++lbclen; }
;
1323 }
1324
1325 *lbp = lb; /* Update caller's information. */
1326 *lbclenp = lbclen;
1327 *lblenp = lblen;
1328 return (0);
1329}