1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 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 /*
25da2e3ebdSchin  * Glenn Fowler
26da2e3ebdSchin  * AT&T Research
27da2e3ebdSchin  *
28da2e3ebdSchin  * keyword printf support
29da2e3ebdSchin  */
30da2e3ebdSchin 
31da2e3ebdSchin #include <ast.h>
32da2e3ebdSchin #include <ccode.h>
33da2e3ebdSchin #include <ctype.h>
34da2e3ebdSchin #include <sfdisc.h>
35da2e3ebdSchin #include <regex.h>
36da2e3ebdSchin 
37da2e3ebdSchin #define FMT_case	1
38da2e3ebdSchin #define FMT_edit	2
39da2e3ebdSchin 
40da2e3ebdSchin typedef struct
41da2e3ebdSchin {
42da2e3ebdSchin 	Sffmt_t			fmt;
43da2e3ebdSchin 	void*			handle;
44da2e3ebdSchin 	Sf_key_lookup_t		lookup;
45da2e3ebdSchin 	Sf_key_convert_t	convert;
46da2e3ebdSchin 	Sfio_t*			tmp[2];
47da2e3ebdSchin 	regex_t			red[2];
48da2e3ebdSchin 	regex_t*		re[2];
49da2e3ebdSchin 	int			invisible;
50da2e3ebdSchin 	int			level;
51da2e3ebdSchin 	int			version;
52da2e3ebdSchin } Fmt_t;
53da2e3ebdSchin 
54da2e3ebdSchin typedef struct
55da2e3ebdSchin {
56da2e3ebdSchin 	char*			next;
57da2e3ebdSchin 	int			delimiter;
58da2e3ebdSchin 	int			first;
59da2e3ebdSchin } Field_t;
60da2e3ebdSchin 
61da2e3ebdSchin typedef union
62da2e3ebdSchin {
63da2e3ebdSchin 	char**			p;
64da2e3ebdSchin 	char*			s;
65da2e3ebdSchin 	Sflong_t		q;
66da2e3ebdSchin 	long			l;
67da2e3ebdSchin 	int			i;
68da2e3ebdSchin 	short			h;
69da2e3ebdSchin 	char			c;
70da2e3ebdSchin } Value_t;
71da2e3ebdSchin 
72da2e3ebdSchin #define initfield(f,s)	((f)->first = (f)->delimiter = *((f)->next = (s)))
73da2e3ebdSchin 
74da2e3ebdSchin static char*
getfield(register Field_t * f,int restore)75da2e3ebdSchin getfield(register Field_t* f, int restore)
76da2e3ebdSchin {
77da2e3ebdSchin 	register char*	s;
78da2e3ebdSchin 	register int	n;
79da2e3ebdSchin 	register int	c;
80da2e3ebdSchin 	register int	lp;
81da2e3ebdSchin 	register int	rp;
82da2e3ebdSchin 	char*		b;
83da2e3ebdSchin 
84da2e3ebdSchin 	if (!f->delimiter)
85da2e3ebdSchin 		return 0;
86da2e3ebdSchin 	s = f->next;
87da2e3ebdSchin 	if (f->first)
88da2e3ebdSchin 		f->first = 0;
89da2e3ebdSchin 	else if (restore)
90da2e3ebdSchin 		*s = f->delimiter;
91da2e3ebdSchin 	b = ++s;
92da2e3ebdSchin 	lp = rp = n = 0;
93da2e3ebdSchin 	for (;;)
94da2e3ebdSchin 	{
95da2e3ebdSchin 		if (!(c = *s++))
96da2e3ebdSchin 		{
97da2e3ebdSchin 			f->delimiter = 0;
98da2e3ebdSchin 			break;
99da2e3ebdSchin 		}
100da2e3ebdSchin 		else if (c == CC_esc || c == '\\')
101da2e3ebdSchin 		{
102da2e3ebdSchin 			if (*s)
103da2e3ebdSchin 				s++;
104da2e3ebdSchin 		}
105da2e3ebdSchin 		else if (c == lp)
106da2e3ebdSchin 			n++;
107da2e3ebdSchin 		else if (c == rp)
108da2e3ebdSchin 			n--;
109da2e3ebdSchin 		else if (n <= 0)
110da2e3ebdSchin 		{
111da2e3ebdSchin 			if (c == '(' && restore)
112da2e3ebdSchin 			{
113da2e3ebdSchin 				lp = '(';
114da2e3ebdSchin 				rp = ')';
115da2e3ebdSchin 				n = 1;
116da2e3ebdSchin 			}
117da2e3ebdSchin 			else if (c == '[' && restore)
118da2e3ebdSchin 			{
119da2e3ebdSchin 				lp = '[';
120da2e3ebdSchin 				rp = ']';
121da2e3ebdSchin 				n = 1;
122da2e3ebdSchin 			}
123da2e3ebdSchin 			else if (c == f->delimiter)
124da2e3ebdSchin 			{
125da2e3ebdSchin 				*(f->next = --s) = 0;
126da2e3ebdSchin 				break;
127da2e3ebdSchin 			}
128da2e3ebdSchin 		}
129da2e3ebdSchin 	}
130da2e3ebdSchin 	return b;
131da2e3ebdSchin }
132da2e3ebdSchin 
133da2e3ebdSchin /*
134da2e3ebdSchin  * sfio %! extension function
135da2e3ebdSchin  */
136da2e3ebdSchin 
137da2e3ebdSchin static int
getfmt(Sfio_t * sp,void * vp,Sffmt_t * dp)138da2e3ebdSchin getfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
139da2e3ebdSchin {
140da2e3ebdSchin 	register Fmt_t*	fp = (Fmt_t*)dp;
141da2e3ebdSchin 	Value_t*	value = (Value_t*)vp;
142da2e3ebdSchin 	register char*	v;
143da2e3ebdSchin 	char*		t;
144da2e3ebdSchin 	char*		b;
145da2e3ebdSchin 	char*		a = 0;
146da2e3ebdSchin 	char*		s = 0;
147da2e3ebdSchin 	Sflong_t	n = 0;
148da2e3ebdSchin 	int		h = 0;
149da2e3ebdSchin 	int		i = 0;
150da2e3ebdSchin 	int		x = 0;
151da2e3ebdSchin 	int		d;
152da2e3ebdSchin 	Field_t		f;
153da2e3ebdSchin 	regmatch_t	match[10];
154da2e3ebdSchin 
155da2e3ebdSchin 	fp->level++;
156da2e3ebdSchin 	if (fp->fmt.t_str && fp->fmt.n_str > 0 && (v = fmtbuf(fp->fmt.n_str + 1)))
157da2e3ebdSchin 	{
158da2e3ebdSchin 		memcpy(v, fp->fmt.t_str, fp->fmt.n_str);
159da2e3ebdSchin 		v[fp->fmt.n_str] = 0;
160da2e3ebdSchin 		b = v;
161da2e3ebdSchin 		for (;;)
162da2e3ebdSchin 		{
163da2e3ebdSchin 			switch (*v++)
164da2e3ebdSchin 			{
165da2e3ebdSchin 			case 0:
166da2e3ebdSchin 				break;
167da2e3ebdSchin 			case '(':
168da2e3ebdSchin 				h++;
169da2e3ebdSchin 				continue;
170da2e3ebdSchin 			case ')':
171da2e3ebdSchin 				h--;
172da2e3ebdSchin 				continue;
173da2e3ebdSchin 			case '=':
174da2e3ebdSchin 			case ':':
175da2e3ebdSchin 			case ',':
176da2e3ebdSchin 				if (h <= 0)
177da2e3ebdSchin 				{
178da2e3ebdSchin 					a = v;
179da2e3ebdSchin 					break;
180da2e3ebdSchin 				}
181da2e3ebdSchin 				continue;
182da2e3ebdSchin 			default:
183da2e3ebdSchin 				continue;
184da2e3ebdSchin 			}
185da2e3ebdSchin 			if (i = *--v)
186da2e3ebdSchin 			{
187da2e3ebdSchin 				*v = 0;
188da2e3ebdSchin 				if (i == ':' && fp->fmt.fmt == 's' && strlen(a) > 4 && !isalnum(*(a + 4)))
189da2e3ebdSchin 				{
190da2e3ebdSchin 					d = *(a + 4);
191da2e3ebdSchin 					*(a + 4) = 0;
192da2e3ebdSchin 					if (streq(a, "case"))
193da2e3ebdSchin 						x = FMT_case;
194da2e3ebdSchin 					else if (streq(a, "edit"))
195da2e3ebdSchin 						x = FMT_edit;
196da2e3ebdSchin 					*(a + 4) = d;
197da2e3ebdSchin 					if (x)
198da2e3ebdSchin 						a = 0;
199da2e3ebdSchin 				}
200da2e3ebdSchin 			}
201da2e3ebdSchin 			break;
202da2e3ebdSchin 		}
203da2e3ebdSchin 		n = i;
204da2e3ebdSchin 		t = fp->fmt.t_str;
205da2e3ebdSchin 		fp->fmt.t_str = b;
206da2e3ebdSchin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
207da2e3ebdSchin 		fp->fmt.t_str = t;
208da2e3ebdSchin 		if (i)
209da2e3ebdSchin 			*v++ = i;
210da2e3ebdSchin 	}
211da2e3ebdSchin 	else
212da2e3ebdSchin 	{
213da2e3ebdSchin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
214da2e3ebdSchin 		v = 0;
215da2e3ebdSchin 	}
216da2e3ebdSchin 	fp->fmt.flags |= SFFMT_VALUE;
217da2e3ebdSchin 	switch (fp->fmt.fmt)
218da2e3ebdSchin 	{
219da2e3ebdSchin 	case 'c':
220da2e3ebdSchin 		value->c = s ? *s : n;
221da2e3ebdSchin 		break;
222da2e3ebdSchin 	case 'd':
223da2e3ebdSchin 	case 'i':
224da2e3ebdSchin 		fp->fmt.size = sizeof(Sflong_t);
225da2e3ebdSchin 		value->q = (Sflong_t)(s ? strtoll(s, NiL, 0) : n);
226da2e3ebdSchin 		break;
227da2e3ebdSchin 	case 'o':
228da2e3ebdSchin 	case 'u':
229da2e3ebdSchin 	case 'x':
230da2e3ebdSchin 		fp->fmt.size = sizeof(Sflong_t);
231da2e3ebdSchin 		value->q = s ? (Sflong_t)strtoull(s, NiL, 0) : n;
232da2e3ebdSchin 		break;
233da2e3ebdSchin 	case 'p':
234da2e3ebdSchin 		if (s)
235da2e3ebdSchin 			n = strtoll(s, NiL, 0);
236da2e3ebdSchin 		value->p = pointerof(n);
237da2e3ebdSchin 		break;
238da2e3ebdSchin 	case 'q':
239da2e3ebdSchin 		if (s)
240da2e3ebdSchin 		{
241da2e3ebdSchin 			fp->fmt.fmt = 's';
242da2e3ebdSchin 			value->s = fmtquote(s, "$'", "'", strlen(s), 0);
243da2e3ebdSchin 		}
244da2e3ebdSchin 		else
245da2e3ebdSchin 		{
246da2e3ebdSchin 			fp->fmt.fmt = 'd';
247da2e3ebdSchin 			value->q = n;
248da2e3ebdSchin 		}
249da2e3ebdSchin 		break;
250da2e3ebdSchin 	case 's':
251da2e3ebdSchin 		if (!s && (!h || !fp->tmp[1] && !(fp->tmp[1] = sfstropen()) || sfprintf(fp->tmp[1], "%I*d", sizeof(n), n) <= 0 || !(s = sfstruse(fp->tmp[1]))))
252da2e3ebdSchin 			s = "";
253da2e3ebdSchin 		if (x)
254da2e3ebdSchin 		{
255da2e3ebdSchin 			h = 0;
256da2e3ebdSchin 			d = initfield(&f, v + 4);
257da2e3ebdSchin 			switch (x)
258da2e3ebdSchin 			{
259da2e3ebdSchin 			case FMT_case:
260da2e3ebdSchin 				while ((a = getfield(&f, 1)) && (v = getfield(&f, 0)))
261da2e3ebdSchin 				{
262da2e3ebdSchin 					if (strmatch(s, a))
263da2e3ebdSchin 					{
264da2e3ebdSchin 						Fmt_t	fmt;
265da2e3ebdSchin 
266da2e3ebdSchin 						fmt = *fp;
267da2e3ebdSchin 						fmt.fmt.form = v;
268da2e3ebdSchin 						for (h = 0; h < elementsof(fmt.tmp); h++)
269da2e3ebdSchin 							fmt.tmp[h] = 0;
270da2e3ebdSchin 						if (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%!", &fmt) <= 0 || !(s = sfstruse(fp->tmp[0])))
271da2e3ebdSchin 							s = "";
272da2e3ebdSchin 						*(v - 1) = d;
273da2e3ebdSchin 						if (f.delimiter)
274da2e3ebdSchin 							*f.next = d;
275da2e3ebdSchin 						for (h = 0; h < elementsof(fmt.tmp); h++)
276da2e3ebdSchin 							if (fmt.tmp[h])
277da2e3ebdSchin 								sfclose(fmt.tmp[h]);
278da2e3ebdSchin 						h = 1;
279da2e3ebdSchin 						break;
280da2e3ebdSchin 					}
281da2e3ebdSchin 					*(v - 1) = d;
282da2e3ebdSchin 				}
283da2e3ebdSchin 				break;
284da2e3ebdSchin 			case FMT_edit:
285da2e3ebdSchin 				for (x = 0; *f.next; x ^= 1)
286da2e3ebdSchin 				{
287da2e3ebdSchin 					if (fp->re[x])
288da2e3ebdSchin 						regfree(fp->re[x]);
289da2e3ebdSchin 					else
290da2e3ebdSchin 						fp->re[x] = &fp->red[x];
291da2e3ebdSchin 					if (regcomp(fp->re[x], f.next, REG_DELIMITED|REG_NULL))
292da2e3ebdSchin 						break;
293da2e3ebdSchin 					f.next += fp->re[x]->re_npat;
294da2e3ebdSchin 					if (regsubcomp(fp->re[x], f.next, NiL, 0, 0))
295da2e3ebdSchin 						break;
296da2e3ebdSchin 					f.next += fp->re[x]->re_npat;
297da2e3ebdSchin 					if (!regexec(fp->re[x], s, elementsof(match), match, 0) && !regsubexec(fp->re[x], s, elementsof(match), match))
298da2e3ebdSchin 					{
299da2e3ebdSchin 						s = fp->re[x]->re_sub->re_buf;
300da2e3ebdSchin 						if (fp->re[x]->re_sub->re_flags & REG_SUB_STOP)
301da2e3ebdSchin 							break;
302da2e3ebdSchin 					}
303da2e3ebdSchin 				}
304da2e3ebdSchin 				h = 1;
305da2e3ebdSchin 				break;
306da2e3ebdSchin 			}
307da2e3ebdSchin 			if (!h)
308da2e3ebdSchin 				s = "";
309da2e3ebdSchin 		}
310da2e3ebdSchin 		value->s = s;
311da2e3ebdSchin 		if (fp->level == 1)
312da2e3ebdSchin 			while ((s = strchr(s, CC_esc)) && *(s + 1) == '[')
313da2e3ebdSchin 				do fp->invisible++; while (*s && !islower(*s++));
314da2e3ebdSchin 		break;
315da2e3ebdSchin 	case 'Z':
316da2e3ebdSchin 		fp->fmt.fmt = 'c';
317da2e3ebdSchin 		value->c = 0;
318da2e3ebdSchin 		break;
319da2e3ebdSchin 	case '\n':
320da2e3ebdSchin 		value->s = "\n";
321da2e3ebdSchin 		break;
322da2e3ebdSchin 	case '.':
323da2e3ebdSchin 		value->i = n;
324da2e3ebdSchin 		break;
325da2e3ebdSchin 	default:
326da2e3ebdSchin 		if ((!fp->convert || !(value->s = (*fp->convert)(fp->handle, &fp->fmt, a, s, n))) && (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%%%c", fp->fmt.fmt) <= 0 || !(value->s = sfstruse(fp->tmp[0]))))
327da2e3ebdSchin 			value->s = "";
328da2e3ebdSchin 		break;
329da2e3ebdSchin 	}
330da2e3ebdSchin 	fp->level--;
331da2e3ebdSchin 	return 0;
332da2e3ebdSchin }
333da2e3ebdSchin 
334da2e3ebdSchin /*
335*b30d1939SAndy Fiddaman  * this is the original interface
336da2e3ebdSchin  */
337da2e3ebdSchin 
338*b30d1939SAndy Fiddaman #undef	sfkeyprintf
339*b30d1939SAndy Fiddaman 
340da2e3ebdSchin int
sfkeyprintf(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)341da2e3ebdSchin sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
342da2e3ebdSchin {
343da2e3ebdSchin 	register int	i;
344da2e3ebdSchin 	int		r;
345da2e3ebdSchin 	Fmt_t		fmt;
346da2e3ebdSchin 
347da2e3ebdSchin 	memset(&fmt, 0, sizeof(fmt));
348da2e3ebdSchin 	fmt.fmt.version = SFIO_VERSION;
349da2e3ebdSchin 	fmt.fmt.form = (char*)format;
350da2e3ebdSchin 	fmt.fmt.extf = getfmt;
351da2e3ebdSchin 	fmt.handle = handle;
352da2e3ebdSchin 	fmt.lookup = lookup;
353da2e3ebdSchin 	fmt.convert = convert;
354da2e3ebdSchin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
355da2e3ebdSchin 	for (i = 0; i < elementsof(fmt.tmp); i++)
356da2e3ebdSchin 		if (fmt.tmp[i])
357da2e3ebdSchin 			sfclose(fmt.tmp[i]);
358*b30d1939SAndy Fiddaman 	for (i = 0; i < elementsof(fmt.re); i++)
359*b30d1939SAndy Fiddaman 		if (fmt.re[i])
360*b30d1939SAndy Fiddaman 			regfree(fmt.re[i]);
361da2e3ebdSchin 	return r;
362da2e3ebdSchin }
363da2e3ebdSchin 
364*b30d1939SAndy Fiddaman #undef	_AST_API_H
365*b30d1939SAndy Fiddaman 
366*b30d1939SAndy Fiddaman #include <ast_api.h>
367*b30d1939SAndy Fiddaman 
368da2e3ebdSchin /*
369*b30d1939SAndy Fiddaman  * Sffmt_t* callback args
370da2e3ebdSchin  */
371da2e3ebdSchin 
372da2e3ebdSchin int
sfkeyprintf_20000308(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)373*b30d1939SAndy Fiddaman sfkeyprintf_20000308(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
374da2e3ebdSchin {
375da2e3ebdSchin 	register int	i;
376da2e3ebdSchin 	int		r;
377da2e3ebdSchin 	Fmt_t		fmt;
378da2e3ebdSchin 
379da2e3ebdSchin 	memset(&fmt, 0, sizeof(fmt));
380*b30d1939SAndy Fiddaman 	fmt.version = 20030909;
381da2e3ebdSchin 	fmt.fmt.version = SFIO_VERSION;
382da2e3ebdSchin 	fmt.fmt.form = (char*)format;
383da2e3ebdSchin 	fmt.fmt.extf = getfmt;
384da2e3ebdSchin 	fmt.handle = handle;
385da2e3ebdSchin 	fmt.lookup = lookup;
386da2e3ebdSchin 	fmt.convert = convert;
387da2e3ebdSchin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
388da2e3ebdSchin 	for (i = 0; i < elementsof(fmt.tmp); i++)
389da2e3ebdSchin 		if (fmt.tmp[i])
390da2e3ebdSchin 			sfclose(fmt.tmp[i]);
391da2e3ebdSchin 	return r;
392da2e3ebdSchin }
393