View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000490 | tcsh | General | public | 2023-12-01 21:41 | 2024-02-14 14:57 |
Reporter | MProG10 | Assigned To | |||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | new | Resolution | open | ||
Summary | 0000490: Introduce 'function' built-in. | ||||
Description | This is a wrapper around goto and source. The script recurses and searches for a goto label. It's an error for labels not contain an exit to their end. Function calls outside labels are, by default, labeled main. The use is exclusive for scripts. | ||||
Additional Information | https://github.com/tcsh-org/tcsh/pull/77 | ||||
Tags | No tags attached. | ||||
|
sh.h.diff (486 bytes)
--- a/sh.h +++ b/sh.h @@ -1305,5 +1305,16 @@ extern int filec; #define TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */ #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */ +/* Function variable(s) and function(s). */ +extern Char *Sgoal; +extern int Stype; +extern struct funcargs { + Char **v; + struct command *t; + struct funcargs *prev, + *next; + int eof; +} *fargv; +extern int getword(struct Strbuf *); #endif /* _h_sh */ sh.decls.h.diff (772 bytes)
--- a/sh.decls.h +++ b/sh.decls.h @@ -105,6 +105,7 @@ extern void xfree_indirect(void *); extern void errinit (void); extern void seterror (unsigned int, ...); extern void fixerror (void); +extern void funcerror (Char *, Char *); extern void stderror (unsigned int, ...) __attribute__((__noreturn__)); @@ -150,6 +151,7 @@ extern void doend (Char **, struct command *); extern void doeval (Char **, struct command *); extern void doexit (Char **, struct command *); extern void doforeach (Char **, struct command *); +extern void dofunction (Char **, struct command *); extern void doglob (Char **, struct command *); extern void dogoto (Char **, struct command *); extern void doif (Char **, struct command *); sh.c.diff (3,194 bytes)
--- a/sh.c +++ b/sh.c @@ -111,6 +111,7 @@ int exitset = 0; static time_t chktim; /* Time mail last checked */ char *progname; int tcsh; +struct funcargs *fargv = NULL; /* * This preserves the input state of the shell. It is used by @@ -1768,6 +1769,114 @@ srcunit(int unit, int onlyown, int hflg, Char **av) cleanup_push(&pintr_disabled, disabled_cleanup); } + /* Functions must have an exit to their end. + * if (!fargv->prev) is only true if this is a first function call. + * First seek for an ending exit before jumping to the label, + * then seek for an ending exit on the requested label. + * Function arguments are passed to STRargv. + * STRargv is reset after the function is done. */ + if (fargv) { + Char funcexit[] = { 'e', 'x', 'i', 't', 0 }, + funcmain[] = { 'm', 'a', 'i', 'n', 0 }; + struct Strbuf aword = Strbuf_INIT; + Sgoal = fargv->v[2]; + Stype = TC_GOTO; + fargv->eof = 0; + + if (!fargv->prev) + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1; + + while (1) { + do { + (void) getword(NULL); + (void) getword(&aword); + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(funcmain, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(funcmain, funcexit); + + (void) getword(NULL); + } + + setq(STRargv, &fargv->v[3], &shvhed, VAR_READWRITE); + dogoto(&fargv->v[1], fargv->t); + + { + struct Ain a; + + Stype = TC_EXIT; + a.type = TCSH_F_SEEK; + btell(&a); + + cleanup_push(&aword, Strbuf_cleanup); + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1, eof = 0; + + fargv->eof = 1; + while (1) { + do { + (void) getword(NULL); + if ((intptr_t) getword(&aword) == (intptr_t) &fargv) { + Strbuf_terminate(&aword); + eof = 1; + break; + } + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (eof) { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(Sgoal, funcexit); + + (void) getword(NULL); + } + + bseek(&a); + } + + cleanup_until(&aword); + } + process(0); /* 0 -> blow away on errors */ /* Restore the old state */ @@ -1995,6 +2104,7 @@ process(int catch) getexit(osetexit); omark = cleanup_push_mark(); + for (;;) { struct command *t; int hadhist, old_pintr_disabled; @@ -2179,6 +2289,7 @@ process(int catch) else haderr = 1; } + cleanup_pop_mark(omark); resexit(osetexit); exitset--; sh.err.c.diff (929 bytes)
--- a/sh.err.c +++ b/sh.err.c @@ -187,7 +187,8 @@ extern int enterhist; #define ERR_INVALID 133 #define ERR_BADCOLORVAR 134 #define ERR_EOF 135 -#define NO_ERRORS 136 +#define ERR_FUNC 136 +#define NO_ERRORS 137 static const char *elst[NO_ERRORS] INIT_ZERO_STRUCT; @@ -365,6 +366,7 @@ errinit(void) elst[ERR_BADJOB] = CSAVS(1, 136, "No such job (badjob)"); elst[ERR_BADCOLORVAR] = CSAVS(1, 137, "Unknown %s color variable '%c%c'"); elst[ERR_EOF] = CSAVS(1, 138, "Unexpected end of file"); + elst[ERR_FUNC] = CSAVS(1, 139, "Functions are only supported for scripts"); } /* Cleanup data. */ @@ -654,3 +656,13 @@ stderror(unsigned int id, ...) reset(); /* Unwind */ } + +void +funcerror(Char *n, Char *msg) +{ + char nconv[Strlen(n) + 1], + msgconv[Strlen(msg) + 1]; + + setname(strcpy(nconv, short2str(n))); + stderror(ERR_NAME | ERR_NOTFOUND, strcpy(msgconv, short2str(msg))); +} sh.func.c.diff (1,931 bytes)
--- 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,51 @@ getYN(const char *prompt) continue; return doit; } + +void +dofunction(Char **v, struct command *t) +{ + if (!dolzero) + stderror(ERR_FUNC); + + { + int i, j; + Char **vh; + + for (i = 0; v[i]; i++) + ; + + vh = xmalloc(sizeof(Char [i + 2])); + vh[i + 1] = NULL; + + for (j = i--; i; i--, j--) { + vh[j] = xmalloc(sizeof(Char [Strlen(v[i]) + 1])); + Strcpy(vh[j], v[i]); + } + vh[1] = xmalloc(sizeof (Char [Strlen(ffile) + 1])); + Strcpy(vh[1], ffile); + *vh = xmalloc(sizeof (Char [Strlen(*v) + 1])); + Strcpy(*vh, *v); + + if (fargv) { + fargv->next = malloc(sizeof *fargv); + fargv->next->prev = fargv; + fargv = fargv->next; + } else { + fargv = malloc(sizeof *fargv); + fargv->prev = NULL; + } + + dosource(fargv->v = vh, fargv->t = t); + /* Reset STRargv on function exit. */ + setv(STRargv, NULL, VAR_READWRITE); + + if (fargv->prev) { + fargv = fargv->prev; + free(fargv->next); + } else { + free(fargv); + fargv = NULL; + } + } +} |
|
tcsh.man.in.diff (1,096 bytes)
--- a/tcsh.man.in +++ b/tcsh.man.in @@ -5515,6 +5515,30 @@ the loop are executed. If you make a mistake typing in a loop at the terminal you can rub it out. . +.It Ic function Ar label Xo +.Op Ar arg +\&... (+) +.Xc +.Ar label +is a +.Ic goto +label. The shell recurses the current script, +searches for and continues execution after a line of the form +.Dl Ar label Ns No \&: +.Ar arg +is a list of arguments to be passed to +.Ic argv Ns No \&. +Use outside a label is labeled +.Ar main Ns No \&. +It's an error +.Sq Ar label Ns No \&: +not contain an ending +.Ic exit Ns No \&. +It's an error +.Ar main +not contain an ending +.Ic exit Ns No \&. +. .El .Bl -tag -width 6n . @@ -10637,6 +10661,12 @@ and message catalog code to interface to Windows. .br Color ls additions. . +.It Matheus Garcia , +2023. +.br +.Ic function +built-in. +. .El . .Sh THANKS TO @@ -10739,6 +10769,10 @@ cycles or backward .Ic goto Ns s. .Pp +Functions fallthrough if the ending +.Ic exit +is piped from or executed in background. +.Pp Report bugs at .Lk @PACKAGE_BUGREPORT@ preferably with fixes. commands.at.diff (1,110 bytes)
--- a/tests/commands.at +++ b/tests/commands.at @@ -636,6 +636,39 @@ c AT_CLEANUP() +AT_SETUP([function]) +AT_KEYWORDS([commands]) + +AT_DATA([function.csh], +[[ +if ( ! { function test test } ) then + echo 'FAIL: '\''function'\'' is not passing arguments!' + exit 1 +else if >& /dev/null ( { function test2 } ) then + echo 'FAIL: '\''function'\'' is not seeking for an ending exit!' + exit 1 +else if >& /dev/null ( ! { function test3 } ) then + echo 'FAIL: '\''function'\'' is not seeking for an ending exit on EOF!' + exit 1 +endif +exit + +test: +if ( "$1" == ) exit 1 +exit + +test2: +exit +echo test + +test3: +exit +]]) +AT_CHECK([tcsh -f function.csh]) + +AT_CLEANUP() + + dnl dnl getspath dnl @@ -1870,3 +1903,22 @@ endif AT_CHECK([tcsh -f time_output.csh], 0, [ignore]) AT_CLEANUP() + +AT_SETUP([main function]) +AT_KEYWORDS([commands]) + +AT_DATA([main.csh], +[[ +if >& /dev/null ( { function test } ) then + echo 'FAIL: '\''function'\'' is not seeking for an ending first exit!' + exit 1 +endif +exit +echo test + +test: +exit +]]) +AT_CHECK([tcsh -f main.csh]) + +AT_CLEANUP() sh.init.c.diff (325 bytes)
--- a/sh.init.c +++ b/sh.init.c @@ -80,6 +80,7 @@ const struct biltins bfunc[] = { { "fg", dofg, 0, INF }, { "filetest", dofiletest, 2, INF }, { "foreach", doforeach, 3, INF }, + { "function", dofunction, 1, INF }, #ifdef TCF { "getspath", dogetspath, 0, 0 }, { "getxvers", dogetxvers, 0, 0 }, |
|
Prefer srcfile() over dosource() sh.h-2.diff (516 bytes)
--- a/sh.h +++ b/sh.h @@ -1305,5 +1305,16 @@ extern int filec; #define TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */ #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */ +/* Function variable(s) and function(s). */ +extern Char *Sgoal; +extern int Stype; +extern struct funcargs { + Char **v; + int eof; + struct funcargs *prev, + *next; +} *fargv; +extern int getword(struct Strbuf *); +extern int srcfile(const char *, int, int, Char **); #endif /* _h_sh */ sh.func.c-2.diff (1,765 bytes)
--- 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; + } +} sh.c-2.diff (3,818 bytes)
--- a/sh.c +++ b/sh.c @@ -111,6 +111,7 @@ int exitset = 0; static time_t chktim; /* Time mail last checked */ char *progname; int tcsh; +struct funcargs *fargv = NULL; /* * This preserves the input state of the shell. It is used by @@ -141,11 +142,6 @@ struct saved_state { }; static int srccat (Char *, Char *); -#ifndef WINNT_NATIVE -static int srcfile (const char *, int, int, Char **); -#else -int srcfile (const char *, int, int, Char **); -#endif /*WINNT_NATIVE*/ static void srcunit (int, int, int, Char **); static void mailchk (void); #ifndef _PATH_DEFPATH @@ -1543,11 +1539,7 @@ srccat(Char *cp, Char *dp) /* * Source to a file putting the file descriptor in a safe place (> 2). */ -#ifndef WINNT_NATIVE -static int -#else int -#endif /*WINNT_NATIVE*/ srcfile(const char *f, int onlyown, int flag, Char **av) { int unit; @@ -1768,6 +1760,114 @@ srcunit(int unit, int onlyown, int hflg, Char **av) cleanup_push(&pintr_disabled, disabled_cleanup); } + /* Functions must have an exit to their end. + * if (!fargv->prev) is only true if this is a first function call. + * First seek for an ending exit before jumping to the label, + * then seek for an ending exit on the requested label. + * Function arguments are passed to STRargv. + * STRargv is reset after the function is done. */ + if (fargv) { + Char funcexit[] = { 'e', 'x', 'i', 't', 0 }, + funcmain[] = { 'm', 'a', 'i', 'n', 0 }; + struct Strbuf aword = Strbuf_INIT; + Sgoal = fargv->v[0]; + Stype = TC_GOTO; + fargv->eof = 0; + + if (!fargv->prev) + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1; + + while (1) { + do { + (void) getword(NULL); + (void) getword(&aword); + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(funcmain, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(funcmain, funcexit); + + (void) getword(NULL); + } + + setq(STRargv, &fargv->v[1], &shvhed, VAR_READWRITE); + gotolab(fargv->v[0]); + + { + struct Ain a; + + Stype = TC_EXIT; + a.type = TCSH_F_SEEK; + btell(&a); + + cleanup_push(&aword, Strbuf_cleanup); + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1, eof = 0; + + fargv->eof = 1; + while (1) { + do { + (void) getword(NULL); + if ((intptr_t) getword(&aword) == (intptr_t) &fargv) { + Strbuf_terminate(&aword); + eof = 1; + break; + } + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (eof) { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(Sgoal, funcexit); + + (void) getword(NULL); + } + + bseek(&a); + } + + cleanup_until(&aword); + } + process(0); /* 0 -> blow away on errors */ /* Restore the old state */ @@ -1995,6 +2095,7 @@ process(int catch) getexit(osetexit); omark = cleanup_push_mark(); + for (;;) { struct command *t; int hadhist, old_pintr_disabled; @@ -2179,6 +2280,7 @@ process(int catch) else haderr = 1; } + cleanup_pop_mark(omark); resexit(osetexit); exitset--; |
|
Functions should work for sourced scripts. Next, make a table of functions so they can be called globally. Currently, it isn't possible to call functions from sourced files other than the current. sh.h-3.diff (720 bytes)
diff --git a/sh.h b/sh.h index 19bf10d..3d63fea 100644 --- a/sh.h +++ b/sh.h @@ -1305,5 +1305,26 @@ extern int filec; #define TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */ #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */ +/* Function variable(s) and function(s). */ +extern Char *Sgoal; +extern int Stype; +extern struct funccurr { + struct funcargs { + Char **v; + struct funcargs *prev, + *next; + } *fargv; + struct funcfile { + char *file; + struct funcfile *prev, + *next; + } *ffile; + char *file; + int eof, + src, + ready; +} fcurr; +extern int getword(struct Strbuf *); +extern int srcfile(const char *, int, int, Char **); #endif /* _h_sh */ sh.c-3.diff (5,424 bytes)
diff --git a/sh.c b/sh.c index 2d5565f..ba547a8 100644 --- a/sh.c +++ b/sh.c @@ -111,6 +111,7 @@ int exitset = 0; static time_t chktim; /* Time mail last checked */ char *progname; int tcsh; +struct funccurr fcurr; /* * This preserves the input state of the shell. It is used by @@ -141,11 +142,6 @@ struct saved_state { }; static int srccat (Char *, Char *); -#ifndef WINNT_NATIVE -static int srcfile (const char *, int, int, Char **); -#else -int srcfile (const char *, int, int, Char **); -#endif /*WINNT_NATIVE*/ static void srcunit (int, int, int, Char **); static void mailchk (void); #ifndef _PATH_DEFPATH @@ -1543,11 +1539,7 @@ srccat(Char *cp, Char *dp) /* * Source to a file putting the file descriptor in a safe place (> 2). */ -#ifndef WINNT_NATIVE -static int -#else int -#endif /*WINNT_NATIVE*/ srcfile(const char *f, int onlyown, int flag, Char **av) { int unit; @@ -1733,6 +1725,7 @@ static void srcunit(int unit, int onlyown, int hflg, Char **av) { struct saved_state st; + struct funcargs *fargv; st.SHIN = -1; /* st_restore checks this */ @@ -1768,6 +1761,119 @@ srcunit(int unit, int onlyown, int hflg, Char **av) cleanup_push(&pintr_disabled, disabled_cleanup); } + /* Functions must have an exit to their end. + * if (!fargv->prev) is only true if this is a first function call. + * First seek for an ending exit before jumping to the label, + * then seek for an ending exit on the requested label. + * Function arguments are passed to STRargv. + * STRargv is reset after the function is done. */ + if (fcurr.ready) { + Char funcexit[] = { 'e', 'x', 'i', 't', 0 }, + *funcmain = fcurr.ffile ? + strsave(str2short(fcurr.ffile->file)) : + ffile; + struct Strbuf aword = Strbuf_INIT; + + Sgoal = fargv->v[0]; + Stype = TC_GOTO; + fcurr.eof = 0; + if (!(fargv = fcurr.fargv)->prev || fcurr.src) + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1; + + while (1) { + do { + (void) getword(NULL); + (void) getword(&aword); + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(funcmain, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + fcurr.src = 0; + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(funcmain, funcexit); + + (void) getword(NULL); + } + if (funcmain != ffile) + xfree(funcmain); + + setq(STRargv, &fargv->v[1], &shvhed, VAR_READWRITE); + gotolab(fargv->v[0]); + + { + struct Ain a; + + Stype = TC_EXIT; + a.type = TCSH_F_SEEK; + btell(&a); + + cleanup_push(&aword, Strbuf_cleanup); + while (1) { + (void) getword(&aword); + Strbuf_terminate(&aword); + + if (eq(aword.s, funcexit)) { + int last = 1, eof = 0; + + fcurr.eof = 1; + while (1) { + do { + (void) getword(NULL); + if (getword(&aword) == (1 << 1)) { + Strbuf_terminate(&aword); + eof = 1; + break; + } + Strbuf_terminate(&aword); + } while (!aword.s[0]); + if (eof) { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') { + if (!last) + funcerror(Sgoal, funcexit); + break; + } + if (!eq(aword.s, funcexit)) { + last = 0; + continue; + } + last = 1; + } + + break; + } + if (aword.s[0] != ':' && lastchr(aword.s) == ':') + funcerror(Sgoal, funcexit); + + (void) getword(NULL); + } + + bseek(&a); + } + + cleanup_until(&aword); + } + process(0); /* 0 -> blow away on errors */ /* Restore the old state */ @@ -1995,6 +2101,7 @@ process(int catch) getexit(osetexit); omark = cleanup_push_mark(); + for (;;) { struct command *t; int hadhist, old_pintr_disabled; @@ -2179,6 +2286,7 @@ process(int catch) else haderr = 1; } + cleanup_pop_mark(omark); resexit(osetexit); exitset--; @@ -2192,6 +2300,7 @@ dosource(Char **t, struct command *c) Char *f; int hflg = 0; char *file; + struct funcfile **ffile = NULL; USE(c); t++; @@ -2207,13 +2316,39 @@ dosource(Char **t, struct command *c) } f = globone(*t++, G_ERROR); - file = strsave(short2str(f)); + fcurr.file = file = strsave(short2str(f)); cleanup_push(file, xfree); xfree(f); t = glob_all_or_error(t); cleanup_push(t, blk_cleanup); + if (fcurr.fargv) { + if (*(ffile = &fcurr.ffile)) { + (*ffile)->next = malloc(sizeof **ffile); + (*ffile)->next->prev = *ffile; + *ffile = (*ffile)->next; + (*ffile)->file = fcurr.file; + } else { + *ffile = malloc(sizeof **ffile); + (*ffile)->prev = NULL; + (*ffile)->file = fcurr.file; + } + } + + fcurr.ready = 0; + fcurr.src = 1; if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) stderror(ERR_SYSTEM, file, strerror(errno)); + if (ffile) { + if ((*ffile)->prev) { + *ffile = (*ffile)->prev; + free((*ffile)->next); + fcurr.file = (*ffile)->file; + } else { + fcurr.file = (*ffile)->file = NULL; + free(*ffile); + *ffile = NULL; + } + } cleanup_until(file); } sh.func.c-3.diff (2,081 bytes)
diff --git a/sh.func.c b/sh.func.c index a9c0dd6..185b994 100644 --- 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 (fcurr.eof) + return 1 << 1; + setname(short2str(Sgoal)); + stderror(ERR_NAME | ERR_NOTFOUND, "exit"); + break; + default: break; } @@ -2719,3 +2725,53 @@ getYN(const char *prompt) continue; return doit; } + +void +dofunction(Char **v, struct command *t) +{ + char *file; + struct funcargs **fargv; + + if (!dolzero) + stderror(ERR_FUNC); + + if (*(fargv = &fcurr.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; + } + fcurr.ready = 1; + + if (!srcfile(file = fcurr.file ? fcurr.file : + strsave(short2str(ffile)), 0, 0, NULL)) + stderror(ERR_SYSTEM, file, strerror(errno)); + if (file != fcurr.file) + xfree(file); + /* Reset STRargv on function exit. */ + setv(STRargv, NULL, VAR_READWRITE); + + if ((*fargv)->prev) { + *fargv = (*fargv)->prev; + free((*fargv)->next); + } else { + free(*fargv); + *fargv = NULL; + } +} |
Date Modified | Username | Field | Change |
---|---|---|---|
2023-12-01 21:41 | MProG10 | New Issue | |
2023-12-02 00:49 | MProG10 | Note Added: 0003981 | |
2023-12-02 00:49 | MProG10 | File Added: sh.decls.h.diff | |
2023-12-02 00:49 | MProG10 | File Added: sh.c.diff | |
2023-12-02 00:49 | MProG10 | File Added: sh.err.c.diff | |
2023-12-02 00:49 | MProG10 | File Added: sh.func.c.diff | |
2023-12-02 00:49 | MProG10 | File Added: sh.h.diff | |
2023-12-02 03:03 | MProG10 | Note Added: 0003982 | |
2023-12-02 03:03 | MProG10 | File Added: sh.init.c.diff | |
2023-12-02 03:03 | MProG10 | File Added: tcsh.man.in.diff | |
2023-12-02 03:03 | MProG10 | File Added: commands.at.diff | |
2023-12-03 19:44 | MProG10 | Note Added: 0003985 | |
2023-12-03 19:44 | MProG10 | File Added: sh.h-2.diff | |
2023-12-03 19:44 | MProG10 | File Added: sh.func.c-2.diff | |
2023-12-03 19:44 | MProG10 | File Added: sh.c-2.diff | |
2024-02-14 14:57 | MProG10 | Note Added: 0004011 | |
2024-02-14 14:57 | MProG10 | File Added: sh.c-3.diff | |
2024-02-14 14:57 | MProG10 | File Added: sh.h-3.diff | |
2024-02-14 14:57 | MProG10 | File Added: sh.func.c-3.diff |