From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- cyclone/hammer/sprintf.c | 634 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 cyclone/hammer/sprintf.c (limited to 'cyclone/hammer/sprintf.c') diff --git a/cyclone/hammer/sprintf.c b/cyclone/hammer/sprintf.c new file mode 100644 index 0000000..aebfed3 --- /dev/null +++ b/cyclone/hammer/sprintf.c @@ -0,0 +1,634 @@ +/* Copyright (c) 2002-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* FIXME empty string as a default for %s */ + +#include +#include +#include "m_pd.h" +#include "common/loud.h" + +#define SPRINTF_DEBUG 0 + +/* Pattern types. These are the parsing routine's return values. + If returned value is >= SPRINTF_MINSLOTTYPE, then another slot + is created (i.e. an inlet, and a proxy handling it). */ +#define SPRINTF_UNSUPPORTED 0 +#define SPRINTF_LITERAL 1 +#define SPRINTF_MINSLOTTYPE 2 +#define SPRINTF_INT 2 +#define SPRINTF_FLOAT 3 +#define SPRINTF_CHAR 4 +#define SPRINTF_STRING 5 + +/* Numbers: assuming max 62 digits preceding a decimal point in any + fixed-point representation of a t_float (39 in my system) + -- need to be sure, that using max precision would never produce + a representation longer than max width. If this is so, then no number + representation would exceed max width (presumably...). + Strings: for the time being, any string longer than max width would + be truncated (somehow compatible with Str256, but LATER warn-and-allow). */ +/* LATER rethink it all */ +#define SPRINTF_MAXPRECISION 192 +#define SPRINTF_MAXWIDTH 256 + +typedef struct _sprintf +{ + t_object x_ob; + int x_nslots; + int x_nproxies; /* as requested (and allocated) */ + t_pd **x_proxies; + int x_fsize; /* as allocated (i.e. including a terminating 0) */ + char *x_fstring; +} t_sprintf; + +typedef struct _sprintf_proxy +{ + t_object p_ob; + t_sprintf *p_master; + int p_id; + int p_type; /* a value #defined above */ + char *p_pattern; + char *p_pattend; + t_atom p_atom; /* current input */ + int p_size; /* also an input validation flag */ +} t_sprintf_proxy; + +static t_class *sprintf_class; +static t_class *sprintf_proxy_class; + +/* CHECKED: 'symout' argument has no special meaning in max4.07, + LATER investigate */ + +/* LATER use snprintf, if it is available on other systems (should be...) */ +static void sprintf_proxy_checkit(t_sprintf_proxy *x, char *buf, int checkin) +{ + int result = 0; + char *pattend = x->p_pattend; + if (pattend) + { + char tmp = *pattend; + *pattend = 0; + if (x->p_atom.a_type == A_FLOAT) + { + t_float f = x->p_atom.a_w.w_float; + if (x->p_type == SPRINTF_INT) + /* CHECKME large/negative values */ + result = sprintf(buf, x->p_pattern, (int)f); + else if (x->p_type == SPRINTF_FLOAT) + result = sprintf(buf, x->p_pattern, f); + else if (x->p_type == SPRINTF_CHAR) + /* CHECKED: if 0 is input into a %c-slot, the whole output + string is null-terminated */ + /* CHECKED: float into a %c-slot is truncated, + but CHECKME large/negative values */ + result = sprintf(buf, x->p_pattern, (unsigned char)f); + else if (x->p_type == SPRINTF_STRING) + { + /* CHECKED: any number input into a %s-slot is ok */ + char tmp[64]; /* LATER rethink */ + sprintf(tmp, "%g", f); + result = sprintf(buf, x->p_pattern, tmp); + } + else /* LATER consider calling it a bug(), rather than error? */ + loud_error((t_pd *)x->p_master, + "can't convert float to type of argument %d", + x->p_id + 1); + } + else if (x->p_atom.a_type == A_SYMBOL) + { + t_symbol *s = x->p_atom.a_w.w_symbol; + if (x->p_type == SPRINTF_STRING) + { + if (strlen(s->s_name) > SPRINTF_MAXWIDTH) + { + strncpy(buf, s->s_name, SPRINTF_MAXWIDTH); + buf[SPRINTF_MAXWIDTH] = 0; + result = SPRINTF_MAXWIDTH; + } + else result = sprintf(buf, x->p_pattern, s->s_name); + } + else /* CHECKED */ + loud_error((t_pd *)x->p_master, + "can't convert symbol to type of argument %d", + x->p_id + 1); + } + *pattend = tmp; + } + else bug("sprintf_proxy_checkit"); + if (result > 0) + { +#if SPRINTF_DEBUG + if (checkin) post("[%d in \"%s\"]", result, buf); +#endif + x->p_size = result; + } + else + { +#if SPRINTF_DEBUG + if (checkin) post("checkit failed"); +#endif + x->p_size = 0; + } +} + +static void sprintf_dooutput(t_sprintf *x) +{ + int i, outsize; + char *outstring; + outsize = x->x_fsize; /* this is strlen() + 1 */ + /* LATER consider subtracting format pattern sizes */ + for (i = 0; i < x->x_nslots; i++) + { + t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i]; + if (y->p_size) + outsize += y->p_size; + else + { + /* slot i has received an invalid input -- CHECKME if this + condition blocks all subsequent output requests? */ + return; + } + } + if (outsize > 0 && (outstring = getbytes(outsize))) + { + char *inp = x->x_fstring; + char *outp = outstring; + for (i = 0; i < x->x_nslots; i++) + { + t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i]; + int len = y->p_pattern - inp; + if (len > 0) + { + strncpy(outp, inp, len); + outp += len; + } + sprintf_proxy_checkit(y, outp, 0); + outp += y->p_size; /* p_size is never negative */ + inp = y->p_pattend; + } + strcpy(outp, inp); + + outp = outstring; + while (*outp == ' ' || *outp == '\t' + || *outp == '\n' || *outp == '\r') outp++; + if (*outp) + { + t_binbuf *bb = binbuf_new(); + int ac; + t_atom *av; + binbuf_text(bb, outp, strlen(outp)); + ac = binbuf_getnatom(bb); + av = binbuf_getvec(bb); + if (ac) + { + if (av->a_type == A_SYMBOL) + outlet_anything(((t_object *)x)->ob_outlet, + av->a_w.w_symbol, ac - 1, av + 1); + else if (av->a_type == A_FLOAT) + { + if (ac > 1) + outlet_list(((t_object *)x)->ob_outlet, + &s_list, ac, av); + else + outlet_float(((t_object *)x)->ob_outlet, + av->a_w.w_float); + } + } + binbuf_free(bb); + } + freebytes(outstring, outsize); + } +} + +static void sprintf_proxy_bang(t_sprintf_proxy *x) +{ + sprintf_dooutput(x->p_master); /* CHECKED (in any inlet) */ +} + +static void sprintf_proxy_float(t_sprintf_proxy *x, t_float f) +{ + char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */ + SETFLOAT(&x->p_atom, f); + sprintf_proxy_checkit(x, buf, 1); + if (x->p_id == 0 && x->p_size) + sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */ +} + +static void sprintf_proxy_symbol(t_sprintf_proxy *x, t_symbol *s) +{ + char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */ + if (s && *s->s_name) + SETSYMBOL(&x->p_atom, s); + else + SETFLOAT(&x->p_atom, 0); + sprintf_proxy_checkit(x, buf, 1); + if (x->p_id == 0 && x->p_size) + sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */ +} + +static void sprintf_dolist(t_sprintf *x, + t_symbol *s, int ac, t_atom *av, int startid) +{ + int cnt = x->x_nslots - startid; + if (ac > cnt) + ac = cnt; + if (ac-- > 0) + { + int id; + for (id = startid + ac, av += ac; id >= startid; id--, av--) + { + if (av->a_type == A_FLOAT) + sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[id], + av->a_w.w_float); + else if (av->a_type == A_SYMBOL) + sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[id], + av->a_w.w_symbol); + } + } +} + +static void sprintf_doanything(t_sprintf *x, + t_symbol *s, int ac, t_atom *av, int startid) +{ + if (s && s != &s_) + { + sprintf_dolist(x, 0, ac, av, startid + 1); + sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[startid], s); + } + else sprintf_dolist(x, 0, ac, av, startid); +} + +static void sprintf_proxy_list(t_sprintf_proxy *x, + t_symbol *s, int ac, t_atom *av) +{ + sprintf_dolist(x->p_master, s, ac, av, x->p_id); +} + +static void sprintf_proxy_anything(t_sprintf_proxy *x, + t_symbol *s, int ac, t_atom *av) +{ + sprintf_doanything(x->p_master, s, ac, av, x->p_id); +} + +static void sprintf_bang(t_sprintf *x) +{ + if (x->x_nslots) + sprintf_proxy_bang((t_sprintf_proxy *)x->x_proxies[0]); +} + +static void sprintf_float(t_sprintf *x, t_float f) +{ + if (x->x_nslots) + sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[0], f); +} + +static void sprintf_symbol(t_sprintf *x, t_symbol *s) +{ + if (x->x_nslots) + sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[0], s); +} + +static void sprintf_list(t_sprintf *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->x_nslots) + sprintf_dolist(x, s, ac, av, 0); +} + +static void sprintf_anything(t_sprintf *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->x_nslots) + sprintf_doanything(x, s, ac, av, 0); +} + +/* adjusted binbuf_gettext(), LATER do it right */ +static char *hammer_gettext(int ac, t_atom *av, int *sizep) +{ + char *buf = getbytes(1); + int size = 1; + char atomtext[MAXPDSTRING]; + while (ac--) + { + char *newbuf; + int newsize; + if (buf[size-1] == 0 || av->a_type == A_SEMI || av->a_type == A_COMMA) + size--; + atom_string(av, atomtext, MAXPDSTRING); + newsize = size + strlen(atomtext) + 1; + if (!(newbuf = resizebytes(buf, size, newsize))) + { + *sizep = 1; + return (getbytes(1)); + } + buf = newbuf; + strcpy(buf + size, atomtext); + size = newsize; + buf[size-1] = ' '; + av++; + } + buf[size-1] = 0; + *sizep = size; + return (buf); +} + +/* Called twice: 1st pass (with x == 0) is used for counting valid patterns; + 2nd pass (after object allocation) -- for initializing the proxies. + If there is a "%%" pattern, then the buffer is shrinked in the second pass + (LATER rethink). */ +static int sprintf_parsepattern(t_sprintf *x, char **patternp) +{ + int type = SPRINTF_UNSUPPORTED; + char errstring[MAXPDSTRING]; + char *ptr; + char modifier = 0; + int width = 0; + int precision = 0; + int *numfield = &width; + int dotseen = 0; + *errstring = 0; + for (ptr = *patternp; *ptr; ptr++) + { + if (*ptr >= '0' && *ptr <= '9') + { + if (!numfield) + { + if (x) sprintf(errstring, "extra number field"); + break; + } + *numfield = 10 * *numfield + *ptr - '0'; + if (dotseen) + { + if (precision > SPRINTF_MAXPRECISION) + { + if (x) sprintf(errstring, "precision field too large"); + break; + } + } + else + { + if (width > SPRINTF_MAXWIDTH) + { + if (x) sprintf(errstring, "width field too large"); + break; + } + } + continue; + } + if (*numfield) + numfield = 0; + + if (strchr("diouxX", *ptr)) + { + type = SPRINTF_INT; + break; + } + else if (strchr("aAeEfgG", *ptr)) + { + if (modifier) + { + if (x) sprintf(errstring, + "\'%c\' modifier not supported", modifier); + break; + } + type = SPRINTF_FLOAT; + break; + } + else if (strchr("c", *ptr)) + { + if (modifier) + { + if (x) sprintf(errstring, + "\'%c\' modifier not supported", modifier); + break; + } + type = SPRINTF_CHAR; + break; + } + else if (strchr("s", *ptr)) + { + if (modifier) + { + if (x) sprintf(errstring, + "\'%c\' modifier not supported", modifier); + break; + } + type = SPRINTF_STRING; + break; + } + else if (*ptr == '%') + { + type = SPRINTF_LITERAL; + if (x) + { /* buffer-shrinking hack, LATER rethink */ + char *p1 = ptr, *p2 = ptr + 1; + do + *p1++ = *p2; + while (*p2++); + ptr--; + } + break; + } + else if (strchr("CSnm", *ptr)) + { + if (x) sprintf(errstring, "\'%c\' type not supported", *ptr); + break; + } + else if (strchr("l", *ptr)) + { + if (modifier) + { + if (x) sprintf(errstring, "only single modifier is supported"); + break; + } + modifier = *ptr; + } + else if (strchr("hjLqtzZ", *ptr)) + { + if (x) sprintf(errstring, "\'%c\' modifier not supported", *ptr); + break; + } + else if (*ptr == '.') + { + if (dotseen) + { + if (x) sprintf(errstring, "multiple dots"); + break; + } + numfield = &precision; + dotseen = 1; + } + else if (*ptr == '$') + { + if (x) sprintf(errstring, "parameter number field not supported"); + break; + } + else if (*ptr == '*') + { + if (x) sprintf(errstring, "%s parameter not supported", + (dotseen ? "precision" : "width")); + break; + } + else if (!strchr("-+ #\'", *ptr)) + { + if (x) sprintf(errstring, + "\'%c\' format character not supported", *ptr); + break; + } + } + if (*ptr) + ptr++; /* LATER rethink */ + else + if (x) sprintf(errstring, "type not specified"); + if (x && type == SPRINTF_UNSUPPORTED) + { + if (*errstring) + loud_error((t_pd *)x, "slot skipped (%s %s)", + errstring, "in a format pattern"); + else + loud_error((t_pd *)x, "slot skipped"); + } + *patternp = ptr; + return (type); +} + +static void sprintf_free(t_sprintf *x) +{ + if (x->x_proxies) + { + int i = x->x_nslots; + while (i--) + { + t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i]; + pd_free((t_pd *)y); + } + freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies)); + } + if (x->x_fstring) + freebytes(x->x_fstring, x->x_fsize); +} + +static void *sprintf_new(t_symbol *s, int ac, t_atom *av) +{ + t_sprintf *x; + int fsize; + char *fstring; + char *p1, *p2; + int i, nslots, nproxies = 0; + t_pd **proxies; + fstring = hammer_gettext(ac, av, &fsize); + p1 = fstring; + while (p2 = strchr(p1, '%')) + { + int type; + p1 = p2 + 1; + type = sprintf_parsepattern(0, &p1); + if (type >= SPRINTF_MINSLOTTYPE) + nproxies++; + } + if (!nproxies) + { + /* CHECKED: an object without arguments, if created in the editor, + has no inlets/outlets, but it would have one inlet (no outlets) + upon loading. Error message is printed in either case. */ + x = (t_sprintf *)pd_new(sprintf_class); + x->x_nslots = 0; + x->x_nproxies = 0; + x->x_proxies = 0; + x->x_fsize = fsize; + x->x_fstring = fstring; + p1 = fstring; + while (p2 = strchr(p1, '%')) + { + p1 = p2 + 1; + sprintf_parsepattern(x, &p1); + } + loud_error((t_pd *)x, + "an object created without valid format patterns..."); + return (x); + } +#if SPRINTF_DEBUG + post("%d slots:", nproxies); +#endif + /* CHECKED: max creates as many inlets, as there are %-signs, no matter + if they are valid, or not -- if not, it prints ``can't convert'' errors + for any input... */ + if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies)))) + { + freebytes(fstring, fsize); + return (0); + } + for (nslots = 0; nslots < nproxies; nslots++) + if (!(proxies[nslots] = pd_new(sprintf_proxy_class))) break; + if (!nslots) + { + freebytes(fstring, fsize); + freebytes(proxies, nproxies * sizeof(*proxies)); + return (0); + } + x = (t_sprintf *)pd_new(sprintf_class); + x->x_nslots = nslots; + x->x_nproxies = nproxies; + x->x_proxies = proxies; + x->x_fsize = fsize; + x->x_fstring = fstring; + p1 = fstring; + i = 0; + while (p2 = strchr(p1, '%')) + { + int type; + p1 = p2 + 1; + type = sprintf_parsepattern(x, &p1); + if (type >= SPRINTF_MINSLOTTYPE) + { +#if SPRINTF_DEBUG + char tmp = *++p1; + *p1 = 0; + poststring(p2); + endpost(); + *p1 = tmp; +#endif + if (i < nslots) + { + char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */ + t_sprintf_proxy *y = (t_sprintf_proxy *)proxies[i]; + y->p_master = x; + y->p_id = i; + y->p_type = type; + y->p_pattern = p2; + y->p_pattend = p1; + SETFLOAT(&y->p_atom, 0); + y->p_size = 0; + if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0); + sprintf_proxy_checkit(y, buf, 1); + i++; + } + } + } +#if SPRINTF_DEBUG + post("printf(\"%s\", ...)", fstring); +#endif + outlet_new((t_object *)x, &s_anything); + return (x); +} + +void sprintf_setup(void) +{ + sprintf_class = class_new(gensym("sprintf"), + (t_newmethod)sprintf_new, + (t_method)sprintf_free, + sizeof(t_sprintf), 0, A_GIMME, 0); + class_addbang(sprintf_class, sprintf_bang); + class_addfloat(sprintf_class, sprintf_float); + class_addsymbol(sprintf_class, sprintf_symbol); + class_addlist(sprintf_class, sprintf_list); + class_addanything(sprintf_class, sprintf_anything); + sprintf_proxy_class = class_new(gensym("_sprintf_proxy"), 0, 0, + sizeof(t_sprintf_proxy), + CLASS_PD | CLASS_NOINLET, 0); + class_addbang(sprintf_proxy_class, sprintf_proxy_bang); + class_addfloat(sprintf_proxy_class, sprintf_proxy_float); + class_addsymbol(sprintf_proxy_class, sprintf_proxy_symbol); + class_addlist(sprintf_proxy_class, sprintf_proxy_list); + class_addanything(sprintf_proxy_class, sprintf_proxy_anything); +} -- cgit v1.2.1