/*
** builtins.c
**
** Ties together rc's builtin commands.
**
**	NOTE: rc's builtins do not call "rc_error" because they are
**	commands, and rc errors usually arise from syntax errors. e.g.,
**	you probably don't want interpretation of a shell script to stop
**	because of a bad umask.
*/

#include "rc.h"

#include <errno.h>
#include <setjmp.h>

#include <sys/ioctl.h>

#include "addon.h"
#include "jbwrap.h"
#include "sigmsgs.h"

static void b_whatis(char **);

static struct {
	builtin_t *p;
	char *name;
} builtins[] = {
	{ b_builtin,	"builtin" },
	{ b_exec,	"exec" },
	{ b_whatis,	"whatis" },

	{ b_wait,	"wait" },
	{ b_jobs,	"jobs" },
	{ b_fg,		"fg" },
	{ b_bg,		"bg" },
	{ b_disown,	"disown" },
	{ b_reown,	"reown" },
	{ b_quietown,	"quietown" },
	{ b_kill,	"kill" },

	ADDONS
};

extern builtin_t *isbuiltin(char *s) {
	int i;
	for (i = 0; i < arraysize(builtins); i++)
		if (streq(builtins[i].name, s))
			return builtins[i].p;
	return NULL;
}

/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */

extern void funcall(char **av) {
	Jbwrap j;
	Estack e1, e2;
	Edata jreturn, star;
	if (setjmp(j.j))
		return;
	starassign(*av, av+1, TRUE);
	jreturn.jb = &j;
	varassign ("optind", word ("1", NULL), FALSE);
	star.name = "*";
	except(eReturn, jreturn, &e1);
	except(eVarstack, star, &e2);
	walk(treecpy(fnlookup(*av), nalloc), TRUE);
	varrm("*", TRUE);
	unexcept(); /* eVarstack */
	unexcept(); /* eReturn */
}

extern void arg_count(char *name) {
	fprint(2, "too many arguments to %s\n", name);
	set(FALSE);
}

/* a dummy command. (exec() performs "exec" simply by not forking) */

extern void b_exec(char **av) {
}

/* dud function */

extern void b_builtin(char **av) {
}


/*
   whatis without arguments prints all variables and functions. Otherwise, check to see if a name
   is defined as a variable, function or pathname.
*/

#define not(b)	((b)^TRUE)
#define show(b)	(not(eff|vee|pee|bee|ess)|(b))

static bool issig(char *s) {
	int i;
	for (i = 0; i < NUMOFSIGNALS; i++)
		if (streq(s, signals[i].name))
			return TRUE;
	return FALSE;
}

static void b_whatis(char **av) {
	bool ess, eff, vee, pee, bee;
	bool f, found;
	int i, ac, c;
	List *s;
	Node *n;
	char *e;
	for (rc_optind = ac = 0; av[ac] != NULL; ac++)
		; /* count the arguments for getopt */
	ess = eff = vee = pee = bee = FALSE;
	while ((c = rc_getopt(ac, av, "sfvpb")) != -1)
		switch (c) {
		default: set(FALSE); return;
		case 's': ess = TRUE; break;
		case 'f': eff = TRUE; break;
		case 'v': vee = TRUE; break;
		case 'p': pee = TRUE; break;
		case 'b': bee = TRUE; break;
		}
	av += rc_optind;
	if (*av == NULL) {
		if (vee|eff)
			whatare_all_vars(eff, vee);
		if (ess)
			whatare_all_signals();
		if (bee)
			for (i = 0; i < arraysize(builtins); i++)
				fprint(1, "builtin %s\n", builtins[i].name);
		if (pee)
			fprint(2, "whatis -p: must specify argument\n");
		if (show(FALSE)) /* no options? */
			whatare_all_vars(TRUE, TRUE);
		set(TRUE);
		return;
	}
	found = TRUE;
	for (i = 0; av[i] != NULL; i++) {
		f = FALSE;
		errno = ENOENT;
		if (show(vee) && (s = varlookup(av[i])) != NULL) {
			f = TRUE;
			prettyprint_var(1, av[i], s);
		}
		if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) {
			f = TRUE;
			prettyprint_fn(1, av[i], n);
		} else if (show(bee) && isbuiltin(av[i]) != NULL) {
			f = TRUE;
			fprint(1, "builtin %s\n", av[i]);
		} else if (show(pee) && (e = which(av[i], FALSE)) != NULL) {
			f = TRUE;
			fprint(1, "%S\n", e);
		}
		if (!f) {
			found = FALSE;
			if (errno != ENOENT)
				uerror(av[i]);
			else
				fprint(2, "%s not found\n", av[i]);
		}
	}
	set(found);
}
