fn.c: functions for adding and deleting functions from the symbol table.
Support for signal handlers is also found here.
static void fn_handler(int), dud_handler(int);
static bool runexit
= FALSE
;
static Node
*handlers
[NUMOFSIGNALS
], null
;
static void (*def_sigint
)(int) = SIG_DFL
,
(*def_sigquit
)(int) = SIG_DFL
,
(*def_sigterm
)(int) = SIG_DFL
;
Set signals to default values for rc. This means that interactive
shells ignore SIGTERM, etc.
extern void inithandler() {
null
.u
[0].p
= null
.u
[1].p
= NULL
;
for (i
= 1; i
< NUMOFSIGNALS
; i
++)
if (sighandlers
[i
] == SIG_IGN
)
fnassign(signals
[i
].name
, NULL
); /* ignore incoming ignored signals */
if (interactive
|| sighandlers
[SIGINT
] != SIG_IGN
) {
fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
if (interactive
|| sighandlers
[SIGQUIT
] != SIG_IGN
) {
def_sigquit
= dud_handler
;
fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
def_sigterm
= dud_handler
;
fnrm("sigterm"); /* ditto for SIGTERM */
/* only run this in a child process! resets signals to their default values */
extern void setsigdefaults(bool sysvbackground
) {
General housekeeping: setsigdefaults happens after fork(),
so it's a convenient place to clean up open file descriptors.
(history file, scripts, etc.)
Restore signals to SIG_DFL, paying close attention to
a few quirks: SIGINT, SIGQUIT and are treated specially
depending on whether we are doing v7-style backgrounding
or not; the default action for SIGINT, SIGQUIT and SIGTERM
must be set to the appropriate action; finally, care must
be taken not to set to SIG_DFL any signals which are being
for (i
= 1; i
< NUMOFSIGNALS
; i
++)
if (sighandlers
[i
] != SIG_IGN
) {
fnassign("sigint", NULL
); /* ignore */
fnassign("sigquit", NULL
); /* ignore */
if (sighandlers
[i
] != SIG_DFL
) {
delete_fn(signals
[i
].name
);
runexit
= FALSE
; /* No sigexit on subshells */
/* rc's exit. if runexit is set, run the sigexit function. */
extern void rc_exit(int stat
) {
static char *sigexit
[2] = {
/* The signal handler for all functions. calls walk() */
static void fn_handler(int s
) {
if (s
< 1 || s
>= NUMOFSIGNALS
)
dollarzero
->w
= signals
[s
].name
;
varassign("*", dollarzero
, TRUE
);
except(eVarstack
, star
, &e
);
unexcept(); /* eVarstack */
/* A dud signal handler for SIGQUIT and SIGTERM */
static void dud_handler(int s
) {
Assign a function in Node form. Check to see if the function is also
a signal, and set the signal vectors appropriately.
extern void fnassign(char *name
, Node
*def
) {
Node
*newdef
= treecpy(def
== NULL
? &null
: def
, ealloc
); /* important to do the treecopy first */
Function
*new = get_fn_place(name
);
if (strncmp(name
, "sig", conststrlen("sig")) == 0) { /* slight optimization */
if (streq(name
, "sigexit"))
for (i
= 1; i
< NUMOFSIGNALS
; i
++) /* zero is a bogus signal */
if (streq(signals
[i
].name
, name
)) {
rc_signal(i
, fn_handler
);
/* Assign a function from the environment. Store just the external representation */
extern void fnassign_string(char *extdef
) {
char *name
= get_name(extdef
+3); /* +3 to skip over "fn_" */
new = get_fn_place(name
);
new->extdef
= ecpy(extdef
);
/* Return a function in Node form, evaluating an entry from the environment if necessary */
extern Node
*fnlookup(char *name
) {
Function
*look
= lookup_fn(name
);
return NULL
; /* not found */
if (look
->extdef
== NULL
) /* function was set to null, e.g., fn foo {} */
ret
= parse_fn(name
, look
->extdef
);
return look
->def
= treecpy(ret
, ealloc
); /* Need to take it out of nalloc space */
/* Return a function in string form (used by makeenv) */
extern char *fnlookup_string(char *name
) {
Function
*look
= lookup_fn(name
);
if (look
->extdef
!= NULL
)
return look
->extdef
= fun2str(name
, look
->def
);
Remove a function from the symbol table. If it also defines a signal
handler, restore the signal handler to its default value.
extern void fnrm(char *name
) {
for (i
= 1; i
< NUMOFSIGNALS
; i
++)
if (streq(signals
[i
].name
, name
)) {
rc_signal(i
, def_sigint
);
rc_signal(i
, def_sigquit
);
rc_signal(i
, def_sigterm
);
if (streq(name
, "sigexit"))
extern void whatare_all_signals() {
for (i
= 1; i
< NUMOFSIGNALS
; i
++)
if (*signals
[i
].name
!= '\0')
if (sighandlers
[i
] == SIG_IGN
)
fprint(1, "fn %s {}\n", signals
[i
].name
);
else if (sighandlers
[i
] == fn_handler
)
fprint(1, "fn %S {%T}\n", signals
[i
].name
, handlers
[i
]);
fprint(1, "fn %s\n", signals
[i
].name
);
extern void prettyprint_fn(int fd
, char *name
, Node
*n
) {
fprint(fd
, "fn %S {%T}\n", name
, n
);