/*  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;
}