/*
** $Id: string.c,v 1.4 2008/12/18 04:18:43 dredd Exp $
**
** $Source: /cvsroot/swlpc/swlpc/modules/string.c,v $
** $Revision: 1.4 $
** $Date: 2008/12/18 04:18:43 $
** $State: Exp $
**
** Author: Geoff Wong, 1999
**
** See the file "Copying" distributed with this file.
*/
#include <strings.h>
#include <ctype.h>
#include "stack.h"
Val * lpc_atoi(Val * str)
{
return make_number(atoi(str->u.string->str));
}
Val * lpc_ator(Val * str)
{
return make_number(atof(str->u.string->str));
}
Val * lpc_strlen(Val * str)
{
return make_number(str->u.string->length);
}
Val * lpc_capitalize(Val * arg)
{
Val * ret = 0;
if (arg->u.string->str[0] == '\0')
{
return share_string(arg->u.string);
}
if (islower(arg->u.string->str[0]))
{
char *s = malloc(1 + arg->u.string->length);
strcpy(s, arg->u.string->str);
s[0] += 'A' - 'a';
ret = make_string(s); /* add it to string table again */
free(s);
return ret;
}
return share_string(arg->u.string);
}
Val * lpc_downcase(Val * arg)
{
Val *ret;
int i;
char *s = malloc(1 + arg->u.string->length);
strcpy(s, arg->u.string->str);
for (i = strlen(s) - 1; i >= 0; i--)
if (isalpha(s[i]))
s[i] |= 'a' - 'A';
ret = make_string(s);
free(s);
return ret;
}
Val *lpc_split(Shared *shstr, Shared *del)
{
int num = 0, len;
char * p, * beg;
char * buff;
char * str = shstr->str;
int slen = shstr->length;
Val * ret;
len = del->length;
if (slen >= len)
{
// Skip leading 'del' strings, if any.
while ((memcmp(str, del->str, len) == 0))
{
str += len;
if ((str - shstr->str) == slen) return Const(0);
else if ((str - shstr->str) < len) break;
}
// fix length
slen = slen - (str - shstr->str);
// Find number of occurences of the delimiter 'del'.
for (p = str; (p-str) <= (slen-len);)
{
if (memcmp(p, del->str, len) == 0)
{
num++;
p += len;
}
else
p++;
}
// Compute number of array items. It is either number of delimiters, or,
// one more.
if ((memcmp(str + slen - len, del->str, len) != 0)) num++;
}
else
{
num++;
}
// adjust for new length
buff = malloc(slen + 1);
ret = allocate_array(num);
for (p = str, beg = str, num = 0; (p-str) <= (slen-len);)
{
if (memcmp(p, del->str, len) == 0)
{
memcpy(buff, beg, p - beg);
buff[p - beg] = '\0';
if (num >= ret->u.vec->size)
{
efun_error("Array size exceeded in explode (%s)!\n", Scurrent()->name);
free(buff);
return ret;
}
assign_value(&ret->u.vec->item[num], make_nstring(buff, p - beg));
num++;
beg = p + len;
p = beg;
}
else
{
p += 1;
}
}
// Copy last occurence, if there was not a 'del' at the end.
if ((beg-str) < slen)
{
assign_value(&ret->u.vec->item[num], make_nstring(beg, slen-(beg-str)));
}
free(buff);
return ret;
}
Val *lpc_join(Val * varr, Val * vdel)
{
int size, i, num, tot;
char *p, *q;
Val *ret;
struct vector * arr = varr->u.vec;
Shared * del = vdel->u.string;
for (i = 0, size = 0, num = 0; i < arr->size; i++)
{
if (arr->item[i].type == T_STRING)
{
size += arr->item[i].u.string->length;
num++;
}
}
if (num == 0) return Const(0);
tot = size + (num - 1) * del->length;
p = malloc(tot + 1);
q = p;
p[0] = '\0';
for (i = 0, size = 0, num = 0; i < arr->size; i++)
{
if (arr->item[i].type == T_STRING)
{
if (num > 0)
{
memcpy(p, del->str, del->length);
p += del->length;
}
memcpy(p, arr->item[i].u.string->str,
arr->item[i].u.string->length);
p += arr->item[i].u.string->length;
num++;
}
}
q[tot] = '\0';
ret = make_nstring(q, tot);
free(q);
return ret;
}
/* Support functions for lpc_sscanf */
char * find_percent(char *str)
{
while (1)
{
str = strchr(str, '%');
if (str == NULL) return 0;
if (str[1] != '%') return str;
str++;
}
return 0;
}
int count_percent(char * str)
{
int tot = 0;
while (1)
{
str = strchr(str, '%');
if (str == NULL) return 0;
if (str[1] != '%') tot++;
else str++;
str++;
}
return 0;
}
Val * lpc_sscanf(Val * vstr, Val * vfmt)
{
Val * result;
char *fmt; /* Format description */
char *in_string; /* The string to be parsed. */
int matches;
char *cp;
int argc;
/* Get the string to parse */
in_string = vstr->u.string->str;
if (in_string == NULL) return Const(0);
/* Now get the format description. */
fmt = vfmt->u.string->str;
if (fmt == NULL) return Const(0);
/* First, skip and match leading text. */
for (cp = find_percent(fmt); fmt != cp; fmt++, in_string++)
{
if (in_string[0] == '\0' || fmt[0] != in_string[0])
{
return Const(0);
}
}
/* Find # of %'s in string */
argc = count_percent(fmt);
result = allocate_array(argc);
/* For every % or substring in the format. */
for (matches = 0; matches < argc; matches++)
{
int i, type;
if (fmt[0] == '\0')
{
/*
* We have reached end of the format string. If there are any
* chars left in the in_string, then we put them in the last
* element (if any).
*/
if (in_string[0])
{
assign_value(&(result->u.vec->item[matches++]), make_string(in_string));
}
break;
}
if (fmt[0] != '%')
fatal("Should be a %% now !\n");
type = T_STRING;
if (fmt[1] == 'd')
type = T_NUMBER;
else if (fmt[1] == 'f')
type = T_REAL;
else if (fmt[1] != 's')
{
efun_error("Bad type specification : '%%%c' in sscanf fmt string.",
fmt[1]);
return Const(0);
}
fmt += 2;
/*
* Parsing a number is the easy case. Just use strtol() to find the
* end of the number.
*/
if (type == T_NUMBER)
{
extern long strtol();
char *tmp = in_string;
int tmp_num;
tmp_num = (int) strtol(in_string, &in_string, 0);
if (tmp == in_string)
{
/* No match */
break;
}
/* free first? */
assign_value(&(result->u.vec->item[matches]), make_number(tmp_num));
while (fmt[0] && fmt[0] == in_string[0])
fmt++, in_string++;
if (fmt[0] != '%')
{
matches++;
break;
}
continue;
}
if (type == T_REAL)
{
extern double strtod();
char *tmp = in_string;
float tmp_num;
tmp_num = (float) strtod(in_string, &in_string);
if (tmp == in_string)
{
/* No match */
break;
}
assign_value(&(result->u.vec->item[matches]), make_real(tmp_num));
while (fmt[0] && fmt[0] == in_string[0])
fmt++, in_string++;
if (fmt[0] != '%')
{
matches++;
break;
}
continue;
}
/*
* Now we have the string case.
*/
cp = find_percent(fmt);
if (cp == fmt)
{
efun_error("Illegal to have 2 adjacent %'s in fmt string in sscanf.");
return Const(0);
}
if (cp == 0) cp = fmt + strlen(fmt);
/*
* First case: There was no extra characters to match. Then this is
* the last match.
*/
if (cp == fmt)
{
assign_value(&(result->u.vec->item[matches]),make_string(in_string));
matches++;
break;
}
for (i = 0; in_string[i]; i++)
{
if (strncmp(in_string + i, fmt, cp - fmt) == 0)
{
char *match;
/*
* Found a match !
*/
match = malloc(i + 1);
(void) strncpy(match, in_string, i);
in_string += i + (cp - fmt);
match[i] = '\0';
assign_value(&(result->u.vec->item[matches]), make_string(match));
free(match);
fmt = cp; /* Advance fmt to next % */
break;
}
}
/*
* No match was found. Then we stop here, and return the result so
* far !
*/
if (fmt != cp) break;
}
return result;
}
Val * lpc_rindex(Val * a, Val * s, Val * off, Val * step)
{
struct vector *arr;
char *str;
int start = off->u.number;
int skip = step->u.number;
int i;
if (skip <= 0) skip = 1;
if (a->type == T_POINTER)
{
// array rindex
arr = a->u.vec;
if (start < 1) start = arr->size - 1;
if (arr->size < start) return Const(-1);
for (i = start; i >= 0; i -= skip)
{
if (arr->item[i].type == T_STRING && s->type == T_STRING)
if (arr->item[i].u.string == s->u.string
/*|| !strcmp(arr->item[i].u.string, s->u.string) */ )
return make_number(i);
/* should be ok with shared strings */
/* if (!strcmp(arr->item[i].u.string,s->u.string)) return i; */
if (arr->item[i].type == T_NUMBER && s->type == T_NUMBER)
if (arr->item[i].u.number == s->u.number)
return make_number(i);
if (arr->item[i].type == T_REAL && s->type == T_REAL)
if (arr->item[i].u.real == s->u.real)
return make_number(i);
if (arr->item[i].type == T_POINTER && s->type == T_POINTER)
if (arr->item[i].u.vec == s->u.vec)
return make_number(i);
if (arr->item[i].type == T_OBJECT && s->type == T_OBJECT)
if (arr->item[i].u.ob == s->u.ob)
return make_number(i);
}
return Const(-1);
}
else if (a->type == T_STRING)
{
// string rindex
int j;
if (start < 1) start = a->u.string->length - 1;
if (a->u.string->length < start) return Const(-1);
str = a->u.string->str;
if (s->type != T_STRING)
{
int m;
m = s->u.number;
for (j = start; j >= 0; j -= skip)
{
if (str[j] == m) return make_number(j);
}
}
else
{
int x;
char * m;
m = s->u.string->str;
x = s->u.string->length;
for (j = start; j >= 0; j -= skip)
{
if (!memcmp(&(str[j]), m, x)) return make_number(j);
}
}
return Const(-1);
}
else
return Const(-1);
}