Subject: /bin/sh patch
To: None <current-users@NetBSD.ORG>
From: Christos Zoulas <christos@deshaw.com>
List: current-users
Date: 01/12/1995 23:18:51
To support:
${VAR#PAT}
${VAR##PAT}
${VAR%PAT}
${VAR%%PAT}
${#VAR}
I have not tested this much, so use at own risk.
Please let me know if you find any problems...
christos
*** 1.1 1995/01/13 04:12:37
--- expand.c 1995/01/13 04:10:26
***************
*** 59,64 ****
--- 59,65 ----
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
+ #include "extern.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
***************
*** 443,452 ****
--- 444,456 ----
int varflags;
char *var;
char *val;
+ char *pat;
int c;
int set;
int special;
int startloc;
+ int varlen;
+ int easy;
int quotes = flag & (EXP_FULL | EXP_CASE);
varflags = *p++;
***************
*** 468,498 ****
} else
set = 1;
}
startloc = expdest - stackblock();
if (set && subtype != VSPLUS) {
/* insert the value of the variable */
if (special) {
varvalue(*var, varflags & VSQUOTE, flag & EXP_FULL);
} else {
char const *syntax = (varflags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
! while (*val) {
! if (quotes && syntax[*val] == CCTL)
! STPUTC(CTLESC, expdest);
! STPUTC(*val++, expdest);
}
}
}
if (subtype == VSPLUS)
set = ! set;
! if (((varflags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1))
! && (set || subtype == VSNORMAL))
! recordregion(startloc, expdest - stackblock(), varflags & VSQUOTE);
! if (! set && subtype != VSNORMAL) {
! if (subtype == VSPLUS || subtype == VSMINUS) {
! argstr(p, flag);
! } else {
char *startp;
int saveherefd = herefd;
struct nodelist *saveargbackq = argbackq;
herefd = -1;
--- 472,552 ----
} else
set = 1;
}
+ varlen = 0;
startloc = expdest - stackblock();
if (set && subtype != VSPLUS) {
/* insert the value of the variable */
if (special) {
+ char *exp, *oexpdest = expdest;
varvalue(*var, varflags & VSQUOTE, flag & EXP_FULL);
+ if (subtype == VSLENGTH) {
+ for (exp = oexpdest;exp != expdest; exp++)
+ varlen++;
+ expdest = oexpdest;
+ }
} else {
char const *syntax = (varflags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
! if (subtype == VSLENGTH) {
! for (;*val; val++)
! varlen++;
! }
! else {
! while (*val) {
! if (quotes && syntax[*val] == CCTL)
! STPUTC(CTLESC, expdest);
! STPUTC(*val++, expdest);
! }
!
}
}
}
+
if (subtype == VSPLUS)
set = ! set;
!
! easy = ((varflags & VSQUOTE) == 0 ||
! (*var == '@' && shellparam.nparam != 1)) && set;
!
!
! switch (subtype) {
! case VSLENGTH:
! expdest = cvtnum(varlen, expdest);
! /* FALLTHROUGH */
!
! case VSNORMAL:
! record:
! recordregion(startloc, expdest - stackblock(),
! varflags & VSQUOTE);
! break;
!
! case VSPLUS:
! case VSMINUS:
! if (easy)
! goto record;
! argstr(p, flag);
! break;
!
! case VSTRIMLEFT:
! case VSTRIMLEFTMAX:
! case VSTRIMRIGHT:
! case VSTRIMRIGHTMAX:
! STPUTC('\0', expdest);
! pat = expdest;
! /* FALLTHROUGH */
! easy = 0;
!
! case VSASSIGN:
! case VSQUESTION:
! if (easy)
! goto record;
! /* FALLTHROUGH */
!
! {
!
char *startp;
+ char *loc;
+ int c = 0;
int saveherefd = herefd;
struct nodelist *saveargbackq = argbackq;
herefd = -1;
***************
*** 501,521 ****
herefd = saveherefd;
argbackq = saveargbackq;
startp = stackblock() + startloc;
! if (subtype == VSASSIGN) {
setvar(var, startp, 0);
STADJUST(startp - expdest, expdest);
! varflags &=~ VSNUL;
goto again;
}
- /* subtype == VSQUESTION */
- if (*p != CTLENDVAR) {
- outfmt(&errout, "%s\n", startp);
- error((char *)NULL);
- }
- error("%.*s: parameter %snot set", p - var - 1,
- var, (varflags & VSNUL)? "null or " : nullstr);
}
}
if (subtype != VSNORMAL) { /* skip to end of alternative */
int nesting = 1;
for (;;) {
--- 555,639 ----
herefd = saveherefd;
argbackq = saveargbackq;
startp = stackblock() + startloc;
!
! switch (subtype) {
! case VSASSIGN:
setvar(var, startp, 0);
STADJUST(startp - expdest, expdest);
! varflags &= ~VSNUL;
! if (c != 0)
! *loc = c;
goto again;
+
+ case VSQUESTION:
+ if (*p != CTLENDVAR) {
+ outfmt(&errout, "%s\n", startp);
+ error((char *)NULL);
+ }
+ error("%.*s: parameter %snot set", p - var - 1,
+ var, (varflags & VSNUL) ? "null or "
+ : nullstr);
+ break;
+
+ case VSTRIMLEFT:
+ for (loc = startp; loc < pat - 1; loc++) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(pat, startp)) {
+ *loc = c;
+ goto recordleft;
+ }
+ *loc = c;
+ }
+ break;
+
+ case VSTRIMLEFTMAX:
+ for (loc = pat - 1; loc >= startp; loc--) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(pat, startp)) {
+ *loc = c;
+ goto recordleft;
+ }
+ *loc = c;
+ }
+ break;
+
+ case VSTRIMRIGHT:
+ for (loc = pat - 1; loc >= startp; loc--) {
+ if (patmatch(pat, loc)) {
+ expdest = loc;
+ goto record;
+ }
+ }
+ break;
+
+ case VSTRIMRIGHTMAX:
+ for (loc = startp; loc < pat - 1; loc++) {
+ if (patmatch(pat, loc)) {
+ expdest = loc;
+ goto record;
+ }
+ }
+ break;
+
+ recordleft:
+ expdest = (pat - 1) - (loc - startp);
+ while (loc != pat - 1)
+ *startp++ = *loc++;
+ goto record;
+
+ default:
+ abort();
}
}
+ break;
+
+
+ default:
+ abort();
}
+
if (subtype != VSNORMAL) { /* skip to end of alternative */
int nesting = 1;
for (;;) {
***************
*** 577,583 ****
int allow_split;
{
int num;
- char temp[32];
char *p;
int i;
extern int exitstatus;
--- 695,700 ----
***************
*** 613,625 ****
case '!':
num = backgndpid;
numvar:
! p = temp + 31;
! temp[31] = '\0';
! do {
! *--p = num % 10 + '0';
! } while ((num /= 10) != 0);
! while (*p)
! STPUTC(*p++, expdest);
break;
case '-':
for (i = 0 ; i < NOPTS ; i++) {
--- 730,736 ----
case '!':
num = backgndpid;
numvar:
! cvtnum(num, expdest);
break;
case '-':
for (i = 0 ; i < NOPTS ; i++) {
*** 1.1 1995/01/13 00:50:03
--- extern.h 1995/01/13 01:46:00
***************
*** 31,34 ****
void readcmdfile __P((char *));
void trargs __P((char **));
void trputs __P((char *));
!
--- 31,34 ----
void readcmdfile __P((char *));
void trargs __P((char **));
void trputs __P((char *));
! char *cvtnum __P((int, char *));
*** 1.1 1995/01/13 00:27:01
--- main.c 1995/01/13 02:59:09
***************
*** 213,219 ****
flushout(&output);
}
n = parsecmd(inter);
! /* showtree(n); DEBUG */
if (n == NEOF) {
if (!top || numeof >= 50)
break;
--- 213,221 ----
flushout(&output);
}
n = parsecmd(inter);
! #if DEBUG > 1
! showtree(n);
! #endif
if (n == NEOF) {
if (!top || numeof >= 50)
break;
*** 1.1 1994/12/19 01:36:32
--- parser.c 1995/01/13 04:15:03
***************
*** 1136,1142 ****
subtype = VSNORMAL;
if (c == '{') {
c = pgetc();
! subtype = 0;
}
if (is_name(c)) {
do {
--- 1136,1147 ----
subtype = VSNORMAL;
if (c == '{') {
c = pgetc();
! if (c == '#') {
! subtype = VSLENGTH;
! c = pgetc();
! }
! else
! subtype = 0;
}
if (is_name(c)) {
do {
***************
*** 1152,1165 ****
STPUTC('=', out);
flags = 0;
if (subtype == 0) {
! if (c == ':') {
flags = VSNUL;
c = pgetc();
}
- p = strchr(types, c);
- if (p == NULL)
- goto badsub;
- subtype = p - types + VSNORMAL;
} else {
pungetc();
}
--- 1157,1187 ----
STPUTC('=', out);
flags = 0;
if (subtype == 0) {
! switch (c) {
! case ':':
flags = VSNUL;
c = pgetc();
+ /*FALLTHROUGH*/
+ default:
+ p = strchr(types, c);
+ if (p == NULL)
+ goto badsub;
+ subtype = p - types + VSNORMAL;
+ break;
+ case '%':
+ case '#':
+ {
+ int cc = c;
+ subtype = c == '#' ? VSTRIMLEFT :
+ VSTRIMRIGHT;
+ c = pgetc();
+ if (c == cc)
+ subtype++;
+ else
+ pungetc();
+ break;
+ }
}
} else {
pungetc();
}
***************
*** 1407,1410 ****
--- 1429,1458 ----
default:
return "<internal prompt error>";
}
+ }
+
+ /*
+ * Our own itoa().
+ */
+ char *
+ cvtnum(num, buf)
+ int num;
+ char *buf;
+ {
+ char temp[32];
+ int neg = num < 0;
+ char *p = temp + 31;
+
+ temp[31] = '\0';
+
+ do {
+ *--p = num % 10 + '0';
+ } while ((num /= 10) != 0);
+
+ if (neg)
+ *--p = '-';
+
+ while (*p)
+ STPUTC(*p++, buf);
+ return buf;
}
*** 1.1 1995/01/13 00:14:29
--- parser.h 1995/01/13 00:14:38
***************
*** 48,63 ****
#define CTLENDARI '\207'
/* variable substitution byte (follows CTLVAR) */
! #define VSTYPE 07 /* type of variable substitution */
! #define VSNUL 040 /* colon--treat the empty string as unset */
! #define VSQUOTE 0100 /* inside double quotes--suppress splitting */
/* values of VSTYPE field */
! #define VSNORMAL 1 /* normal variable: $var or ${var} */
! #define VSMINUS 2 /* ${var-text} */
! #define VSPLUS 3 /* ${var+text} */
! #define VSQUESTION 4 /* ${var?message} */
! #define VSASSIGN 5 /* ${var=text} */
/*
--- 48,68 ----
#define CTLENDARI '\207'
/* variable substitution byte (follows CTLVAR) */
! #define VSTYPE 0x0f /* type of variable substitution */
! #define VSNUL 0x10 /* colon--treat the empty string as unset */
! #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
/* values of VSTYPE field */
! #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
! #define VSMINUS 0x2 /* ${var-text} */
! #define VSPLUS 0x3 /* ${var+text} */
! #define VSQUESTION 0x4 /* ${var?message} */
! #define VSASSIGN 0x5 /* ${var=text} */
! #define VSTRIMLEFT 0x6 /* ${var#pattern} */
! #define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
! #define VSTRIMRIGHT 0x8 /* ${var%pattern} */
! #define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
! #define VSLENGTH 0xa /* ${#var} */
/*
*** 1.1 1995/01/13 00:14:42
--- show.c 1995/01/13 00:33:27
***************
*** 71,76 ****
--- 71,79 ----
struct nodelist *lp;
char *s;
+ if (n == NULL)
+ return;
+
indent(ind, pfx, fp);
switch(n->type) {
case NSEMI:
***************
*** 178,187 ****
--- 181,195 ----
putc('$', fp);
putc('{', fp);
subtype = *++p;
+ if (subtype == VSLENGTH)
+ putc('#', fp);
+
while (*p != '=')
putc(*p++, fp);
+
if (subtype & VSNUL)
putc(':', fp);
+
switch (subtype & VSTYPE) {
case VSNORMAL:
putc('}', fp);
***************
*** 197,202 ****
--- 205,226 ----
break;
case VSASSIGN:
putc('=', fp);
+ break;
+ case VSTRIMLEFT:
+ putc('#', fp);
+ break;
+ case VSTRIMLEFTMAX:
+ putc('#', fp);
+ putc('#', fp);
+ break;
+ case VSTRIMRIGHT:
+ putc('%', fp);
+ break;
+ case VSTRIMRIGHTMAX:
+ putc('%', fp);
+ putc('%', fp);
+ break;
+ case VSLENGTH:
break;
default:
printf("<subtype %d>", subtype);