Logo Search packages:      
Sourcecode: ksh version File versions

tokscan.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * scan s for tokens in fmt
 * s modified in place and not restored
 * if nxt!=0 then it will point to the first unread char in s
 * the number of scanned tokens is returned
 * -1 returned if s was not empty and fmt failed to match
 *
 * ' ' in fmt matches 0 or more {space,tab}
 * '\n' in fmt eats remainder of current line
 * "..." and '...' quotes interpreted
 * newline is equivalent to end of buf except when quoted
 * \\ quotes following char
 *
 * message support for %s and %v data
 *
 *    (5:12345)         fixed length strings, ) may be \t
 *    (null)                  NiL
 *
 * "..." and '...' may span \n, and \\n is the line splice
 * quoted '\r' translated to '\n'
 * otherwise tokenizing is unconditionally terminated by '\n'
 *
 * a null arg pointer skips that arg
 *
 *    %c          char
 *    %[hl]d            [short|int|long] base 10
 *    %f          double
 *    %g          double
 *    %[hl]n            [short|int|long] C-style base
 *    %[hl]o            [short|int|long] base 8
 *    %s          string
 *    %[hl]u            same as %[hl]n
 *    %v          argv, elements
 *    %[hl]x            [short|int|long] base 16
 *
 * unmatched char args are set to "", int args to 0
 */

#include <ast.h>
#include <tok.h>

static char empty[1];

/*
 * get one string token into p
 */

static char*
lextok(register char* s, register int c, char** p, int* n)
{
      register char*    t;
      register int      q;
      char*       b;
      char*       u;

      if (*s == '(' && (!c || c == ' ' || c == '\n'))
      {
            q = strtol(s + 1, &b, 10);
            if (*b == ':')
            {
                  if (*(t = ++b + q) == ')' || *t == '\t')
                  {
                        s = t;
                        *s++ = 0;
                        goto end;
                  }
            }
            else if (strneq(b, "null)", 5))
            {
                  s = b + 5;
                  b = 0;
                  goto end;
            }
      }
      b = s;
      q = 0;
      t = 0;
      for (;;)
      {
            if (!*s || !q && *s == '\n')
            {
                  if (!q)
                  {
                        if (!c || c == ' ' || c == '\n') (*n)++;
                        else
                        {
                              s = b;
                              b = empty;
                              break;
                        }
                  }
                  if (t) *t = 0;
                  break;
            }
            else if (*s == '\\')
            {
                  u = s;
                  if (!*++s || *s == '\n' && (!*++s || *s == '\n')) continue;
                  if (p)
                  {
                        if (b == u) b = s;
                        else if (!t) t = u;
                  }
            }
            else if (q)
            {
                  if (*s == q)
                  {
                        q = 0;
                        if (!t) t = s;
                        s++;
                        continue;
                  }
                  else if (*s == '\r') *s = '\n';
            }
            else if (*s == '"' || *s == '\'')
            {
                  q = *s++;
                  if (p)
                  {
                        if (b == (s - 1)) b = s;
                        else if (!t) t = s - 1;
                  }
                  continue;
            }
            else if (*s == c || c == ' ' && *s == '\t')
            {
                  *s++ = 0;
                  if (t) *t = 0;
            end:
                  if (c == ' ') while (*s == ' ' || *s == '\t') s++;
                  (*n)++;
                  break;
            }
            if (t) *t++ = *s;
            s++;
      }
      if (p) *p = b;
      return(s);
}

/*
 * scan entry
 */

int
tokscan(register char* s, char** nxt, const char* fmt, ...)
{
      register int      c;
      register char*    f;
      int         num = 0;
      char*       skip = 0;
      int         q;
      int         onum;
      long        val;
      double            dval;
      va_list           ap;
      char*       p_char;
      double*           p_double;
      int*        p_int;
      long*       p_long;
      short*            p_short;
      char**            p_string;
      char*       prv_f = 0;
      va_list           prv_ap;

      va_start(ap, fmt);
      if (!*s || *s == '\n')
      {
            skip = s;
            s = empty;
      }
      f = (char*)fmt;
      for (;;) switch (c = *f++)
      {
      case 0:
            if (f = prv_f)
            {
                  prv_f = 0;
                  /* prv_ap value is guarded by prv_f */
                  va_copy(ap, prv_ap);
                  continue;
            }
            goto done;
      case ' ':
            while (*s == ' ' || *s == '\t') s++;
            break;
      case '%':
            onum = num;
            switch (c = *f++)
            {
            case 'h':
            case 'l':
                  q = c;
                  c = *f++;
                  break;
            default:
                  q = 0;
                  break;
            }
            switch (c)
            {
            case 0:
            case '%':
                  f--;
                  continue;
            case ':':
                  prv_f = f;
                  f = va_arg(ap, char*);
                  va_copy(prv_ap, ap);
                  va_copy(ap, va_listval(va_arg(ap, va_listarg)));
                  continue;
            case 'c':
                  p_char = va_arg(ap, char*);
                  if (!(c = *s) || c == '\n')
                  {
                        if (p_char) *p_char = 0;
                  }
                  else
                  {
                        if (p_char) *p_char = c;
                        s++;
                        num++;
                  }
                  break;
            case 'd':
            case 'n':
            case 'o':
            case 'u':
            case 'x':
                  switch (c)
                  {
                  case 'd':
                        c = 10;
                        break;
                  case 'n':
                  case 'u':
                        c = 0;
                        break;
                  case 'o':
                        c = 8;
                        break;
                  case 'x':
                        c = 16;
                        break;
                  }
                  if (!*s || *s == '\n')
                  {
                        val = 0;
                        p_char = s;
                  }
                  else val = strtol(s, &p_char, c);
                  switch (q)
                  {
                  case 'h':
                        if (p_short = va_arg(ap, short*)) *p_short = (short)val;
                        break;
                  case 'l':
                        if (p_long = va_arg(ap, long*)) *p_long = val;
                        break;
                  default:
                        if (p_int = va_arg(ap, int*)) *p_int = (int)val;
                        break;
                  }
                  if (s != p_char)
                  {
                        s = p_char;
                        num++;
                  }
                  break;
            case 'f':
            case 'g':
                  if (!*s || *s == '\n')
                  {
                        dval = 0;
                        p_char = s;
                  }
                  else dval = strtod(s, &p_char);
                  if (p_double = va_arg(ap, double*)) *p_double = dval;
                  if (s != p_char)
                  {
                        s = p_char;
                        num++;
                  }
                  break;
            case 's':
                  p_string = va_arg(ap, char**);
                  if (q = *f) f++;
                  if (!*s || *s == '\n')
                  {
                        if (p_string) *p_string = s;
                  }
                  else s = lextok(s, q, p_string, &num);
                  break;
            case 'v':
                  p_string = va_arg(ap, char**);
                  c = va_arg(ap, int);
                  if (q = *f) f++;
                  if ((!*s || *s == '\n') && p_string)
                  {
                        *p_string = 0;
                        p_string = 0;
                  }
                  while (*s && *s != '\n' && --c > 0)
                  {
                        s = lextok(s, q, p_string, &num);
                        if (p_string) p_string++;
                  }
                  if (p_string) *p_string = 0;
                  break;
            }
            if (skip) num = onum;
            else if (num == onum)
            {
                  if (!num) num = -1;
                  skip = s;
                  s = empty;
            }
            break;
      case '\n':
            goto done;
      default:
            if ((*s++ != c) && !skip)
            {
                  skip = s - 1;
                  s = empty;
            }
            break;
      }
 done:
      va_end(ap);
      if (*s == '\n') *s++ = 0;
      if (nxt) *nxt = skip ? skip : s;
      return(num);
}

Generated by  Doxygen 1.6.0   Back to index