Skip to content

Commit

Permalink
Retought on functions
Browse files Browse the repository at this point in the history
I think functions based on pipes makes a simpler feature, as well as allows for use in interactive sessions, resembling Bourne-compatible Shells better. Unlike the goto-based version, functions may only be called if they were previously declared (i.e: no forward jumps), making a similar behavior to Bourne-compatible Shells.

This version relies on a tree derived from variables and aliases. Unlike to aliases and variables, the tree is restrictive. Once a function is declared, may not be redeclared or undeclared.
  • Loading branch information
Krush206 committed Jun 1, 2024
1 parent c60a4c2 commit 5318cfb
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 280 deletions.
191 changes: 12 additions & 179 deletions sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,47 +111,19 @@ 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
* 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 **);
#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
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 @@ -1539,7 +1511,11 @@ 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;
Expand All @@ -1561,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 @@ -1663,7 +1639,7 @@ st_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av)
/*
* Restore the shell to a saved state
*/
static void
void
st_restore(void *xst)
{
struct saved_state *st;
Expand Down Expand Up @@ -1725,7 +1701,6 @@ 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 */

Expand Down Expand Up @@ -1761,119 +1736,6 @@ 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 */
Expand Down Expand Up @@ -2101,7 +1963,6 @@ process(int catch)

getexit(osetexit);
omark = cleanup_push_mark();

for (;;) {
struct command *t;
int hadhist, old_pintr_disabled;
Expand Down Expand Up @@ -2286,7 +2147,6 @@ process(int catch)
else
haderr = 1;
}

cleanup_pop_mark(omark);
resexit(osetexit);
exitset--;
Expand All @@ -2300,7 +2160,6 @@ dosource(Char **t, struct command *c)
Char *f;
int hflg = 0;
char *file;
struct funcfile **ffile = NULL;

USE(c);
t++;
Expand All @@ -2316,39 +2175,13 @@ dosource(Char **t, struct command *c)
}

f = globone(*t++, G_ERROR);
fcurr.file = file = strsave(short2str(f));
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);
}

Expand Down
3 changes: 3 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 @@ -166,6 +168,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
20 changes: 8 additions & 12 deletions sh.err.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ extern int enterhist;
#define ERR_EOF 135
#define ERR_UNAVAILABLE 136
#define ERR_FUNC 137
#define NO_ERRORS 138
#define ERR_RETURN 138
#define ERR_FUNCBEGIN 139
#define ERR_FUNCALNUM 140
#define NO_ERRORS 141

static const char *elst[NO_ERRORS] INIT_ZERO_STRUCT;

Expand Down Expand Up @@ -368,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_FUNC] = CSAVS(1, 140, "Functions are only supported for scripts");
elst[ERR_FUNC] = CSAVS(1, 140, "%S: Undeclared function");
elst[ERR_RETURN] = CSAVS(1, 141, "Not in a declaration");
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");
}

/* Cleanup data. */
Expand Down Expand Up @@ -658,13 +664,3 @@ 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)));
}
Loading

0 comments on commit 5318cfb

Please sign in to comment.