/* A new sscanf() like efun /Gwendolyn@nannymud.lysator.liu.se 2000 */
--------------------------------------------------------------
NAME
xscanf - match strings and return an array of matched
SYNOPSIS
mixed *xscanf(string str, string fmt)
DESCRIPTION
This one is similar to sscanf in that it match a string
against a pattern. The most important difference is that
instead of taking a list of variables to put the values
in it returns the matched items in an array. Also it
recognizes some extra types:
%s - string
%d - decimal integer
%c - character (gives the char as an int)
%n - matched characters sofar
%o - octal integer
%x - hexadecimal integer
SEE ALSO
sscanf
-----------------------------------------------------------
struct vector *xscanf(char *str, char *fmt)
{
struct vector *match, *vec;
char *mem, *tst;
int i, j, k, l, num = 0;
for(i = 0; i < strlen(fmt);)
{
if(fmt[i++] == '%' && i < strlen(fmt) &&
(fmt[i] == 'c' || fmt[i] == 'd' || fmt[i] == 'n' || fmt[i] == 's' || fmt[i] == 'o' || fmt[i] == 'x'))
num++;
}
if(num == 0)
{
if(strncmp(str, fmt, strlen(fmt)))
match = (struct vector *) 0;
else
match = allocate_array(0);
return match;
}
match = allocate_array(num);
for(i = 0, j = 0, k = 0; fmt[j]; j++, k++)
{
if(!str[k])
break;
if(fmt[j] == '%' && fmt[j + 1] == 's')
{
for(j++, tst = fmt + j + 1; tst[0] && tst[0] != '%'; tst++);
if(tst == fmt + j + 1)
l = strlen(str);
else
{
for(l = k; l < strlen(str); l++)
{
if(!strncmp(str + l, fmt + j + 1, tst - fmt - j - 1))
break;
}
if(l >= strlen(str))
break;
}
if((mem = (char *) malloc(l - k + 1)) == NULL)
{
free_vector(match);
error("Internal error.");
}
if(l > k)
(void) strncpy(mem, str + k, l - k);
mem[l - k] = '\0';
match->item[i].type = T_STRING;
match->item[i].string_type = STRING_MALLOC;
match->item[i].u.string = mem;
k = l - 1;
i++;
}
else if(fmt[j] == '%' && fmt[j + 1] == 'd')
{
for(l = 0; str[k] >= '0' && str[k] <= '9'; k++)
l = l * 10 + str[k] - '0';
match->item[i].type = T_NUMBER;
match->item[i].u.number = l;
k--;
j++;
i++;
}
else if(fmt[j] == '%' && fmt[j + 1] == 'c')
{
match->item[i].type = T_NUMBER;
match->item[i].u.number = (int) str[k];
j++;
i++;
}
else if(fmt[j] == '%' && fmt[j + 1] == 'n')
{
match->item[i].type = T_NUMBER;
match->item[i].u.number = k;
k--;
j++;
i++;
}
else if(fmt[j] == '%' && fmt[j + 1] == 'o')
{
for(l = 0; str[k] >= '0' && str[k] <= '7'; k++)
l = l * 8 + str[k] - '0';
match->item[i].type = T_NUMBER;
match->item[i].u.number = l;
k--;
j++;
i++;
}
else if(fmt[j] == '%' && fmt[j + 1] == 'x')
{
for(l = 0; (str[k] >= '0' && str[k] <= '9') ||
(str[k] >= 'a' && str[k] <= 'f') ||
(str[k] >= 'A' && str[k] <= 'F'); k++)
{
l *= 16;
if(str[k] >= '0' && str[k] <= '9')
l += str[k] - '0';
else if(str[k] >= 'a' && str[k] <= 'f')
l += str[k] - 'a' + 10;
else
l += str[k] - 'A' + 10;
}
match->item[i].type = T_NUMBER;
match->item[i].u.number = l;
k--;
j++;
i++;
}
else if(fmt[j] != str[k])
break;
}
if(!i)
{
free_vector(match);
vec = allocate_array(0);
}
else if(i == num)
vec = match;
else
{
vec = slice_array(match, 0, i - 1);
free_vector(match);
}
return vec;
}