1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#pragma prototyped
23/*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * token stream routines
28 */
29
30#include <ast.h>
31#include <tok.h>
32
33#define FLG_RESTORE	01		/* restore string on close	*/
34#define FLG_NEWLINE	02		/* return newline token next	*/
35
36typedef struct Tok_s			/* token stream state		*/
37{
38	union
39	{
40	char*		end;		/* end ('\0') of last token	*/
41	struct Tok_s*	nxt;		/* next in free list		*/
42	}		ptr;
43	char		chr;		/* replace *end with this	*/
44	char		flg;		/* FLG_*			*/
45} Tok_t;
46
47static Tok_t*		freelist;
48
49/*
50 * open a new token stream on s
51 * if f==0 then string is not restored
52 */
53
54char*
55tokopen(register char* s, int f)
56{
57	register Tok_t*	p;
58
59	if (p = freelist)
60		freelist = freelist->ptr.nxt;
61	else if (!(p = newof(0, Tok_t, 1, 0)))
62		return 0;
63	p->chr = *(p->ptr.end = s);
64	p->flg = f ? FLG_RESTORE : 0;
65	return (char*)p;
66}
67
68/*
69 * close a token stream
70 * restore the string to its original state
71 */
72
73void
74tokclose(char* u)
75{
76	register Tok_t*	p = (Tok_t*)u;
77
78	if (p->flg == FLG_RESTORE && *p->ptr.end != p->chr)
79		*p->ptr.end = p->chr;
80	p->ptr.nxt = freelist;
81	freelist = p;
82}
83
84/*
85 * return next space separated token
86 * "\n" is returned as a token
87 * 0 returned when no tokens remain
88 * "..." and '...' quotes are honored with \ escapes
89 */
90
91char*
92tokread(char* u)
93{
94	register Tok_t*	p = (Tok_t*)u;
95	register char*	s;
96	register char*	r;
97	register int	q;
98	register int	c;
99
100	/*
101	 * restore string on each call
102	 */
103
104	if (!p->chr)
105		return 0;
106	s = p->ptr.end;
107	switch (p->flg)
108	{
109	case FLG_NEWLINE:
110		p->flg = 0;
111		return "\n";
112	case FLG_RESTORE:
113		if (*s != p->chr)
114			*s = p->chr;
115		break;
116	default:
117		if (!*s)
118			s++;
119		break;
120	}
121
122	/*
123	 * skip leading space
124	 */
125
126	while (*s == ' ' || *s == '\t')
127		s++;
128	if (!*s)
129	{
130		p->ptr.end = s;
131		p->chr = 0;
132		return 0;
133	}
134
135	/*
136	 * find the end of this token
137	 */
138
139	r = s;
140	q = 0;
141	for (;;)
142		switch (c = *r++)
143		{
144		case '\n':
145			if (!q)
146			{
147				if (s == (r - 1))
148				{
149					if (!p->flg)
150					{
151						p->ptr.end = r;
152						return "\n";
153					}
154					r++;
155				}
156				else if (!p->flg)
157					p->flg = FLG_NEWLINE;
158			}
159			/*FALLTHROUGH*/
160		case ' ':
161		case '\t':
162			if (q)
163				break;
164			/*FALLTHROUGH*/
165		case 0:
166			if (s == --r)
167			{
168				p->ptr.end = r;
169				p->chr = 0;
170			}
171			else
172			{
173				p->chr = *(p->ptr.end = r);
174				if (*r)
175					*r = 0;
176			}
177			return s;
178		case '\\':
179			if (*r)
180				r++;
181			break;
182		case '"':
183		case '\'':
184			if (c == q)
185				q = 0;
186			else if (!q)
187				q = c;
188			break;
189		}
190}
191