--- a/sh.func.c
+++ b/sh.func.c
@@ -56,7 +56,6 @@ static	void	preread		(void);
 static	void	doagain		(void);
 static  const char *isrchx	(int);
 static	void	search		(int, int, Char *);
-static	int	getword		(struct Strbuf *);
 static	struct wordent	*histgetword	(struct wordent *);
 static	void	toend		(void);
 static	void	xecho		(int, Char **);
@@ -742,8 +741,8 @@ isrchx(int n)
 }
 
 
-static int Stype;
-static Char *Sgoal;
+int Stype;
+Char *Sgoal;
 
 static void
 search(int type, int level, Char *goal)
@@ -1000,7 +999,7 @@ past:
     return NULL;
 }
 
-static int
+int
 getword(struct Strbuf *wp)
 {
     int found = 0, first;
@@ -1096,6 +1095,13 @@ past:
 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
 	break;
 
+    case TC_EXIT:
+	if (fargv->eof)
+	    return (intptr_t) &fargv;
+	setname(short2str(Sgoal));
+	stderror(ERR_NAME | ERR_NOTFOUND, "exit");
+	break;
+
     default:
 	break;
     }
@@ -2719,3 +2725,45 @@ getYN(const char *prompt)
 	continue;
     return doit;
 }
+
+void
+dofunction(Char **v, struct command *t)
+{
+    if (!dolzero)
+	stderror(ERR_FUNC);
+
+    if (fargv) {
+	fargv->next = malloc(sizeof *fargv);
+	fargv->next->prev = fargv;
+	fargv = fargv->next;
+    } else {
+	fargv = malloc(sizeof *fargv);
+	fargv->prev = NULL;
+    }
+
+    {
+	int i = 0;
+	Char **vh = NULL;
+
+	for (v++; *v; v++, i++) {
+	    vh = xrealloc(vh, sizeof(Char *[i + 2]));
+	    vh[i] = xmalloc(sizeof(Char [Strlen(*v) + 1]));
+	    Strcpy(vh[i], *v);
+	}
+
+	vh[i] = NULL;
+	fargv->v = vh;
+    }
+
+    srcfile(short2str(ffile), 0, 0, NULL);
+    /* Reset STRargv on function exit. */
+    setv(STRargv, NULL, VAR_READWRITE);
+
+    if (fargv->prev) {
+	fargv = fargv->prev;
+	free(fargv->next);
+    } else {
+	free(fargv);
+	fargv = NULL;
+    }
+}
