From 51c2de25c188e649012891a7904f6b46a0b75e91 Mon Sep 17 00:00:00 2001 From: anton Date: Tue, 4 Jul 2017 11:46:15 +0000 Subject: [PATCH] Backout previous due to a bug discovered by zhuk@ that requires some tinkering and is not an easy fix for now. --- bin/ksh/eval.c | 142 +-------------------------------------- bin/ksh/ksh.1 | 14 +--- bin/ksh/lex.c | 4 +- bin/ksh/misc.c | 17 +---- bin/ksh/sh.h | 5 +- regress/bin/ksh/strsub.t | 14 ++++ 6 files changed, 24 insertions(+), 172 deletions(-) diff --git a/bin/ksh/eval.c b/bin/ksh/eval.c index a73906bbfda..ee8f3132727 100644 --- a/bin/ksh/eval.c +++ b/bin/ksh/eval.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eval.c,v 1.52 2017/07/04 07:29:32 anton Exp $ */ +/* $OpenBSD: eval.c,v 1.53 2017/07/04 11:46:15 anton Exp $ */ /* * Expansion - quoting, separation, substitution, globbing @@ -50,7 +50,6 @@ typedef struct Expand { static int varsub(Expand *, char *, char *, int *, int *); static int comsub(Expand *, char *); -static char *strsub(char *, char *, int); static char *trimsub(char *, char *, int); static void glob(char *, XPtrV *, int); static void globit(XString *, char **, char *, XPtrV *, int); @@ -144,7 +143,6 @@ typedef struct SubType { short f; /* saved value of f (DOPAT, etc) */ struct tbl *var; /* variable for ${var..} */ short quote; /* saved value of quote (for ${..[%#]..}) */ - int strsub; /* set to 1 if pat in /pat/rep has been ended */ struct SubType *prev; /* old type */ struct SubType *next; /* poped type (to avoid re-allocating) */ } SubType; @@ -211,21 +209,6 @@ expand(char *cp, /* input word */ break; case CHAR: c = *sp++; - if (st->strsub == 0 && - (st->stype & 0x7f) == '/' && c == '/') { - st->strsub = 1; - /* Write end of pattern. */ - *dp++ = MAGIC; - *dp++ = ')'; - *dp++ = '\0'; - /* - * Reset quote and flags for the - * upcoming replacement. - */ - quote = 0; - f = 0; - continue; - } break; case QCHAR: quote |= 2; /* temporary quote */ @@ -334,7 +317,6 @@ expand(char *cp, /* input word */ switch (stype & 0x7f) { case '#': case '%': - case '/': /* ! DOBLANK,DOBRACE_,DOTILDE */ f = DOPAT | (f&DONTRUNCOMMAND) | DOTEMP_; @@ -396,20 +378,13 @@ expand(char *cp, /* input word */ case '%': /* Append end-pattern */ *dp++ = MAGIC; *dp++ = ')'; *dp = '\0'; - /* FALLTHROUGH */ - case '/': dp = Xrestpos(ds, dp, st->base); /* Must use st->var since calling * global would break things * like x[i+=1]. */ - if ((st->stype & 0x7f) == '/') - x.str = strsub(str_val(st->var), - dp, st->stype); - else - x.str = trimsub( - str_val(st->var), - dp, st->stype); + x.str = trimsub(str_val(st->var), + dp, st->stype); if (x.str[0] != '\0' || st->quote) type = XSUB; else @@ -778,9 +753,6 @@ varsub(Expand *xp, char *sp, char *word, stype = 0x80; c = word[slen + 0] == CHAR ? word[slen + 1] : 0; } - if (c == '/' && Flag(FPOSIX)) - return -1; - if (ctype(c, C_SUBOP1)) { slen += 2; stype |= c; @@ -922,114 +894,6 @@ comsub(Expand *xp, char *cp) return XCOM; } -static char * -strsub(char *str, char *pat, int how) -{ - char *actpat, *dst, *prepat, *rep, *src; - size_t beg, dstlen, dstsiz, end, match, len, patlen, replen; - - len = strlen(str); - if (len == 0) - return str; - src = str; - - dstlen = 0; - dstsiz = len + 1; /* NUL */ - dst = alloc(dstsiz, ATEMP); - - actpat = pat; - patlen = strlen(actpat) + 1; /* NUL */ - prepat = alloc(patlen + 2, ATEMP); /* make room for wildcard */ - /* - * Copy actpat to prepat and add a wildcard after the open pattern - * prefix. - */ - memcpy(prepat, actpat, 2); - prepat[2] = MAGIC; - prepat[3] = '*'; - memcpy(&prepat[4], &actpat[2], patlen - 2); - - rep = &actpat[patlen]; - replen = strlen(rep); - - for (;;) { - /* - * Find the wildcard prefix in prepat followed by actpat. - * This allows occurrences of actpat to be found anywhere in the - * string. - */ - match = 0; - for (end = 1; end <= len; end++) - if (gnmatch(src, end, prepat, 0)) - match = end; - else if (match) - break; - if (!match) - break; - end = match; - - /* - * Find the prefix, if any, that was matched by the wildcard in - * prepat. - */ - match = 0; - for (beg = 0; beg < end; beg++) - if ((match = gnmatch(src + beg, end - beg, actpat, 0))) - break; - - /* - * At this point, [src, beg) contains the prefix that is present - * before the actual pattern and [beg, end) what was matched by - * the actual pattern. - * The first range will be copied over to dst and the latter - * replaced with rep. - */ - if (match && beg > 0) { - if (beg + dstlen >= dstsiz) { - dst = areallocarray(dst, 1, dstsiz + beg + 1, - ATEMP); - dstsiz += beg + 1; - } - memcpy(&dst[dstlen], src, beg); - dstlen += beg; - } - - if (replen + dstlen >= dstsiz) { - dst = areallocarray(dst, 1, dstsiz + replen + 1, ATEMP); - dstsiz += replen + 1; - } - memcpy(&dst[dstlen], rep, replen); - dstlen += replen; - - src += end; - len -= end; - if (len == 0 || how == '/') - break; - } - - afree(prepat, ATEMP); - - if (str == src) { - /* No substitutions performed. */ - afree(dst, ATEMP); - - return str; - } - - /* Copy unmatched suffix from src. */ - if (len > 0) { - if (len + dstlen >= dstsiz) { - dst = areallocarray(dst, 1, dstsiz + len + 1, ATEMP); - dstsiz += len + 1; - } - memcpy(&dst[dstlen], src, len); - dstlen += len; - } - dst[dstlen] = '\0'; - - return dst; -} - /* * perform #pattern and %pattern substitution in ${} */ diff --git a/bin/ksh/ksh.1 b/bin/ksh/ksh.1 index 4902e06ffae..64b08b13df8 100644 --- a/bin/ksh/ksh.1 +++ b/bin/ksh/ksh.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ksh.1,v 1.189 2017/07/04 07:29:32 anton Exp $ +.\" $OpenBSD: ksh.1,v 1.190 2017/07/04 11:46:15 anton Exp $ .\" .\" Public Domain .\" @@ -1240,18 +1240,6 @@ of them result in the longest match. .It Pf ${ Ar name Ns % Ns Ar pattern Ns } .It Pf ${ Ar name Ns %% Ns Ar pattern Ns } Like ${..#..} substitution, but it deletes from the end of the value. -.Pp -.It Pf ${ Ns Ar name Ns / Ns Ar pattern Ns / Ns Ar replacement Ns } -.It Pf ${ Ns Ar name Ns // Ns Ar pattern Ns / Ns Ar replacement Ns } -The first longest match of -.Ar pattern -in the value of parameter -.Ar name -is substituted with -.Ar replacement . -Using -.Ql // , -all matches are substituted. .El .Pp The following special parameters are implicitly set by the shell and cannot be diff --git a/bin/ksh/lex.c b/bin/ksh/lex.c index 31af92c67ec..724b81fa484 100644 --- a/bin/ksh/lex.c +++ b/bin/ksh/lex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lex.c,v 1.70 2017/07/04 07:29:32 anton Exp $ */ +/* $OpenBSD: lex.c,v 1.71 2017/07/04 11:46:15 anton Exp $ */ /* * lexical analysis and source input @@ -385,7 +385,7 @@ yylex(int cf) /* If this is a trim operation, * treat (,|,) specially in STBRACE. */ - if (c == '#' || c == '%' || c == '/') { + if (c == '#' || c == '%') { ungetsc(c); PUSH_STATE(STBRACE); } else { diff --git a/bin/ksh/misc.c b/bin/ksh/misc.c index b137b1cf898..d4384c584c3 100644 --- a/bin/ksh/misc.c +++ b/bin/ksh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.56 2017/07/04 07:29:32 anton Exp $ */ +/* $OpenBSD: misc.c,v 1.57 2017/07/04 11:46:15 anton Exp $ */ /* * Miscellaneous functions @@ -52,7 +52,7 @@ initctypes(void) setctypes("*@#!$-?", C_VAR1); setctypes(" \t\n", C_IFSWS); setctypes("=-+?", C_SUBOP1); - setctypes("#%/", C_SUBOP2); + setctypes("#%", C_SUBOP2); setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE); } @@ -518,19 +518,6 @@ gmatch(const char *s, const char *p, int isfile) (const unsigned char *) p, (const unsigned char *) pe); } -int -gnmatch(char *s, size_t n, const char *p, int isfile) -{ - int c, match; - - c = s[n]; - s[n] = '\0'; - match = gmatch(s, p, isfile); - s[n] = c; - - return match; -} - /* Returns if p is a syntacticly correct globbing pattern, false * if it contains no pattern characters or if there is a syntax error. * Syntax errors are: diff --git a/bin/ksh/sh.h b/bin/ksh/sh.h index 5efb88f818c..51923961cff 100644 --- a/bin/ksh/sh.h +++ b/bin/ksh/sh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sh.h,v 1.60 2017/07/04 07:29:32 anton Exp $ */ +/* $OpenBSD: sh.h,v 1.61 2017/07/04 11:46:15 anton Exp $ */ /* * Public Domain Bourne/Korn shell @@ -278,7 +278,7 @@ extern int really_exit; #define C_VAR1 BIT(3) /* *@#!$-? */ #define C_IFSWS BIT(4) /* \t \n (IFS white space) */ #define C_SUBOP1 BIT(5) /* "=-+?" */ -#define C_SUBOP2 BIT(6) /* "#%/" */ +#define C_SUBOP2 BIT(6) /* "#%" */ #define C_IFS BIT(7) /* $IFS */ #define C_QUOTE BIT(8) /* \n\t"#$&'()*;<>?[\`| (needing quoting) */ @@ -544,7 +544,6 @@ int parse_args(char **, int, int *); int getn(const char *, int *); int bi_getn(const char *, int *); int gmatch(const char *, const char *, int); -int gnmatch(char *, size_t, const char *, int); int has_globbing(const char *, const char *); const unsigned char *pat_scan(const unsigned char *, const unsigned char *, int); diff --git a/regress/bin/ksh/strsub.t b/regress/bin/ksh/strsub.t index 419ae19d35e..56494675dde 100644 --- a/regress/bin/ksh/strsub.t +++ b/regress/bin/ksh/strsub.t @@ -11,6 +11,10 @@ stdin: v='new old' echo ${v/old/new} echo "${v/old/new}" + foo='baaaaar' + echo ${foo//a/v} + echo ${foo/a/v} +expected-fail: yes expected-stdout: empty empty @@ -18,6 +22,8 @@ expected-stdout: new new new new new new + bvvvvvr + bvaaaar --- name: strsub-multiline @@ -30,6 +36,7 @@ stdin: bsd.sp !` echo ${v/bsd.rd/} +expected-fail: yes expected-stdout: bsd bsd.sp --- @@ -44,6 +51,7 @@ stdin: echo ${v//[[:blank:]]/} v='/usr/src' echo ${v//\////} +expected-fail: yes expected-stdout: new new new whitespace @@ -58,6 +66,7 @@ stdin: echo ${u:-${v/old/new}} v='old new' echo ${v/old/${v/old/new}} +expected-fail: yes expected-stdout: new new new new @@ -72,6 +81,7 @@ stdin: echo ${v/o*/new} echo ${v//old?(\/)/new} echo ${v//?(\/)old//} +expected-fail: yes expected-stdout: new old new @@ -86,6 +96,7 @@ stdin: v=old r=new echo ${v/old/$r} +expected-fail: yes expected-stdout: new --- @@ -96,6 +107,7 @@ description: stdin: v=old echo ${v/old/new*} +expected-fail: yes expected-stdout: new* --- @@ -106,6 +118,7 @@ description: stdin: v=old echo ${v/} +expected-fail: yes expected-stdout: old --- @@ -116,6 +129,7 @@ description: stdin: set -u echo ${v/old/new} +expected-fail: yes expected-stderr-pattern: /v: parameter not set/ expected-exit: 1 -- 2.20.1