# define INCLUDE_FILE_IO
# include "kfun.h"
# include "table.h"
/*
* prototypes
*/
# define FUNCDEF(name, func, proto) extern int func(); extern char proto[];
# include "builtin.c"
# include "std.c"
# include "file.c"
# include "math.c"
# include "extra.c"
# include "debug.c"
# undef FUNCDEF
/*
* kernel function table
*/
static kfunc kforig[] = {
# define FUNCDEF(name, func, proto) { name, proto, func, 0 },
# include "builtin.c"
# include "std.c"
# include "file.c"
# include "math.c"
# include "extra.c"
# include "debug.c"
# undef FUNCDEF
};
kfunc kftab[256]; /* kfun tab */
char kfind[256]; /* n -> index */
static char kfx[256]; /* index -> n */
static int nkfun; /* # kfuns */
static extfunc *kfext; /* additional kfun pointers */
/*
* NAME: kfun->clear()
* DESCRIPTION: clear previously added kfuns from the table
*/
void kf_clear()
{
nkfun = sizeof(kforig) / sizeof(kfunc);
}
/*
* NAME: kfun->callgate()
* DESCRIPTION: extra kfun call gate
*/
static int kf_callgate(f, nargs, kf)
frame *f;
int nargs;
kfunc *kf;
{
value val;
val = nil_value;
(*kfext[kf->num - sizeof(kforig) / sizeof(kfunc)])(f, nargs, &val);
i_pop(f, nargs);
*--f->sp = val;
return 0;
}
/*
* NAME: prototype()
* DESCRIPTION: construct proper prototype for new kfun
*/
static char *prototype(proto)
char *proto;
{
register char *p, *q;
register int nargs;
int class, type;
class = C_STATIC;
type = *proto++;
p = proto;
nargs = 0;
/* pass 1: check prototype */
if (*p != T_VOID) {
if (*p == T_VARARGS) {
/* all arguments are varargs */
class |= C_KFUN_VARARGS | C_VARARGS;
p++;
}
while (*p != '\0') {
if (*p == T_VARARGS) {
/* varargs or ellipsis */
class |= C_KFUN_VARARGS;
} else {
if (*p != T_MIXED) {
/* non-mixed arguments: typecheck this function */
class |= C_TYPECHECKED;
}
nargs++;
}
p++;
}
}
/* allocate new prototype */
p = proto;
q = proto = ALLOC(char, 3 + nargs);
*q++ = class;
*q++ = type;
*q++ = nargs;
/* pass 2: fill in new prototype */
if (*p != T_VOID) {
if (*p == T_VARARGS) {
p++;
}
while (*p != '\0') {
if (*p == T_VARARGS) {
/* varargs or ellipsis */
q[-1] |= T_VARARGS;
} else {
*q++ = *p;
}
p++;
}
}
return proto;
}
/*
* NAME: kfun->ext_kfun()
* DESCRIPTION: add new kfuns
*/
void kf_ext_kfun(kfadd, n)
register extkfunc *kfadd;
register int n;
{
register kfunc *kf;
kfext = ALLOC(extfunc, n) + n;
kfadd += n;
nkfun += n;
kf = kftab + nkfun;
while (n != 0) {
(--kf)->name = (--kfadd)->name;
kf->proto = prototype(kfadd->proto);
kf->func = (int (*)()) &kf_callgate;
*--kfext = kfadd->func;
--n;
}
}
/*
* NAME: kfun->cmp()
* DESCRIPTION: compare two kftable entries
*/
static int kf_cmp(cv1, cv2)
cvoid *cv1, *cv2;
{
return strcmp(((kfunc *) cv1)->name, ((kfunc *) cv2)->name);
}
/*
* NAME: kfun->init()
* DESCRIPTION: initialize the kfun table
*/
void kf_init()
{
register int i;
register char *k1, *k2;
memcpy(kftab, kforig, sizeof(kforig));
for (i = 0; i < nkfun; i++) {
kftab[i].num = i;
}
qsort(kftab + KF_BUILTINS, nkfun - KF_BUILTINS, sizeof(kfunc), kf_cmp);
for (i = nkfun, k1 = kfind + nkfun + 128 - KF_BUILTINS, k2 = kfx + nkfun;
i > KF_BUILTINS; ) {
*--k1 = --i;
*--k2 = i + 128 - KF_BUILTINS;
}
for (k1 = kfind + KF_BUILTINS; i > 0; ) {
*--k1 = --i;
*--k2 = i;
}
}
/*
* NAME: kfun->func()
* DESCRIPTION: search for kfun in the kfun table, return index or -1
*/
int kf_func(name)
register char *name;
{
register unsigned int h, l, m;
register int c;
l = KF_BUILTINS;
h = nkfun;
do {
c = strcmp(name, kftab[m = (l + h) >> 1].name);
if (c == 0) {
return UCHAR(kfx[m]); /* found */
} else if (c < 0) {
h = m; /* search in lower half */
} else {
l = m + 1; /* search in upper half */
}
} while (l < h);
/*
* not found
*/
return -1;
}
typedef struct {
short nbuiltin; /* # builtin kfuns */
short nkfun; /* # other kfuns */
short kfnamelen; /* length of all kfun names */
} dump_header;
static char dh_layout[] = "sss";
/*
* NAME: kfun->dump()
* DESCRIPTION: dump the kfun table
*/
bool kf_dump(fd)
int fd;
{
register int i;
register unsigned int len, buflen;
register kfunc *kf;
dump_header dh;
char *buffer;
bool flag;
/* prepare header */
dh.nbuiltin = KF_BUILTINS;
dh.nkfun = nkfun - KF_BUILTINS;
dh.kfnamelen = 0;
for (i = dh.nkfun, kf = kftab + KF_BUILTINS; i > 0; --i, kf++) {
dh.kfnamelen += strlen(kf->name) + 1;
}
/* write header */
if (P_write(fd, (char *) &dh, sizeof(dump_header)) < 0) {
return FALSE;
}
/* write kfun names */
buffer = ALLOCA(char, dh.kfnamelen);
buflen = 0;
for (i = 0; i < dh.nkfun; i++) {
kf = &KFUN(i + 128);
len = strlen(kf->name) + 1;
memcpy(buffer + buflen, kf->name, len);
buflen += len;
}
flag = (P_write(fd, buffer, buflen) >= 0);
AFREE(buffer);
return flag;
}
/*
* NAME: kfun->restore()
* DESCRIPTION: restore the kfun table
*/
void kf_restore(fd)
int fd;
{
register int i, n, buflen;
dump_header dh;
char *buffer;
/* read header */
conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
/* fix kfuns */
buffer = ALLOCA(char, dh.kfnamelen);
if (P_read(fd, buffer, (unsigned int) dh.kfnamelen) < 0) {
fatal("cannot restore kfun names");
}
buflen = 0;
for (i = 0; i < dh.nkfun; i++) {
n = kf_func(buffer + buflen);
if (n < 0) {
error("Restored unknown kfun: %s", buffer + buflen);
}
n += KF_BUILTINS - 128;
kfind[i + 128] = n;
kfx[n] = i + 128;
buflen += strlen(buffer + buflen) + 1;
}
AFREE(buffer);
if (dh.nkfun < nkfun - KF_BUILTINS) {
/*
* There are more kfuns in the current driver than in the driver
* which created the dump file: deal with those new kfuns.
*/
n = dh.nkfun + 128;
for (i = KF_BUILTINS; i < nkfun; i++) {
if (UCHAR(kfx[i]) >= dh.nkfun + 128 ||
UCHAR(kfind[UCHAR(kfx[i])]) != i) {
/* new kfun */
kfind[n] = i;
kfx[i] = n++;
}
}
}
}