/* -*- mode: c; mode: fold -*- */ # include "config.h" # ifdef SCRIPT_SLANG # ifndef FLOAT_TYPE # define FLOAT_TYPE # endif /* FLOAT_TYPE */ # include # include # include # include # include # 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 */