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