sh: Fix some parameter expansion variants ${#...}.
authorPeter Avalos <pavalos@dragonflybsd.org>
Sat, 16 Apr 2011 21:17:03 +0000 (11:17 -1000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sat, 16 Apr 2011 21:55:46 +0000 (11:55 -1000)
These already worked: $# ${#} ${##} ${#-} ${#?}
These now work as well: ${#+word} ${#-word} ${##word} ${#%word}

There is an ambiguity in the standard with ${#?}: it could be the length of
$? or it could be $# giving an error in the (impossible) case that it is not
set. We continue to use the former interpretation as it seems more useful.

Obtained-from:  FreeBSD

bin/sh/parser.c
tools/regression/bin/sh/expansion/plus-minus8.0 [new file with mode: 0644]
tools/regression/bin/sh/expansion/trim7.0 [new file with mode: 0644]

index f0494a3..74e7cbd 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)parser.c        8.7 (Berkeley) 5/16/95
- * $FreeBSD: src/bin/sh/parser.c,v 1.105 2011/02/05 15:02:19 jilles Exp $
+ * $FreeBSD: src/bin/sh/parser.c,v 1.106 2011/03/13 20:02:39 jilles Exp $
  */
 
 #include <stdio.h>
@@ -1446,6 +1446,7 @@ parsesub: {
        int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
        int linno;
        int length;
+       int c1;
 
        c = pgetc();
        if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
@@ -1472,15 +1473,9 @@ parsesub: {
                if (c == '{') {
                        bracketed_name = 1;
                        c = pgetc();
-                       if (c == '#') {
-                               if ((c = pgetc()) == '}')
-                                       c = '#';
-                               else
-                                       subtype = VSLENGTH;
-                       }
-                       else
-                               subtype = 0;
+                       subtype = 0;
                }
+varname:
                if (!is_eof(c) && is_name(c)) {
                        length = 0;
                        do {
@@ -1510,19 +1505,35 @@ parsesub: {
                                STPUTC(c, out);
                                c = pgetc();
                        }
-               } else {
-                       if (! is_special(c)) {
-                               subtype = VSERROR;
-                               if (c == '}')
-                                       pungetc();
-                               else if (c == '\n' || c == PEOF)
-                                       synerror("Unexpected end of line in substitution");
-                               else
-                                       USTPUTC(c, out);
-                       } else {
-                               USTPUTC(c, out);
+               } else if (is_special(c)) {
+                       c1 = c;
+                       c = pgetc();
+                       if (subtype == 0 && c1 == '#') {
+                               subtype = VSLENGTH;
+                               if (strchr(types, c) == NULL && c != ':' &&
+                                   c != '#' && c != '%')
+                                       goto varname;
+                               c1 = c;
                                c = pgetc();
+                               if (c1 != '}' && c == '}') {
+                                       pungetc();
+                                       c = c1;
+                                       goto varname;
+                               }
+                               pungetc();
+                               c = c1;
+                               c1 = '#';
+                               subtype = 0;
                        }
+                       USTPUTC(c1, out);
+               } else {
+                       subtype = VSERROR;
+                       if (c == '}')
+                               pungetc();
+                       else if (c == '\n' || c == PEOF)
+                               synerror("Unexpected end of line in substitution");
+                       else
+                               USTPUTC(c, out);
                }
                if (subtype == 0) {
                        switch (c) {
diff --git a/tools/regression/bin/sh/expansion/plus-minus8.0 b/tools/regression/bin/sh/expansion/plus-minus8.0
new file mode 100644 (file)
index 0000000..20ebf4b
--- /dev/null
@@ -0,0 +1,5 @@
+# $FreeBSD: src/tools/regression/bin/sh/expansion/plus-minus8.0,v 1.1 2011/03/13 20:02:39 jilles Exp $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${#+hi}" = hi ] || echo '${#+hi} wrong'
+[ "${#-hi}" = 13 ] || echo '${#-hi} wrong'
diff --git a/tools/regression/bin/sh/expansion/trim7.0 b/tools/regression/bin/sh/expansion/trim7.0
new file mode 100644 (file)
index 0000000..274fa43
--- /dev/null
@@ -0,0 +1,16 @@
+# $FreeBSD: src/tools/regression/bin/sh/expansion/trim7.0,v 1.1 2011/03/13 20:02:39 jilles Exp $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${##1}" = 3 ] || echo '${##1} wrong'
+[ "${###1}" = 3 ] || echo '${###1} wrong'
+[ "${###}" = 13 ] || echo '${###} wrong'
+[ "${#%3}" = 1 ] || echo '${#%3} wrong'
+[ "${#%%3}" = 1 ] || echo '${#%%3} wrong'
+[ "${#%%}" = 13 ] || echo '${#%%} wrong'
+set --
+[ "${##0}" = "" ] || echo '${##0} wrong'
+[ "${###0}" = "" ] || echo '${###0} wrong'
+[ "${###}" = 0 ] || echo '${###} wrong'
+[ "${#%0}" = "" ] || echo '${#%0} wrong'
+[ "${#%%0}" = "" ] || echo '${#%%0} wrong'
+[ "${#%%}" = 0 ] || echo '${#%%} wrong'