# ifndef FUNCDEF
# define INCLUDE_CTYPE
# include "kfun.h"
# include "parse.h"
# endif
# ifdef FUNCDEF
FUNCDEF("crypt", kf_crypt, pt_crypt)
# else
char pt_crypt[] = { C_TYPECHECKED | C_STATIC | C_VARARGS, T_STRING, 2,
T_STRING, T_STRING };
/*
* NAME: kfun->crypt()
* DESCRIPTION: encrypt a string
*/
int kf_crypt(f, nargs)
register frame *f;
int nargs;
{
static char salts[] =
"0123456789./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char salt[3], *p;
if (nargs == 0) {
return -1;
}
if (nargs == 2 && f->sp->u.string->len >= 2) {
/* fixed salt */
salt[0] = f->sp->u.string->text[0];
salt[1] = f->sp->u.string->text[1];
} else {
/* random salt */
salt[0] = salts[P_random() % 64];
salt[1] = salts[P_random() % 64];
}
salt[2] = '\0';
if (nargs == 2) {
str_del((f->sp++)->u.string);
}
i_add_ticks(f, 400);
p = P_crypt(f->sp->u.string->text, salt);
str_del(f->sp->u.string);
str_ref(f->sp->u.string = str_new(p, (long) strlen(p)));
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("ctime", kf_ctime, pt_ctime)
# else
char pt_ctime[] = { C_TYPECHECKED | C_STATIC, T_STRING, 1, T_INT };
/*
* NAME: kfun->ctime()
* DESCRIPTION: convert a time value to a string
*/
int kf_ctime(f)
frame *f;
{
i_add_ticks(f, 5);
f->sp->type = T_STRING;
str_ref(f->sp->u.string = str_new(P_ctime((Uint) f->sp->u.number), 24L));
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("explode", kf_explode, pt_explode)
# else
char pt_explode[] = { C_TYPECHECKED | C_STATIC, T_STRING | (1 << REFSHIFT), 2,
T_STRING, T_STRING };
/*
* NAME: kfun->explode()
* DESCRIPTION: explode a string
*/
int kf_explode(f)
register frame *f;
{
register unsigned int len, slen, size;
register char *p, *s;
register value *v;
array *a;
p = f->sp[1].u.string->text;
len = f->sp[1].u.string->len;
s = f->sp->u.string->text;
slen = f->sp->u.string->len;
if (len == 0) {
/*
* exploding "" always gives an empty array
*/
a = arr_new(f->data, 0L);
} else if (slen == 0) {
/*
* the sepatator is ""; split string into single characters
*/
a = arr_new(f->data, (long) len);
for (v = a->elts; len > 0; v++, --len) {
v->type = T_STRING;
str_ref(v->u.string = str_new(p, 1L));
p++;
}
} else {
/*
* split up the string with the separator
*/
size = 1;
if (len >= slen && memcmp(p, s, slen) == 0) {
/* skip leading separator */
p += slen;
len -= slen;
}
while (len > slen) {
if (memcmp(p, s, slen) == 0) {
/* separator found */
p += slen;
len -= slen;
size++;
} else {
/* next char */
p++;
--len;
}
}
a = arr_new(f->data, (long) size);
v = a->elts;
p = f->sp[1].u.string->text;
len = f->sp[1].u.string->len;
size = 0;
if (len > slen && memcmp(p, s, slen) == 0) {
/* skip leading separator */
p += slen;
len -= slen;
}
while (len > slen) {
if (memcmp(p, s, slen) == 0) {
/* separator found */
v->type = T_STRING;
str_ref(v->u.string = str_new(p - size, (long) size));
v++;
p += slen;
len -= slen;
size = 0;
} else {
/* next char */
p++;
--len;
size++;
}
}
if (len != slen || memcmp(p, s, slen) != 0) {
/* remainder isn't a sepatator */
size += len;
p += len;
}
/* final array element */
v->type = T_STRING;
str_ref(v->u.string = str_new(p - size, (long) size));
}
str_del((f->sp++)->u.string);
str_del(f->sp->u.string);
f->sp->type = T_ARRAY;
arr_ref(f->sp->u.array = a);
i_add_ticks(f, (Int) 2 * a->size);
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("implode", kf_implode, pt_implode)
# else
char pt_implode[] = { C_TYPECHECKED | C_STATIC, T_STRING, 2,
T_STRING | (1 << REFSHIFT), T_STRING };
/*
* NAME: kfun->implode()
* DESCRIPTION: implode an array
*/
int kf_implode(f)
register frame *f;
{
register long len;
register unsigned int i, slen;
register char *p, *s;
register value *v;
string *str;
s = f->sp->u.string->text;
slen = f->sp->u.string->len;
/* first, determine the size of the imploded string */
i = f->sp[1].u.array->size;
i_add_ticks(f, i);
if (i != 0) {
len = (i - 1) * (long) slen; /* size of all separators */
for (v = d_get_elts(f->sp[1].u.array); i > 0; v++, --i) {
if (v->type != T_STRING) {
/* not a (string *) */
return 1;
}
len += v->u.string->len;
}
str = str_new((char *) NULL, len);
/* create the imploded string */
p = str->text;
for (i = f->sp[1].u.array->size, v -= i; i > 1; --i, v++) {
/* copy array part */
memcpy(p, v->u.string->text, v->u.string->len);
p += v->u.string->len;
/* copy separator */
memcpy(p, s, slen);
p += slen;
}
/* copy final array part */
memcpy(p, v->u.string->text, v->u.string->len);
} else {
/* zero size array gives zero size string */
str = str_new((char *) NULL, 0L);
}
str_del((f->sp++)->u.string);
arr_del(f->sp->u.array);
f->sp->type = T_STRING;
str_ref(f->sp->u.string = str);
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("random", kf_random, pt_random)
# else
char pt_random[] = { C_TYPECHECKED | C_STATIC, T_INT, 1, T_INT };
/*
* NAME: kfun->random()
* DESCRIPTION: return a random number
*/
int kf_random(f)
register frame *f;
{
i_add_ticks(f, 1);
f->sp->u.number = (f->sp->u.number > 0) ? P_random() % f->sp->u.number : 0;
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("sscanf", kf_sscanf, pt_sscanf)
# else
char pt_sscanf[] = { C_TYPECHECKED | C_STATIC | C_VARARGS, T_INT, 3,
T_STRING, T_STRING, T_LVALUE | T_ELLIPSIS };
/*
* NAME: match
* DESCRIPTION: match a string possibly including %%, up to the next %[sdfc] or
* the end of the string
*/
static bool match(f, s, flenp, slenp)
register char *f, *s;
unsigned int *flenp, *slenp;
{
register char *p;
register unsigned int flen, slen;
flen = *flenp;
slen = *slenp;
while (flen > 0) {
/* look for first % */
p = (char *) memchr(f, '%', flen);
if (p == (char *) NULL) {
/* no remaining % */
if (memcmp(f, s, flen) == 0) {
*slenp -= slen - flen;
return TRUE;
} else {
return FALSE; /* no match */
}
}
if (p[1] == '%') {
/* %% */
if (memcmp(f, s, ++p - f) == 0) {
/* matched up to and including the first % */
s += p - f;
slen -= p - f;
flen -= ++p - f;
f = p;
} else {
return FALSE; /* no match */
}
} else if (memcmp(f, s, p - f) == 0) {
/* matched up to the first % */
*flenp -= flen - (p - f);
*slenp -= slen - (p - f);
return TRUE;
} else {
return FALSE; /* no match */
}
}
*slenp -= slen;
return TRUE;
}
/*
* NAME: kfun->sscanf()
* DESCRIPTION: scan a string
*/
int kf_sscanf(f, nargs)
register frame *f;
int nargs;
{
register unsigned int flen, slen, size;
register char *format, *x;
value *lval, *val;
unsigned int fl, sl;
int matches, assignments;
char *s;
xfloat flt;
bool skip;
if (nargs < 2) {
return -1;
} else if (nargs > MAX_LOCALS + 2) {
return 4;
}
s = f->sp[nargs - 1].u.string->text;
slen = f->sp[nargs - 1].u.string->len;
format = f->sp[nargs - 2].u.string->text;
flen = f->sp[nargs - 2].u.string->len;
lval = &f->sp[nargs - 2];
val = --(f->sp); /* there's room for this */
val->type = T_INVALID;
nargs -= 2;
i_add_ticks(f, 8 * nargs);
matches = assignments = 0;
while (flen > 0) {
if (format[0] != '%' || format[1] == '%') {
/* match initial part */
fl = flen;
sl = slen;
if (!match(format, s, &fl, &sl) || fl == flen) {
goto no_match;
}
format += fl;
flen -= fl;
s += sl;
slen -= sl;
}
/* skip first % */
format++;
--flen;
/*
* check for %*
*/
if (*format == '*') {
/* no assignment */
format++;
--flen;
skip = TRUE;
} else {
skip = FALSE;
}
--flen;
switch (*format++) {
case 's':
/* %s */
if (format[0] == '%' && format[1] != '%') {
switch ((format[1] == '*') ? format[2] : format[1]) {
case 'd':
/*
* %s%d
*/
size = slen;
x = s;
while (!isdigit(*x)) {
if (slen == 0) {
goto no_match;
}
if (x[0] == '-' && isdigit(x[1])) {
break;
}
x++;
--slen;
}
size -= slen;
break;
case 'f':
/*
* %s%f
*/
size = slen;
x = s;
while (!isdigit(*x)) {
if (slen == 0) {
goto no_match;
}
if ((x[0] == '-' || x[0] == '.') && isdigit(x[1])) {
break;
}
x++;
--slen;
}
size -= slen;
break;
default:
error("Bad sscanf format string");
}
} else {
/*
* %s followed by non-%
*/
if (flen == 0) {
/* match whole string */
size = slen;
x = s + slen;
slen = 0;
} else {
/* get # of chars to match after string */
for (x = format, size = 0; (x - format) != flen;
x++, size++) {
x = (char *) memchr(x, '%', flen - (x - format));
if (x == (char *) NULL) {
x = format + flen;
break;
} else if (x[1] != '%') {
break;
}
}
size = (x - format) - size;
x = s;
for (;;) {
sl = slen - (x - s);
if (sl < size) {
goto no_match;
}
x = (char *) memchr(x, format[0], sl - size + 1);
if (x == (char *) NULL) {
goto no_match;
}
fl = flen;
if (match(format, x, &fl, &sl)) {
format += fl;
flen -= fl;
size = x - s;
x += sl;
slen -= size + sl;
break;
}
x++;
}
}
}
if (!skip) {
if (nargs == 0) {
error("No lvalue for %%s");
}
--nargs;
val->type = T_STRING;
str_ref(val->u.string = str_new(s, (long) size));
i_store(f, --lval, val);
lval->type = T_INVALID;
val->u.string->ref--;
assignments++;
}
s = x;
break;
case 'd':
/* %d */
x = s;
val->u.number = strtol(s, &s, 10);
if (s == x) {
goto no_match;
}
slen -= (s - x);
if (!skip) {
if (nargs == 0) {
error("No lvalue for %%d");
}
--nargs;
val->type = T_INT;
i_store(f, --lval, val);
lval->type = T_INVALID;
assignments++;
}
break;
case 'f':
/* %f */
x = s;
if (!flt_atof(&s, &flt)) {
goto no_match;
}
slen -= (s - x);
if (!skip) {
if (nargs == 0) {
error("No lvalue for %%f");
}
--nargs;
val->type = T_FLOAT;
VFLT_PUT(val, flt);
i_store(f, --lval, val);
lval->type = T_INVALID;
assignments++;
}
break;
case 'c':
/* %c */
if (slen == 0) {
goto no_match;
}
if (!skip) {
if (nargs == 0) {
error("No lvalue for %%c");
}
--nargs;
val->type = T_INT;
val->u.number = UCHAR(*s);
i_store(f, --lval, val);
lval->type = T_INVALID;
assignments++;
}
s++;
--slen;
break;
default:
error("Bad sscanf format string");
}
matches++;
}
no_match:
f->sp++; /* pop value */
if (nargs > 0) {
i_pop(f, nargs); /* pop superfluous arguments */
}
f->sp += assignments; /* pop lvalues */
str_del((f->sp++)->u.string);
str_del(f->sp->u.string);
f->sp->type = T_INT;
f->sp->u.number = matches;
return 0;
}
# endif
# ifdef FUNCDEF
FUNCDEF("parse_string", kf_parse_string, pt_parse_string)
# else
char pt_parse_string[] = { C_TYPECHECKED | C_STATIC | C_VARARGS,
T_MIXED | (1 << REFSHIFT), 3,
T_STRING, T_STRING, T_INT };
/*
* NAME: kfun->parse_string()
* DESCRIPTION: parse a string
*/
int kf_parse_string(f, nargs)
register frame *f;
int nargs;
{
Int maxalt;
array *a;
if (nargs < 2) {
return -1;
}
if (nargs > 2) {
maxalt = (f->sp++)->u.number + 1;
if (maxalt <= 0) {
return 3;
}
} else {
maxalt = 1; /* default: just one valid parse tree */
}
if (f->obj->flags & (O_USER | O_EDITOR)) {
error("parse_string() from editor or user object");
}
a = ps_parse_string(f, f->sp[1].u.string, f->sp->u.string, maxalt);
str_del((f->sp++)->u.string);
str_del(f->sp->u.string);
if (a != (array *) NULL) {
/* return parse tree */
f->sp->type = T_ARRAY;
arr_ref(f->sp->u.array = a);
} else {
/* parsing failed */
f->sp->type = T_INT;
f->sp->u.number = 0;
}
return 0;
}
# endif