[BusyBox] Forbidden characters in shell function names?
Felipe Kellermann
stdfk at terra.com.br
Sun Jan 2 15:24:04 UTC 2005
On Sun, 2 Jan 2005 1:45pm +0100, Patrick Spousta wrote:
> Hi all,
> I tried to cross over from BB 0.6 (from WISP linux distribution!) to 1.0 and
> now I can see some shell scripts have wrong function names :-(
Hi Patrick,
> test_01
> [root at tmp]# busybox sh test_underline
> test with underline
> [root at tmp]#
>
> What I'm doing wrong? Or is normal that function name can't contain these
> characters?
Although (almost) every shell implementation permits `.', `-', etc., these
are just extensions to the standard. Quoting XCU, 2.9.5:
"The function is named fname; the application shall ensure that it is a
name (see the Base Definitions volume of IEEE Std 1003.1-2001, Section
3.230, Name). An implementation may allow other characters in a function
name as an extension. (...)"
Quoting XBD, Section 3.230:
"In the shell command language, a word consisting solely of underscores,
digits, and alphabetics from the portable character set. The first
character of a name is not a digit."
So the "portable" identifier would be ``[_[:alnum:]]''.
Note that busybox's ash is just applying the same rules for various types
of identifiers (parameter (variable) names, function names, etc). So this
could be seen as a simplification; other shells (eg, ksh, zsh, bash) uses
different rules for different identifiers:
$ a.b=1
bash: a.b=1: command not found
$ a.b() { echo $FUNCNAME; }
$ a.b
a.b
I don't use non-portable identifier in my scripts, but I think it would be
nice to have busybox's ash accepting the "common extensions". Attached is
very simple patch that adds an option to enable implementation-specific
characters in function names: `.' and `-':
ash$ a.b=1
-sh: a.b=1: not found
ash$ a.b() { echo a.b; }
ash$ a.b
a.b
ash$ a-b() { echo $(($1 - $2)); }
ash$ a-b 3 1
2
ash$ a-b=2
-sh: a-b=2: not found
--
Felipe Kellermann
-------------- next part --------------
Index: shell/Config.in
===================================================================
RCS file: /var/cvs/busybox/shell/Config.in,v
retrieving revision 1.18
diff -u -3 -p -u -p -r1.18 Config.in
--- shell/Config.in 24 Sep 2004 09:09:44 -0000 1.18
+++ shell/Config.in 2 Jan 2005 15:18:45 -0000
@@ -117,6 +117,14 @@ config CONFIG_ASH_RANDOM_SUPPORT
After "unset RANDOM" then generator will switch off and this
variable will no longer have special treatment.
+config CONFIG_ASH_FN_EXT
+ bool " Enable `.' and `_' characters in function names"
+ default y
+ depends on CONFIG_ASH
+ help
+ Enable implementation-specific (as defined in XCU, 2.9.5)
+ characters (`.' and `_') in function names.
+
config CONFIG_HUSH
bool "hush"
default n
Index: shell/ash.c
===================================================================
RCS file: /var/cvs/busybox/shell/ash.c,v
retrieving revision 1.108
diff -u -3 -p -u -p -r1.108 ash.c
--- shell/ash.c 8 Oct 2004 09:43:34 -0000 1.108
+++ shell/ash.c 2 Jan 2005 15:19:21 -0000
@@ -600,6 +600,9 @@ static union node *parsecmd(int);
static void fixredir(union node *, const char *, int);
static const char *const *findkwd(const char *);
static char *endofname(const char *);
+#ifdef CONFIG_ASH_FN_EXT
+static char *endoffuncname(const char *);
+#endif
/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
@@ -753,6 +756,9 @@ static const char *tokname(int tok)
#define is_digit(c) ((unsigned)((c) - '0') <= 9)
#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
+#ifdef CONFIG_ASH_FN_EXT
+#define is_fn_ext(c) ((c) == '.' || (c) == '-')
+#endif
/*
* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
@@ -3512,6 +3518,15 @@ goodname(const char *p)
return !*endofname(p);
}
+#ifdef CONFIG_ASH_FN_EXT
+static inline int
+goodfuncname(const char *p)
+{
+ return !*endoffuncname(p);
+}
+#endif
+
+
/*
* Search for a command. This is called before we fork so that the
* location of the command will be available in the parent as well as
@@ -9792,7 +9807,11 @@ simplecmd(void) {
synexpect(TRP);
name = n->narg.text;
if (
+#ifdef CONFIG_ASH_FN_EXT
+ !goodfuncname(name) || (
+#else
!goodname(name) || (
+#endif
(bcmd = find_builtin(name)) &&
IS_BUILTIN_SPECIAL(bcmd)
)
@@ -10839,6 +10858,28 @@ endofname(const char *name)
return p;
}
+/*
+ * Return of a legal function name (a letter or underscore followed by zero or
+ * more letters, underscores, digits, and extension-specific characters).
+ */
+
+#ifdef CONFIG_ASH_FN_EXT
+static char *
+endoffuncname(const char *name)
+{
+ char *p;
+
+ p = (char *) name;
+ if (! (is_name(*p) || is_fn_ext(*p)))
+ return p;
+ while (*++p) {
+ if (! (is_in_name(*p) || is_fn_ext(*p)))
+ break;
+ }
+ return p;
+}
+#endif /* CONFIG_ASH_FN_EXT */
+
/*
* Called when an unexpected token is read during the parse. The argument
More information about the busybox
mailing list