capi4yaps/slang.c

693 lines
14 KiB
C

/* -*- mode: c; mode: fold -*- */
# include "config.h"
# ifdef SCRIPT_SLANG
# ifndef FLOAT_TYPE
# define FLOAT_TYPE
# endif /* FLOAT_TYPE */
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <slang.h>
# include "pager.h"
# include "script.h"
# define STARTUP "Startup.sl"
/*{{{ string class */
static char *ifmt = NULL;
static char *ffmt = NULL;
static inline char *
make_scratch (unsigned char typ, VOID_STAR p)
{
char buf[128];
buf[0] = '\0';
switch (typ) {
case INT_TYPE:
sprintf (buf, (ifmt ? ifmt : "%d"), *(int *) p);
break;
case FLOAT_TYPE:
sprintf (buf, (ffmt ? ffmt : "%f"), (double) (*(float64 *) p));
break;
}
return strdup (buf);
}
static int
binop_string (int op, unsigned char atyp, unsigned char btyp,
VOID_STAR ap, VOID_STAR bp)
{
char *scratch;
char *a, *b;
int la, lb;
int len;
int n;
char *ptr;
char *res;
scratch = NULL;
if ((atyp == STRING_TYPE) && (btyp == STRING_TYPE)) {
a = (char *) ap;
b = (char *) bp;
} else if (atyp == STRING_TYPE) {
a = (char *) ap;
scratch = make_scratch (btyp, bp);
b = scratch;
} else {
b = (char *) ap;
scratch = make_scratch (atyp, ap);
a = scratch;
}
if (! (a && b))
return 0;
res = NULL;
switch (op) {
case SLANG_PLUS:
la = strlen (a);
lb = strlen (b);
if (res = SLMALLOC (la + lb + 1)) {
strcpy (res, a);
strcat (res, b);
}
break;
case SLANG_MINUS:
la = strlen (a);
lb = strlen (b);
if (ptr = strstr (a, b)) {
if (res = SLMALLOC (la - lb + 1)) {
len = (int) ((unsigned long) ptr - (unsigned long) a);
strncpy (res, a, len);
res[len] = '\0';
strcat (res, a + len + lb);
}
} else if (res = SLMALLOC (la + 1))
strcpy (res, a);
break;
case SLANG_TIMES:
la = strlen (a);
if ((n = atoi (b)) > 0) {
if (res = SLMALLOC (la * n + 1)) {
ptr = res;
while (n-- > 0) {
strcpy (ptr, a);
while (*ptr)
++ptr;
}
}
} else if (res = SLMALLOC (2))
res[0] = '\0';
break;
case SLANG_DIVIDE:
for (ptr = a; *ptr; ++ptr)
if (! strchr (b, *ptr))
break;
if (res = SLMALLOC (strlen (ptr) + 1)) {
strcpy (res, ptr);
if (res[0]) {
for (ptr = res; *ptr; ++ptr)
;
--ptr;
while (ptr != res)
if (strchr (b, *ptr))
*ptr-- = '\0';
else
break;
}
}
break;
case SLANG_EQ:
SLang_push_integer (strcmp (a, b) == 0 ? 1 : 0);
break;
case SLANG_NE:
SLang_push_integer (strcmp (a, b) ? 1 : 0);
break;
case SLANG_GT:
SLang_push_integer (strcmp (a, b) > 0 ? 1 : 0);
break;
case SLANG_GE:
SLang_push_integer (strcmp (a, b) >= 0 ? 1 : 0);
break;
case SLANG_LT:
SLang_push_integer (strcmp (a, b) < 0 ? 1 : 0);
break;
case SLANG_LE:
SLang_push_integer (strcmp (a, b) <= 0 ? 1 : 0);
break;
default:
return 0;
}
if (scratch)
free (scratch);
if (res)
SLang_push_malloced_string (res);
return 1;
}
static int
unop_string (int op, unsigned char typ, VOID_STAR p)
{
char *s;
char *r;
int len;
s = (char *) p;
switch (op) {
case SLANG_ABS:
SLang_push_integer (strlen (s));
break;
case SLANG_SIGN:
SLang_push_integer (*s ? 1 : 0);
break;
case SLANG_SQR:
break;
case SLANG_MUL2:
len = strlen (s);
if (r = SLMALLOC (len * 2 + 1)) {
strcpy (r, s);
strcat (r, s);
SLang_push_malloced_string (r);
}
break;
case SLANG_CHS:
SLang_push_string (s);
break;
default:
return 0;
}
return 1;
}
static void
get_format (char **var)
{
char *fmt;
int fre;
if (*var) {
free (*var);
*var = NULL;
}
if (SLang_pop_string (& fmt, & fre))
return;
*var = strdup (fmt);
if (fre)
SLFREE (fmt);
}
static void
str_iformat (void)
{
get_format (& ifmt);
}
static void
str_fformat (void)
{
get_format (& ffmt);
}
static SLang_Name_Type avail_string[] = {
/* void str_iformat (string format); */
MAKE_INTRINSIC (".str_iformat", str_iformat, VOID_TYPE, 0),
/* void str_fformat (string format); */
MAKE_INTRINSIC (".str_fformat", str_fformat, VOID_TYPE, 0),
/*
MAKE_INTRINSIC (".", , _TYPE, 0),
MAKE_INTRINSIC (".function_name", c_function, TYPE, 0),
MAKE_VARIABLE (".", & , TYPE, ),
MAKE_VARIABLE (".var", &c_variable, TYPE, flag),
*/
SLANG_END_TABLE
};
static int
string_class (void)
{
if ((! SLang_register_class (STRING_TYPE, NULL, NULL)) ||
(! SLang_add_binary_op (STRING_TYPE, STRING_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_binary_op (STRING_TYPE, INT_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_binary_op (STRING_TYPE, FLOAT_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_unary_op (STRING_TYPE,
(VOID_STAR) unop_string)) ||
(! SLang_add_table (avail_string, "string")))
return 0;
return 1;
}
/*}}}*/
/*{{{ statics */
static Bool isinit = False;
static script *sls = NULL;
static char *slline = NULL;
static int slsiz = 0;
static SLang_Name_Type *slcb = NULL;
/*}}}*/
/*{{{ callable functions and variables */
static void
sllogger (void)
{
char *str;
int fre;
int typ;
if (SLang_pop_string (& str, & fre) ||
SLang_pop_integer (& typ))
return;
if (sls && sls -> logger) {
if (! typ)
typ = LG_INF;
(*sls -> logger) ((char) typ, "%s\n", str);
}
if (fre)
SLFREE (str);
}
static void
slcallback (void *sp, string_t *s, char_t sep, void *data)
{
int len;
char *str;
if (str = sextract (s)) {
len = strlen (str);
if (len + 2 >= slsiz) {
slsiz = len + 64;
if (! (slline = Realloc (slline, slsiz + 4)))
slsiz = 0;
}
if (slline) {
sprintf (slline, "%s%c", str, (char) sep);
if (slcb) {
SLang_push_string (slline);
SLexecute_function (slcb);
}
}
free (str);
}
}
static void
slsetcb (void)
{
char *func, *sep;
int fr1, fr2;
if (SLang_pop_string (& sep, & fr2) ||
SLang_pop_string (& func, & fr1))
return;
if (func && *func)
slcb = SLang_get_function (func);
else
slcb = NULL;
if (sls && sls -> sp)
tty_set_line_callback (sls -> sp, slcallback, sep, NULL);
if (fr1)
SLFREE (func);
if (fr2)
SLFREE (sep);
}
static void
slclrcb (void)
{
slcb = NULL;
if (sls && sls -> sp)
tty_set_line_callback (sls -> sp, NULL, NULL, NULL);
}
static void
slget_line (void)
{
SLang_push_string (slline ? slline : "");
}
static void
slhangup (void)
{
int msec;
if (SLang_pop_integer (& msec))
return;
if (sls && sls -> sp)
tty_hangup (sls -> sp, msec);
}
static int
slsend (void)
{
int ret;
char *str;
int fre;
if (SLang_pop_string (& str, & fre))
return 0;
ret = 0;
if (sls && sls -> sp)
if (tty_send_string (sls -> sp, str) != -1)
ret = 1;
if (fre)
SLFREE (str);
return ret;
}
static int
slcsend (void)
{
int ret;
char *str;
int fre;
char *rstr;
if (SLang_pop_string (& str, & fre))
return 0;
ret = 0;
if (sls && sls -> sp)
if (rstr = scr_convert (sls, str)) {
if (tty_send_string (sls -> sp, rstr) != -1)
ret = 1;
free (rstr);
}
if (fre)
SLFREE (str);
return ret;
}
static int
slexpect (void)
{
int ret;
int cnt;
char **str;
int *fre;
int *len;
int tout;
int n;
if (SLang_pop_integer (& cnt))
return -1;
ret = -1;
if ((str = (char **) malloc ((cnt + 2) * sizeof (char *))) &&
(fre = (int *) malloc ((cnt + 2) * sizeof (int))) &&
(len = (int *) malloc ((cnt + 2) * sizeof (int)))) {
for (n = cnt - 1; n >= 0; --n)
if (SLang_pop_string (& str[n], & fre[n]))
return -1;
else
len[n] = strlen (str[n]);
str[cnt] = NULL;
len[cnt] = 0;
if (SLang_pop_integer (& tout))
return -1;
if (sls && sls -> sp)
ret = tty_expect_list (sls -> sp, tout, str, len);
for (n = 0; n < cnt; ++n)
if (fre[n])
SLFREE (str[n]);
free (str);
free (fre);
free (len);
}
return ret;
}
static int
slsend_expect (void)
{
int tout;
char *str;
int fre;
int ret;
if (SLang_pop_string (& str, & fre) ||
SLang_pop_integer (& tout))
return 0;
ret = 0;
if (sls && sls -> sp)
if (tty_send_expect (sls -> sp, tout, str, NULL) != -1)
ret = 1;
if (fre)
SLFREE (str);
return ret;
}
static void
sldrain (void)
{
int secs;
if (SLang_pop_integer (& secs))
return;
if (sls && sls -> sp)
tty_drain (sls -> sp, secs);
}
static void
slcvdef (void)
{
int src, dst;
if (SLang_pop_integer (& dst) ||
SLang_pop_integer (& src))
return;
if (sls) {
if (! sls -> ctab)
sls -> ctab = cv_new ();
if (sls -> ctab)
cv_define (sls -> ctab, (char_t) src, (char_t) dst);
}
}
static void
slcvundef (void)
{
int ch;
if (SLang_pop_integer (& ch))
return;
if (sls && sls -> ctab)
cv_undefine (sls -> ctab, (char_t) ch);
}
static void
slcvinval (void)
{
int ch;
if (SLang_pop_integer (& ch))
return;
if (sls) {
if (! sls -> ctab)
sls -> ctab = cv_new ();
if (sls -> ctab)
cv_invalid (sls -> ctab, (char_t) ch);
}
}
static void
slconv (void)
{
char *str;
int fre;
char *rstr;
if (SLang_pop_string (& str, & fre))
return;
if (sls)
rstr = scr_convert (sls, str);
else
rstr = NULL;
SLang_push_string (rstr ? rstr : str);
if (rstr)
free (rstr);
if (fre)
SLFREE (str);
}
static int no_err = NO_ERR,
err_fail = ERR_FAIL,
err_fatal = ERR_FATAL,
err_abort = ERR_ABORT;
static date_t sldelay, slexpire;
static int slrds = 0;
static int xFalse = (int) False,
xTrue = (int) True;
static char xNull_String[2] = "";
/*}}}*/
/*{{{ function/variable table */
static SLang_Name_Type avail[] = {
/* void logger (string str); */
MAKE_INTRINSIC (".logger", sllogger, VOID_TYPE, 0),
/* void setcb (string func, string sep); */
MAKE_INTRINSIC (".setcb", slsetcb, VOID_TYPE, 0),
/* void clrcb (void); */
MAKE_INTRINSIC (".clrcb", slclrcb, VOID_TYPE, 0),
/* string line (void); */
MAKE_INTRINSIC (".line", slget_line, VOID_TYPE, 0),
/* void hangup (int msec); */
MAKE_INTRINSIC (".hangup", slhangup, VOID_TYPE, 0),
/* int send (string str); */
MAKE_INTRINSIC (".send", slsend, INT_TYPE, 0),
/* int csend (string str); */
MAKE_INTRINSIC (".csend", slcsend, INT_TYPE, 0),
/* int expect (int tout, string e1, ..., string en,
int cnt); */
MAKE_INTRINSIC (".expect", slexpect, INT_TYPE, 0),
/* int send_expect (int tout, string str); */
MAKE_INTRINSIC (".send_expect", slsend_expect, INT_TYPE, 0),
/* void drain (int secs); */
MAKE_INTRINSIC (".drain", sldrain, INT_TYPE, 0),
/* void cvdef (int src, int dst); */
MAKE_INTRINSIC (".cvdef", slcvdef, VOID_TYPE, 0),
/* void cvundef (int ch); */
MAKE_INTRINSIC (".cvundef", slcvundef, VOID_TYPE, 0),
/* void cvinval (int ch); */
MAKE_INTRINSIC (".cvinval", slcvinval, VOID_TYPE, 0),
/* string conv (string str); */
MAKE_INTRINSIC (".conv", slconv, VOID_TYPE, 0),
MAKE_VARIABLE (".NO_ERR", & no_err, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_FAIL", & err_fail, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_FATAL", & err_fatal, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_ABORT", & err_abort, INT_TYPE, 1),
MAKE_VARIABLE (".delay_day", & sldelay.day, INT_TYPE, 1),
MAKE_VARIABLE (".delay_mon", & sldelay.mon, INT_TYPE, 1),
MAKE_VARIABLE (".delay_year", & sldelay.year, INT_TYPE, 1),
MAKE_VARIABLE (".delay_hour", & sldelay.hour, INT_TYPE, 1),
MAKE_VARIABLE (".delay_min", & sldelay.min, INT_TYPE, 1),
MAKE_VARIABLE (".delay_sec", & sldelay.sec, INT_TYPE, 1),
MAKE_VARIABLE (".expire_day", & slexpire.day, INT_TYPE, 1),
MAKE_VARIABLE (".expire_mon", & slexpire.mon, INT_TYPE, 1),
MAKE_VARIABLE (".expire_year", & slexpire.year, INT_TYPE, 1),
MAKE_VARIABLE (".expire_hour", & slexpire.hour, INT_TYPE, 1),
MAKE_VARIABLE (".expire_min", & slexpire.min, INT_TYPE, 1),
MAKE_VARIABLE (".expire_sec", & slexpire.sec, INT_TYPE, 1),
MAKE_VARIABLE (".rds", & slrds, INT_TYPE, 1),
MAKE_VARIABLE (".False", & xFalse, INT_TYPE, 1),
MAKE_VARIABLE (".True", & xTrue, INT_TYPE, 1),
MAKE_VARIABLE (".Null_String", & xNull_String, STRING_TYPE, 1),
/*
MAKE_INTRINSIC (".", , _TYPE, 0),
MAKE_INTRINSIC (".function_name", c_function, TYPE, 0),
MAKE_VARIABLE (".", & , TYPE, ),
MAKE_VARIABLE (".var", &c_variable, TYPE, flag),
*/
SLANG_END_TABLE
};
/*}}}*/
/*{{{ init/deinit */
static int
slang_init (script *s, char *libdir)
{
char *fname;
if (! isinit) {
if ((! init_SLang ()) || (! init_SLmath ()) ||
(! init_SLunix ()) || (! init_SLfiles ()) ||
(! string_class ()) || (! SLang_add_table (avail, "yaps")))
return -1;
if (libdir && (fname = malloc (strlen (libdir) + sizeof (STARTUP) + 4))) {
sprintf (fname, "%s/%s", libdir, STARTUP);
if (access (fname, R_OK) != -1)
if ((! SLang_load_file (fname)) || SLang_Error)
SLang_restart (1);
free (fname);
}
isinit = True;
}
if (slline)
slline[0] = '\0';
return NO_ERR;
}
static void
slang_deinit (script *s)
{
if (slline) {
free (slline);
slline = NULL;
}
slsiz = 0;
}
/*}}}*/
/*{{{ execute */
static int
slang_execute (script *s, char *label, char *parm)
{
SLang_Name_Type *func;
int ret;
ret = NO_ERR;
if (func = SLang_get_function (label)) {
SLang_push_string (parm ? parm : "");
sldelay = s -> delay;
slexpire = s -> expire;
slrds = s -> rds;
sls = s;
SLexecute_function (func);
if (sls -> sp)
tty_set_line_callback (sls -> sp, NULL, NULL, NULL);
sls = NULL;
if (SLang_Error || SLang_pop_integer (& ret)) {
ret = ERR_FATAL;
SLang_restart (1);
}
}
return ret;
}
/*}}}*/
/*{{{ loading */
static int
slang_load_string (script *s, char *scr)
{
int err;
err = ERR_FATAL;
if (SLang_load_string (scr) && (! SLang_Error))
err = NO_ERR;
else
SLang_restart (1);
return err;
}
static int
slang_load_file (script *s, char *fname)
{
int err;
err = ERR_FATAL;
if (SLang_load_file (fname) && (! SLang_Error))
err = NO_ERR;
else
SLang_restart (1);
return err;
}
/*}}}*/
/*{{{ preinit/postdeinit/scriptentry */
static int
slang_preinit (char *libdir)
{
return slang_init (NULL, libdir);
}
static void
slang_postdeinit (void)
{
slang_deinit (NULL);
}
funcs fslang = {
"SLang",
slang_init,
slang_deinit,
slang_execute,
slang_load_string,
slang_load_file,
slang_preinit,
slang_postdeinit
};
/*}}}*/
# endif /* SCRIPT_SLANG */