Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce 'function' built-in. #77

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
faab6cc
Introduce 'function' built-in
Krush206 Jul 7, 2023
b683769
sh.c: Sgoal shouldn't be assigned funcmain
Krush206 Jul 7, 2023
4d90ff3
sh.c: cleanup_push() raises SIGSEGV
Krush206 Jul 8, 2023
715a882
fargv should be freed from dofunction()
Krush206 Jul 8, 2023
5e37bfc
Move function tests to srcunit()
Krush206 Aug 5, 2023
235b358
Better function parsing
Krush206 Nov 21, 2023
4a54e05
Create tests for 'function' built-in
Krush206 Nov 21, 2023
5bc9252
sh.c: call cleanup_push() properly
Krush206 Nov 21, 2023
b1e4135
Documentation for 'function' built-in
Krush206 Nov 21, 2023
ede350d
Rename ERR_DOLFUNC to ERR_FUNC
Krush206 Nov 21, 2023
fc7dbd3
sh.func.c: prefer dolzero over ffile
Krush206 Nov 21, 2023
d762fba
sh.func.c: allocate memory properly
Krush206 Nov 21, 2023
951264d
sh.func.c: assign NULL after deallocating fargv
Krush206 Nov 22, 2023
7d6eef8
Prefer srcfile() over dosource()
Krush206 Dec 3, 2023
c60a4c2
Functions should work for sourced scripts.
Krush206 Feb 14, 2024
954cfd6
Rethought on functions
Krush206 May 18, 2024
15d4e30
Do not fork & fix interrupts
Krush206 Jun 2, 2024
042e84b
Refactor
Krush206 Jun 3, 2024
2fa7967
tcsh.man.in: correction & additional information
Krush206 Jun 3, 2024
b950b85
sh.err.c: recursion/nest
Krush206 Jun 3, 2024
d840e89
Create aliases for functions
Krush206 Jun 3, 2024
22d3150
sh.func.c: replace setexit with cleanup_push
Krush206 Jun 4, 2024
adea1b6
Avoid SIGPIPE on doexit
Krush206 Jun 4, 2024
d0167d4
sh.func.c: don't catch OLDSTD
Krush206 Jun 4, 2024
911ed6e
22d3150: move remaining parts to st_restore
Krush206 Jun 6, 2024
56e5e7d
911ed6e: more remaining parts
Krush206 Jun 7, 2024
c8b8f51
Prefer dozip over doreturn
Krush206 Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 19 additions & 36 deletions sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,34 +112,6 @@ static time_t chktim; /* Time mail last checked */
char *progname;
int tcsh;

/*
* This preserves the input state of the shell. It is used by
* st_save and st_restore to manupulate shell state.
*/
struct saved_state {
int insource;
int OLDSTD;
int SHIN;
int SHOUT;
int SHDIAG;
int intty;
struct whyle *whyles;
Char *gointr;
Char *arginp;
Char *evalp;
Char **evalvec;
Char *alvecp;
Char **alvec;
int onelflg;
int enterhist;
Char **argv;
Char **av;
Char HIST;
int cantell;
struct Bin B;
int justpr;
};

static int srccat (Char *, Char *);
#ifndef WINNT_NATIVE
static int srcfile (const char *, int, int, Char **);
Expand All @@ -152,10 +124,6 @@ static void mailchk (void);
static Char **defaultpath (void);
#endif
static void record (void);
static void st_save (struct saved_state *, int, int,
Char **, Char **);
static void st_restore (void *);

int main (int, char **);

#ifndef LOCALEDIR
Expand Down Expand Up @@ -1569,7 +1537,7 @@ srcfile(const char *f, int onlyown, int flag, Char **av)
* Save the shell state, and establish new argument vector, and new input
* fd.
*/
static void
void
st_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av)
{
st->insource = insource;
Expand Down Expand Up @@ -1659,19 +1627,28 @@ st_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av)
gointr = 0;
evalvec = 0;
evalp = 0;
alvec = al;
alvecp = 0;
enterhist = hflg;
if (enterhist)
HIST = '\0';
insource = 1;
if (al == &fdecl) {
alvec = NULL;
insource = 2;
st->fpipe = fpipe;
st->fdecl = *al;
flvl++;
}
else {
alvec = al;
insource = 1;
}
}


/*
* Restore the shell to a saved state
*/
static void
void
st_restore(void *xst)
{
struct saved_state *st;
Expand All @@ -1696,6 +1673,12 @@ st_restore(void *xst)

xclose(SHIN);

if (insource == 2) {
xclose(fpipe);
fpipe = st->fpipe;
fdecl = st->fdecl;
flvl--;
}
insource = st->insource;
SHIN = st->SHIN;
if (st->OLDSTD != -1)
Expand Down
4 changes: 4 additions & 0 deletions sh.decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ extern void done (int) __attribute__((__noreturn__));
extern void xexit (int) __attribute__((__noreturn__));
#endif
extern int grabpgrp (int, pid_t);
extern void st_save (struct saved_state *, int, int, Char **, Char **);
extern void st_restore (void *);

/*
* sh.dir.c
Expand Down Expand Up @@ -150,6 +152,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 *);
Expand All @@ -164,6 +167,7 @@ extern void dohup (Char **, struct command *);
extern void doonintr (Char **, struct command *);
extern void doprintenv (Char **, struct command *);
extern void dorepeat (Char **, struct command *);
extern void doreturn (Char **, struct command *);
extern void dofiletest (Char **, struct command *);
extern void dosetenv (Char **, struct command *);
extern void dosuspend (Char **, struct command *);
Expand Down
11 changes: 9 additions & 2 deletions sh.err.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ extern int enterhist;
#define ERR_BADCOLORVAR 134
#define ERR_EOF 135
#define ERR_UNAVAILABLE 136
#define NO_ERRORS 137
#define ERR_UNDFUNC 137
#define ERR_FUNCBEGIN 138
#define ERR_FUNCALNUM 139
#define ERR_RECURSION 140
#define NO_ERRORS 141

static const char *elst[NO_ERRORS] INIT_ZERO_STRUCT;

Expand Down Expand Up @@ -367,7 +371,10 @@ errinit(void)
elst[ERR_BADCOLORVAR] = CSAVS(1, 137, "Unknown %s color variable '%c%c'");
elst[ERR_EOF] = CSAVS(1, 138, "Unexpected end of file");
elst[ERR_UNAVAILABLE] = CSAVS(1, 139, "%s: Feature is not available for this platform");

elst[ERR_UNDFUNC] = CSAVS(1, 140, "%S: Undeclared function");
elst[ERR_FUNCBEGIN] = CSAVS(1, 142, "Function name must begin with a letter");
elst[ERR_FUNCALNUM] = CSAVS(1, 143, "Function name must contain alphanumeric characters");
elst[ERR_RECURSION] = CSAVS(1, 144, "Too deep a recursion or nest");
}

/* Cleanup data. */
Expand Down
143 changes: 139 additions & 4 deletions sh.func.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,11 +498,18 @@ doexit(Char **v, struct command *c)
stderror(ERR_NAME | ERR_EXPRESSION);
}
btoeof();
#if 0
if (intty)
#endif
/* Always close, why only on ttys? */

/* Always close, except in the context of
* dosource or dofunction.
* st_restore will handle. */
switch (insource) {
case 0:
xclose(SHIN);
SHIN = -1;
break;
case 2:
fdecl += Strlen(fdecl);
}
}

/*ARGSUSED*/
Expand Down Expand Up @@ -1096,6 +1103,11 @@ getword(struct Strbuf *wp)
stderror(ERR_NAME | ERR_NOTFOUND, "label");
break;

case TC_EXIT:
setname(short2str(Sgoal));
stderror(ERR_NAME | ERR_NOTFOUND, "return");
break;

default:
break;
}
Expand Down Expand Up @@ -2719,3 +2731,126 @@ getYN(const char *prompt)
continue;
return doit;
}

int flvl,
fpipe = -1;
Char *fdecl;

void
dofunction(Char **v, struct command *c)
{
if (*++v == NULL) {
plist(&functions, VAR_READONLY);

return;
}
Sgoal = *v++;
Stype = TC_EXIT;
{
int pv[2];
struct saved_state st;
struct varent *varp;
Char *p;

if (!letter(*(p = Sgoal)))
stderror(ERR_NAME | ERR_FUNCBEGIN);
while (*++p)
if (!alnum(*p))
stderror(ERR_NAME | ERR_FUNCALNUM);
if ((varp = adrof1(Sgoal, &functions))) {
if (flvl == 100)
stderror(ERR_RECURSION);
mypipe(pv);
cleanup_push(&st, st_restore);
st_save(&st, pv[0], 0, &fdecl, v);
fpipe = pv[1];
fdecl = *varp->vec;
process(0);
cleanup_until(&st);

return;
}
if (*v || c->t_dlef || c->t_drit ||
c->t_dflg & (F_PIPEIN | F_PIPEOUT))
stderror(ERR_UNDFUNC, Sgoal);
{
Char funcexit[] = { 'r', 'e', 't', 'u', 'r', 'n', '\0' },
alarg[] = { '!', '*', '\0' },
*(*varvec)[4];
struct Strbuf aword = Strbuf_INIT,
func = Strbuf_INIT;
struct wordent *histent = NULL,
*ohistent = NULL;

cleanup_push(&aword, Strbuf_cleanup);
while (1) {
if (intty) {
histent = xmalloc(sizeof(*histent));
ohistent = xmalloc(sizeof(*histent));
ohistent->word = STRNULL;
ohistent->next = histent;
histent->prev = ohistent;
}
if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
printprompt(1, bname);
(void) getword(&aword);
Strbuf_terminate(&aword);
if (intty && Strlen(aword.s) > 0) {
histent->word = Strsave(aword.s);
histent->next = xmalloc(sizeof(*histent));
histent->next->prev = histent;
histent = histent->next;
}

if (eq(aword.s, funcexit))
break;
Strbuf_append(&func, aword.s);
Strbuf_append1(&func, ' ');
while (getword(&aword)) {
Strbuf_terminate(&aword);
if (intty && Strlen(aword.s) > 0) {
histent->word = Strsave(aword.s);
histent->next = xmalloc(sizeof(*histent));
histent->next->prev = histent;
histent = histent->next;
}
Strbuf_append(&func, aword.s);
Strbuf_append1(&func, ' ');
}
func.s[func.len - 1] = '\n';

if (intty) {
ohistent->prev = histgetword(histent);
ohistent->prev->next = ohistent;
savehist(ohistent, 0);
freelex(ohistent);
xfree(ohistent);
} else
(void) getword(NULL);
}

if (intty) {
ohistent->prev = histgetword(histent);
ohistent->prev->next = ohistent;
savehist(ohistent, 0);
freelex(ohistent);
xfree(ohistent);
}
cleanup_until(&aword);
if (!func.len)
return;
Strbuf_terminate(&func);
**(varvec = xcalloc(1, sizeof *varvec -
(sizeof **varvec * 2))) =
func.s;
setq(Sgoal, *varvec, &functions, VAR_READONLY);
**(varvec = xcalloc(1, sizeof *varvec)) =
Strsave(str2short(bname));
(*varvec)[1] = Strsave(Sgoal);
(*varvec)[2] = Strsave(alarg);
setq(Sgoal, *varvec, &aliases, VAR_READWRITE);

tw_cmd_free();
}
}
}
39 changes: 38 additions & 1 deletion sh.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,9 @@ EXTERN struct varent {
#define VAR_LAST 64
struct varent *v_link[3]; /* The links, see below */
int v_bal; /* Balance factor */
} shvhed IZERO_STRUCT, aliases IZERO_STRUCT;
} shvhed IZERO_STRUCT,
aliases IZERO_STRUCT,
functions IZERO_STRUCT;

#define v_left v_link[0]
#define v_right v_link[1]
Expand Down Expand Up @@ -1266,6 +1268,36 @@ EXTERN nl_catd catd;
extern int filec;
#endif /* FILEC */

/*
* This preserves the input state of the shell. It is used by
* st_save and st_restore to manupulate shell state.
*/
struct saved_state {
int insource;
int OLDSTD;
int SHIN;
int SHOUT;
int SHDIAG;
int intty;
struct whyle *whyles;
Char *gointr;
Char *arginp;
Char *evalp;
Char **evalvec;
Char *alvecp;
Char **alvec;
int onelflg;
int enterhist;
Char **argv;
Char **av;
Char HIST;
int cantell;
struct Bin B;
int justpr;
int fpipe;
Char *fdecl;
};

#include "sh.decls.h"
/*
* Since on some machines characters are unsigned, and the signed
Expand Down Expand Up @@ -1305,5 +1337,10 @@ 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 */

extern int flvl, /* Level of nesting or recursion used
* used by dofunction. */
fpipe; /* Write end of a pipe used by dofunction. */
extern Char *fdecl; /* Pointer to function declaration
* used by dofunction. */

#endif /* _h_sh */
2 changes: 2 additions & 0 deletions sh.init.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const struct biltins bfunc[] = {
{ "fg", dofg, 0, INF },
{ "filetest", dofiletest, 2, INF },
{ "foreach", doforeach, 3, INF },
{ "function", dofunction, 0, INF },
#ifdef TCF
{ "getspath", dogetspath, 0, 0 },
{ "getxvers", dogetxvers, 0, 0 },
Expand Down Expand Up @@ -122,6 +123,7 @@ const struct biltins bfunc[] = {
{ "pushd", dopushd, 0, INF },
{ "rehash", dohash, 0, 3 },
{ "repeat", dorepeat, 2, INF },
{ "return", dozip, 0, 0 },
#ifdef apollo
{ "rootnode", dorootnode, 1, 1 },
#endif /* apollo */
Expand Down
5 changes: 5 additions & 0 deletions sh.lex.c
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,11 @@ bgetc(void)
buf = (int) feobp / BUFSIZE;
balloc(buf);
roomleft = BUFSIZE - off;
if (insource == 2) {
if (!*fdecl)
return CHAR_ERR;
(void) xwrite(fpipe, fdecl++, (size_t) 1);
}
c = wide_read(SHIN, fbuf[buf] + off, roomleft, 0);
if (c > 0)
feobp += c;
Expand Down
Loading