Blame src/lib/libast/string/tokscan.c

Packit 992a25
/***********************************************************************
Packit 992a25
*                                                                      *
Packit 992a25
*               This software is part of the ast package               *
Packit 992a25
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
Packit 992a25
*                      and is licensed under the                       *
Packit 992a25
*                 Eclipse Public License, Version 1.0                  *
Packit 992a25
*                    by AT&T Intellectual Property                     *
Packit 992a25
*                                                                      *
Packit 992a25
*                A copy of the License is available at                 *
Packit 992a25
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit 992a25
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit 992a25
*                                                                      *
Packit 992a25
*              Information and Software Systems Research               *
Packit 992a25
*                            AT&T Research                             *
Packit 992a25
*                           Florham Park NJ                            *
Packit 992a25
*                                                                      *
Packit 992a25
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit 992a25
*                  David Korn <dgk@research.att.com>                   *
Packit 992a25
*                   Phong Vo <kpv@research.att.com>                    *
Packit 992a25
*                                                                      *
Packit 992a25
***********************************************************************/
Packit 992a25
#pragma prototyped
Packit 992a25
/*
Packit 992a25
 * Glenn Fowler
Packit 992a25
 * AT&T Research
Packit 992a25
 *
Packit 992a25
 * scan s for tokens in fmt
Packit 992a25
 * s modified in place and not restored
Packit 992a25
 * if nxt!=0 then it will point to the first unread char in s
Packit 992a25
 * the number of scanned tokens is returned
Packit 992a25
 * -1 returned if s was not empty and fmt failed to match
Packit 992a25
 *
Packit 992a25
 * ' ' in fmt matches 0 or more {space,tab}
Packit 992a25
 * '\n' in fmt eats remainder of current line
Packit 992a25
 * "..." and '...' quotes interpreted
Packit 992a25
 * newline is equivalent to end of buf except when quoted
Packit 992a25
 * \\ quotes following char
Packit 992a25
 *
Packit 992a25
 * message support for %s and %v data
Packit 992a25
 *
Packit 992a25
 *	(5:12345)		fixed length strings, ) may be \t
Packit 992a25
 *	(null)			NiL
Packit 992a25
 *
Packit 992a25
 * "..." and '...' may span \n, and \\n is the line splice
Packit 992a25
 * quoted '\r' translated to '\n'
Packit 992a25
 * otherwise tokenizing is unconditionally terminated by '\n'
Packit 992a25
 *
Packit 992a25
 * a null arg pointer skips that arg
Packit 992a25
 *
Packit 992a25
 *	%c		char
Packit 992a25
 *	%[hl]d		[short|int|long] base 10
Packit 992a25
 *	%f		double
Packit 992a25
 *	%g		double
Packit 992a25
 *	%[hl]n		[short|int|long] C-style base
Packit 992a25
 *	%[hl]o		[short|int|long] base 8
Packit 992a25
 *	%s		string
Packit 992a25
 *	%[hl]u		same as %[hl]n
Packit 992a25
 *	%v		argv, elements
Packit 992a25
 *	%[hl]x		[short|int|long] base 16
Packit 992a25
 *
Packit 992a25
 * unmatched char args are set to "", int args to 0
Packit 992a25
 */
Packit 992a25
Packit 992a25
#include <ast.h>
Packit 992a25
#include <tok.h>
Packit 992a25
Packit 992a25
static char	empty[1];
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * get one string token into p
Packit 992a25
 */
Packit 992a25
Packit 992a25
static char*
Packit 992a25
lextok(register char* s, register int c, char** p, int* n)
Packit 992a25
{
Packit 992a25
	register char*	t;
Packit 992a25
	register int	q;
Packit 992a25
	char*		b;
Packit 992a25
	char*		u;
Packit 992a25
Packit 992a25
	if (*s == '(' && (!c || c == ' ' || c == '\n'))
Packit 992a25
	{
Packit 992a25
		q = strtol(s + 1, &b, 10);
Packit 992a25
		if (*b == ':')
Packit 992a25
		{
Packit 992a25
			if (*(t = ++b + q) == ')' || *t == '\t')
Packit 992a25
			{
Packit 992a25
				s = t;
Packit 992a25
				*s++ = 0;
Packit 992a25
				goto end;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if (strneq(b, "null)", 5))
Packit 992a25
		{
Packit 992a25
			s = b + 5;
Packit 992a25
			b = 0;
Packit 992a25
			goto end;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	b = s;
Packit 992a25
	q = 0;
Packit 992a25
	t = 0;
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		if (!*s || !q && *s == '\n')
Packit 992a25
		{
Packit 992a25
			if (!q)
Packit 992a25
			{
Packit 992a25
				if (!c || c == ' ' || c == '\n') (*n)++;
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					s = b;
Packit 992a25
					b = empty;
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			if (t) *t = 0;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		else if (*s == '\\')
Packit 992a25
		{
Packit 992a25
			u = s;
Packit 992a25
			if (!*++s || *s == '\n' && (!*++s || *s == '\n')) continue;
Packit 992a25
			if (p)
Packit 992a25
			{
Packit 992a25
				if (b == u) b = s;
Packit 992a25
				else if (!t) t = u;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if (q)
Packit 992a25
		{
Packit 992a25
			if (*s == q)
Packit 992a25
			{
Packit 992a25
				q = 0;
Packit 992a25
				if (!t) t = s;
Packit 992a25
				s++;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			else if (*s == '\r') *s = '\n';
Packit 992a25
		}
Packit 992a25
		else if (*s == '"' || *s == '\'')
Packit 992a25
		{
Packit 992a25
			q = *s++;
Packit 992a25
			if (p)
Packit 992a25
			{
Packit 992a25
				if (b == (s - 1)) b = s;
Packit 992a25
				else if (!t) t = s - 1;
Packit 992a25
			}
Packit 992a25
			continue;
Packit 992a25
		}
Packit 992a25
		else if (*s == c || c == ' ' && *s == '\t')
Packit 992a25
		{
Packit 992a25
			*s++ = 0;
Packit 992a25
			if (t) *t = 0;
Packit 992a25
		end:
Packit 992a25
			if (c == ' ') while (*s == ' ' || *s == '\t') s++;
Packit 992a25
			(*n)++;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		if (t) *t++ = *s;
Packit 992a25
		s++;
Packit 992a25
	}
Packit 992a25
	if (p) *p = b;
Packit 992a25
	return(s);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * scan entry
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
tokscan(register char* s, char** nxt, const char* fmt, ...)
Packit 992a25
{
Packit 992a25
	register int	c;
Packit 992a25
	register char*	f;
Packit 992a25
	int		num = 0;
Packit 992a25
	char*		skip = 0;
Packit 992a25
	int		q;
Packit 992a25
	int		onum;
Packit 992a25
	long		val;
Packit 992a25
	double		dval;
Packit 992a25
	va_list		ap;
Packit 992a25
	char*		p_char;
Packit 992a25
	double*		p_double;
Packit 992a25
	int*		p_int;
Packit 992a25
	long*		p_long;
Packit 992a25
	short*		p_short;
Packit 992a25
	char**		p_string;
Packit 992a25
	char*		prv_f = 0;
Packit 992a25
	va_list		prv_ap;
Packit 992a25
Packit 992a25
	va_start(ap, fmt);
Packit 992a25
	if (!*s || *s == '\n')
Packit 992a25
	{
Packit 992a25
		skip = s;
Packit 992a25
		s = empty;
Packit 992a25
	}
Packit 992a25
	f = (char*)fmt;
Packit 992a25
	for (;;) switch (c = *f++)
Packit 992a25
	{
Packit 992a25
	case 0:
Packit 992a25
		if (f = prv_f)
Packit 992a25
		{
Packit 992a25
			prv_f = 0;
Packit 992a25
			/* prv_ap value is guarded by prv_f */
Packit 992a25
			va_copy(ap, prv_ap);
Packit 992a25
			continue;
Packit 992a25
		}
Packit 992a25
		goto done;
Packit 992a25
	case ' ':
Packit 992a25
		while (*s == ' ' || *s == '\t') s++;
Packit 992a25
		break;
Packit 992a25
	case '%':
Packit 992a25
		onum = num;
Packit 992a25
		switch (c = *f++)
Packit 992a25
		{
Packit 992a25
		case 'h':
Packit 992a25
		case 'l':
Packit 992a25
			q = c;
Packit 992a25
			c = *f++;
Packit 992a25
			break;
Packit 992a25
		default:
Packit 992a25
			q = 0;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		switch (c)
Packit 992a25
		{
Packit 992a25
		case 0:
Packit 992a25
		case '%':
Packit 992a25
			f--;
Packit 992a25
			continue;
Packit 992a25
		case ':':
Packit 992a25
			prv_f = f;
Packit 992a25
			f = va_arg(ap, char*);
Packit 992a25
			va_copy(prv_ap, ap);
Packit 992a25
			va_copy(ap, va_listval(va_arg(ap, va_listarg)));
Packit 992a25
			continue;
Packit 992a25
		case 'c':
Packit 992a25
			p_char = va_arg(ap, char*);
Packit 992a25
			if (!(c = *s) || c == '\n')
Packit 992a25
			{
Packit 992a25
				if (p_char) *p_char = 0;
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				if (p_char) *p_char = c;
Packit 992a25
				s++;
Packit 992a25
				num++;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case 'd':
Packit 992a25
		case 'n':
Packit 992a25
		case 'o':
Packit 992a25
		case 'u':
Packit 992a25
		case 'x':
Packit 992a25
			switch (c)
Packit 992a25
			{
Packit 992a25
			case 'd':
Packit 992a25
				c = 10;
Packit 992a25
				break;
Packit 992a25
			case 'n':
Packit 992a25
			case 'u':
Packit 992a25
				c = 0;
Packit 992a25
				break;
Packit 992a25
			case 'o':
Packit 992a25
				c = 8;
Packit 992a25
				break;
Packit 992a25
			case 'x':
Packit 992a25
				c = 16;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			if (!*s || *s == '\n')
Packit 992a25
			{
Packit 992a25
				val = 0;
Packit 992a25
				p_char = s;
Packit 992a25
			}
Packit 992a25
			else val = strtol(s, &p_char, c);
Packit 992a25
			switch (q)
Packit 992a25
			{
Packit 992a25
			case 'h':
Packit 992a25
				if (p_short = va_arg(ap, short*)) *p_short = (short)val;
Packit 992a25
				break;
Packit 992a25
			case 'l':
Packit 992a25
				if (p_long = va_arg(ap, long*)) *p_long = val;
Packit 992a25
				break;
Packit 992a25
			default:
Packit 992a25
				if (p_int = va_arg(ap, int*)) *p_int = (int)val;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			if (s != p_char)
Packit 992a25
			{
Packit 992a25
				s = p_char;
Packit 992a25
				num++;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case 'f':
Packit 992a25
		case 'g':
Packit 992a25
			if (!*s || *s == '\n')
Packit 992a25
			{
Packit 992a25
				dval = 0;
Packit 992a25
				p_char = s;
Packit 992a25
			}
Packit 992a25
			else dval = strtod(s, &p_char);
Packit 992a25
			if (p_double = va_arg(ap, double*)) *p_double = dval;
Packit 992a25
			if (s != p_char)
Packit 992a25
			{
Packit 992a25
				s = p_char;
Packit 992a25
				num++;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case 's':
Packit 992a25
			p_string = va_arg(ap, char**);
Packit 992a25
			if (q = *f) f++;
Packit 992a25
			if (!*s || *s == '\n')
Packit 992a25
			{
Packit 992a25
				if (p_string) *p_string = s;
Packit 992a25
			}
Packit 992a25
			else s = lextok(s, q, p_string, &num);
Packit 992a25
			break;
Packit 992a25
		case 'v':
Packit 992a25
			p_string = va_arg(ap, char**);
Packit 992a25
			c = va_arg(ap, int);
Packit 992a25
			if (q = *f) f++;
Packit 992a25
			if ((!*s || *s == '\n') && p_string)
Packit 992a25
			{
Packit 992a25
				*p_string = 0;
Packit 992a25
				p_string = 0;
Packit 992a25
			}
Packit 992a25
			while (*s && *s != '\n' && --c > 0)
Packit 992a25
			{
Packit 992a25
				s = lextok(s, q, p_string, &num);
Packit 992a25
				if (p_string) p_string++;
Packit 992a25
			}
Packit 992a25
			if (p_string) *p_string = 0;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		if (skip) num = onum;
Packit 992a25
		else if (num == onum)
Packit 992a25
		{
Packit 992a25
			if (!num) num = -1;
Packit 992a25
			skip = s;
Packit 992a25
			s = empty;
Packit 992a25
		}
Packit 992a25
		break;
Packit 992a25
	case '\n':
Packit 992a25
		goto done;
Packit 992a25
	default:
Packit 992a25
		if ((*s++ != c) && !skip)
Packit 992a25
		{
Packit 992a25
			skip = s - 1;
Packit 992a25
			s = empty;
Packit 992a25
		}
Packit 992a25
		break;
Packit 992a25
	}
Packit 992a25
 done:
Packit 992a25
	va_end(ap);
Packit 992a25
	if (*s == '\n') *s++ = 0;
Packit 992a25
	if (nxt) *nxt = skip ? skip : s;
Packit 992a25
	return(num);
Packit 992a25
}