/* -*- mode: C; mode: fold; -*- */
/* Standard intrinsic functions for S-Lang. Included here are string
and array operations */
/* Copyright (c) 1992, 1995 John E. Davis
* All rights reserved.
*
* You may distribute under the terms of either the GNU General Public
* License or the Perl Artistic License.
*/
#include "config.h"
#include "sl-feat.h"
/*{{{ Include Files */
#include <stdio.h>
#include <time.h>
#ifndef __QNX__
# if defined(__GO32__) || defined(__WATCOMC__)
# include <dos.h>
# include <bios.h>
# endif
#endif
#include "slang.h"
#include "_slang.h"
#if SLANG_HAS_FLOAT
#include <math.h>
#endif
#include <string.h>
#include <stdarg.h>
/*}}}*/
/* builtin stack manipulation functions */
int SLdo_pop(void) /*{{{*/
{
return SLdo_pop_n (1);
}
/*}}}*/
int SLdo_pop_n (unsigned int n)
{
SLang_Object_Type x;
while (n--)
{
if (SLang_pop(&x)) return -1;
SLang_free_object (&x);
}
return 0;
}
static void do_dup(void) /*{{{*/
{
SLang_Class_Type *cl;
SLang_Object_Type x;
if (-1 == SLang_pop(&x)) return;
SLang_push(&x);
cl = _SLclass_get_class (x.data_type);
(*cl->cl_push) (x.data_type, (VOID_STAR) &x.v.p_val);
}
/*}}}*/
static char Utility_Char_Table [256];
static void set_utility_char_table (char *pos) /*{{{*/
{
register char *t = Utility_Char_Table, *tmax;
register unsigned char ch;
tmax = t + 256;
while (t < tmax) *t++ = 0;
t = Utility_Char_Table;
while ((ch = (unsigned char) *pos++) != 0) t[ch] = 1;
}
/*}}}*/
static void SLdo_strcat (char *a, char *b) /*{{{*/
{
char *c;
c = SLang_concat_slstrings (a, b);
if (c != NULL)
_SLang_push_slstring (c); /* frees upon error */
}
/*}}}*/
static int do_trim (char **beg, char **end, char *white) /*{{{*/
{
int len;
char *a, *b;
set_utility_char_table (white);
a = *beg;
len = strlen (a);
b = a + (len - 1);
while (Utility_Char_Table[(unsigned char) *a]) a++;
while ((b >= a) && (Utility_Char_Table[(unsigned char) *b])) b--;
b++;
len = (int) (b - a);
*beg = a;
*end = b;
return len;
}
/*}}}*/
static void SLdo_strtrim(void) /*{{{*/
{
char *a, *beg, *end;
/* Go through SLpop_string to get a private copy since it will be
* modified.
*/
if (SLpop_string(&a)) return;
beg = a;
(void) do_trim (&beg, &end, " \t\n");
/* Since a is a malloced string that will be freed, massage it.
*/
*end = 0;
SLang_push_string (beg);
SLfree (a);
}
/*}}}*/
static void SLdo_strcompress (void) /*{{{*/
{
char *str, *white, *c;
unsigned char *s, *beg, *end;
unsigned int len;
if (SLpop_string (&white)) return;
if (SLpop_string (&str))
{
SLfree (white);
return;
}
beg = (unsigned char *) str;
(void) do_trim ((char **) &beg, (char **) &end, white);
SLfree (white);
/* Determine the effective length */
len = 0;
s = (unsigned char *) beg;
while (s < end)
{
len++;
if (Utility_Char_Table[*s++])
{
while ((s < end) && Utility_Char_Table[*s]) s++;
}
}
if (NULL != (c = SLmalloc (len + 1)))
{
s = (unsigned char *) c;
while (beg < end)
{
*s++ = *beg;
if (Utility_Char_Table[*beg++])
{
while ((beg < end) && Utility_Char_Table[*beg]) beg++;
}
}
*s = 0;
SLang_push_malloced_string(c);
}
SLfree(str);
}
/*}}}*/
static int str_replace (char *orig, char *match, char *rep) /*{{{*/
{
char *s, *newstr;
int ret;
unsigned int rep_len, match_len, new_len;
new_len = strlen (orig);
if ((NULL != (s = strstr (orig, match)))
&& (NULL != (newstr = SLmake_nstring (orig, new_len))))
{
match_len = strlen (match);
rep_len = strlen (rep);
if (rep_len > match_len)
{
new_len += rep_len - match_len;
newstr = (char *) SLrealloc (newstr, new_len + 1);
/* SLrealloc will set SLang_Error upon failure. */
}
if (!SLang_Error)
{
char *s1 = newstr + (int) (s - orig);
strcpy (s1 + rep_len, s + match_len);
SLMEMCPY (s1, rep, rep_len);
SLang_push_malloced_string (newstr);
}
ret = 1;
}
else ret = 0;
return ret;
}
/*}}}*/
/* This routine returns the string with text removed between single character
comment delimiters from the set b and e. */
static void uncomment_string (char *str, char *b, char *e) /*{{{*/
{
unsigned char chb, che;
unsigned char *s, *cbeg, *mark;
if (strlen(b) != strlen(e))
{
SLang_doerror ("Comment delimiter length mismatch.");
return;
}
set_utility_char_table (b);
if (NULL == (str = (char *) SLmake_string(str))) return;
s = (unsigned char *) str;
while ((chb = *s++) != 0)
{
if (Utility_Char_Table [chb] == 0) continue;
mark = s - 1;
cbeg = (unsigned char *) b;
while (*cbeg != chb) cbeg++;
che = (unsigned char) *(e + (int) (cbeg - (unsigned char *) b));
while (((chb = *s++) != 0) && (chb != che));
if (chb == 0)
{
/* end of string and end not found. Just truncate it a return; */
*mark = 0;
break;
}
strcpy ((char *) mark, (char *)s);
s = mark;
}
SLang_push_malloced_string (str);
}
/*}}}*/
static void SLquote_string (char *str, char *quotes, int *slash_ptr) /*{{{*/
{
char *q;
int slash;
unsigned int len;
register char *t, *s, *q1;
register unsigned char ch;
slash = *slash_ptr;
if ((slash > 255) || (slash < 0))
{
SLang_Error = SL_INVALID_PARM;
return;
}
/* setup the utility table to have 1s at quote char postitions. */
set_utility_char_table (quotes);
t = Utility_Char_Table;
t[(unsigned int) slash] = 1;
/* calculate length */
s = str;
len = 0;
while ((ch = (unsigned char) *s++) != 0) if (t[ch]) len++;
len += (unsigned int) (s - str);
if (NULL != (q = SLmalloc(len)))
{
s = str; q1 = q;
while ((ch = (unsigned char) *s++) != 0)
{
if (t[ch]) *q1++ = slash;
*q1++ = (char) ch;
}
*q1 = 0;
SLang_push_malloced_string(q);
}
}
/*}}}*/
/* returns the position of substrin in a string or null */
static int intrin_issubstr (char *a, char *b) /*{{{*/
{
char *c;
if (NULL == (c = (char *) strstr(a, b)))
return 0;
return 1 + (int) (c - a);
}
/*}}}*/
/* returns to stack string at pos n to n + m of a */
static void SLdo_substr (char *a, int *n_ptr, int *m_ptr) /*{{{*/
{
char *b;
int n, m;
int lena;
n = *n_ptr;
m = *m_ptr;
lena = strlen (a);
if (n > lena) n = lena + 1;
if (n < 1)
{
SLang_Error = SL_INVALID_PARM;
return;
}
n--;
if (m < 0) m = lena;
if (n + m > lena) m = lena - n;
b = SLang_create_nslstring (a + n, (unsigned int) m);
if (b != NULL)
_SLang_push_slstring (b);
}
/*}}}*/
/* substitute char m at positin string n in string*/
static void SLdo_strsub (int *nptr, int *mptr) /*{{{*/
{
char *a;
int n, m;
unsigned int lena;
if (-1 == SLpop_string (&a))
return;
n = *nptr;
m = *mptr;
lena = strlen (a);
if ((n <= 0) || (lena < (unsigned int) n))
{
SLang_Error = SL_INVALID_PARM;
SLfree(a);
return;
}
a[n - 1] = (char) m;
SLang_push_malloced_string (a);
}
/*}}}*/
static void SLdo_strup(void) /*{{{*/
{
unsigned char c, *a;
char *str;
if (SLpop_string (&str))
return;
a = (unsigned char *) str;
while ((c = *a) != 0)
{
/* if ((*a >= 'a') && (*a <= 'z')) *a -= 32; */
*a = UPPER_CASE(c);
a++;
}
SLang_push_malloced_string (str);
}
/*}}}*/
static int do_upper (int *ch) /*{{{*/
{
return UPPER_CASE(*ch);
}
/*}}}*/
static int do_lower (int *ch) /*{{{*/
{
return LOWER_CASE(*ch);
}
/*}}}*/
static void SLdo_strlow (void) /*{{{*/
{
unsigned char c, *a;
char *str;
if (SLpop_string(&str)) return;
a = (unsigned char *) str;
while ((c = *a) != 0)
{
/* if ((*a >= 'a') && (*a <= 'z')) *a -= 32; */
*a = LOWER_CASE(c);
a++;
}
SLang_push_malloced_string ((char *) str);
}
/*}}}*/
static int do_strchop (char *str, int *delim_ptr, int *quote_ptr) /*{{{*/
{
int delim, quote, count;
char *s0, *elm;
register char *s1;
register unsigned char ch;
int quoted;
quote = *quote_ptr;
delim = *delim_ptr;
if ((quote < 0) || (quote > 255)
|| (delim <= 0) || (delim > 255))
{
SLang_Error = SL_TYPE_MISMATCH;
return 0;
}
s1 = s0 = str;
quoted = 0;
count = 0;
while (1)
{
ch = (unsigned char) *s1;
if ((ch == quote) && quote)
{
s1++;
quoted = 1;
if (*s1 != 0) s1++;
}
else if ((ch == delim) || (ch == 0))
{
if (NULL == (elm = SLmake_nstring (s0, (unsigned int)(s1 - s0))))
break;
/* Now unquote it */
if (quoted)
{
register char ch1, *p, *p1;
p = p1 = elm;
do
{
ch1 = *p1++;
if (ch1 == '\\') ch1 = *p1++;
*p++ = ch1;
}
while (ch1 != 0);
quoted = 0;
}
SLang_push_malloced_string (elm);
if (SLang_Error) break;
count++;
if (ch == 0) break;
s1++; /* skip past delim */
s0 = s1; /* and reset */
}
else s1++;
}
if (SLang_Error)
{
while (count != 0)
{
count--;
SLdo_pop ();
}
count = 0;
}
return count;
}
/*}}}*/
static int do_strchopr (char *str, int *q, int *d) /*{{{*/
{
int count;
count = do_strchop (str, q, d);
if (count <= 0) return count;
_SLreverse_stack (count);
return count;
}
/*}}}*/
static int intrin_strcmp (char *a, char *b) /*{{{*/
{
return strcmp(a, b);
}
/*}}}*/
static int intrin_strncmp (char *a, char *b, int *n) /*{{{*/
{
return strncmp(a, b, (unsigned int) *n);
}
/*}}}*/
static int intrin_strlen (char *s) /*{{{*/
{
return (int) strlen (s);
}
/*}}}*/
static int intrin_isdigit (char *what) /*{{{*/
{
return ((*what >= '0') && (*what <= '9'));
}
/*}}}*/
/* convert integer to a string of length 1 */
static void SLdo_char (int *x) /*{{{*/
{
char ch, buf[2];
ch = (char) *x;
buf[0] = ch;
buf[1] = 0;
SLang_push_string (buf);
}
/*}}}*/
/* format object into a string and returns slstring */
char *_SLstringize_object (SLang_Object_Type *obj) /*{{{*/
{
SLang_Class_Type *cl;
unsigned char stype;
VOID_STAR p;
char *s, *s1;
stype = obj->data_type;
p = (VOID_STAR) &obj->v.p_val;
cl = _SLclass_get_class (stype);
s = (*cl->cl_string) (stype, p);
if (s != NULL)
{
s1 = SLang_create_slstring (s);
SLfree (s);
s = s1;
}
return s;
}
/*}}}*/
int SLang_run_hooks(char *hook, unsigned int num_args, ...)
{
unsigned int i;
va_list ap;
if (SLang_Error) return -1;
if (0 == SLang_is_defined (hook))
return 0;
(void) SLang_start_arg_list ();
va_start (ap, num_args);
for (i = 0; i < num_args; i++)
{
char *arg;
arg = va_arg (ap, char *);
if (-1 == SLang_push_string (arg))
break;
}
va_end (ap);
(void) SLang_end_arg_list ();
if (SLang_Error) return -1;
return SLang_execute_function (hook);
}
static void intrin_getenv_cmd (char *s)
{
SLang_push_string (getenv (s));
}
static void intrin_extract_element (char *list, int *nth_ptr, int *delim_ptr)
{
char buf[1024], *b;
b = buf;
if (-1 == SLextract_list_element (list, *nth_ptr, *delim_ptr, buf, sizeof(buf)))
b = NULL;
SLang_push_string (b);
}
#ifdef HAVE_PUTENV
static void intrin_putenv (void) /*{{{*/
{
char *s;
/* Some putenv implementations required malloced strings. */
if (SLpop_string(&s)) return;
if (putenv (s))
{
SLang_Error = SL_INTRINSIC_ERROR;
SLfree (s);
}
/* Note that s is NOT freed */
}
/*}}}*/
#endif
static void lang_print_stack (void) /*{{{*/
{
SLang_Object_Type *x = _SLStack_Pointer;
char buf[32];
while (--x >= _SLRun_Stack)
{
sprintf (buf, "(%d)", (int)(x - _SLRun_Stack));
_SLdump_objects (buf, x, 1, 1);
}
}
/*}}}*/
/* sprintf functionality for S-Lang */
static char *SLdo_sprintf (char *fmt) /*{{{*/
{
register char *p = fmt, ch;
char *out = NULL, *outp = NULL;
char dfmt[80]; /* used to hold part of format */
char *f;
VOID_STAR varp;
int var, want_width, width, precis, use_varp;
unsigned int len = 0, malloc_len = 0, dlen;
int do_free, guess_size;
#if SLANG_HAS_FLOAT
int tmp1, tmp2, use_double;
double x;
#endif
while (1)
{
while ((ch = *p) != 0)
{
if (ch == '%')
break;
p++;
}
/* p points at '%' or 0 */
dlen = (unsigned int) (p - fmt);
if (len + dlen >= malloc_len)
{
malloc_len = len + dlen;
if (out == NULL) outp = SLmalloc(malloc_len + 1);
else outp = SLrealloc(out, malloc_len + 1);
if (NULL == outp)
return out;
out = outp;
outp = out + len;
}
strncpy(outp, fmt, dlen);
len += dlen;
outp = out + len;
*outp = 0;
if (ch == 0) break;
/* bump it beyond '%' */
++p;
fmt = p;
f = dfmt;
*f++ = ch;
/* handle flag char */
ch = *p++;
if ((ch == '-') || (ch == '+') || (ch == ' ') || (ch == '#'))
{
*f++ = ch;
ch = *p++;
}
/* width */
/* I have got to parse it myself so that I can see how big it needs
to be. */
want_width = width = 0;
if (ch == '*')
{
if (SLang_pop_integer(&width)) return (out);
want_width = 1;
ch = *p++;
}
else
{
if (ch == '0')
{
*f++ = '0';
ch = *p++;
}
while ((ch <= '9') && (ch >= '0'))
{
width = width * 10 + (ch - '0');
ch = *p++;
want_width = 1;
}
}
if (want_width)
{
sprintf(f, "%d", width);
while (*f) f++;
}
precis = 0;
/* precision -- also indicates max number of chars from string */
if (ch == '.')
{
*f++ = ch;
ch = *p++;
want_width = 0;
if (ch == '*')
{
if (SLang_pop_integer(&precis)) return (out);
ch = *p++;
want_width = 1;
}
else while ((ch <= '9') && (ch >= '0'))
{
precis = precis * 10 + (ch - '0');
ch = *p++;
want_width = 1;
}
if (want_width)
{
sprintf(f, "%d", precis);
while (*f) f++;
}
else precis = 0;
}
/* not supported */
if ((ch == 'l') || (ch == 'h')) ch = *p++;
var = 0;
varp = NULL;
guess_size = 32;
#if SLANG_HAS_FLOAT
use_double = 0;
#endif
use_varp = 0;
do_free = 0;
/* Now the actual format specifier */
switch (ch)
{
case 's':
if (SLang_pop_slstring((char **) &varp)) return (out);
do_free = 1;
guess_size = strlen((char *) varp);
use_varp = 1;
break;
#if 1
case '%':
guess_size = 1;
do_free = 0;
use_varp = 1;
varp = (VOID_STAR) "%";
break;
#endif
case 'c': guess_size = 1;
/* drop */
case 'd':
case 'i':
case 'o':
case 'u':
case 'X':
case 'x':
if (SLang_pop_integer(&var)) return(out);
break;
case 'f':
case 'e':
case 'g':
case 'E':
case 'G':
#if SLANG_HAS_FLOAT
if (SLang_pop_double(&x, &tmp1, &tmp2)) return (out);
use_double = 1;
guess_size = 64;
(void) tmp1; (void) tmp2;
break;
#endif
case 'p':
guess_size = 32;
/* Pointer type?? Why?? */
if (-1 == SLdo_pop ())
return out;
varp = (VOID_STAR) _SLStack_Pointer;
use_varp = 1;
break;
default:
SLang_doerror("Invalid Format.");
return(out);
}
*f++ = ch; *f = 0;
width = width + precis;
if (width > guess_size) guess_size = width;
if (len + guess_size > malloc_len)
{
outp = (char *) SLrealloc(out, len + guess_size + 1);
if (outp == NULL)
{
SLang_Error = SL_MALLOC_ERROR;
return (out);
}
out = outp;
outp = out + len;
malloc_len = len + guess_size;
}
if (use_varp)
{
sprintf(outp, dfmt, varp);
if (do_free) SLang_free_slstring ((char *)varp);
}
#if SLANG_HAS_FLOAT
else if (use_double) sprintf(outp, dfmt, x);
#endif
else sprintf(outp, dfmt, var);
len += strlen(outp);
outp = out + len;
fmt = p;
}
if (out != NULL)
{
outp = SLrealloc (out, (unsigned int) (outp - out) + 1);
if (outp != NULL) out = outp;
}
return (out);
}
/*}}}*/
static int do_sprintf_n (int n) /*{{{*/
{
char *p;
char *fmt;
SLang_Object_Type *ptr;
int ofs;
if (-1 == (ofs = _SLreverse_stack (n + 1)))
return -1;
ptr = _SLRun_Stack + ofs;
if (SLang_pop_slstring(&fmt))
return -1;
p = SLdo_sprintf (fmt);
SLang_free_slstring (fmt);
while (_SLStack_Pointer > ptr)
SLdo_pop ();
if (SLang_Error
|| (-1 == SLang_push_malloced_string (p)))
{
SLfree(p);
return -1;
}
return 0;
}
/*}}}*/
static void intrin_sprintf (void)
{
do_sprintf_n (SLang_Num_Function_Args - 1); /* do not include format */
}
/* converts string s to a form that can be used in an eval */
static void make_printable_string(char *s) /*{{{*/
{
unsigned int len;
register char *s1 = s, ch, *ss1;
char *ss;
/* compute length */
len = 3;
while ((ch = *s1++) != 0)
{
if ((ch == '\n') || (ch == '\\') || (ch == '"')) len++;
len++;
}
if (NULL == (ss = SLmalloc(len)))
return;
s1 = s;
ss1 = ss;
*ss1++ = '"';
while ((ch = *s1++) != 0)
{
if (ch == '\n')
{
ch = 'n';
*ss1++ = '\\';
}
else if ((ch == '\\') || (ch == '"'))
{
*ss1++ = '\\';
}
*ss1++ = ch;
}
*ss1++ = '"';
*ss1 = 0;
if (-1 == SLang_push_string (ss))
SLfree (ss);
}
/*}}}*/
static int intrin_is_list_element (char *list, char *elem, int *d_ptr)
{
char ch;
int d, n;
unsigned int len;
char *lbeg, *lend;
d = *d_ptr;
len = strlen (elem);
n = 1;
lend = list;
while (1)
{
lbeg = lend;
while ((0 != (ch = *lend)) && (ch != (char) d)) lend++;
if ((lbeg + len == lend)
&& (0 == strncmp (elem, lbeg, len)))
break;
if (ch == 0)
{
n = 0;
break;
}
lend++; /* skip delim */
n++;
}
return n;
}
/*}}}*/
/* Regular expression routines for strings */
static SLRegexp_Type regexp_reg;
static int intrin_string_match (char *str, char *pat, int *nptr) /*{{{*/
{
int n;
unsigned int len;
unsigned char rbuf[512], *match;
n = *nptr;
regexp_reg.case_sensitive = 1;
regexp_reg.buf = rbuf;
regexp_reg.pat = (unsigned char *) pat;
regexp_reg.buf_len = sizeof (rbuf);
if (SLang_regexp_compile (®exp_reg))
{
SLang_verror (SL_INVALID_PARM, "Unable to compile pattern");
return -1;
}
n--;
len = strlen(str);
if ((n < 0) || ((unsigned int) n >= len))
{
/* SLang_Error = SL_INVALID_PARM; */
return 0;
}
str += n;
len -= n;
if (NULL == (match = SLang_regexp_match((unsigned char *) str, len, ®exp_reg)))
return 0;
/* adjust offsets */
regexp_reg.offset = n;
return (1 + (int) ((char *) match - str));
}
/*}}}*/
static int intrin_string_match_nth (int *nptr) /*{{{*/
{
int n, beg;
n = *nptr;
if ((n < 0) || (n > 9) || (regexp_reg.pat == NULL)
|| ((beg = regexp_reg.beg_matches[n]) == -1))
{
SLang_Error = SL_INVALID_PARM;
return -1;
}
SLang_push_integer(beg + regexp_reg.offset);
return regexp_reg.end_matches[n];
}
/*}}}*/
#include <time.h>
#if defined(__GO32__)
static char *djgpp_current_time (void) /*{{{*/
{
union REGS rg;
unsigned int year;
unsigned char month, day, weekday, hour, minute, sec;
char days[] = "SunMonTueWedThuFriSat";
char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char the_date[26];
rg.h.ah = 0x2A;
#ifndef __WATCOMC__
int86(0x21, &rg, &rg);
year = rg.x.cx & 0xFFFF;
#else
int386(0x21, &rg, &rg);
year = rg.x.ecx & 0xFFFF;
#endif
month = 3 * (rg.h.dh - 1);
day = rg.h.dl;
weekday = 3 * rg.h.al;
rg.h.ah = 0x2C;
#ifndef __WATCOMC__
int86(0x21, &rg, &rg);
#else
int386(0x21, &rg, &rg);
#endif
hour = rg.h.ch;
minute = rg.h.cl;
sec = rg.h.dh;
/* we want this form: Thu Apr 14 15:43:39 1994\n */
sprintf(the_date, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
days + weekday, months + month,
day, hour, minute, sec, year);
return the_date;
}
/*}}}*/
#endif
char *SLcurrent_time_string (void) /*{{{*/
{
char *the_time;
#ifndef __GO32__
time_t myclock;
myclock = time((time_t *) 0);
the_time = (char *) ctime(&myclock);
#else
the_time = djgpp_current_time ();
#endif
/* returns the form Sun Sep 16 01:03:52 1985\n\0 */
the_time[24] = '\0';
return(the_time);
}
/*}}}*/
static void byte_compile_file (char *f, int *m)
{
SLang_byte_compile_file (f, *m);
}
static void intrin_type_info (void)
{
SLang_Object_Type obj;
if (-1 == SLang_pop (&obj))
return;
_SLang_push_datatype (obj.data_type);
SLang_free_object (&obj);
}
static void intrin_string(void) /*{{{*/
{
SLang_Object_Type x;
char *s;
if (SLang_pop (&x)) return;
if (NULL != (s = _SLstringize_object (&x)))
_SLang_push_slstring (s);
SLang_free_object (&x);
}
/*}}}*/
static void intrin_typecast (void)
{
unsigned char to_type;
if (0 == _SLang_pop_datatype (&to_type))
(void) _SLclass_typecast (to_type, 0, 1);
}
#if SLANG_HAS_FLOAT
static void intrin_double (void)
{
(void) _SLclass_typecast (SLANG_DOUBLE_TYPE, 0, 1);
}
#ifndef HAVE_STDLIB_H
/* Oh dear. Where is the prototype for atof? If not in stdlib, then
* I do not know where. Not in math.h onsome systems either.
*/
extern double atof ();
#endif
static double intrin_atof (char *s)
{
return atof (s);
}
#endif
static void intrin_int (void) /*{{{*/
{
(void) _SLclass_typecast (SLANG_INT_TYPE, 0, 1);
}
/*}}}*/
static char *
intrin_function_name (void)
{
if (NULL == _SLang_Current_Function_Name)
return "";
return _SLang_Current_Function_Name;
}
static void intrin_message (char *s)
{
SLang_vmessage ("%s", s);
}
static void intrin_error (char *s)
{
SLang_verror (SL_USER_ERROR, "%s", s);
}
static void intrin_pop_n (int *n)
{
SLdo_pop_n ((unsigned int) *n);
}
static void intrin_reverse_stack (int *n)
{
_SLreverse_stack (*n);
}
static void intrin_sprintf_n (int *n)
{
do_sprintf_n (*n);
}
static void intrin_roll_stack (int *n)
{
_SLroll_stack (*n);
}
/* Convert string to integer */
static int intrin_integer (char *s)
{
int i;
i = SLatoi ((unsigned char *) s);
if (SLang_Error)
SLang_verror (SL_TYPE_MISMATCH, "Unable to convert string to integer");
return i;
}
/*}}}*/
static void guess_type (char *s)
{
_SLang_push_datatype (SLang_guess_type(s));
}
static int load_file (char *s)
{
if (-1 == SLang_load_file (s))
return 0;
return 1;
}
static void get_doc_string (char *file, char *topic)
{
FILE *fp;
char line[1024];
unsigned int topic_len, str_len;
char *str;
char ch;
if (NULL == (fp = fopen (file, "r")))
{
_SLang_push_null ();
return;
}
topic_len = strlen (topic);
ch = *topic;
while (1)
{
if (NULL == fgets (line, sizeof(line), fp))
{
fclose (fp);
(void) _SLang_push_null ();
return;
}
if ((ch == *line)
&& (0 == strncmp (line, topic, topic_len))
&& ((line[topic_len] == '\n') || (line [topic_len] == 0)
|| (line[topic_len] == ' ') || (line[topic_len] == '\t')))
break;
}
if (NULL == (str = SLmake_string (line)))
{
fclose (fp);
(void) _SLang_push_null ();
return;
}
str_len = strlen (str);
while (NULL != fgets (line, sizeof (line), fp))
{
unsigned int len;
char *new_str;
ch = *line;
if (ch == '#') continue;
if (ch == '-') break;
len = strlen (line);
if (NULL == (new_str = SLrealloc (str, str_len + len + 1)))
{
SLfree (str);
str = NULL;
break;
}
str = new_str;
strcpy (str + str_len, line);
str_len += len;
}
fclose (fp);
if (-1 == SLang_push_malloced_string (str))
SLfree (str);
}
static int intrin_apropos (char *s, int *what)
{
return _SLang_apropos (s, (unsigned int) *what);
}
static void intrin_create_delimited_string (int *nptr)
{
unsigned int n, i, delim_len;
char **strings;
unsigned int len;
char *delim, *str;
str = NULL;
n = 1 + (unsigned int) *nptr; /* n includes delimiter */
if (NULL == (strings = (char **)SLmalloc (n * sizeof (char *))))
{
SLdo_pop_n (n);
return;
}
SLMEMSET((char *)strings, 0, n * sizeof (char *));
i = n;
while (i != 0)
{
i--;
if (-1 == SLang_pop_slstring (strings + i))
goto return_error;
}
len = 1; /* for \0 */
for (i = 1; i < n; i++)
len += strlen (strings[i]);
delim = strings[0];
delim_len = strlen (delim);
if (n > 1)
len += (n - 1) * delim_len;
if (NULL == (str = SLmalloc (len)))
goto return_error;
*str = 0;
if (n > 1)
{
char *s = str;
unsigned int n1 = n - 1;
for (i = 1; i < n1; i++)
{
strcpy (s, strings[i]);
s += strlen (strings[i]);
strcpy (s, delim);
s += delim_len;
}
strcpy (s, strings[n1]);
}
/* drop */
return_error:
for (i = 0; i < n; i++) SLang_free_slstring (strings[i]);
SLfree ((char *)strings);
if (str != NULL)
{
/* Means no error */
if (-1 == SLang_push_malloced_string (str))
SLfree (str);
}
}
static SLang_Intrin_Fun_Type SLang_Basic_Table [] = /*{{{*/
{
MAKE_INTRINSIC_I("create_delimited_string", intrin_create_delimited_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SS("get_doc_string_from_file", get_doc_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SS("autoload", SLang_autoload, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SS("strcmp", intrin_strcmp, SLANG_INT_TYPE),
MAKE_INTRINSIC_SSI("strncmp", intrin_strncmp, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("strcat", SLdo_strcat, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("strlen", intrin_strlen, SLANG_INT_TYPE),
MAKE_INTRINSIC_SII("strchop", do_strchop, SLANG_INT_TYPE),
MAKE_INTRINSIC_SII("strchopr", do_strchopr, SLANG_INT_TYPE),
MAKE_INTRINSIC_SSS("str_replace", str_replace, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("is_defined", SLang_is_defined, SLANG_INT_TYPE),
MAKE_INTRINSIC("string", intrin_string, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_S("getenv", intrin_getenv_cmd, SLANG_VOID_TYPE),
#ifdef HAVE_PUTENV
MAKE_INTRINSIC("putenv", intrin_putenv, SLANG_VOID_TYPE, 0),
#endif
MAKE_INTRINSIC_S("evalfile", load_file, SLANG_INT_TYPE),
MAKE_INTRINSIC_1("char", SLdo_char, SLANG_VOID_TYPE, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("eval", SLang_load_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC("dup", do_dup, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_SII("substr", SLdo_substr, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("integer", intrin_integer, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("is_substr", intrin_issubstr, SLANG_INT_TYPE),
MAKE_INTRINSIC_II("strsub", SLdo_strsub, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SII("extract_element", intrin_extract_element, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SSI("is_list_element", intrin_is_list_element, SLANG_INT_TYPE),
MAKE_INTRINSIC_SSI("string_match", intrin_string_match, SLANG_INT_TYPE),
MAKE_INTRINSIC_I("string_match_nth", intrin_string_match_nth, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("system", SLsystem, SLANG_INT_TYPE),
MAKE_INTRINSIC_SI("_apropos", intrin_apropos, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("_trace_function", _SLang_trace_fun, SLANG_VOID_TYPE),
MAKE_INTRINSIC("strlow", SLdo_strlow, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_I("tolower", do_lower, SLANG_INT_TYPE),
MAKE_INTRINSIC_I("toupper", do_upper, SLANG_INT_TYPE),
MAKE_INTRINSIC("strup", SLdo_strup, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_S("isdigit", intrin_isdigit, SLANG_INT_TYPE),
MAKE_INTRINSIC("strtrim", SLdo_strtrim, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC("strcompress", SLdo_strcompress, SLANG_VOID_TYPE, 0),
#if SLANG_HAS_FLOAT
MAKE_INTRINSIC_S("atof", intrin_atof, SLANG_DOUBLE_TYPE),
MAKE_INTRINSIC("double", intrin_double, SLANG_VOID_TYPE, 0),
#endif
MAKE_INTRINSIC("int", intrin_int, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC("typecast", intrin_typecast, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC("_stkdepth", _SLstack_depth, SLANG_INT_TYPE, 0),
MAKE_INTRINSIC_I("_stk_reverse", intrin_reverse_stack, SLANG_VOID_TYPE),
MAKE_INTRINSIC("typeof", intrin_type_info, VOID_TYPE, 0),
MAKE_INTRINSIC_I("_pop_n", intrin_pop_n, SLANG_VOID_TYPE),
MAKE_INTRINSIC("_print_stack", lang_print_stack, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_I("_stk_roll", intrin_roll_stack, SLANG_VOID_TYPE),
MAKE_INTRINSIC_I("Sprintf", intrin_sprintf_n, SLANG_VOID_TYPE),
MAKE_INTRINSIC("sprintf", intrin_sprintf, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC_SI("byte_compile_file", byte_compile_file, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("make_printable_string", make_printable_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SSI("str_quote_string", SLquote_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SSS("str_uncomment_string", uncomment_string, SLANG_VOID_TYPE),
MAKE_INTRINSIC_II("define_case", SLang_define_case, SLANG_VOID_TYPE),
MAKE_INTRINSIC("_clear_error", _SLang_clear_error, SLANG_VOID_TYPE, 0),
MAKE_INTRINSIC("_function_name", intrin_function_name, SLANG_STRING_TYPE, 0),
#if SLANG_HAS_FLOAT
MAKE_INTRINSIC_S("set_float_format", _SLset_double_format, SLANG_VOID_TYPE),
#endif
MAKE_INTRINSIC_S("_slang_guess_type", guess_type, SLANG_VOID_TYPE),
MAKE_INTRINSIC("time", SLcurrent_time_string, SLANG_STRING_TYPE, 0),
MAKE_INTRINSIC_S("error", intrin_error, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("message", intrin_message, SLANG_VOID_TYPE),
SLANG_END_TABLE
};
/*}}}*/
static SLang_Intrin_Var_Type Intrin_Vars[] =
{
MAKE_VARIABLE("_debug_info", &_SLang_Compile_Line_Num_Info, SLANG_INT_TYPE, 0),
MAKE_VARIABLE("_traceback", &SLang_Traceback, SLANG_INT_TYPE, 0),
MAKE_VARIABLE("_slangtrace", &_SLang_Trace, SLANG_INT_TYPE, 0),
MAKE_VARIABLE("_slang_version", &SLang_Version, SLANG_INT_TYPE, 1),
MAKE_VARIABLE("_NARGS", &SLang_Num_Function_Args, SLANG_INT_TYPE, 1),
MAKE_VARIABLE("NULL", NULL, SLANG_NULL_TYPE, 1),
SLANG_END_TABLE
};
int SLang_init_slang (void) /*{{{*/
{
char name[3];
unsigned int i;
char **s;
static char *sys_defines [] =
{
#if defined(__os2__)
"OS2",
#endif
#if defined(__MSDOS__)
"MSDOS",
#endif
#if defined (__WIN32__)
"WIN32",
#endif
#if defined(__NT__)
"NT",
#endif
#if defined (VMS)
"VMS",
#endif
#ifdef REAL_UNIX_SYSTEM
"UNIX",
#endif
#if SLANG_HAS_FLOAT
"SLANG_DOUBLE_TYPE",
#endif
NULL
};
if (-1 == _SLregister_types ()) return -1;
if ((-1 == SLadd_intrin_fun_table(SLang_Basic_Table, NULL))
|| (-1 == SLadd_intrin_var_table (Intrin_Vars, NULL))
|| (-1 == _SLstruct_init ())
#if SLANG_HAS_COMPLEX
|| (-1 == _SLinit_slcomplex ())
#endif
)
return -1;
SLadd_global_variable (SLANG_SYSTEM_NAME);
s = sys_defines;
while (*s != NULL)
{
if (-1 == SLdefine_for_ifdef (*s)) return -1;
s++;
}
/* give temp global variables $0 --> $9 */
name[2] = 0; name[0] = '$';
for (i = 0; i < 10; i++)
{
name[1] = (char) (i + '0');
SLadd_global_variable (name);
}
SLang_init_case_tables ();
/* Now add a couple of macros */
SLang_load_string (".(_NARGS 1 - Sprintf error)verror");
SLang_load_string (".(_NARGS 1 - Sprintf message)vmessage");
if (SLang_Error)
return -1;
return 0;
}
/*}}}*/