1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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* 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 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 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 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