1*cc73507aSchristos /* $NetBSD: ex_subst.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
23a571abcSchristos /*-
33a571abcSchristos * Copyright (c) 1992, 1993, 1994
43a571abcSchristos * The Regents of the University of California. All rights reserved.
53a571abcSchristos * Copyright (c) 1992, 1993, 1994, 1995, 1996
63a571abcSchristos * Keith Bostic. All rights reserved.
73a571abcSchristos *
83a571abcSchristos * See the LICENSE file for redistribution information.
93a571abcSchristos */
103a571abcSchristos
113a571abcSchristos #include "config.h"
123a571abcSchristos
13*cc73507aSchristos #include <sys/cdefs.h>
14*cc73507aSchristos #if 0
153a571abcSchristos #ifndef lint
163a571abcSchristos static const char sccsid[] = "Id: ex_subst.c,v 10.50 2002/02/09 21:18:23 skimo Exp (Berkeley) Date: 2002/02/09 21:18:23 ";
173a571abcSchristos #endif /* not lint */
18*cc73507aSchristos #else
19*cc73507aSchristos __RCSID("$NetBSD: ex_subst.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
20*cc73507aSchristos #endif
213a571abcSchristos
223a571abcSchristos #include <sys/types.h>
233a571abcSchristos #include <sys/queue.h>
243a571abcSchristos #include <sys/time.h>
253a571abcSchristos
263a571abcSchristos #include <bitstring.h>
273a571abcSchristos #include <ctype.h>
283a571abcSchristos #include <errno.h>
293a571abcSchristos #include <limits.h>
303a571abcSchristos #include <stdio.h>
313a571abcSchristos #include <stdlib.h>
323a571abcSchristos #include <string.h>
333a571abcSchristos #include <unistd.h>
343a571abcSchristos
353a571abcSchristos #include "../common/common.h"
363a571abcSchristos #include "../vi/vi.h"
373a571abcSchristos
383a571abcSchristos #define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
393a571abcSchristos #define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
403a571abcSchristos
413a571abcSchristos static int re_conv __P((SCR *, CHAR_T **, size_t *, int *));
423a571abcSchristos static int re_cscope_conv __P((SCR *, CHAR_T **, size_t *, int *));
433a571abcSchristos static int re_sub __P((SCR *,
443a571abcSchristos CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]));
453a571abcSchristos static int re_tag_conv __P((SCR *, CHAR_T **, size_t *, int *));
463a571abcSchristos static int s __P((SCR *, EXCMD *, CHAR_T *, regex_t *, u_int));
473a571abcSchristos
483a571abcSchristos /*
493a571abcSchristos * ex_s --
503a571abcSchristos * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
513a571abcSchristos *
523a571abcSchristos * Substitute on lines matching a pattern.
533a571abcSchristos *
543a571abcSchristos * PUBLIC: int ex_s __P((SCR *, EXCMD *));
553a571abcSchristos */
563a571abcSchristos int
ex_s(SCR * sp,EXCMD * cmdp)573a571abcSchristos ex_s(SCR *sp, EXCMD *cmdp)
583a571abcSchristos {
593a571abcSchristos regex_t *re;
603a571abcSchristos size_t blen, len;
613a571abcSchristos u_int flags;
6208d478e3Schristos ARG_CHAR_T delim;
633a571abcSchristos CHAR_T *bp, *p, *ptrn, *rep, *t;
643a571abcSchristos
653a571abcSchristos /*
663a571abcSchristos * Skip leading white space.
673a571abcSchristos *
683a571abcSchristos * !!!
693a571abcSchristos * Historic vi allowed any non-alphanumeric to serve as the
703a571abcSchristos * substitution command delimiter.
713a571abcSchristos *
723a571abcSchristos * !!!
733a571abcSchristos * If the arguments are empty, it's the same as &, i.e. we
743a571abcSchristos * repeat the last substitution.
753a571abcSchristos */
763a571abcSchristos if (cmdp->argc == 0)
773a571abcSchristos goto subagain;
783a571abcSchristos for (p = cmdp->argv[0]->bp,
793a571abcSchristos len = cmdp->argv[0]->len; len > 0; --len, ++p) {
8008d478e3Schristos if (!ISBLANK((UCHAR_T)*p))
813a571abcSchristos break;
823a571abcSchristos }
833a571abcSchristos if (len == 0)
843a571abcSchristos subagain: return (ex_subagain(sp, cmdp));
853a571abcSchristos
8608d478e3Schristos delim = (UCHAR_T)*p++;
8708d478e3Schristos if (ISALNUM(delim) || delim == '\\')
883a571abcSchristos return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR));
893a571abcSchristos
903a571abcSchristos /*
913a571abcSchristos * !!!
923a571abcSchristos * The full-blown substitute command reset the remembered
933a571abcSchristos * state of the 'c' and 'g' suffices.
943a571abcSchristos */
953a571abcSchristos sp->c_suffix = sp->g_suffix = 0;
963a571abcSchristos
973a571abcSchristos /*
983a571abcSchristos * Get the pattern string, toss escaping characters.
993a571abcSchristos *
1003a571abcSchristos * !!!
1013a571abcSchristos * Historic vi accepted any of the following forms:
1023a571abcSchristos *
1033a571abcSchristos * :s/abc/def/ change "abc" to "def"
1043a571abcSchristos * :s/abc/def change "abc" to "def"
1053a571abcSchristos * :s/abc/ delete "abc"
1063a571abcSchristos * :s/abc delete "abc"
1073a571abcSchristos *
1083a571abcSchristos * QUOTING NOTE:
1093a571abcSchristos *
1103a571abcSchristos * Only toss an escaping character if it escapes a delimiter.
1113a571abcSchristos * This means that "s/A/\\\\f" replaces "A" with "\\f". It
1123a571abcSchristos * would be nice to be more regular, i.e. for each layer of
1133a571abcSchristos * escaping a single escaping character is removed, but that's
1143a571abcSchristos * not how the historic vi worked.
1153a571abcSchristos */
1163a571abcSchristos for (ptrn = t = p;;) {
1173a571abcSchristos if (p[0] == '\0' || p[0] == delim) {
1183a571abcSchristos if (p[0] == delim)
1193a571abcSchristos ++p;
1203a571abcSchristos /*
1213a571abcSchristos * !!!
1223a571abcSchristos * Nul terminate the pattern string -- it's passed
1233a571abcSchristos * to regcomp which doesn't understand anything else.
1243a571abcSchristos */
1253a571abcSchristos *t = '\0';
1263a571abcSchristos break;
1273a571abcSchristos }
12808d478e3Schristos if (p[0] == '\\') {
1293a571abcSchristos if (p[1] == delim)
1303a571abcSchristos ++p;
1313a571abcSchristos else if (p[1] == '\\')
1323a571abcSchristos *t++ = *p++;
13308d478e3Schristos }
1343a571abcSchristos *t++ = *p++;
1353a571abcSchristos }
1363a571abcSchristos
1373a571abcSchristos /*
1383a571abcSchristos * If the pattern string is empty, use the last RE (not just the
1393a571abcSchristos * last substitution RE).
1403a571abcSchristos */
1413a571abcSchristos if (*ptrn == '\0') {
1423a571abcSchristos if (sp->re == NULL) {
1433a571abcSchristos ex_emsg(sp, NULL, EXM_NOPREVRE);
1443a571abcSchristos return (1);
1453a571abcSchristos }
1463a571abcSchristos
1473a571abcSchristos /* Re-compile the RE if necessary. */
1483a571abcSchristos if (!F_ISSET(sp, SC_RE_SEARCH) &&
1493a571abcSchristos re_compile(sp, sp->re, sp->re_len,
1503a571abcSchristos NULL, NULL, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
1513a571abcSchristos return (1);
1523a571abcSchristos flags = 0;
1533a571abcSchristos } else {
1543a571abcSchristos /*
1553a571abcSchristos * !!!
1563a571abcSchristos * Compile the RE. Historic practice is that substitutes set
1573a571abcSchristos * the search direction as well as both substitute and search
1583a571abcSchristos * RE's. We compile the RE twice, as we don't want to bother
1593a571abcSchristos * ref counting the pattern string and (opaque) structure.
1603a571abcSchristos */
1613a571abcSchristos if (re_compile(sp, ptrn, t - ptrn, &sp->re,
1623a571abcSchristos &sp->re_len, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
1633a571abcSchristos return (1);
1643a571abcSchristos if (re_compile(sp, ptrn, t - ptrn, &sp->subre,
1653a571abcSchristos &sp->subre_len, &sp->subre_c, SEARCH_CSUBST | SEARCH_MSG))
1663a571abcSchristos return (1);
1673a571abcSchristos
1683a571abcSchristos flags = SUB_FIRST;
1693a571abcSchristos sp->searchdir = FORWARD;
1703a571abcSchristos }
1713a571abcSchristos re = &sp->re_c;
1723a571abcSchristos
1733a571abcSchristos /*
1743a571abcSchristos * Get the replacement string.
1753a571abcSchristos *
1763a571abcSchristos * The special character & (\& if O_MAGIC not set) matches the
1773a571abcSchristos * entire RE. No handling of & is required here, it's done by
1783a571abcSchristos * re_sub().
1793a571abcSchristos *
1803a571abcSchristos * The special character ~ (\~ if O_MAGIC not set) inserts the
1813a571abcSchristos * previous replacement string into this replacement string.
1823a571abcSchristos * Count ~'s to figure out how much space we need. We could
1833a571abcSchristos * special case nonexistent last patterns or whether or not
1843a571abcSchristos * O_MAGIC is set, but it's probably not worth the effort.
1853a571abcSchristos *
1863a571abcSchristos * QUOTING NOTE:
1873a571abcSchristos *
1883a571abcSchristos * Only toss an escaping character if it escapes a delimiter or
1893a571abcSchristos * if O_MAGIC is set and it escapes a tilde.
1903a571abcSchristos *
1913a571abcSchristos * !!!
1923a571abcSchristos * If the entire replacement pattern is "%", then use the last
1933a571abcSchristos * replacement pattern. This semantic was added to vi in System
1943a571abcSchristos * V and then percolated elsewhere, presumably around the time
1953a571abcSchristos * that it was added to their version of ed(1).
1963a571abcSchristos */
1973a571abcSchristos if (p[0] == L('\0') || p[0] == delim) {
1983a571abcSchristos if (p[0] == delim)
1993a571abcSchristos ++p;
2003a571abcSchristos if (sp->repl != NULL)
2013a571abcSchristos free(sp->repl);
2023a571abcSchristos sp->repl = NULL;
2033a571abcSchristos sp->repl_len = 0;
2043a571abcSchristos } else if (p[0] == L('%') && (p[1] == L('\0') || p[1] == delim))
2053a571abcSchristos p += p[1] == delim ? 2 : 1;
2063a571abcSchristos else {
2073a571abcSchristos for (rep = p, len = 0;
2083a571abcSchristos p[0] != L('\0') && p[0] != delim; ++p, ++len)
2093a571abcSchristos if (p[0] == L('~'))
2103a571abcSchristos len += sp->repl_len;
2113a571abcSchristos GET_SPACE_RETW(sp, bp, blen, len);
2123a571abcSchristos for (t = bp, len = 0, p = rep;;) {
2133a571abcSchristos if (p[0] == L('\0') || p[0] == delim) {
2143a571abcSchristos if (p[0] == delim)
2153a571abcSchristos ++p;
2163a571abcSchristos break;
2173a571abcSchristos }
2183a571abcSchristos if (p[0] == L('\\')) {
2193a571abcSchristos if (p[1] == delim)
2203a571abcSchristos ++p;
2213a571abcSchristos else if (p[1] == L('\\')) {
2223a571abcSchristos *t++ = *p++;
2233a571abcSchristos ++len;
2243a571abcSchristos } else if (p[1] == L('~')) {
2253a571abcSchristos ++p;
2263a571abcSchristos if (!O_ISSET(sp, O_MAGIC))
2273a571abcSchristos goto tilde;
2283a571abcSchristos }
2293a571abcSchristos } else if (p[0] == L('~') && O_ISSET(sp, O_MAGIC)) {
2303a571abcSchristos tilde: ++p;
2313a571abcSchristos MEMCPYW(t, sp->repl, sp->repl_len);
2323a571abcSchristos t += sp->repl_len;
2333a571abcSchristos len += sp->repl_len;
2343a571abcSchristos continue;
2353a571abcSchristos }
2363a571abcSchristos *t++ = *p++;
2373a571abcSchristos ++len;
2383a571abcSchristos }
2393a571abcSchristos if ((sp->repl_len = len) != 0) {
2403a571abcSchristos if (sp->repl != NULL)
2413a571abcSchristos free(sp->repl);
2423a571abcSchristos if ((sp->repl = malloc(len * sizeof(CHAR_T))) == NULL) {
2433a571abcSchristos msgq(sp, M_SYSERR, NULL);
2443a571abcSchristos FREE_SPACEW(sp, bp, blen);
2453a571abcSchristos return (1);
2463a571abcSchristos }
2473a571abcSchristos MEMCPYW(sp->repl, bp, len);
2483a571abcSchristos }
2493a571abcSchristos FREE_SPACEW(sp, bp, blen);
2503a571abcSchristos }
2513a571abcSchristos return (s(sp, cmdp, p, re, flags));
2523a571abcSchristos }
2533a571abcSchristos
2543a571abcSchristos /*
2553a571abcSchristos * ex_subagain --
2563a571abcSchristos * [line [,line]] & [cgr] [count] [#lp]]
2573a571abcSchristos *
2583a571abcSchristos * Substitute using the last substitute RE and replacement pattern.
2593a571abcSchristos *
2603a571abcSchristos * PUBLIC: int ex_subagain __P((SCR *, EXCMD *));
2613a571abcSchristos */
2623a571abcSchristos int
ex_subagain(SCR * sp,EXCMD * cmdp)2633a571abcSchristos ex_subagain(SCR *sp, EXCMD *cmdp)
2643a571abcSchristos {
2653a571abcSchristos if (sp->subre == NULL) {
2663a571abcSchristos ex_emsg(sp, NULL, EXM_NOPREVRE);
2673a571abcSchristos return (1);
2683a571abcSchristos }
2693a571abcSchristos if (!F_ISSET(sp, SC_RE_SUBST) &&
2703a571abcSchristos re_compile(sp, sp->subre, sp->subre_len,
2713a571abcSchristos NULL, NULL, &sp->subre_c, SEARCH_CSUBST | SEARCH_MSG))
2723a571abcSchristos return (1);
2733a571abcSchristos return (s(sp,
2743a571abcSchristos cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->subre_c, 0));
2753a571abcSchristos }
2763a571abcSchristos
2773a571abcSchristos /*
2783a571abcSchristos * ex_subtilde --
2793a571abcSchristos * [line [,line]] ~ [cgr] [count] [#lp]]
2803a571abcSchristos *
2813a571abcSchristos * Substitute using the last RE and last substitute replacement pattern.
2823a571abcSchristos *
2833a571abcSchristos * PUBLIC: int ex_subtilde __P((SCR *, EXCMD *));
2843a571abcSchristos */
2853a571abcSchristos int
ex_subtilde(SCR * sp,EXCMD * cmdp)2863a571abcSchristos ex_subtilde(SCR *sp, EXCMD *cmdp)
2873a571abcSchristos {
2883a571abcSchristos if (sp->re == NULL) {
2893a571abcSchristos ex_emsg(sp, NULL, EXM_NOPREVRE);
2903a571abcSchristos return (1);
2913a571abcSchristos }
2923a571abcSchristos if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, sp->re,
2933a571abcSchristos sp->re_len, NULL, NULL, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
2943a571abcSchristos return (1);
2953a571abcSchristos return (s(sp,
2963a571abcSchristos cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->re_c, 0));
2973a571abcSchristos }
2983a571abcSchristos
2993a571abcSchristos /*
3003a571abcSchristos * s --
3013a571abcSchristos * Do the substitution. This stuff is *really* tricky. There are lots of
3023a571abcSchristos * special cases, and general nastiness. Don't mess with it unless you're
3033a571abcSchristos * pretty confident.
3043a571abcSchristos *
3053a571abcSchristos * The nasty part of the substitution is what happens when the replacement
3063a571abcSchristos * string contains newlines. It's a bit tricky -- consider the information
3073a571abcSchristos * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is
3083a571abcSchristos * to build a set of newline offsets which we use to break the line up later,
3093a571abcSchristos * when the replacement is done. Don't change it unless you're *damned*
3103a571abcSchristos * confident.
3113a571abcSchristos */
3123a571abcSchristos #define NEEDNEWLINE(sp) { \
3133a571abcSchristos if (sp->newl_len == sp->newl_cnt) { \
3143a571abcSchristos sp->newl_len += 25; \
3153a571abcSchristos REALLOC(sp, sp->newl, size_t *, \
3163a571abcSchristos sp->newl_len * sizeof(size_t)); \
3173a571abcSchristos if (sp->newl == NULL) { \
3183a571abcSchristos sp->newl_len = 0; \
3193a571abcSchristos return (1); \
3203a571abcSchristos } \
3213a571abcSchristos } \
3223a571abcSchristos }
3233a571abcSchristos
3243a571abcSchristos #define BUILD(sp, l, len) { \
3253a571abcSchristos if (lbclen + (len) > lblen) { \
3263a571abcSchristos lblen += MAX(lbclen + (len), 256); \
3273a571abcSchristos REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T)); \
3283a571abcSchristos if (lb == NULL) { \
3293a571abcSchristos lbclen = 0; \
3303a571abcSchristos return (1); \
3313a571abcSchristos } \
3323a571abcSchristos } \
3333a571abcSchristos MEMCPYW(lb + lbclen, l, len); \
3343a571abcSchristos lbclen += len; \
3353a571abcSchristos }
3363a571abcSchristos
3373a571abcSchristos #define NEEDSP(sp, len, pnt) { \
3383a571abcSchristos if (lbclen + (len) > lblen) { \
3393a571abcSchristos lblen += MAX(lbclen + (len), 256); \
3403a571abcSchristos REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T)); \
3413a571abcSchristos if (lb == NULL) { \
3423a571abcSchristos lbclen = 0; \
3433a571abcSchristos return (1); \
3443a571abcSchristos } \
3453a571abcSchristos pnt = lb + lbclen; \
3463a571abcSchristos } \
3473a571abcSchristos }
3483a571abcSchristos
3493a571abcSchristos static int
s(SCR * sp,EXCMD * cmdp,CHAR_T * st,regex_t * re,u_int flags)35008d478e3Schristos s(SCR *sp, EXCMD *cmdp, CHAR_T *st, regex_t *re, u_int flags)
3513a571abcSchristos {
3523a571abcSchristos EVENT ev;
3533a571abcSchristos MARK from, to;
3543a571abcSchristos TEXTH tiq;
3553a571abcSchristos db_recno_t elno, lno, slno;
3563a571abcSchristos u_long ul;
3573a571abcSchristos regmatch_t match[10];
3583a571abcSchristos size_t blen, cnt, last, lbclen, lblen, len, llen;
3593a571abcSchristos size_t offset, saved_offset, scno;
36008d478e3Schristos int lflag, nflag, pflag, rflag;
3613a571abcSchristos int didsub, do_eol_match, eflags, empty_ok, eval;
3623a571abcSchristos int linechanged, matched, quit, rval;
36308d478e3Schristos CHAR_T *lb, *bp;
3643a571abcSchristos enum nresult nret;
3653a571abcSchristos
3663a571abcSchristos NEEDFILE(sp, cmdp);
3673a571abcSchristos
3683a571abcSchristos slno = sp->lno;
3693a571abcSchristos scno = sp->cno;
3703a571abcSchristos
3713a571abcSchristos /*
3723a571abcSchristos * !!!
3733a571abcSchristos * Historically, the 'g' and 'c' suffices were always toggled as flags,
3743a571abcSchristos * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was
3753a571abcSchristos * not set, they were initialized to 0 for all substitute commands. If
3763a571abcSchristos * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user
3773a571abcSchristos * specified substitute/replacement patterns (see ex_s()).
3783a571abcSchristos */
3793a571abcSchristos if (!O_ISSET(sp, O_EDCOMPATIBLE))
3803a571abcSchristos sp->c_suffix = sp->g_suffix = 0;
3813a571abcSchristos
3823a571abcSchristos /*
3833a571abcSchristos * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
3843a571abcSchristos * it only displayed the last change. I'd disallow them, but they are
3853a571abcSchristos * useful in combination with the [v]global commands. In the current
3863a571abcSchristos * model the problem is combining them with the 'c' flag -- the screen
3873a571abcSchristos * would have to flip back and forth between the confirm screen and the
3883a571abcSchristos * ex print screen, which would be pretty awful. We do display all
3893a571abcSchristos * changes, though, for what that's worth.
3903a571abcSchristos *
3913a571abcSchristos * !!!
3923a571abcSchristos * Historic vi was fairly strict about the order of "options", the
3933a571abcSchristos * count, and "flags". I'm somewhat fuzzy on the difference between
3943a571abcSchristos * options and flags, anyway, so this is a simpler approach, and we
3953a571abcSchristos * just take it them in whatever order the user gives them. (The ex
3963a571abcSchristos * usage statement doesn't reflect this.)
3973a571abcSchristos */
39808d478e3Schristos lflag = nflag = pflag = rflag = 0;
39908d478e3Schristos if (st == NULL)
4003a571abcSchristos goto noargs;
40108d478e3Schristos for (lno = OOBLNO; *st != '\0'; ++st)
40208d478e3Schristos switch (*st) {
4033a571abcSchristos case ' ':
4043a571abcSchristos case '\t':
4053a571abcSchristos continue;
4063a571abcSchristos case '+':
4073a571abcSchristos ++cmdp->flagoff;
4083a571abcSchristos break;
4093a571abcSchristos case '-':
4103a571abcSchristos --cmdp->flagoff;
4113a571abcSchristos break;
4123a571abcSchristos case '0': case '1': case '2': case '3': case '4':
4133a571abcSchristos case '5': case '6': case '7': case '8': case '9':
4143a571abcSchristos if (lno != OOBLNO)
4153a571abcSchristos goto usage;
4163a571abcSchristos errno = 0;
41708d478e3Schristos nret = nget_uslong(sp, &ul, st, &st, 10);
4183a571abcSchristos lno = ul;
41908d478e3Schristos if (*st == '\0') /* Loop increment correction. */
42008d478e3Schristos --st;
4213a571abcSchristos if (nret != NUM_OK) {
4223a571abcSchristos if (nret == NUM_OVER)
4233a571abcSchristos msgq(sp, M_ERR, "153|Count overflow");
4243a571abcSchristos else if (nret == NUM_UNDER)
4253a571abcSchristos msgq(sp, M_ERR, "154|Count underflow");
4263a571abcSchristos else
4273a571abcSchristos msgq(sp, M_SYSERR, NULL);
4283a571abcSchristos return (1);
4293a571abcSchristos }
4303a571abcSchristos /*
4313a571abcSchristos * In historic vi, the count was inclusive from the
4323a571abcSchristos * second address.
4333a571abcSchristos */
4343a571abcSchristos cmdp->addr1.lno = cmdp->addr2.lno;
4353a571abcSchristos cmdp->addr2.lno += lno - 1;
4363a571abcSchristos if (!db_exist(sp, cmdp->addr2.lno) &&
4373a571abcSchristos db_last(sp, &cmdp->addr2.lno))
4383a571abcSchristos return (1);
4393a571abcSchristos break;
4403a571abcSchristos case '#':
4413a571abcSchristos nflag = 1;
4423a571abcSchristos break;
4433a571abcSchristos case 'c':
4443a571abcSchristos sp->c_suffix = !sp->c_suffix;
4453a571abcSchristos
4463a571abcSchristos /* Ex text structure initialization. */
4473a571abcSchristos if (F_ISSET(sp, SC_EX)) {
4483a571abcSchristos memset(&tiq, 0, sizeof(TEXTH));
4490b5c88f5Schristos TAILQ_INIT(&tiq);
4503a571abcSchristos }
4513a571abcSchristos break;
4523a571abcSchristos case 'g':
4533a571abcSchristos sp->g_suffix = !sp->g_suffix;
4543a571abcSchristos break;
4553a571abcSchristos case 'l':
4563a571abcSchristos lflag = 1;
4573a571abcSchristos break;
4583a571abcSchristos case 'p':
4593a571abcSchristos pflag = 1;
4603a571abcSchristos break;
4613a571abcSchristos case 'r':
4623a571abcSchristos if (LF_ISSET(SUB_FIRST)) {
4633a571abcSchristos msgq(sp, M_ERR,
4643a571abcSchristos "155|Regular expression specified; r flag meaningless");
4653a571abcSchristos return (1);
4663a571abcSchristos }
4673a571abcSchristos if (!F_ISSET(sp, SC_RE_SEARCH)) {
4683a571abcSchristos ex_emsg(sp, NULL, EXM_NOPREVRE);
4693a571abcSchristos return (1);
4703a571abcSchristos }
4713a571abcSchristos rflag = 1;
4723a571abcSchristos re = &sp->re_c;
4733a571abcSchristos break;
4743a571abcSchristos default:
4753a571abcSchristos goto usage;
4763a571abcSchristos }
4773a571abcSchristos
47808d478e3Schristos if (*st != '\0' || (!rflag && LF_ISSET(SUB_MUSTSETR))) {
4793a571abcSchristos usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
4803a571abcSchristos return (1);
4813a571abcSchristos }
4823a571abcSchristos
4833a571abcSchristos noargs: if (F_ISSET(sp, SC_VI) && sp->c_suffix && (lflag || nflag || pflag)) {
4843a571abcSchristos msgq(sp, M_ERR,
4853a571abcSchristos "156|The #, l and p flags may not be combined with the c flag in vi mode");
4863a571abcSchristos return (1);
4873a571abcSchristos }
4883a571abcSchristos
4893a571abcSchristos /*
4903a571abcSchristos * bp: if interactive, line cache
4913a571abcSchristos * blen: if interactive, line cache length
4923a571abcSchristos * lb: build buffer pointer.
4933a571abcSchristos * lbclen: current length of built buffer.
4943a571abcSchristos * lblen; length of build buffer.
4953a571abcSchristos */
4963a571abcSchristos bp = lb = NULL;
4973a571abcSchristos blen = lbclen = lblen = 0;
4983a571abcSchristos
4993a571abcSchristos /* For each line... */
5003a571abcSchristos lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno;
5013a571abcSchristos for (matched = quit = 0,
5023a571abcSchristos elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
5033a571abcSchristos
5043a571abcSchristos /* Someone's unhappy, time to stop. */
5053a571abcSchristos if (INTERRUPTED(sp))
5063a571abcSchristos break;
5073a571abcSchristos
5083a571abcSchristos /* Get the line. */
50908d478e3Schristos if (db_get(sp, lno, DBG_FATAL, &st, &llen))
5103a571abcSchristos goto err;
5113a571abcSchristos
5123a571abcSchristos /*
5133a571abcSchristos * Make a local copy if doing confirmation -- when calling
5143a571abcSchristos * the confirm routine we're likely to lose the cached copy.
5153a571abcSchristos */
5163a571abcSchristos if (sp->c_suffix) {
5173a571abcSchristos if (bp == NULL) {
5183a571abcSchristos GET_SPACE_RETW(sp, bp, blen, llen);
5193a571abcSchristos } else
5203a571abcSchristos ADD_SPACE_RETW(sp, bp, blen, llen);
52108d478e3Schristos MEMCPYW(bp, st, llen);
52208d478e3Schristos st = bp;
5233a571abcSchristos }
5243a571abcSchristos
5253a571abcSchristos /* Start searching from the beginning. */
5263a571abcSchristos offset = 0;
5273a571abcSchristos len = llen;
5283a571abcSchristos
5293a571abcSchristos /* Reset the build buffer offset. */
5303a571abcSchristos lbclen = 0;
5313a571abcSchristos
5323a571abcSchristos /* Reset empty match flag. */
5333a571abcSchristos empty_ok = 1;
5343a571abcSchristos
5353a571abcSchristos /*
5363a571abcSchristos * We don't want to have to do a setline if the line didn't
5373a571abcSchristos * change -- keep track of whether or not this line changed.
5383a571abcSchristos * If doing confirmations, don't want to keep setting the
5393a571abcSchristos * line if change is refused -- keep track of substitutions.
5403a571abcSchristos */
5413a571abcSchristos didsub = linechanged = 0;
5423a571abcSchristos
5433a571abcSchristos /* New line, do an EOL match. */
5443a571abcSchristos do_eol_match = 1;
5453a571abcSchristos
5463a571abcSchristos /* It's not nul terminated, but we pretend it is. */
5473a571abcSchristos eflags = REG_STARTEND;
5483a571abcSchristos
5493a571abcSchristos /*
55008d478e3Schristos * The search area is from st + offset to the EOL.
5513a571abcSchristos *
5523a571abcSchristos * Generally, match[0].rm_so is the offset of the start
5533a571abcSchristos * of the match from the start of the search, and offset
5543a571abcSchristos * is the offset of the start of the last search.
5553a571abcSchristos */
5563a571abcSchristos nextmatch: match[0].rm_so = 0;
5573a571abcSchristos match[0].rm_eo = len;
5583a571abcSchristos
5593a571abcSchristos /* Get the next match. */
56008d478e3Schristos eval = regexec(re, st + offset, 10, match, eflags);
5613a571abcSchristos
5623a571abcSchristos /*
5633a571abcSchristos * There wasn't a match or if there was an error, deal with
5643a571abcSchristos * it. If there was a previous match in this line, resolve
5653a571abcSchristos * the changes into the database. Otherwise, just move on.
5663a571abcSchristos */
5673a571abcSchristos if (eval == REG_NOMATCH)
5683a571abcSchristos goto endmatch;
5693a571abcSchristos if (eval != 0) {
5703a571abcSchristos re_error(sp, eval, re);
5713a571abcSchristos goto err;
5723a571abcSchristos }
5733a571abcSchristos matched = 1;
5743a571abcSchristos
5753a571abcSchristos /* Only the first search can match an anchored expression. */
5763a571abcSchristos eflags |= REG_NOTBOL;
5773a571abcSchristos
5783a571abcSchristos /*
5793a571abcSchristos * !!!
5803a571abcSchristos * It's possible to match 0-length strings -- for example, the
5813a571abcSchristos * command s;a*;X;, when matched against the string "aabb" will
5823a571abcSchristos * result in "XbXbX", i.e. the matches are "aa", the space
5833a571abcSchristos * between the b's and the space between the b's and the end of
5843a571abcSchristos * the string. There is a similar space between the beginning
5853a571abcSchristos * of the string and the a's. The rule that we use (because vi
5863a571abcSchristos * historically used it) is that any 0-length match, occurring
5873a571abcSchristos * immediately after a match, is ignored. Otherwise, the above
5883a571abcSchristos * example would have resulted in "XXbXbX". Another example is
5893a571abcSchristos * incorrectly using " *" to replace groups of spaces with one
5903a571abcSchristos * space.
5913a571abcSchristos *
5923a571abcSchristos * The way we do this is that if we just had a successful match,
5933a571abcSchristos * the starting offset does not skip characters, and the match
5943a571abcSchristos * is empty, ignore the match and move forward. If there's no
5953a571abcSchristos * more characters in the string, we were attempting to match
5963a571abcSchristos * after the last character, so quit.
5973a571abcSchristos */
5983a571abcSchristos if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) {
5993a571abcSchristos empty_ok = 1;
6003a571abcSchristos if (len == 0)
6013a571abcSchristos goto endmatch;
60208d478e3Schristos BUILD(sp, st + offset, 1)
6033a571abcSchristos ++offset;
6043a571abcSchristos --len;
6053a571abcSchristos goto nextmatch;
6063a571abcSchristos }
6073a571abcSchristos
6083a571abcSchristos /* Confirm change. */
6093a571abcSchristos if (sp->c_suffix) {
6103a571abcSchristos /*
6113a571abcSchristos * Set the cursor position for confirmation. Note,
6123a571abcSchristos * if we matched on a '$', the cursor may be past
6133a571abcSchristos * the end of line.
6143a571abcSchristos */
6153a571abcSchristos from.lno = to.lno = lno;
6163a571abcSchristos from.cno = match[0].rm_so + offset;
6173a571abcSchristos to.cno = match[0].rm_eo + offset;
6183a571abcSchristos /*
6193a571abcSchristos * Both ex and vi have to correct for a change before
6203a571abcSchristos * the first character in the line.
6213a571abcSchristos */
6223a571abcSchristos if (llen == 0)
6233a571abcSchristos from.cno = to.cno = 0;
6243a571abcSchristos if (F_ISSET(sp, SC_VI)) {
6253a571abcSchristos /*
6263a571abcSchristos * Only vi has to correct for a change after
6273a571abcSchristos * the last character in the line.
6283a571abcSchristos *
6293a571abcSchristos * XXX
6303a571abcSchristos * It would be nice to change the vi code so
6313a571abcSchristos * that we could display a cursor past EOL.
6323a571abcSchristos */
6333a571abcSchristos if (to.cno >= llen)
6343a571abcSchristos to.cno = llen - 1;
6353a571abcSchristos if (from.cno >= llen)
6363a571abcSchristos from.cno = llen - 1;
6373a571abcSchristos
6383a571abcSchristos sp->lno = from.lno;
6393a571abcSchristos sp->cno = from.cno;
6403a571abcSchristos if (vs_refresh(sp, 1))
6413a571abcSchristos goto err;
6423a571abcSchristos
6433a571abcSchristos vs_update(sp, msg_cat(sp,
6443a571abcSchristos "169|Confirm change? [n]", NULL), NULL);
6453a571abcSchristos
6463a571abcSchristos if (v_event_get(sp, &ev, 0, 0))
6473a571abcSchristos goto err;
6483a571abcSchristos switch (ev.e_event) {
6493a571abcSchristos case E_CHARACTER:
6503a571abcSchristos break;
6513a571abcSchristos case E_EOF:
6523a571abcSchristos case E_ERR:
6533a571abcSchristos case E_INTERRUPT:
6543a571abcSchristos goto lquit;
6553a571abcSchristos default:
6563a571abcSchristos v_event_err(sp, &ev);
6573a571abcSchristos goto lquit;
6583a571abcSchristos }
6593a571abcSchristos } else {
6603a571abcSchristos if (ex_print(sp, cmdp, &from, &to, 0) ||
6613a571abcSchristos ex_scprint(sp, &from, &to))
6623a571abcSchristos goto lquit;
6633a571abcSchristos if (ex_txt(sp, &tiq, 0, TXT_CR))
6643a571abcSchristos goto err;
6650b5c88f5Schristos ev.e_c = TAILQ_FIRST(&tiq)->lb[0];
6663a571abcSchristos }
6673a571abcSchristos
6683a571abcSchristos switch (ev.e_c) {
6693a571abcSchristos case CH_YES:
6703a571abcSchristos break;
6713a571abcSchristos default:
6723a571abcSchristos case CH_NO:
6733a571abcSchristos didsub = 0;
67408d478e3Schristos BUILD(sp, st + offset, match[0].rm_eo);
6753a571abcSchristos goto skip;
6763a571abcSchristos case CH_QUIT:
6773a571abcSchristos /* Set the quit/interrupted flags. */
6783a571abcSchristos lquit: quit = 1;
6793a571abcSchristos F_SET(sp->gp, G_INTERRUPTED);
6803a571abcSchristos
6813a571abcSchristos /*
6823a571abcSchristos * Resolve any changes, then return to (and
6833a571abcSchristos * exit from) the main loop.
6843a571abcSchristos */
6853a571abcSchristos goto endmatch;
6863a571abcSchristos }
6873a571abcSchristos }
6883a571abcSchristos
6893a571abcSchristos /*
6903a571abcSchristos * Set the cursor to the last position changed, converting
6913a571abcSchristos * from 1-based to 0-based.
6923a571abcSchristos */
6933a571abcSchristos sp->lno = lno;
6943a571abcSchristos sp->cno = match[0].rm_so;
6953a571abcSchristos
6963a571abcSchristos /* Copy the bytes before the match into the build buffer. */
69708d478e3Schristos BUILD(sp, st + offset, match[0].rm_so);
6983a571abcSchristos
6993a571abcSchristos /* Substitute the matching bytes. */
7003a571abcSchristos didsub = 1;
70108d478e3Schristos if (re_sub(sp, st + offset, &lb, &lbclen, &lblen, match))
7023a571abcSchristos goto err;
7033a571abcSchristos
7043a571abcSchristos /* Set the change flag so we know this line was modified. */
7053a571abcSchristos linechanged = 1;
7063a571abcSchristos
7073a571abcSchristos /* Move past the matched bytes. */
7083a571abcSchristos skip: offset += match[0].rm_eo;
7093a571abcSchristos len -= match[0].rm_eo;
7103a571abcSchristos
7113a571abcSchristos /* A match cannot be followed by an empty pattern. */
7123a571abcSchristos empty_ok = 0;
7133a571abcSchristos
7143a571abcSchristos /*
7153a571abcSchristos * If doing a global change with confirmation, we have to
7163a571abcSchristos * update the screen. The basic idea is to store the line
7173a571abcSchristos * so the screen update routines can find it, and restart.
7183a571abcSchristos */
7193a571abcSchristos if (didsub && sp->c_suffix && sp->g_suffix) {
7203a571abcSchristos /*
7213a571abcSchristos * The new search offset will be the end of the
7223a571abcSchristos * modified line.
7233a571abcSchristos */
7243a571abcSchristos saved_offset = lbclen;
7253a571abcSchristos
7263a571abcSchristos /* Copy the rest of the line. */
7273a571abcSchristos if (len)
72808d478e3Schristos BUILD(sp, st + offset, len)
7293a571abcSchristos
7303a571abcSchristos /* Set the new offset. */
7313a571abcSchristos offset = saved_offset;
7323a571abcSchristos
7333a571abcSchristos /* Store inserted lines, adjusting the build buffer. */
7343a571abcSchristos last = 0;
7353a571abcSchristos if (sp->newl_cnt) {
7363a571abcSchristos for (cnt = 0;
7373a571abcSchristos cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
7383a571abcSchristos if (db_insert(sp, lno,
7393a571abcSchristos lb + last, sp->newl[cnt] - last))
7403a571abcSchristos goto err;
7413a571abcSchristos last = sp->newl[cnt] + 1;
7423a571abcSchristos ++sp->rptlines[L_ADDED];
7433a571abcSchristos }
7443a571abcSchristos lbclen -= last;
7453a571abcSchristos offset -= last;
7463a571abcSchristos sp->newl_cnt = 0;
7473a571abcSchristos }
7483a571abcSchristos
7493a571abcSchristos /* Store and retrieve the line. */
7503a571abcSchristos if (db_set(sp, lno, lb + last, lbclen))
7513a571abcSchristos goto err;
75208d478e3Schristos if (db_get(sp, lno, DBG_FATAL, &st, &llen))
7533a571abcSchristos goto err;
7543a571abcSchristos ADD_SPACE_RETW(sp, bp, blen, llen)
75508d478e3Schristos MEMCPYW(bp, st, llen);
75608d478e3Schristos st = bp;
7573a571abcSchristos len = llen - offset;
7583a571abcSchristos
7593a571abcSchristos /* Restart the build. */
7603a571abcSchristos lbclen = 0;
76108d478e3Schristos BUILD(sp, st, offset);
7623a571abcSchristos
7633a571abcSchristos /*
7643a571abcSchristos * If we haven't already done the after-the-string
7653a571abcSchristos * match, do one. Set REG_NOTEOL so the '$' pattern
7663a571abcSchristos * only matches once.
7673a571abcSchristos */
7683a571abcSchristos if (!do_eol_match)
7693a571abcSchristos goto endmatch;
7703a571abcSchristos if (offset == len) {
7713a571abcSchristos do_eol_match = 0;
7723a571abcSchristos eflags |= REG_NOTEOL;
7733a571abcSchristos }
7743a571abcSchristos goto nextmatch;
7753a571abcSchristos }
7763a571abcSchristos
7773a571abcSchristos /*
7783a571abcSchristos * If it's a global:
7793a571abcSchristos *
7803a571abcSchristos * If at the end of the string, do a test for the after
7813a571abcSchristos * the string match. Set REG_NOTEOL so the '$' pattern
7823a571abcSchristos * only matches once.
7833a571abcSchristos */
7843a571abcSchristos if (sp->g_suffix && do_eol_match) {
7853a571abcSchristos if (len == 0) {
7863a571abcSchristos do_eol_match = 0;
7873a571abcSchristos eflags |= REG_NOTEOL;
7883a571abcSchristos }
7893a571abcSchristos goto nextmatch;
7903a571abcSchristos }
7913a571abcSchristos
7923a571abcSchristos endmatch: if (!linechanged)
7933a571abcSchristos continue;
7943a571abcSchristos
7953a571abcSchristos /* Copy any remaining bytes into the build buffer. */
7963a571abcSchristos if (len)
79708d478e3Schristos BUILD(sp, st + offset, len)
7983a571abcSchristos
7993a571abcSchristos /* Store inserted lines, adjusting the build buffer. */
8003a571abcSchristos last = 0;
8013a571abcSchristos if (sp->newl_cnt) {
8023a571abcSchristos for (cnt = 0;
8033a571abcSchristos cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
8043a571abcSchristos if (db_insert(sp,
8053a571abcSchristos lno, lb + last, sp->newl[cnt] - last))
8063a571abcSchristos goto err;
8073a571abcSchristos last = sp->newl[cnt] + 1;
8083a571abcSchristos ++sp->rptlines[L_ADDED];
8093a571abcSchristos }
8103a571abcSchristos lbclen -= last;
8113a571abcSchristos sp->newl_cnt = 0;
8123a571abcSchristos }
8133a571abcSchristos
8143a571abcSchristos /* Store the changed line. */
8153a571abcSchristos if (db_set(sp, lno, lb + last, lbclen))
8163a571abcSchristos goto err;
8173a571abcSchristos
8183a571abcSchristos /* Update changed line counter. */
8193a571abcSchristos if (sp->rptlchange != lno) {
8203a571abcSchristos sp->rptlchange = lno;
8213a571abcSchristos ++sp->rptlines[L_CHANGED];
8223a571abcSchristos }
8233a571abcSchristos
8243a571abcSchristos /*
8253a571abcSchristos * !!!
8263a571abcSchristos * Display as necessary. Historic practice is to only
8273a571abcSchristos * display the last line of a line split into multiple
8283a571abcSchristos * lines.
8293a571abcSchristos */
8303a571abcSchristos if (lflag || nflag || pflag) {
8313a571abcSchristos from.lno = to.lno = lno;
8323a571abcSchristos from.cno = to.cno = 0;
8333a571abcSchristos if (lflag)
8343a571abcSchristos (void)ex_print(sp, cmdp, &from, &to, E_C_LIST);
8353a571abcSchristos if (nflag)
8363a571abcSchristos (void)ex_print(sp, cmdp, &from, &to, E_C_HASH);
8373a571abcSchristos if (pflag)
8383a571abcSchristos (void)ex_print(sp, cmdp, &from, &to, E_C_PRINT);
8393a571abcSchristos }
8403a571abcSchristos }
8413a571abcSchristos
8423a571abcSchristos /*
8433a571abcSchristos * !!!
8443a571abcSchristos * Historically, vi attempted to leave the cursor at the same place if
8453a571abcSchristos * the substitution was done at the current cursor position. Otherwise
8463a571abcSchristos * it moved it to the first non-blank of the last line changed. There
8473a571abcSchristos * were some problems: for example, :s/$/foo/ with the cursor on the
8483a571abcSchristos * last character of the line left the cursor on the last character, or
8493a571abcSchristos * the & command with multiple occurrences of the matching string in the
8503a571abcSchristos * line usually left the cursor in a fairly random position.
8513a571abcSchristos *
8523a571abcSchristos * We try to do the same thing, with the exception that if the user is
8533a571abcSchristos * doing substitution with confirmation, we move to the last line about
8543a571abcSchristos * which the user was consulted, as opposed to the last line that they
8553a571abcSchristos * actually changed. This prevents a screen flash if the user doesn't
8563a571abcSchristos * change many of the possible lines.
8573a571abcSchristos */
8583a571abcSchristos if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) {
8593a571abcSchristos sp->cno = 0;
8603a571abcSchristos (void)nonblank(sp, sp->lno, &sp->cno);
8613a571abcSchristos }
8623a571abcSchristos
8633a571abcSchristos /*
8643a571abcSchristos * If not in a global command, and nothing matched, say so.
8653a571abcSchristos * Else, if none of the lines displayed, put something up.
8663a571abcSchristos */
8673a571abcSchristos rval = 0;
8683a571abcSchristos if (!matched) {
8693a571abcSchristos if (!F_ISSET(sp, SC_EX_GLOBAL)) {
8703a571abcSchristos msgq(sp, M_ERR, "157|No match found");
8713a571abcSchristos goto err;
8723a571abcSchristos }
8733a571abcSchristos } else if (!lflag && !nflag && !pflag)
8743a571abcSchristos F_SET(cmdp, E_AUTOPRINT);
8753a571abcSchristos
8763a571abcSchristos if (0) {
8773a571abcSchristos err: rval = 1;
8783a571abcSchristos }
8793a571abcSchristos
8803a571abcSchristos if (bp != NULL)
8813a571abcSchristos FREE_SPACEW(sp, bp, blen);
8823a571abcSchristos if (lb != NULL)
8833a571abcSchristos free(lb);
8843a571abcSchristos return (rval);
8853a571abcSchristos }
8863a571abcSchristos
8873a571abcSchristos /*
8883a571abcSchristos * re_compile --
8893a571abcSchristos * Compile the RE.
8903a571abcSchristos *
8913a571abcSchristos * PUBLIC: int re_compile __P((SCR *,
8923a571abcSchristos * PUBLIC: CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
8933a571abcSchristos */
8943a571abcSchristos int
re_compile(SCR * sp,CHAR_T * ptrn,size_t plen,CHAR_T ** ptrnp,size_t * lenp,regex_t * rep,u_int flags)8953a571abcSchristos re_compile(SCR *sp, CHAR_T *ptrn, size_t plen, CHAR_T **ptrnp, size_t *lenp, regex_t *rep, u_int flags)
8963a571abcSchristos {
8973a571abcSchristos size_t len;
8983a571abcSchristos int reflags, replaced, rval;
8993a571abcSchristos CHAR_T *p;
9003a571abcSchristos
9013a571abcSchristos /* Set RE flags. */
9023a571abcSchristos reflags = 0;
9033a571abcSchristos if (LF_ISSET(SEARCH_EXTEND))
9043a571abcSchristos reflags |= REG_EXTENDED;
9053a571abcSchristos if (LF_ISSET(SEARCH_IC))
9063a571abcSchristos reflags |= REG_ICASE;
9073a571abcSchristos if (LF_ISSET(SEARCH_LITERAL))
9083a571abcSchristos reflags |= REG_NOSPEC;
9093a571abcSchristos if (!LF_ISSET(SEARCH_NOOPT | SEARCH_CSCOPE | SEARCH_TAG)) {
9103a571abcSchristos if (O_ISSET(sp, O_EXTENDED))
9113a571abcSchristos reflags |= REG_EXTENDED;
9123a571abcSchristos if (O_ISSET(sp, O_IGNORECASE))
9133a571abcSchristos reflags |= REG_ICASE;
9143a571abcSchristos if (O_ISSET(sp, O_ICLOWER))
9153a571abcSchristos goto iclower;
9163a571abcSchristos }
9173a571abcSchristos if (LF_ISSET(SEARCH_ICL)) {
9183a571abcSchristos iclower: for (p = ptrn, len = plen; len > 0; ++p, --len)
91908d478e3Schristos if (ISUPPER((UCHAR_T)*p))
9203a571abcSchristos break;
9213a571abcSchristos if (len == 0)
9223a571abcSchristos reflags |= REG_ICASE;
9233a571abcSchristos }
9243a571abcSchristos
9253a571abcSchristos /* If we're replacing a saved value, clear the old one. */
9263a571abcSchristos if (LF_ISSET(SEARCH_CSEARCH) && F_ISSET(sp, SC_RE_SEARCH)) {
9273a571abcSchristos regfree(&sp->re_c);
9283a571abcSchristos F_CLR(sp, SC_RE_SEARCH);
9293a571abcSchristos }
9303a571abcSchristos if (LF_ISSET(SEARCH_CSUBST) && F_ISSET(sp, SC_RE_SUBST)) {
9313a571abcSchristos regfree(&sp->subre_c);
9323a571abcSchristos F_CLR(sp, SC_RE_SUBST);
9333a571abcSchristos }
9343a571abcSchristos
9353a571abcSchristos /*
9363a571abcSchristos * If we're saving the string, it's a pattern we haven't seen before,
9373a571abcSchristos * so convert the vi-style RE's to POSIX 1003.2 RE's. Save a copy for
9383a571abcSchristos * later recompilation. Free any previously saved value.
9393a571abcSchristos */
9403a571abcSchristos if (ptrnp != NULL) {
9413a571abcSchristos replaced = 0;
9423a571abcSchristos if (LF_ISSET(SEARCH_CSCOPE)) {
9433a571abcSchristos if (re_cscope_conv(sp, &ptrn, &plen, &replaced))
9443a571abcSchristos return (1);
9453a571abcSchristos /*
9463a571abcSchristos * XXX
9473a571abcSchristos * Currently, the match-any-<blank> expression used in
9483a571abcSchristos * re_cscope_conv() requires extended RE's. This may
9493a571abcSchristos * not be right or safe.
9503a571abcSchristos */
9513a571abcSchristos reflags |= REG_EXTENDED;
9523a571abcSchristos } else if (LF_ISSET(SEARCH_TAG)) {
9533a571abcSchristos if (re_tag_conv(sp, &ptrn, &plen, &replaced))
9543a571abcSchristos return (1);
9553a571abcSchristos } else if (!LF_ISSET(SEARCH_LITERAL))
9563a571abcSchristos if (re_conv(sp, &ptrn, &plen, &replaced))
9573a571abcSchristos return (1);
9583a571abcSchristos
9593a571abcSchristos /* Discard previous pattern. */
9603a571abcSchristos if (*ptrnp != NULL) {
9613a571abcSchristos free(*ptrnp);
9623a571abcSchristos *ptrnp = NULL;
9633a571abcSchristos }
9643a571abcSchristos if (lenp != NULL)
9653a571abcSchristos *lenp = plen;
9663a571abcSchristos
9673a571abcSchristos /*
9683a571abcSchristos * Copy the string into allocated memory.
9693a571abcSchristos *
9703a571abcSchristos * XXX
9713a571abcSchristos * Regcomp isn't 8-bit clean, so the pattern is nul-terminated
9723a571abcSchristos * for now. There's just no other solution.
9733a571abcSchristos */
9743a571abcSchristos MALLOC(sp, *ptrnp, CHAR_T *, (plen + 1) * sizeof(CHAR_T));
9753a571abcSchristos if (*ptrnp != NULL) {
9763a571abcSchristos MEMCPYW(*ptrnp, ptrn, plen);
9773a571abcSchristos (*ptrnp)[plen] = '\0';
9783a571abcSchristos }
9793a571abcSchristos
9803a571abcSchristos /* Free up conversion-routine-allocated memory. */
9813a571abcSchristos if (replaced)
9823a571abcSchristos FREE_SPACEW(sp, ptrn, 0);
9833a571abcSchristos
9843a571abcSchristos if (*ptrnp == NULL)
9853a571abcSchristos return (1);
9863a571abcSchristos
9873a571abcSchristos ptrn = *ptrnp;
9883a571abcSchristos }
9893a571abcSchristos
9903a571abcSchristos /*
9913a571abcSchristos * XXX
9923a571abcSchristos * Regcomp isn't 8-bit clean, so we just lost if the pattern
9933a571abcSchristos * contained a nul. Bummer!
9943a571abcSchristos */
9953a571abcSchristos if ((rval = regcomp(rep, ptrn, /* plen, */ reflags)) != 0) {
9963a571abcSchristos if (LF_ISSET(SEARCH_MSG))
9973a571abcSchristos re_error(sp, rval, rep);
9983a571abcSchristos return (1);
9993a571abcSchristos }
10003a571abcSchristos
10013a571abcSchristos if (LF_ISSET(SEARCH_CSEARCH))
10023a571abcSchristos F_SET(sp, SC_RE_SEARCH);
10033a571abcSchristos if (LF_ISSET(SEARCH_CSUBST))
10043a571abcSchristos F_SET(sp, SC_RE_SUBST);
10053a571abcSchristos
10063a571abcSchristos return (0);
10073a571abcSchristos }
10083a571abcSchristos
10093a571abcSchristos /*
10103a571abcSchristos * re_conv --
10113a571abcSchristos * Convert vi's regular expressions into something that the
10123a571abcSchristos * the POSIX 1003.2 RE functions can handle.
10133a571abcSchristos *
10143a571abcSchristos * There are three conversions we make to make vi's RE's (specifically
10153a571abcSchristos * the global, search, and substitute patterns) work with POSIX RE's.
10163a571abcSchristos *
10173a571abcSchristos * 1: If O_MAGIC is not set, strip backslashes from the magic character
10183a571abcSchristos * set (.[*~) that have them, and add them to the ones that don't.
10193a571abcSchristos * 2: If O_MAGIC is not set, the string "\~" is replaced with the text
10203a571abcSchristos * from the last substitute command's replacement string. If O_MAGIC
10213a571abcSchristos * is set, it's the string "~".
10223a571abcSchristos * 3: The pattern \<ptrn\> does "word" searches, convert it to use the
10233a571abcSchristos * new RE escapes.
10243a571abcSchristos *
10253a571abcSchristos * !!!/XXX
10263a571abcSchristos * This doesn't exactly match the historic behavior of vi because we do
10273a571abcSchristos * the ~ substitution before calling the RE engine, so magic characters
10283a571abcSchristos * in the replacement string will be expanded by the RE engine, and they
10293a571abcSchristos * weren't historically. It's a bug.
10303a571abcSchristos */
10313a571abcSchristos static int
re_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)10323a571abcSchristos re_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
10333a571abcSchristos {
10343a571abcSchristos size_t blen, len, needlen;
10353a571abcSchristos int magic;
10363a571abcSchristos CHAR_T *bp, *p, *t;
10373a571abcSchristos
10383a571abcSchristos /*
10393a571abcSchristos * First pass through, we figure out how much space we'll need.
10403a571abcSchristos * We do it in two passes, on the grounds that most of the time
10413a571abcSchristos * the user is doing a search and won't have magic characters.
10423a571abcSchristos * That way we can skip most of the memory allocation and copies.
10433a571abcSchristos */
10443a571abcSchristos magic = 0;
10453a571abcSchristos for (p = *ptrnp, len = *plenp, needlen = 0; len > 0; ++p, --len)
10463a571abcSchristos switch (*p) {
10473a571abcSchristos case '\\':
10483a571abcSchristos if (len > 1) {
10493a571abcSchristos --len;
10503a571abcSchristos switch (*++p) {
10513a571abcSchristos case '<':
10523a571abcSchristos magic = 1;
10533a571abcSchristos needlen += RE_WSTART_LEN + 1;
10543a571abcSchristos break;
10553a571abcSchristos case '>':
10563a571abcSchristos magic = 1;
10573a571abcSchristos needlen += RE_WSTOP_LEN + 1;
10583a571abcSchristos break;
10593a571abcSchristos case '~':
10603a571abcSchristos if (!O_ISSET(sp, O_MAGIC)) {
10613a571abcSchristos magic = 1;
10623a571abcSchristos needlen += sp->repl_len;
10633a571abcSchristos }
10643a571abcSchristos break;
10653a571abcSchristos case '.':
10663a571abcSchristos case '[':
10673a571abcSchristos case '*':
10683a571abcSchristos if (!O_ISSET(sp, O_MAGIC)) {
10693a571abcSchristos magic = 1;
10703a571abcSchristos needlen += 1;
10713a571abcSchristos }
10723a571abcSchristos break;
10733a571abcSchristos default:
10743a571abcSchristos needlen += 2;
10753a571abcSchristos }
10763a571abcSchristos } else
10773a571abcSchristos needlen += 1;
10783a571abcSchristos break;
10793a571abcSchristos case '~':
10803a571abcSchristos if (O_ISSET(sp, O_MAGIC)) {
10813a571abcSchristos magic = 1;
10823a571abcSchristos needlen += sp->repl_len;
10833a571abcSchristos }
10843a571abcSchristos break;
10853a571abcSchristos case '.':
10863a571abcSchristos case '[':
10873a571abcSchristos case '*':
10883a571abcSchristos if (!O_ISSET(sp, O_MAGIC)) {
10893a571abcSchristos magic = 1;
10903a571abcSchristos needlen += 2;
10913a571abcSchristos }
10923a571abcSchristos break;
10933a571abcSchristos default:
10943a571abcSchristos needlen += 1;
10953a571abcSchristos break;
10963a571abcSchristos }
10973a571abcSchristos
10983a571abcSchristos if (!magic) {
10993a571abcSchristos *replacedp = 0;
11003a571abcSchristos return (0);
11013a571abcSchristos }
11023a571abcSchristos
11033a571abcSchristos /* Get enough memory to hold the final pattern. */
11043a571abcSchristos *replacedp = 1;
11053a571abcSchristos GET_SPACE_RETW(sp, bp, blen, needlen);
11063a571abcSchristos
11073a571abcSchristos for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len)
11083a571abcSchristos switch (*p) {
11093a571abcSchristos case '\\':
11103a571abcSchristos if (len > 1) {
11113a571abcSchristos --len;
11123a571abcSchristos switch (*++p) {
11133a571abcSchristos case '<':
11143a571abcSchristos MEMCPY(t,
11153a571abcSchristos RE_WSTART, RE_WSTART_LEN);
11163a571abcSchristos t += RE_WSTART_LEN;
11173a571abcSchristos break;
11183a571abcSchristos case '>':
11193a571abcSchristos MEMCPY(t,
11203a571abcSchristos RE_WSTOP, RE_WSTOP_LEN);
11213a571abcSchristos t += RE_WSTOP_LEN;
11223a571abcSchristos break;
11233a571abcSchristos case '~':
11243a571abcSchristos if (O_ISSET(sp, O_MAGIC))
11253a571abcSchristos *t++ = '~';
11263a571abcSchristos else {
11273a571abcSchristos MEMCPYW(t,
11283a571abcSchristos sp->repl, sp->repl_len);
11293a571abcSchristos t += sp->repl_len;
11303a571abcSchristos }
11313a571abcSchristos break;
11323a571abcSchristos case '.':
11333a571abcSchristos case '[':
11343a571abcSchristos case '*':
11353a571abcSchristos if (O_ISSET(sp, O_MAGIC))
11363a571abcSchristos *t++ = '\\';
11373a571abcSchristos *t++ = *p;
11383a571abcSchristos break;
11393a571abcSchristos default:
11403a571abcSchristos *t++ = '\\';
11413a571abcSchristos *t++ = *p;
11423a571abcSchristos }
11433a571abcSchristos } else
11443a571abcSchristos *t++ = '\\';
11453a571abcSchristos break;
11463a571abcSchristos case '~':
11473a571abcSchristos if (O_ISSET(sp, O_MAGIC)) {
11483a571abcSchristos MEMCPYW(t, sp->repl, sp->repl_len);
11493a571abcSchristos t += sp->repl_len;
11503a571abcSchristos } else
11513a571abcSchristos *t++ = '~';
11523a571abcSchristos break;
11533a571abcSchristos case '.':
11543a571abcSchristos case '[':
11553a571abcSchristos case '*':
11563a571abcSchristos if (!O_ISSET(sp, O_MAGIC))
11573a571abcSchristos *t++ = '\\';
11583a571abcSchristos *t++ = *p;
11593a571abcSchristos break;
11603a571abcSchristos default:
11613a571abcSchristos *t++ = *p;
11623a571abcSchristos break;
11633a571abcSchristos }
11643a571abcSchristos
11653a571abcSchristos *ptrnp = bp;
11663a571abcSchristos *plenp = t - bp;
11673a571abcSchristos return (0);
11683a571abcSchristos }
11693a571abcSchristos
11703a571abcSchristos /*
11713a571abcSchristos * re_tag_conv --
11723a571abcSchristos * Convert a tags search path into something that the POSIX
11733a571abcSchristos * 1003.2 RE functions can handle.
11743a571abcSchristos */
11753a571abcSchristos static int
re_tag_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)11763a571abcSchristos re_tag_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
11773a571abcSchristos {
11783a571abcSchristos size_t blen, len;
11793a571abcSchristos int lastdollar;
11803a571abcSchristos CHAR_T *bp, *p, *t;
11813a571abcSchristos
11823a571abcSchristos len = *plenp;
11833a571abcSchristos
11843a571abcSchristos /* Max memory usage is 2 times the length of the string. */
11853a571abcSchristos *replacedp = 1;
11863a571abcSchristos GET_SPACE_RETW(sp, bp, blen, len * 2);
11873a571abcSchristos
11883a571abcSchristos p = *ptrnp;
11893a571abcSchristos t = bp;
11903a571abcSchristos
11913a571abcSchristos /* If the last character is a '/' or '?', we just strip it. */
11923a571abcSchristos if (len > 0 && (p[len - 1] == '/' || p[len - 1] == '?'))
11933a571abcSchristos --len;
11943a571abcSchristos
11953a571abcSchristos /* If the next-to-last or last character is a '$', it's magic. */
11963a571abcSchristos if (len > 0 && p[len - 1] == '$') {
11973a571abcSchristos --len;
11983a571abcSchristos lastdollar = 1;
11993a571abcSchristos } else
12003a571abcSchristos lastdollar = 0;
12013a571abcSchristos
12023a571abcSchristos /* If the first character is a '/' or '?', we just strip it. */
12033a571abcSchristos if (len > 0 && (p[0] == '/' || p[0] == '?')) {
12043a571abcSchristos ++p;
12053a571abcSchristos --len;
12063a571abcSchristos }
12073a571abcSchristos
12083a571abcSchristos /* If the first or second character is a '^', it's magic. */
12093a571abcSchristos if (p[0] == '^') {
12103a571abcSchristos *t++ = *p++;
12113a571abcSchristos --len;
12123a571abcSchristos }
12133a571abcSchristos
12143a571abcSchristos /*
12153a571abcSchristos * Escape every other magic character we can find, meanwhile stripping
12163a571abcSchristos * the backslashes ctags inserts when escaping the search delimiter
12173a571abcSchristos * characters.
12183a571abcSchristos */
12193a571abcSchristos for (; len > 0; --len) {
12203a571abcSchristos if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) {
12213a571abcSchristos ++p;
12223a571abcSchristos --len;
12233a571abcSchristos } else if (strchr("^.[]$*", p[0]))
12243a571abcSchristos *t++ = '\\';
12253a571abcSchristos *t++ = *p++;
12263a571abcSchristos }
12273a571abcSchristos if (lastdollar)
12283a571abcSchristos *t++ = '$';
12293a571abcSchristos
12303a571abcSchristos *ptrnp = bp;
12313a571abcSchristos *plenp = t - bp;
12323a571abcSchristos return (0);
12333a571abcSchristos }
12343a571abcSchristos
12353a571abcSchristos /*
12363a571abcSchristos * re_cscope_conv --
12373a571abcSchristos * Convert a cscope search path into something that the POSIX
12383a571abcSchristos * 1003.2 RE functions can handle.
12393a571abcSchristos */
12403a571abcSchristos static int
re_cscope_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)12413a571abcSchristos re_cscope_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
12423a571abcSchristos {
12433a571abcSchristos size_t blen, len, nspaces;
12443a571abcSchristos CHAR_T *bp, *t;
12453a571abcSchristos CHAR_T *p;
124608d478e3Schristos const CHAR_T *wp;
12473a571abcSchristos size_t wlen;
12483a571abcSchristos
12493a571abcSchristos /*
12503a571abcSchristos * Each space in the source line printed by cscope represents an
12513a571abcSchristos * arbitrary sequence of spaces, tabs, and comments.
12523a571abcSchristos */
12533a571abcSchristos #define CSCOPE_RE_SPACE "([ \t]|/\\*([^*]|\\*/)*\\*/)*"
12543a571abcSchristos #define CSCOPE_LEN sizeof(CSCOPE_RE_SPACE) - 1
12553a571abcSchristos CHAR2INT(sp, CSCOPE_RE_SPACE, CSCOPE_LEN, wp, wlen);
12563a571abcSchristos for (nspaces = 0, p = *ptrnp, len = *plenp; len > 0; ++p, --len)
12573a571abcSchristos if (*p == ' ')
12583a571abcSchristos ++nspaces;
12593a571abcSchristos
12603a571abcSchristos /*
12613a571abcSchristos * Allocate plenty of space:
12623a571abcSchristos * the string, plus potential escaping characters;
12633a571abcSchristos * nspaces + 2 copies of CSCOPE_RE_SPACE;
12643a571abcSchristos * ^, $, nul terminator characters.
12653a571abcSchristos */
12663a571abcSchristos *replacedp = 1;
12673a571abcSchristos len = (p - *ptrnp) * 2 + (nspaces + 2) * sizeof(CSCOPE_RE_SPACE) + 3;
12683a571abcSchristos GET_SPACE_RETW(sp, bp, blen, len);
12693a571abcSchristos
12703a571abcSchristos p = *ptrnp;
12713a571abcSchristos t = bp;
12723a571abcSchristos
12733a571abcSchristos *t++ = '^';
12743a571abcSchristos MEMCPYW(t, wp, wlen);
12753a571abcSchristos t += wlen;
12763a571abcSchristos
12773a571abcSchristos for (len = *plenp; len > 0; ++p, --len)
12783a571abcSchristos if (*p == ' ') {
12793a571abcSchristos MEMCPYW(t, wp, wlen);
12803a571abcSchristos t += wlen;
12813a571abcSchristos } else {
12823a571abcSchristos if (strchr("\\^.[]$*+?()|{}", *p))
12833a571abcSchristos *t++ = '\\';
12843a571abcSchristos *t++ = *p;
12853a571abcSchristos }
12863a571abcSchristos
12873a571abcSchristos MEMCPYW(t, wp, wlen);
12883a571abcSchristos t += wlen;
12893a571abcSchristos *t++ = '$';
12903a571abcSchristos
12913a571abcSchristos *ptrnp = bp;
12923a571abcSchristos *plenp = t - bp;
12933a571abcSchristos return (0);
12943a571abcSchristos }
12953a571abcSchristos
12963a571abcSchristos /*
12973a571abcSchristos * re_error --
12983a571abcSchristos * Report a regular expression error.
12993a571abcSchristos *
13003a571abcSchristos * PUBLIC: void re_error __P((SCR *, int, regex_t *));
13013a571abcSchristos */
13023a571abcSchristos void
re_error(SCR * sp,int errcode,regex_t * preg)13033a571abcSchristos re_error(SCR *sp, int errcode, regex_t *preg)
13043a571abcSchristos {
130508d478e3Schristos size_t sz;
13063a571abcSchristos char *oe;
13073a571abcSchristos
130808d478e3Schristos sz = regerror(errcode, preg, NULL, 0);
130908d478e3Schristos if ((oe = malloc(sz)) == NULL)
13103a571abcSchristos msgq(sp, M_SYSERR, NULL);
13113a571abcSchristos else {
131208d478e3Schristos (void)regerror(errcode, preg, oe, sz);
13133a571abcSchristos msgq(sp, M_ERR, "RE error: %s", oe);
13143a571abcSchristos free(oe);
13153a571abcSchristos }
13163a571abcSchristos }
13173a571abcSchristos
13183a571abcSchristos /*
13193a571abcSchristos * re_sub --
13203a571abcSchristos * Do the substitution for a regular expression.
13213a571abcSchristos */
13223a571abcSchristos static int
re_sub(SCR * sp,CHAR_T * ip,CHAR_T ** lbp,size_t * lbclenp,size_t * lblenp,regmatch_t * match)13233a571abcSchristos re_sub(SCR *sp, CHAR_T *ip, CHAR_T **lbp, size_t *lbclenp, size_t *lblenp, regmatch_t *match)
13243a571abcSchristos
13253a571abcSchristos /* Input line. */
13263a571abcSchristos
13273a571abcSchristos
13283a571abcSchristos
13293a571abcSchristos {
133008d478e3Schristos enum { C_NOT_SET, C_LOWER, C_ONE_LOWER, C_ONE_UPPER, C_UPPER } conv;
13313a571abcSchristos size_t lbclen, lblen; /* Local copies. */
13323a571abcSchristos size_t mlen; /* Match length. */
13333a571abcSchristos size_t rpl; /* Remaining replacement length. */
13343a571abcSchristos CHAR_T *rp; /* Replacement pointer. */
13353a571abcSchristos int ch;
13363a571abcSchristos int no; /* Match replacement offset. */
13373a571abcSchristos CHAR_T *p, *t; /* Buffer pointers. */
13383a571abcSchristos CHAR_T *lb; /* Local copies. */
13393a571abcSchristos
13403a571abcSchristos lb = *lbp; /* Get local copies. */
13413a571abcSchristos lbclen = *lbclenp;
13423a571abcSchristos lblen = *lblenp;
13433a571abcSchristos
13443a571abcSchristos /*
13453a571abcSchristos * QUOTING NOTE:
13463a571abcSchristos *
13473a571abcSchristos * There are some special sequences that vi provides in the
13483a571abcSchristos * replacement patterns.
13493a571abcSchristos * & string the RE matched (\& if nomagic set)
13503a571abcSchristos * \# n-th regular subexpression
13513a571abcSchristos * \E end \U, \L conversion
13523a571abcSchristos * \e end \U, \L conversion
13533a571abcSchristos * \l convert the next character to lower-case
13543a571abcSchristos * \L convert to lower-case, until \E, \e, or end of replacement
13553a571abcSchristos * \u convert the next character to upper-case
13563a571abcSchristos * \U convert to upper-case, until \E, \e, or end of replacement
13573a571abcSchristos *
13583a571abcSchristos * Otherwise, since this is the lowest level of replacement, discard
13593a571abcSchristos * all escaping characters. This (hopefully) matches historic practice.
13603a571abcSchristos */
13613a571abcSchristos #define OUTCH(ch, nltrans) { \
136208d478e3Schristos ARG_CHAR_T __ch = (ch); \
136308d478e3Schristos e_key_t __value = KEY_VAL(sp, __ch); \
13643a571abcSchristos if (nltrans && (__value == K_CR || __value == K_NL)) { \
13653a571abcSchristos NEEDNEWLINE(sp); \
13663a571abcSchristos sp->newl[sp->newl_cnt++] = lbclen; \
136708d478e3Schristos } else if (conv != C_NOT_SET) { \
13683a571abcSchristos switch (conv) { \
136908d478e3Schristos case C_ONE_LOWER: \
137008d478e3Schristos conv = C_NOT_SET; \
13713a571abcSchristos /* FALLTHROUGH */ \
13723a571abcSchristos case C_LOWER: \
137308d478e3Schristos if (ISUPPER(__ch)) \
137408d478e3Schristos __ch = TOLOWER(__ch); \
13753a571abcSchristos break; \
137608d478e3Schristos case C_ONE_UPPER: \
137708d478e3Schristos conv = C_NOT_SET; \
13783a571abcSchristos /* FALLTHROUGH */ \
13793a571abcSchristos case C_UPPER: \
138008d478e3Schristos if (ISLOWER(__ch)) \
138108d478e3Schristos __ch = TOUPPER(__ch); \
13823a571abcSchristos break; \
13833a571abcSchristos default: \
13843a571abcSchristos abort(); \
13853a571abcSchristos } \
13863a571abcSchristos } \
13873a571abcSchristos NEEDSP(sp, 1, p); \
13883a571abcSchristos *p++ = __ch; \
13893a571abcSchristos ++lbclen; \
13903a571abcSchristos }
139108d478e3Schristos conv = C_NOT_SET;
13923a571abcSchristos for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
13933a571abcSchristos switch (ch = *rp++) {
13943a571abcSchristos case '&':
13953a571abcSchristos if (O_ISSET(sp, O_MAGIC)) {
13963a571abcSchristos no = 0;
13973a571abcSchristos goto subzero;
13983a571abcSchristos }
13993a571abcSchristos break;
14003a571abcSchristos case '\\':
14013a571abcSchristos if (rpl == 0)
14023a571abcSchristos break;
14033a571abcSchristos --rpl;
14043a571abcSchristos switch (ch = *rp) {
14053a571abcSchristos case '&':
14063a571abcSchristos ++rp;
14073a571abcSchristos if (!O_ISSET(sp, O_MAGIC)) {
14083a571abcSchristos no = 0;
14093a571abcSchristos goto subzero;
14103a571abcSchristos }
14113a571abcSchristos break;
14123a571abcSchristos case '0': case '1': case '2': case '3': case '4':
14133a571abcSchristos case '5': case '6': case '7': case '8': case '9':
14143a571abcSchristos no = *rp++ - '0';
14153a571abcSchristos subzero: if (match[no].rm_so == -1 ||
14163a571abcSchristos match[no].rm_eo == -1)
14173a571abcSchristos break;
14183a571abcSchristos mlen = match[no].rm_eo - match[no].rm_so;
14193a571abcSchristos for (t = ip + match[no].rm_so; mlen--; ++t)
142008d478e3Schristos OUTCH((UCHAR_T)*t, 0);
14213a571abcSchristos continue;
14223a571abcSchristos case 'e':
14233a571abcSchristos case 'E':
14243a571abcSchristos ++rp;
142508d478e3Schristos conv = C_NOT_SET;
14263a571abcSchristos continue;
14273a571abcSchristos case 'l':
14283a571abcSchristos ++rp;
142908d478e3Schristos conv = C_ONE_LOWER;
14303a571abcSchristos continue;
14313a571abcSchristos case 'L':
14323a571abcSchristos ++rp;
14333a571abcSchristos conv = C_LOWER;
14343a571abcSchristos continue;
14353a571abcSchristos case 'u':
14363a571abcSchristos ++rp;
143708d478e3Schristos conv = C_ONE_UPPER;
14383a571abcSchristos continue;
14393a571abcSchristos case 'U':
14403a571abcSchristos ++rp;
14413a571abcSchristos conv = C_UPPER;
14423a571abcSchristos continue;
14433a571abcSchristos default:
14443a571abcSchristos ++rp;
14453a571abcSchristos break;
14463a571abcSchristos }
14473a571abcSchristos }
14483a571abcSchristos OUTCH(ch, 1);
14493a571abcSchristos }
14503a571abcSchristos
14513a571abcSchristos *lbp = lb; /* Update caller's information. */
14523a571abcSchristos *lbclenp = lbclen;
14533a571abcSchristos *lblenp = lblen;
14543a571abcSchristos return (0);
14553a571abcSchristos }
1456