ash: introduce bash-like $FUNCNAME

Patch adapted from Roberto A. Foglietta <roberto.foglietta@gmail.com>
work.

function                                             old     new   delta
lookupvar                                            106     150     +44
evalfun                                              369     408     +39
ash_main                                            1218    1242     +24
varinit_data                                         156     168     +12
.rodata                                           104162  104172     +10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 129/0)             Total: 129 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash.c b/shell/ash.c
index b12b859..4bc4f55 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2158,6 +2158,7 @@
 	{ VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
 #endif
 	{ VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
+	{ VSTRFIXED|VTEXTFIXED       , NULL /* inited to funcnamevar */, NULL },
 #if ENABLE_ASH_RANDOM_SUPPORT
 	{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
 #endif
@@ -2184,6 +2185,8 @@
 	struct var varinit[ARRAY_SIZE(varinit_data)];
 	int lineno;
 	char linenovar[sizeof("LINENO=") + sizeof(int)*3];
+	char funcnamevar[sizeof("FUNCNAME=") + 64];
+	char *funcname;
 	unsigned trap_depth;
 	bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
 };
@@ -2196,6 +2199,8 @@
 #define varinit       (G_var.varinit      )
 #define lineno        (G_var.lineno       )
 #define linenovar     (G_var.linenovar    )
+#define funcnamevar   (G_var.funcnamevar  )
+#define funcname      (G_var.funcname     )
 #define trap_depth    (G_var.trap_depth   )
 #define in_trap_ERR   (G_var.in_trap_ERR  )
 #define vifs      varinit[0]
@@ -2213,13 +2218,14 @@
 #endif
 #define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
 #define vlineno   varinit[VAR_OFFSET2 + 5]
+#define vfuncname varinit[VAR_OFFSET2 + 6]
 #if ENABLE_ASH_RANDOM_SUPPORT
-# define vrandom  varinit[VAR_OFFSET2 + 6]
+# define vrandom  varinit[VAR_OFFSET2 + 7]
 #endif
 #define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
 #if BASH_EPOCH_VARS
-# define vepochs  varinit[VAR_OFFSET3 + 6]
-# define vepochr  varinit[VAR_OFFSET3 + 7]
+# define vepochs  varinit[VAR_OFFSET3 + 7]
+# define vepochr  varinit[VAR_OFFSET3 + 8]
 #endif
 #define INIT_G_var() do { \
 	unsigned i; \
@@ -2232,6 +2238,8 @@
 	} \
 	strcpy(linenovar, "LINENO="); \
 	vlineno.var_text = linenovar; \
+	strcpy(funcnamevar, "FUNCNAME="); \
+	vfuncname.var_text = funcnamevar; \
 } while (0)
 
 /*
@@ -2371,6 +2379,9 @@
 		if (!(v->flags & VUNSET)) {
 			if (v->var_text == linenovar) {
 				fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
+			} else
+			if (v->var_text == funcnamevar) {
+				safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
 			}
 			return var_end(v->var_text);
 		}
@@ -9875,6 +9886,7 @@
 	int e;
 	int savelineno;
 	int savefuncline;
+	char *savefuncname;
 	char *savetrap = NULL;
 
 	if (!Eflag) {
@@ -9884,6 +9896,7 @@
 	savelineno = lineno;
 	saveparam = shellparam;
 	savefuncline = funcline;
+	savefuncname = funcname;
 	savehandler = exception_handler;
 	e = setjmp(jmploc.loc);
 	if (e) {
@@ -9893,6 +9906,7 @@
 	exception_handler = &jmploc;
 	shellparam.malloced = 0;
 	func->count++;
+	funcname = func->n.ndefun.text;
 	funcline = func->n.ndefun.linno;
 	INT_ON;
 	shellparam.nparam = argc - 1;
@@ -9904,6 +9918,7 @@
 	evaltree(func->n.ndefun.body, flags & EV_TESTED);
  funcdone:
 	INT_OFF;
+	funcname = savefuncname;
 	if (savetrap) {
 		if (!trap[NTRAP_ERR])
 			trap[NTRAP_ERR] = savetrap;
@@ -13639,6 +13654,12 @@
 	if (argv[1])
 		savestatus = number(argv[1]);
 
+//TODO: this script
+// trap 'echo trap:$FUNCNAME' EXIT
+// f() { exit; }
+// f
+//prints "trap:f" in bash. We can call exitshell() here to achieve this.
+//For now, keeping dash code:
 	raise_exception(EXEXIT);
 	/* NOTREACHED */
 }