1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * Glenn Fowler
25da2e3ebdSchin  * AT&T Research
26da2e3ebdSchin  *
27da2e3ebdSchin  * return an Sfio_t* to a file or string that
28da2e3ebdSchin  *
29da2e3ebdSchin  *	splices \\n to single lines
30da2e3ebdSchin  *	checks for "..." and '...' spanning newlines
31da2e3ebdSchin  *	drops #...\n comments
32da2e3ebdSchin  *
33da2e3ebdSchin  * if <arg> is a file and first line matches
34da2e3ebdSchin  *	#!!! <level> <message> !!!
35da2e3ebdSchin  * then error(<lev>,"%s: %s",<arg>,<msg>) called
36da2e3ebdSchin  *
37da2e3ebdSchin  * NOTE: seek disabled and string disciplines cannot be composed
38da2e3ebdSchin  *	 quoted \n translated to \r
39da2e3ebdSchin  */
40da2e3ebdSchin 
41da2e3ebdSchin #include <ast.h>
42da2e3ebdSchin #include <error.h>
43da2e3ebdSchin #include <tok.h>
44da2e3ebdSchin 
45da2e3ebdSchin typedef struct
46da2e3ebdSchin {
47da2e3ebdSchin 	Sfdisc_t	disc;
48da2e3ebdSchin 	Sfio_t*		sp;
49da2e3ebdSchin 	int		quote;
50da2e3ebdSchin 	int*		line;
51da2e3ebdSchin } Splice_t;
52da2e3ebdSchin 
53da2e3ebdSchin /*
54da2e3ebdSchin  * the splicer
55da2e3ebdSchin  */
56da2e3ebdSchin 
57da2e3ebdSchin static int
spliceline(Sfio_t * s,int op,void * val,Sfdisc_t * ad)58da2e3ebdSchin spliceline(Sfio_t* s, int op, void* val, Sfdisc_t* ad)
59da2e3ebdSchin {
60da2e3ebdSchin 	Splice_t*	d = (Splice_t*)ad;
61da2e3ebdSchin 	register char*	b;
62da2e3ebdSchin 	register int	c;
63da2e3ebdSchin 	register int	n;
64da2e3ebdSchin 	register int	q;
65da2e3ebdSchin 	register int	j;
66da2e3ebdSchin 	register char*	e;
67da2e3ebdSchin 	char*		buf;
68da2e3ebdSchin 
69da2e3ebdSchin 	NoP(val);
70da2e3ebdSchin 	switch (op)
71da2e3ebdSchin 	{
72da2e3ebdSchin 	case SF_CLOSING:
73da2e3ebdSchin 		sfclose(d->sp);
74da2e3ebdSchin 		return 0;
75da2e3ebdSchin 	case SF_DPOP:
76da2e3ebdSchin 		free(d);
77da2e3ebdSchin 		return 0;
78da2e3ebdSchin 	case SF_READ:
79da2e3ebdSchin 		do
80da2e3ebdSchin 		{
81da2e3ebdSchin 			if (!(buf = sfgetr(d->sp, '\n', 0)) && !(buf = sfgetr(d->sp, '\n', -1)))
82da2e3ebdSchin 				return 0;
83da2e3ebdSchin 			n = sfvalue(d->sp);
84da2e3ebdSchin 			q = d->quote;
85da2e3ebdSchin 			j = 0;
86da2e3ebdSchin 			(*d->line)++;
87da2e3ebdSchin 			if (n > 1 && buf[n - 2] == '\\')
88da2e3ebdSchin 			{
89da2e3ebdSchin 				j = 1;
90da2e3ebdSchin 				n -= 2;
91da2e3ebdSchin 				if (q == '#')
92da2e3ebdSchin 				{
93da2e3ebdSchin 					n = 0;
94da2e3ebdSchin 					continue;
95da2e3ebdSchin 				}
96da2e3ebdSchin 			}
97da2e3ebdSchin 			else if (q == '#')
98da2e3ebdSchin 			{
99da2e3ebdSchin 				q = 0;
100da2e3ebdSchin 				n = 0;
101da2e3ebdSchin 				continue;
102da2e3ebdSchin 			}
103da2e3ebdSchin 			if (n > 0)
104da2e3ebdSchin 			{
105da2e3ebdSchin 				e = (b = buf) + n;
106da2e3ebdSchin 				while (b < e)
107da2e3ebdSchin 				{
108da2e3ebdSchin 					if ((c = *b++) == '\\')
109da2e3ebdSchin 						b++;
110da2e3ebdSchin 					else if (c == q)
111da2e3ebdSchin 						q = 0;
112da2e3ebdSchin 					else if (!q)
113da2e3ebdSchin 					{
114da2e3ebdSchin 						if (c == '\'' || c == '"')
115da2e3ebdSchin 							q = c;
116da2e3ebdSchin 						else if (c == '#' && (b == (buf + 1) || (c = *(b - 2)) == ' ' || c == '\t'))
117da2e3ebdSchin 						{
118da2e3ebdSchin 							if (buf[n - 1] != '\n')
119da2e3ebdSchin 							{
120da2e3ebdSchin 								q = '#';
121da2e3ebdSchin 								n = b - buf - 2;
122da2e3ebdSchin 							}
123da2e3ebdSchin 							else if (n = b - buf - 1)
124da2e3ebdSchin 								buf[n - 1] = '\n';
125da2e3ebdSchin 							break;
126da2e3ebdSchin 						}
127da2e3ebdSchin 					}
128da2e3ebdSchin 				}
129da2e3ebdSchin 				if (n > 0)
130da2e3ebdSchin 				{
131da2e3ebdSchin 					if (!j && buf[n - 1] != '\n' && (s->_flags & SF_STRING))
132da2e3ebdSchin 						buf[n++] = '\n';
133da2e3ebdSchin 					if (q && buf[n - 1] == '\n')
134da2e3ebdSchin 						buf[n - 1] = '\r';
135da2e3ebdSchin 				}
136da2e3ebdSchin 			}
137da2e3ebdSchin 		} while (n <= 0);
138da2e3ebdSchin 		sfsetbuf(s, buf, n);
139da2e3ebdSchin 		d->quote = q;
140da2e3ebdSchin 		return 1;
141da2e3ebdSchin 	default:
142da2e3ebdSchin 		return 0;
143da2e3ebdSchin 	}
144da2e3ebdSchin }
145da2e3ebdSchin 
146da2e3ebdSchin /*
147da2e3ebdSchin  * open a stream to parse lines
148da2e3ebdSchin  *
149da2e3ebdSchin  *	flags: 0		arg: open Sfio_t*
150da2e3ebdSchin  *	flags: SF_READ		arg: file name
151da2e3ebdSchin  *	flags: SF_STRING	arg: null terminated char*
152da2e3ebdSchin  *
153da2e3ebdSchin  * if line!=0 then it points to a line count that starts at 0
154da2e3ebdSchin  * and is incremented for each input line
155da2e3ebdSchin  */
156da2e3ebdSchin 
157da2e3ebdSchin Sfio_t*
tokline(const char * arg,int flags,int * line)158da2e3ebdSchin tokline(const char* arg, int flags, int* line)
159da2e3ebdSchin {
160da2e3ebdSchin 	Sfio_t*		f;
161da2e3ebdSchin 	Sfio_t*		s;
162da2e3ebdSchin 	Splice_t*	d;
163da2e3ebdSchin 	char*		p;
164da2e3ebdSchin 	char*		e;
165da2e3ebdSchin 
166da2e3ebdSchin 	static int	hidden;
167da2e3ebdSchin 
168da2e3ebdSchin 	if (!(d = newof(0, Splice_t, 1, 0)))
169da2e3ebdSchin 		return 0;
170da2e3ebdSchin 	if (!(s = sfopen(NiL, NiL, "s")))
171da2e3ebdSchin 	{
172da2e3ebdSchin 		free(d);
173da2e3ebdSchin 		return 0;
174da2e3ebdSchin 	}
175da2e3ebdSchin 	if (!(flags & (SF_STRING|SF_READ)))
176da2e3ebdSchin 		f = (Sfio_t*)arg;
177da2e3ebdSchin 	else if (!(f = sfopen(NiL, arg, (flags & SF_STRING) ? "s" : "r")))
178da2e3ebdSchin 	{
179da2e3ebdSchin 		free(d);
180da2e3ebdSchin 		sfclose(s);
181da2e3ebdSchin 		return 0;
182da2e3ebdSchin 	}
183da2e3ebdSchin 	else if ((p = sfreserve(f, 0, 0)) && sfvalue(f) > 11 && strmatch(p, "#!!! +([-0-9]) *([!\n]) !!!\n*") && (e = strchr(p, '\n')))
184da2e3ebdSchin 	{
185da2e3ebdSchin 		flags = strtol(p + 5, &p, 10);
186da2e3ebdSchin 		error(flags, "%s:%-.*s", arg, e - p - 4, p);
187da2e3ebdSchin 	}
188da2e3ebdSchin 	d->disc.exceptf = spliceline;
189da2e3ebdSchin 	d->sp = f;
190da2e3ebdSchin 	*(d->line = line ? line : &hidden) = 0;
191da2e3ebdSchin 	sfdisc(s, (Sfdisc_t*)d);
192da2e3ebdSchin 	return s;
193da2e3ebdSchin }
194