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