1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * keyword printf support
1N/A */
1N/A
1N/A#define _AST_API_H 1
1N/A
1N/A#include <ast.h>
1N/A#include <ccode.h>
1N/A#include <ctype.h>
1N/A#include <sfdisc.h>
1N/A#include <regex.h>
1N/A
1N/A#define FMT_case 1
1N/A#define FMT_edit 2
1N/A
1N/Atypedef struct
1N/A{
1N/A Sffmt_t fmt;
1N/A void* handle;
1N/A Sf_key_lookup_t lookup;
1N/A Sf_key_convert_t convert;
1N/A Sfio_t* tmp[2];
1N/A regex_t red[2];
1N/A regex_t* re[2];
1N/A int invisible;
1N/A int level;
1N/A int version;
1N/A} Fmt_t;
1N/A
1N/Atypedef struct
1N/A{
1N/A char* next;
1N/A int delimiter;
1N/A int first;
1N/A} Field_t;
1N/A
1N/Atypedef union
1N/A{
1N/A char** p;
1N/A char* s;
1N/A Sflong_t q;
1N/A long l;
1N/A int i;
1N/A short h;
1N/A char c;
1N/A} Value_t;
1N/A
1N/A#define initfield(f,s) ((f)->first = (f)->delimiter = *((f)->next = (s)))
1N/A
1N/Astatic char*
1N/Agetfield(register Field_t* f, int restore)
1N/A{
1N/A register char* s;
1N/A register int n;
1N/A register int c;
1N/A register int lp;
1N/A register int rp;
1N/A char* b;
1N/A
1N/A if (!f->delimiter)
1N/A return 0;
1N/A s = f->next;
1N/A if (f->first)
1N/A f->first = 0;
1N/A else if (restore)
1N/A *s = f->delimiter;
1N/A b = ++s;
1N/A lp = rp = n = 0;
1N/A for (;;)
1N/A {
1N/A if (!(c = *s++))
1N/A {
1N/A f->delimiter = 0;
1N/A break;
1N/A }
1N/A else if (c == CC_esc || c == '\\')
1N/A {
1N/A if (*s)
1N/A s++;
1N/A }
1N/A else if (c == lp)
1N/A n++;
1N/A else if (c == rp)
1N/A n--;
1N/A else if (n <= 0)
1N/A {
1N/A if (c == '(' && restore)
1N/A {
1N/A lp = '(';
1N/A rp = ')';
1N/A n = 1;
1N/A }
1N/A else if (c == '[' && restore)
1N/A {
1N/A lp = '[';
1N/A rp = ']';
1N/A n = 1;
1N/A }
1N/A else if (c == f->delimiter)
1N/A {
1N/A *(f->next = --s) = 0;
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A return b;
1N/A}
1N/A
1N/A/*
1N/A * sfio %! extension function
1N/A */
1N/A
1N/Astatic int
1N/Agetfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
1N/A{
1N/A register Fmt_t* fp = (Fmt_t*)dp;
1N/A Value_t* value = (Value_t*)vp;
1N/A register char* v;
1N/A char* t;
1N/A char* b;
1N/A char* a = 0;
1N/A char* s = 0;
1N/A Sflong_t n = 0;
1N/A int h = 0;
1N/A int i = 0;
1N/A int x = 0;
1N/A int d;
1N/A Field_t f;
1N/A regmatch_t match[10];
1N/A
1N/A fp->level++;
1N/A if (fp->fmt.t_str && fp->fmt.n_str > 0 && (v = fmtbuf(fp->fmt.n_str + 1)))
1N/A {
1N/A memcpy(v, fp->fmt.t_str, fp->fmt.n_str);
1N/A v[fp->fmt.n_str] = 0;
1N/A b = v;
1N/A for (;;)
1N/A {
1N/A switch (*v++)
1N/A {
1N/A case 0:
1N/A break;
1N/A case '(':
1N/A h++;
1N/A continue;
1N/A case ')':
1N/A h--;
1N/A continue;
1N/A case '=':
1N/A case ':':
1N/A case ',':
1N/A if (h <= 0)
1N/A {
1N/A a = v;
1N/A break;
1N/A }
1N/A continue;
1N/A default:
1N/A continue;
1N/A }
1N/A if (i = *--v)
1N/A {
1N/A *v = 0;
1N/A if (i == ':' && fp->fmt.fmt == 's' && strlen(a) > 4 && !isalnum(*(a + 4)))
1N/A {
1N/A d = *(a + 4);
1N/A *(a + 4) = 0;
1N/A if (streq(a, "case"))
1N/A x = FMT_case;
1N/A else if (streq(a, "edit"))
1N/A x = FMT_edit;
1N/A *(a + 4) = d;
1N/A if (x)
1N/A a = 0;
1N/A }
1N/A }
1N/A break;
1N/A }
1N/A n = i;
1N/A t = fp->fmt.t_str;
1N/A fp->fmt.t_str = b;
1N/A h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
1N/A fp->fmt.t_str = t;
1N/A if (i)
1N/A *v++ = i;
1N/A }
1N/A else
1N/A {
1N/A h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
1N/A v = 0;
1N/A }
1N/A fp->fmt.flags |= SFFMT_VALUE;
1N/A switch (fp->fmt.fmt)
1N/A {
1N/A case 'c':
1N/A value->c = s ? *s : n;
1N/A break;
1N/A case 'd':
1N/A case 'i':
1N/A fp->fmt.size = sizeof(Sflong_t);
1N/A value->q = (Sflong_t)(s ? strtoll(s, NiL, 0) : n);
1N/A break;
1N/A case 'o':
1N/A case 'u':
1N/A case 'x':
1N/A fp->fmt.size = sizeof(Sflong_t);
1N/A value->q = s ? (Sflong_t)strtoull(s, NiL, 0) : n;
1N/A break;
1N/A case 'p':
1N/A if (s)
1N/A n = strtoll(s, NiL, 0);
1N/A value->p = pointerof(n);
1N/A break;
1N/A case 'q':
1N/A if (s)
1N/A {
1N/A fp->fmt.fmt = 's';
1N/A value->s = fmtquote(s, "$'", "'", strlen(s), 0);
1N/A }
1N/A else
1N/A {
1N/A fp->fmt.fmt = 'd';
1N/A value->q = n;
1N/A }
1N/A break;
1N/A case 's':
1N/A 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]))))
1N/A s = "";
1N/A if (x)
1N/A {
1N/A h = 0;
1N/A d = initfield(&f, v + 4);
1N/A switch (x)
1N/A {
1N/A case FMT_case:
1N/A while ((a = getfield(&f, 1)) && (v = getfield(&f, 0)))
1N/A {
1N/A if (strmatch(s, a))
1N/A {
1N/A Fmt_t fmt;
1N/A
1N/A fmt = *fp;
1N/A fmt.fmt.form = v;
1N/A for (h = 0; h < elementsof(fmt.tmp); h++)
1N/A fmt.tmp[h] = 0;
1N/A if (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%!", &fmt) <= 0 || !(s = sfstruse(fp->tmp[0])))
1N/A s = "";
1N/A *(v - 1) = d;
1N/A if (f.delimiter)
1N/A *f.next = d;
1N/A for (h = 0; h < elementsof(fmt.tmp); h++)
1N/A if (fmt.tmp[h])
1N/A sfclose(fmt.tmp[h]);
1N/A h = 1;
1N/A break;
1N/A }
1N/A *(v - 1) = d;
1N/A }
1N/A break;
1N/A case FMT_edit:
1N/A for (x = 0; *f.next; x ^= 1)
1N/A {
1N/A if (fp->re[x])
1N/A regfree(fp->re[x]);
1N/A else
1N/A fp->re[x] = &fp->red[x];
1N/A if (regcomp(fp->re[x], f.next, REG_DELIMITED|REG_NULL))
1N/A break;
1N/A f.next += fp->re[x]->re_npat;
1N/A if (regsubcomp(fp->re[x], f.next, NiL, 0, 0))
1N/A break;
1N/A f.next += fp->re[x]->re_npat;
1N/A if (!regexec(fp->re[x], s, elementsof(match), match, 0) && !regsubexec(fp->re[x], s, elementsof(match), match))
1N/A {
1N/A s = fp->re[x]->re_sub->re_buf;
1N/A if (fp->re[x]->re_sub->re_flags & REG_SUB_STOP)
1N/A break;
1N/A }
1N/A }
1N/A h = 1;
1N/A break;
1N/A }
1N/A if (!h)
1N/A s = "";
1N/A }
1N/A value->s = s;
1N/A if (fp->level == 1)
1N/A while ((s = strchr(s, CC_esc)) && *(s + 1) == '[')
1N/A do fp->invisible++; while (*s && !islower(*s++));
1N/A break;
1N/A case 'Z':
1N/A fp->fmt.fmt = 'c';
1N/A value->c = 0;
1N/A break;
1N/A case '\n':
1N/A value->s = "\n";
1N/A break;
1N/A case '.':
1N/A value->i = n;
1N/A break;
1N/A default:
1N/A 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]))))
1N/A value->s = "";
1N/A break;
1N/A }
1N/A fp->level--;
1N/A return 0;
1N/A}
1N/A
1N/A/*
1N/A * this is the original interface
1N/A */
1N/A
1N/Aint
1N/Asfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
1N/A{
1N/A register int i;
1N/A int r;
1N/A Fmt_t fmt;
1N/A
1N/A memset(&fmt, 0, sizeof(fmt));
1N/A fmt.fmt.version = SFIO_VERSION;
1N/A fmt.fmt.form = (char*)format;
1N/A fmt.fmt.extf = getfmt;
1N/A fmt.handle = handle;
1N/A fmt.lookup = lookup;
1N/A fmt.convert = convert;
1N/A r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
1N/A for (i = 0; i < elementsof(fmt.tmp); i++)
1N/A if (fmt.tmp[i])
1N/A sfclose(fmt.tmp[i]);
1N/A for (i = 0; i < elementsof(fmt.re); i++)
1N/A if (fmt.re[i])
1N/A regfree(fmt.re[i]);
1N/A return r;
1N/A}
1N/A
1N/A#undef _AST_API_H
1N/A
1N/A#include <ast_api.h>
1N/A
1N/A/*
1N/A * Sffmt_t* callback args
1N/A */
1N/A
1N/Aint
1N/Asfkeyprintf_20000308(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
1N/A{
1N/A register int i;
1N/A int r;
1N/A Fmt_t fmt;
1N/A
1N/A memset(&fmt, 0, sizeof(fmt));
1N/A fmt.version = 20030909;
1N/A fmt.fmt.version = SFIO_VERSION;
1N/A fmt.fmt.form = (char*)format;
1N/A fmt.fmt.extf = getfmt;
1N/A fmt.handle = handle;
1N/A fmt.lookup = lookup;
1N/A fmt.convert = convert;
1N/A r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
1N/A for (i = 0; i < elementsof(fmt.tmp); i++)
1N/A if (fmt.tmp[i])
1N/A sfclose(fmt.tmp[i]);
1N/A return r;
1N/A}