1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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
40 typedef 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
54 typedef struct
55 {
56 char* next;
57 int delimiter;
58 int first;
59 } Field_t;
60
61 typedef 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
74 static char*
getfield(register Field_t * f,int restore)75 getfield(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
137 static int
getfmt(Sfio_t * sp,void * vp,Sffmt_t * dp)138 getfmt(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 20000308 interface with Sffmt_t* callback args
336 */
337
338 int
sfkeyprintf(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)339 sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
340 {
341 register int i;
342 int r;
343 Fmt_t fmt;
344
345 memset(&fmt, 0, sizeof(fmt));
346 fmt.version = 20030909;
347 fmt.fmt.version = SFIO_VERSION;
348 fmt.fmt.form = (char*)format;
349 fmt.fmt.extf = getfmt;
350 fmt.handle = handle;
351 fmt.lookup = lookup;
352 fmt.convert = convert;
353 r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
354 for (i = 0; i < elementsof(fmt.tmp); i++)
355 if (fmt.tmp[i])
356 sfclose(fmt.tmp[i]);
357 return r;
358 }
359
360 /*
361 * this is the original interface
362 */
363
364 #undef sfkeyprintf
365
366 int
sfkeyprintf(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)367 sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
368 {
369 register int i;
370 int r;
371 Fmt_t fmt;
372
373 memset(&fmt, 0, sizeof(fmt));
374 fmt.fmt.version = SFIO_VERSION;
375 fmt.fmt.form = (char*)format;
376 fmt.fmt.extf = getfmt;
377 fmt.handle = handle;
378 fmt.lookup = lookup;
379 fmt.convert = convert;
380 r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
381 for (i = 0; i < elementsof(fmt.tmp); i++)
382 if (fmt.tmp[i])
383 sfclose(fmt.tmp[i]);
384 for (i = 0; i < elementsof(fmt.re); i++)
385 if (fmt.re[i])
386 regfree(fmt.re[i]);
387 return r;
388 }
389