diff --git a/pd/src/x_connective.c b/pd/src/x_connective.c index 2e61671dcb9802030c7657e506a822c148e5c137..eba1be124059507ca84a21608d1f039483224b1d 100644 --- a/pd/src/x_connective.c +++ b/pd/src/x_connective.c @@ -1449,50 +1449,251 @@ static void until_setup(void) static t_class *makefilename_class; +typedef enum { + NONE = 0, + INT, + FLOAT, + STRING, + POINTER, +} t_printtype; + typedef struct _makefilename { t_object x_obj; t_symbol *x_format; - t_atomtype x_accept; - int x_intconvert; + t_printtype x_accept; } t_makefilename; -static void makefilename_scanformat(t_makefilename *x) +static const char* makefilename_doscanformat(const char *str, t_printtype *typ, + char *errormsg) { - int infmt=0; - char *str; - if (!x->x_format) return; - x->x_accept = A_NULL; - for (str=x->x_format->s_name; *str; str++) + int infmt = 0, i, hashflag = 0, zeroflag = 0; + for (; *str; str++) { - if (!infmt && *str=='%') + if (!infmt && *str == '%') { - infmt=1; + /* A single '%' character isn't a valid. It needs a conversion + specifier ('g', 's', etc.) to follow it */ + if (*(str+1) == '\0') + { + str++; + sprintf(errormsg, "specifier missing"); + *typ = NONE; + return str; + } + infmt = 1; continue; } if (infmt) { - if (strchr("-.#0123456789",*str)!=0) + /* 1) flags + Check for "%%" which produces a literal '%' in the output */ + if (*str == '%') + { + /* Not in a format specifier after all, so let's reset + infmt and continue searching... */ + infmt = 0; continue; - if (*str=='s') + } + for (i = 0; *str && strchr("-+#0", *str) != 0; str++, i++) + { + /* Check for flags. While a space is a legal flag, Pd's + parser would split it off into a separate arg. And since + makefilename has always truncated extra args we don't + support spaces here. We also don't support the single + quote flag. + Some flag/specifier combinations can cause undefined + behavior so we need to track them. */ + + if (*str == '#') hashflag++; + if (*str == '0') zeroflag++; + + /* Since we're dealing with arbitrary input let's keep + the total number of flags sane. */ + if (i > 15) + { + sprintf(errormsg, "too many flags"); + *typ = NONE; + return str; + } + } + /* 2) width field + Consecutive digits. Technically a width field may also be + '*' to use a variable to set the value. But makefilename has + never supported that, either generating a memory error or crash + upon use. So we exclude it here. */ + if (*str == '*') { - x->x_accept = A_SYMBOL; - x->x_intconvert = 0; - break; + sprintf(errormsg, "variable width value not supported"); + *typ = NONE; + return str; } - if (strchr("fgGeE",*str)!=0) + int maxwidth = 3; + for (i = 0; *str && strchr("0123456789", *str) != 0; str++, i++) { - x->x_accept = A_FLOAT; - x->x_intconvert = 0; - break; + /* Limit width length to prevent out-of-memory errors. */ + if (i >= maxwidth) + { + sprintf(errormsg, "width field cannot be greater than " + "%d digits", maxwidth); + *typ = NONE; + return str; + } } - if (strchr("xXdiouc",*str)!=0) + /* 3) precision field + A '.' followed by consecutive digits. Can also have a '*' for + variable, so we need to check and exclude as with the width + field above. */ + if (*str == '.') { - x->x_accept = A_FLOAT; - x->x_intconvert = 1; - break; + str++; + if (*str == '*') + { + sprintf(errormsg, "variable precision field not supported"); + *typ = NONE; + return str; + } + int maxwidth = 3; + for (i = 0; *str && strchr("0123456789", *str) != 0; str++, i++) + { + if (i >= maxwidth) + { + sprintf(errormsg, "precision field cannot be greater " + "than %d digits", maxwidth); + *typ = NONE; + return str; + } + } + /* precision isn't defined for all conversion specifiers. */ + if (*str && strchr("diouxXeEfFgGs", *str) == 0) + { + sprintf(errormsg, "precision field restricted to " + "[diouxXeEfFgGs] specifiers"); + *typ = NONE; + return str; + } } - infmt=0; + /* 4) length field + Fairly certain the length field doesn't make any sense + here. At least I've never seen it used, so let's skip it. */ + + /* 5) conversion specifier + The type of value we want to fill the slot with. */ + + /* First, check our flags against the allowed specifiers */ + if (*str && hashflag && strchr("fFgGeExXo", *str) == 0) + { + sprintf(errormsg, "'#' flag restricted to [fFgGeExXo] " + "specifiers"); + *typ = NONE; + return str; + } + if (*str && zeroflag && strchr("diouxXeEfFgG", *str) == 0) + { + sprintf(errormsg, "'0' flag restricted to [diouxXeEfFgG] " + "specifiers"); + *typ = NONE; + return str; + } + + /* a C string */ + if (*str == 's') + { + *typ = STRING; + return str; + } + + /* a float. There's also 'a' and 'A' from C99, but let's stick + to the old school ones for now... */ + if (*str && strchr("fFgGeE", *str) != 0) + { + *typ = FLOAT; + return str; + } + + /* an int */ + if (*str && strchr("xXdiouc", *str) != 0) + { + *typ = INT; + return str; + } + + /* a pointer. We don't suppor this in Purr Data because of the + possibility of both undefined and implementation-specific + behavior. */ + if (*str && strchr("p", *str) != 0) + { + /* *typ = POINTER; */ + /* return str; */ + sprintf(errormsg, "p specifier not supported"); + *typ = NONE; + return str; + } + + /* if we've gotten here it means we are missing a type field. + Undefined behavior would result, so we will bail here */ + + /* First, let's check for any remaining type fields which + we don't support. That way we can give a better error message. */ + if (*str == 'a' || *str == 'A') + sprintf(errormsg, "hexfloat specifier not supported. If you " + "need this feature make a case on the " + "mailing list and we'll consider adding it"); + else if (*str == 'n') + sprintf(errormsg, "n specifier not supported"); + else if (*str == 'm') + sprintf(errormsg, "m specifier not supported"); + else if (*str) + sprintf(errormsg, "bad specifier type '%c'", *str); + else + sprintf(errormsg, "specifier missing"); + *typ = NONE; + return str; + } + } + *typ = NONE; + return str; +} + +static void makefilename_scanformat(t_makefilename *x) +{ + char errorbuf[MAXPDSTRING]; + errorbuf[0] = '\0'; + const char *str; + t_printtype typ; + if (!x->x_format) return; + str = x->x_format->s_name; + /* First attempt at parsing the format string for the field type. */ + str = makefilename_doscanformat(str, &typ, errorbuf); + /* If we got any errors we will have some content in our errorbuf... */ + if (*errorbuf) + { + pd_error(x, "makefilename: invalid format string '%s' " + "(%s). Supressing output.", + x->x_format->s_name, errorbuf); + /* set the format string to zero. It would be great to refuse to + create the object here, but we also have to deal with new format + strings with the 'set' message. So for consistency we zero out + the format string and make it a runtimer error. */ + x->x_format = 0; + return; + } + x->x_accept = typ; + if (str && (typ != NONE)) + { + /* try again, to see if there's another format specifier + (which we forbid) */ + str = makefilename_doscanformat(str, &typ, errorbuf); + /* If we've got a type other than none-- OR if we've got something + in our errorbuf-- we've got a syntax error. */ + if (typ != NONE || *errorbuf) + { + pd_error(x, "makefilename: invalid format string '%s' " + "(too many specifiers). " + "Suppressing output.", + x->x_format->s_name); + x->x_format = 0; + return; } } } @@ -1504,40 +1705,129 @@ static void *makefilename_new(t_symbol *s) s = gensym("file.%d"); outlet_new(&x->x_obj, &s_symbol); x->x_format = s; - x->x_accept = A_NULL; - x->x_intconvert = 0; + x->x_accept = NONE; makefilename_scanformat(x); return (x); } +static void makefilename_snprintf(t_makefilename *x, char *buf, char *fmt, ...) +{ + int length_minus_null_terminator; + va_list ap; + va_start(ap, fmt); + length_minus_null_terminator = + vsnprintf(buf, MAXPDSTRING, fmt, ap); + va_end(ap); + if (length_minus_null_terminator >= MAXPDSTRING) + { + /* Just don't trust snprintf... */ + buf[MAXPDSTRING-1] = '\0'; + pd_error(x, "makefilename: output truncated to %d characters", + MAXPDSTRING); + } +} + static void makefilename_float(t_makefilename *x, t_floatarg f) { char buf[MAXPDSTRING]; - if (x->x_accept == A_FLOAT) + if (!x->x_format) { - if (x->x_intconvert) - sprintf(buf, x->x_format->s_name, (int)f); - else sprintf(buf, x->x_format->s_name, f); + pd_error(x, "makefilename: no format specifier given"); + return; } - else + switch(x->x_accept) { + case FLOAT: + makefilename_snprintf(x, buf, x->x_format->s_name, f); + break; + case INT: + makefilename_snprintf(x, buf, x->x_format->s_name, (int)f); + break; + case STRING: { char buf2[MAXPDSTRING]; - sprintf(buf2, "%g", f); - sprintf(buf, x->x_format->s_name, buf2); + makefilename_snprintf(x, buf2, "%g", f); + makefilename_snprintf(x, buf, x->x_format->s_name, buf2); + break; + case NONE: + makefilename_snprintf(x, buf, x->x_format->s_name); + break; } - if (buf[0]!=0) - outlet_symbol(x->x_obj.ob_outlet, gensym(buf)); + default: + /* POINTER type would fall here. We probably don't want to expose + implementation-specific output for whatever rando float values + the user wants to hurl at makefilename. */ + pd_error(x, "cannot convert float with specifier: %s", + x->x_format->s_name); + return; + } + if (buf[0] != 0) + outlet_symbol(x->x_obj.ob_outlet, gensym(buf)); } static void makefilename_symbol(t_makefilename *x, t_symbol *s) { char buf[MAXPDSTRING]; - if (x->x_accept == A_SYMBOL) - sprintf(buf, x->x_format->s_name, s->s_name); - else - sprintf(buf, x->x_format->s_name, 0); - if (buf[0]!=0) - outlet_symbol(x->x_obj.ob_outlet, gensym(buf)); + if (!x->x_format) + { + pd_error(x, "makefilename: no format specifier given"); + return; + } + switch(x->x_accept) + { + case STRING: + makefilename_snprintf(x, buf, x->x_format->s_name, s->s_name); + break; + case INT: + makefilename_snprintf(x, buf, x->x_format->s_name, 0); + break; + case FLOAT: + makefilename_snprintf(x, buf, x->x_format->s_name, 0.); + break; + case NONE: + makefilename_snprintf(x, buf, x->x_format->s_name); + break; + default: + /* POINTER case falls here. Technically we could print out + symbol addys using whatever the compiler's implementation-specific + output format happens to be. But that probably shouldn't be exposed + within the patch like this. */ + pd_error(x, "cannot convert symbol with specifier: %s", + x->x_format->s_name); + return; + } + if (buf[0] != 0) + outlet_symbol(x->x_obj.ob_outlet, gensym(buf)); +} + +static void makefilename_bang(t_makefilename *x) +{ + char buf[MAXPDSTRING]; + if(!x->x_format) + { + pd_error(x, "makefilename: no format specifier given"); + return; + } + switch(x->x_accept) + { + case INT: + makefilename_snprintf(x, buf, x->x_format->s_name, 0); + break; + case FLOAT: + makefilename_snprintf(x, buf, x->x_format->s_name, 0.); + break; + case STRING: + makefilename_snprintf(x, buf, x->x_format->s_name, ""); + break; + case NONE: + makefilename_snprintf(x, buf, x->x_format->s_name); + break; + default: + pd_error(x, "cannot convert bang with specifier: %s", + x->x_format->s_name); + return; + } + if (buf[0] != 0) + outlet_symbol(x->x_obj.ob_outlet, gensym(buf)); } static void makefilename_set(t_makefilename *x, t_symbol *s) @@ -1553,6 +1843,7 @@ static void makefilename_setup(void) sizeof(t_makefilename), 0, A_DEFSYM, 0); class_addfloat(makefilename_class, makefilename_float); class_addsymbol(makefilename_class, makefilename_symbol); + class_addbang(makefilename_class, makefilename_bang); class_addmethod(makefilename_class, (t_method)makefilename_set, gensym("set"), A_SYMBOL, 0); } diff --git a/scripts/regression_tests.pd b/scripts/regression_tests.pd index 37ba956bc54cf02415e3bdfc8e49648c182384dd..a7566b0ccbbac8d2ae964b9c575aa9ce590f260b 100644 --- a/scripts/regression_tests.pd +++ b/scripts/regression_tests.pd @@ -1,29 +1,29 @@ #N canvas 3 60 749 617 12; -#X obj 345 301 r \$0-result; -#X obj 345 326 route 0; -#X obj 453 470 print failure; -#X obj 430 336 tgl 28 0 empty empty Print_All_Results 31 11 0 12 -262144 --1 -1 1 1; +#X obj 475 301 r \$0-result; +#X obj 475 326 route 0; +#X obj 583 470 print failure; +#X obj 560 336 tgl 28 0 empty empty Print_All_Results 31 11 0 12 -262144 +-1 -1 0 1; #X obj 159 149 bng 31 250 50 0 empty empty Run_all 39 13 0 12 -262144 -1 -1; #X obj 56 25 r init; #X obj 345 191 route dollarzero; -#X obj 345 411 t b a; -#X obj 345 541 s pd; +#X obj 475 411 t b a; +#X obj 475 541 s pd; #X obj 56 120 trigger bang bang anything; #X msg 56 145 gui; #X obj 56 170 pdinfo; #X obj 56 195 sel 0; #X obj 56 245 s pd; -#X msg 345 516 quit 1; +#X msg 475 516 quit 1; #X msg 56 220 quit; #X obj 145 191 rtest msg_dollarzero; #X obj 145 246 rtest msg_dollarzero_semi; #X obj 145 302 rtest msg_click; #X obj 345 216 rtest binbuf_dollarzero; -#X msg 345 440 gui; -#X obj 345 465 pdinfo; -#X obj 345 490 sel 0; +#X msg 475 440 gui; +#X obj 475 465 pdinfo; +#X obj 475 490 sel 0; #X text 117 25 <- we start Pd with the -send "init etc." flag. This will automatically start the tests and allow us to send a comma-separated list of messages which will be evaluated by Pd without a target. This @@ -34,13 +34,22 @@ is handy for some binbuf tests.; #X text 536 150 <- we have to escape the arg; #X text 556 190 escape it in a comment.; #X text 556 170 in bash but we can't; -#X obj 391 374 spigot; -#X obj 407 440 route 1; -#X obj 407 495 print success; +#X obj 521 374 spigot; +#X obj 537 440 route 1; +#X obj 537 495 print success; #X obj 145 358 rtest unpost_sanity; #X obj 145 414 rtest unpost_error; #X obj 145 465 rtest unpost_print; #X obj 145 516 rtest unpost_long_message; +#X obj 145 569 rtest makefilename_double_percent; +#X obj 145 620 rtest makefilename_code_coverage; +#N canvas 461 242 450 323 (subpatch) 0; +#X restore 148 1105 pd; +#X obj 145 671 rtest makefilename_default; +#X obj 145 722 rtest makefilename_default_bang; +#X obj 145 773 rtest makefilename_float; +#X obj 145 824 rtest makefilename_symbol; +#X obj 145 875 rtest makefilename_bang; #X connect 0 0 1 0; #X connect 1 0 7 0; #X connect 1 1 29 0; @@ -70,3 +79,10 @@ is handy for some binbuf tests.; #X connect 32 0 33 0; #X connect 33 0 34 0; #X connect 34 0 35 0; +#X connect 35 0 36 0; +#X connect 36 0 37 0; +#X connect 37 0 39 0; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 42 0; +#X connect 42 0 43 0; diff --git a/scripts/regression_tests/makefilename_bang.pd b/scripts/regression_tests/makefilename_bang.pd new file mode 100644 index 0000000000000000000000000000000000000000..be59a3b13e5c625efa54e2abc158deccde11d05b --- /dev/null +++ b/scripts/regression_tests/makefilename_bang.pd @@ -0,0 +1,134 @@ +#N canvas 3 60 1105 621 12; +#X obj 41 8 inlet; +#X obj 41 794 outlet; +#X msg 908 211 set %5.5c; +#X obj 876 183 t a b; +#X obj 795 157 unpost error; +#X obj 876 246 makefilename; +#X text 890 157 supress error; +#X obj 761 283 list; +#X obj 761 132 t b a; +#X obj 761 308 route bang symbol; +#X obj 761 333 f 1; +#X obj 819 333 b; +#X msg 819 358 0; +#X text 325 138 "INT" branch; +#X obj 391 327 symbol; +#X obj 391 168 t b a b; +#X obj 437 201 symbol; +#X obj 414 271 makefilename %i_test; +#X obj 475 407 b; +#X msg 475 432 0; +#X obj 391 399 f 1; +#X obj 41 337 symbol; +#X obj 41 178 t b a b; +#X obj 87 211 symbol; +#X obj 125 417 b; +#X msg 125 442 0; +#X obj 41 409 f 1; +#X obj 64 281 makefilename %g_test; +#X text 56 136 "FLOAT" branch; +#X text 789 109 trigger a type "NONE" branch with broken specifier +; +#X obj 571 327 symbol; +#X obj 571 168 t b a b; +#X obj 617 201 symbol; +#X obj 655 407 b; +#X msg 655 432 0; +#X obj 571 399 f 1; +#X text 563 141 well-formed "NONE" branch; +#X obj 594 271 makefilename test; +#X obj 571 374 select test; +#X obj 41 66 trigger anything anything anything anything anything; +#X obj 221 367 symbol; +#X obj 221 208 t b a b; +#X obj 267 241 symbol; +#X obj 305 447 b; +#X msg 305 472 0; +#X obj 221 439 f 1; +#X text 185 168 "STRING" branch; +#X obj 391 374 select 0_test; +#X obj 41 384 select 0_test; +#X obj 571 492 list append incoming symbol correctly triggers constant +string; +#X obj 391 602 list append incoming symbol correctly converted to int +; +#X obj 221 642 list append incoming symbol correctly converted to symbol +; +#X obj 41 692 list append incoming symbol correctly formatted in outgoing +symbol; +#X obj 761 395 list append broken format string should suppress output +for incoming bang; +#X msg 41 36 bang; +#X obj 244 311 makefilename %s_test; +#X obj 221 414 select _test; +#X connect 0 0 54 0; +#X connect 2 0 5 0; +#X connect 3 0 5 0; +#X connect 3 1 2 0; +#X connect 3 1 7 1; +#X connect 4 1 3 0; +#X connect 5 0 7 1; +#X connect 7 0 9 0; +#X connect 8 0 7 0; +#X connect 8 1 4 0; +#X connect 9 0 10 0; +#X connect 9 1 11 0; +#X connect 10 0 53 0; +#X connect 11 0 12 0; +#X connect 12 0 53 0; +#X connect 14 0 47 0; +#X connect 15 0 14 0; +#X connect 15 1 17 0; +#X connect 15 2 16 0; +#X connect 16 0 14 1; +#X connect 17 0 14 1; +#X connect 18 0 19 0; +#X connect 19 0 50 0; +#X connect 20 0 50 0; +#X connect 21 0 48 0; +#X connect 22 0 21 0; +#X connect 22 1 27 0; +#X connect 22 2 23 0; +#X connect 23 0 21 1; +#X connect 24 0 25 0; +#X connect 25 0 52 0; +#X connect 26 0 52 0; +#X connect 27 0 21 1; +#X connect 30 0 38 0; +#X connect 31 0 30 0; +#X connect 31 1 37 0; +#X connect 31 2 32 0; +#X connect 32 0 30 1; +#X connect 33 0 34 0; +#X connect 34 0 49 0; +#X connect 35 0 49 0; +#X connect 37 0 30 1; +#X connect 38 0 35 0; +#X connect 38 1 33 0; +#X connect 39 0 22 0; +#X connect 39 1 41 0; +#X connect 39 2 15 0; +#X connect 39 3 31 0; +#X connect 39 4 8 0; +#X connect 40 0 56 0; +#X connect 41 0 40 0; +#X connect 41 1 55 0; +#X connect 41 2 42 0; +#X connect 42 0 40 1; +#X connect 43 0 44 0; +#X connect 44 0 51 0; +#X connect 45 0 51 0; +#X connect 47 0 20 0; +#X connect 47 1 18 0; +#X connect 48 0 26 0; +#X connect 48 1 24 0; +#X connect 49 0 1 0; +#X connect 50 0 1 0; +#X connect 51 0 1 0; +#X connect 52 0 1 0; +#X connect 53 0 1 0; +#X connect 54 0 39 0; +#X connect 55 0 40 1; +#X connect 56 0 45 0; +#X connect 56 1 43 0; diff --git a/scripts/regression_tests/makefilename_code_coverage.pd b/scripts/regression_tests/makefilename_code_coverage.pd new file mode 100644 index 0000000000000000000000000000000000000000..33fff49e55a510289d7e402f3e0ed15d4f24320b --- /dev/null +++ b/scripts/regression_tests/makefilename_code_coverage.pd @@ -0,0 +1,112 @@ +#N canvas 96 60 665 633 12; +#X obj 41 8 inlet; +#X msg 41 143 1; +#X obj 43 1229 outlet; +#X text 117 8 makefilename is a strange combination of the already +complicated C format string format specification and Pd's syntax limitations. +This is especially unfortunate given the object only accepts a single +substitution variable.; +#X text 117 88 As a consequence we get an extremely error-prone interface +subject to all kinds of broken format specifiers settable at runtime +with arbitrary user-input. All that complexity for an object of impressively +limited usefulness.; +#X obj 105 982 makefilename; +#X text 184 864 * todo: add check for [makefilename] with no args to +make sure it ouputs file%d; +#X obj 43 982 list; +#X obj 43 1007 route symbol bang; +#X obj 145 1118 list; +#X obj 43 916 trigger bang anything bang anything; +#X obj 43 1032 b; +#X obj 43 1057 f 1; +#X obj 100 1031 f 0; +#X obj 43 1082 t a b; +#X obj 43 1203 list append; +#X msg 145 1149 code coverage for error handling of poorly formed format +specifier: \$@; +#X text 143 292 too many flags; +#X text 50 240 no field type; +#X text 129 414 max width/precision; +#X text 115 354 variable width or precision field not supported; +#X text 148 585 unsupported field types; +#X text 154 650 non-existent field type; +#X msg 41 265 % \, %0; +#X obj 43 861 list prepend set; +#X obj 43 886 list trim; +#X msg 53 317 %-+#0-+#0-+#0-+#0- \, %-+#0-+#0-+#0-+#0-g; +#X msg 63 379 %* \, %*s \, %.*s \, %*.*s; +#X msg 73 439 %9999g \, %.9999g \, %9999.9999g; +#X obj 66 946 unpost error; +#X text 168 947 <- if there's an error we'll get it to the left inlet +in the form of a symbol; +#X obj 41 168 s \$0-b; +#X obj 41 213 r \$0-b; +#X obj 54 291 r \$0-b; +#X obj 63 348 r \$0-b; +#X obj 73 409 r \$0-b; +#X obj 83 467 r \$0-b; +#X obj 93 580 r \$0-b; +#X obj 103 634 r \$0-b; +#X msg 103 660 %z; +#X obj 110 684 r \$0-b; +#X text 185 697 more than one format specifier; +#X msg 110 710 %g%g \, %g%; +#X text 132 477 double dots; +#X msg 83 499 %5..g \, %..g; +#X obj 93 523 r \$0-b; +#X text 142 533 precision field/specifier mismatch; +#X msg 93 555 %5.3c; +#X msg 93 609 %a \, %A \, %n \, %m \, %p; +#X text 117 168 Here \, we trigger every branch of the format specifier +parser to make sure our run-time errors prevent crashes and/or memory +errors. We use [unpost] to redirect the error from the console to the +patch.; +#X obj 120 734 r \$0-b; +#X msg 120 760 %#d \, %#i; +#X obj 120 794 r \$0-b; +#X text 195 747 hash flag mismatch; +#X text 195 807 zero flag mismatch; +#X msg 120 820 %0c \, %0s; +#X connect 0 0 1 0; +#X connect 1 0 31 0; +#X connect 7 0 8 0; +#X connect 8 0 11 0; +#X connect 8 1 13 0; +#X connect 9 0 16 0; +#X connect 10 0 7 0; +#X connect 10 1 29 0; +#X connect 10 2 7 1; +#X connect 10 3 9 1; +#X connect 11 0 12 0; +#X connect 12 0 14 0; +#X connect 13 0 14 0; +#X connect 14 0 15 0; +#X connect 14 1 9 0; +#X connect 15 0 2 0; +#X connect 16 0 15 1; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 10 0; +#X connect 26 0 24 0; +#X connect 27 0 24 0; +#X connect 28 0 24 0; +#X connect 29 0 7 1; +#X connect 29 1 5 0; +#X connect 32 0 23 0; +#X connect 33 0 26 0; +#X connect 34 0 27 0; +#X connect 35 0 28 0; +#X connect 36 0 44 0; +#X connect 37 0 48 0; +#X connect 38 0 39 0; +#X connect 39 0 24 0; +#X connect 40 0 42 0; +#X connect 42 0 24 0; +#X connect 44 0 24 0; +#X connect 45 0 47 0; +#X connect 47 0 24 0; +#X connect 48 0 24 0; +#X connect 50 0 51 0; +#X connect 51 0 24 0; +#X connect 52 0 55 0; +#X connect 55 0 24 0; diff --git a/scripts/regression_tests/makefilename_default.pd b/scripts/regression_tests/makefilename_default.pd new file mode 100644 index 0000000000000000000000000000000000000000..ebbb0da0fbf54e276b90bec7ce3513502845b205 --- /dev/null +++ b/scripts/regression_tests/makefilename_default.pd @@ -0,0 +1,21 @@ +#N canvas 51 212 538 283 12; +#X obj 41 28 inlet; +#X obj 136 153 list prepend 0; +#X obj 41 249 outlet; +#X obj 41 98 makefilename; +#X text 117 28 [makefilename] with no arguments should output the symbol +`file.` concatenated with the number from the input. The incoming float +should be cast to an int before concatenation.; +#X msg 41 73 42.3; +#X obj 41 123 select file.42; +#X msg 41 153 1 file.42; +#X msg 41 187 \$1 default format specifier 'file.%d' with incoming +float cast to int. Expected output: 'file.42'. Actual output: \$2; +#X connect 0 0 5 0; +#X connect 1 0 8 0; +#X connect 3 0 6 0; +#X connect 5 0 3 0; +#X connect 6 0 7 0; +#X connect 6 1 1 0; +#X connect 7 0 8 0; +#X connect 8 0 2 0; diff --git a/scripts/regression_tests/makefilename_default_bang.pd b/scripts/regression_tests/makefilename_default_bang.pd new file mode 100644 index 0000000000000000000000000000000000000000..80dd5bf704f25642a74de41f60557205efddc81d --- /dev/null +++ b/scripts/regression_tests/makefilename_default_bang.pd @@ -0,0 +1,21 @@ +#N canvas 72 248 589 329 12; +#X obj 41 28 inlet; +#X obj 136 153 list prepend 0; +#X obj 41 229 outlet; +#X obj 41 98 makefilename; +#X text 117 28 [makefilename] in Pd Vanilla apparently converts an +incoming bang to zero. Not sure why \, but we check for that default +here.; +#X msg 41 73 bang; +#X obj 41 123 select file.0; +#X msg 41 153 1 file.0; +#X msg 41 187 \$1 a bang should bash to zero. Expected output: 'file.0'. +Actual output: \$2; +#X connect 0 0 5 0; +#X connect 1 0 8 0; +#X connect 3 0 6 0; +#X connect 5 0 3 0; +#X connect 6 0 7 0; +#X connect 6 1 1 0; +#X connect 7 0 8 0; +#X connect 8 0 2 0; diff --git a/scripts/regression_tests/makefilename_double_percent.pd b/scripts/regression_tests/makefilename_double_percent.pd new file mode 100644 index 0000000000000000000000000000000000000000..e510160146183a7eb97710cc244949ad7d2a7b7e --- /dev/null +++ b/scripts/regression_tests/makefilename_double_percent.pd @@ -0,0 +1,22 @@ +#N canvas 176 225 538 369 12; +#X obj 41 28 inlet; +#X msg 41 73 1; +#X obj 41 98 makefilename %%s%g; +#X obj 41 123 select %s1; +#X obj 108 153 list prepend 0; +#X msg 41 153 1 %s1; +#X obj 41 229 outlet; +#X text 117 28 Double percent signs map to a single literal '%'. Some +old patches use this feature in conjunction with the 'set' message +to do string concatenation. So we want to make sure it continues to +work going forward.; +#X msg 41 187 \$1 format specifier '%%' should get converted to a single +'%'. Expected output: '%s1'. Actual output: \$2; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 5 0; +#X connect 3 1 4 0; +#X connect 4 0 8 0; +#X connect 5 0 8 0; +#X connect 8 0 6 0; diff --git a/scripts/regression_tests/makefilename_float.pd b/scripts/regression_tests/makefilename_float.pd new file mode 100644 index 0000000000000000000000000000000000000000..f9f9dbaa0fc19c1c8e2ac774dba4cbc62689b81d --- /dev/null +++ b/scripts/regression_tests/makefilename_float.pd @@ -0,0 +1,134 @@ +#N canvas 3 60 1105 621 12; +#X obj 41 8 inlet; +#X obj 41 794 outlet; +#X msg 908 211 set %5.5c; +#X obj 876 183 t a b; +#X obj 795 157 unpost error; +#X obj 876 246 makefilename; +#X text 890 157 supress error; +#X obj 761 283 list; +#X obj 761 132 t b a; +#X obj 761 308 route bang symbol; +#X obj 761 333 f 1; +#X obj 819 333 b; +#X msg 819 358 0; +#X text 315 148 "INT" branch; +#X obj 391 327 symbol; +#X obj 391 168 t b a b; +#X obj 437 201 symbol; +#X msg 41 36 42.3; +#X obj 414 271 makefilename %i_test; +#X obj 391 374 select 42_test; +#X obj 475 407 b; +#X msg 475 432 0; +#X obj 391 399 f 1; +#X obj 391 602 list append incoming float correctly converted to int +; +#X obj 41 337 symbol; +#X obj 41 178 t b a b; +#X obj 87 211 symbol; +#X obj 125 417 b; +#X msg 125 442 0; +#X obj 41 409 f 1; +#X obj 64 281 makefilename %g_test; +#X obj 41 384 select 42.3_test; +#X obj 41 692 list append incoming float correctly formatted in outgoing +symbol; +#X text 56 136 "FLOAT" branch; +#X text 789 109 trigger a type "NONE" branch with broken specifier +; +#X obj 761 395 list append broken format string should suppress output +for incoming float; +#X obj 571 327 symbol; +#X obj 571 168 t b a b; +#X obj 617 201 symbol; +#X obj 655 407 b; +#X msg 655 432 0; +#X obj 571 399 f 1; +#X text 563 141 well-formed "NONE" branch; +#X obj 571 492 list append incoming float correctly triggers constant +string; +#X obj 594 271 makefilename test; +#X obj 571 374 select test; +#X obj 41 66 trigger anything anything anything anything anything; +#X obj 221 367 symbol; +#X obj 221 208 t b a b; +#X obj 267 241 symbol; +#X obj 305 447 b; +#X msg 305 472 0; +#X obj 221 439 f 1; +#X text 185 168 "STRING" branch; +#X obj 244 311 makefilename %s_test; +#X obj 221 414 select 42.3_test; +#X obj 221 642 list append incoming float correctly converted to symbol +; +#X connect 0 0 17 0; +#X connect 2 0 5 0; +#X connect 3 0 5 0; +#X connect 3 1 2 0; +#X connect 3 1 7 1; +#X connect 4 1 3 0; +#X connect 5 0 7 1; +#X connect 7 0 9 0; +#X connect 8 0 7 0; +#X connect 8 1 4 0; +#X connect 9 0 10 0; +#X connect 9 1 11 0; +#X connect 10 0 35 0; +#X connect 11 0 12 0; +#X connect 12 0 35 0; +#X connect 14 0 19 0; +#X connect 15 0 14 0; +#X connect 15 1 18 0; +#X connect 15 2 16 0; +#X connect 16 0 14 1; +#X connect 17 0 46 0; +#X connect 18 0 14 1; +#X connect 19 0 22 0; +#X connect 19 1 20 0; +#X connect 20 0 21 0; +#X connect 21 0 23 0; +#X connect 22 0 23 0; +#X connect 23 0 1 0; +#X connect 24 0 31 0; +#X connect 25 0 24 0; +#X connect 25 1 30 0; +#X connect 25 2 26 0; +#X connect 26 0 24 1; +#X connect 27 0 28 0; +#X connect 28 0 32 0; +#X connect 29 0 32 0; +#X connect 30 0 24 1; +#X connect 31 0 29 0; +#X connect 31 1 27 0; +#X connect 32 0 1 0; +#X connect 35 0 1 0; +#X connect 36 0 45 0; +#X connect 37 0 36 0; +#X connect 37 1 44 0; +#X connect 37 2 38 0; +#X connect 38 0 36 1; +#X connect 39 0 40 0; +#X connect 40 0 43 0; +#X connect 41 0 43 0; +#X connect 43 0 1 0; +#X connect 44 0 36 1; +#X connect 45 0 41 0; +#X connect 45 1 39 0; +#X connect 46 0 25 0; +#X connect 46 1 48 0; +#X connect 46 2 15 0; +#X connect 46 3 37 0; +#X connect 46 4 8 0; +#X connect 47 0 55 0; +#X connect 48 0 47 0; +#X connect 48 1 54 0; +#X connect 48 2 49 0; +#X connect 49 0 47 1; +#X connect 50 0 51 0; +#X connect 51 0 56 0; +#X connect 52 0 56 0; +#X connect 54 0 47 1; +#X connect 55 0 52 0; +#X connect 55 1 50 0; +#X connect 56 0 1 0; diff --git a/scripts/regression_tests/makefilename_symbol.pd b/scripts/regression_tests/makefilename_symbol.pd new file mode 100644 index 0000000000000000000000000000000000000000..23c97ceecc0f40dc46cd44e0163fdbbfb7ba7a75 --- /dev/null +++ b/scripts/regression_tests/makefilename_symbol.pd @@ -0,0 +1,134 @@ +#N canvas 3 60 1105 621 12; +#X obj 41 8 inlet; +#X obj 41 794 outlet; +#X msg 908 211 set %5.5c; +#X obj 876 183 t a b; +#X obj 795 157 unpost error; +#X obj 876 246 makefilename; +#X text 890 157 supress error; +#X obj 761 283 list; +#X obj 761 132 t b a; +#X obj 761 308 route bang symbol; +#X obj 761 333 f 1; +#X obj 819 333 b; +#X msg 819 358 0; +#X text 325 138 "INT" branch; +#X obj 391 327 symbol; +#X obj 391 168 t b a b; +#X obj 437 201 symbol; +#X obj 414 271 makefilename %i_test; +#X obj 475 407 b; +#X msg 475 432 0; +#X obj 391 399 f 1; +#X obj 41 337 symbol; +#X obj 41 178 t b a b; +#X obj 87 211 symbol; +#X obj 125 417 b; +#X msg 125 442 0; +#X obj 41 409 f 1; +#X obj 64 281 makefilename %g_test; +#X text 56 136 "FLOAT" branch; +#X text 789 109 trigger a type "NONE" branch with broken specifier +; +#X obj 571 327 symbol; +#X obj 571 168 t b a b; +#X obj 617 201 symbol; +#X obj 655 407 b; +#X msg 655 432 0; +#X obj 571 399 f 1; +#X text 563 141 well-formed "NONE" branch; +#X obj 594 271 makefilename test; +#X obj 571 374 select test; +#X obj 41 66 trigger anything anything anything anything anything; +#X obj 221 367 symbol; +#X obj 221 208 t b a b; +#X obj 267 241 symbol; +#X obj 305 447 b; +#X msg 305 472 0; +#X obj 221 439 f 1; +#X text 185 168 "STRING" branch; +#X msg 41 36 symbol test; +#X obj 391 374 select 0_test; +#X obj 41 384 select 0_test; +#X obj 244 311 makefilename %s; +#X obj 221 414 select test; +#X obj 761 395 list append broken format string should suppress output +for incoming symbol; +#X obj 571 492 list append incoming symbol correctly triggers constant +string; +#X obj 391 602 list append incoming symbol correctly converted to int +; +#X obj 221 642 list append incoming symbol correctly converted to symbol +; +#X obj 41 692 list append incoming symbol correctly formatted in outgoing +symbol; +#X connect 0 0 47 0; +#X connect 2 0 5 0; +#X connect 3 0 5 0; +#X connect 3 1 2 0; +#X connect 3 1 7 1; +#X connect 4 1 3 0; +#X connect 5 0 7 1; +#X connect 7 0 9 0; +#X connect 8 0 7 0; +#X connect 8 1 4 0; +#X connect 9 0 10 0; +#X connect 9 1 11 0; +#X connect 10 0 52 0; +#X connect 11 0 12 0; +#X connect 12 0 52 0; +#X connect 14 0 48 0; +#X connect 15 0 14 0; +#X connect 15 1 17 0; +#X connect 15 2 16 0; +#X connect 16 0 14 1; +#X connect 17 0 14 1; +#X connect 18 0 19 0; +#X connect 19 0 54 0; +#X connect 20 0 54 0; +#X connect 21 0 49 0; +#X connect 22 0 21 0; +#X connect 22 1 27 0; +#X connect 22 2 23 0; +#X connect 23 0 21 1; +#X connect 24 0 25 0; +#X connect 25 0 56 0; +#X connect 26 0 56 0; +#X connect 27 0 21 1; +#X connect 30 0 38 0; +#X connect 31 0 30 0; +#X connect 31 1 37 0; +#X connect 31 2 32 0; +#X connect 32 0 30 1; +#X connect 33 0 34 0; +#X connect 34 0 53 0; +#X connect 35 0 53 0; +#X connect 37 0 30 1; +#X connect 38 0 35 0; +#X connect 38 1 33 0; +#X connect 39 0 22 0; +#X connect 39 1 41 0; +#X connect 39 2 15 0; +#X connect 39 3 31 0; +#X connect 39 4 8 0; +#X connect 40 0 51 0; +#X connect 41 0 40 0; +#X connect 41 1 50 0; +#X connect 41 2 42 0; +#X connect 42 0 40 1; +#X connect 43 0 44 0; +#X connect 44 0 55 0; +#X connect 45 0 55 0; +#X connect 47 0 39 0; +#X connect 48 0 20 0; +#X connect 48 1 18 0; +#X connect 49 0 26 0; +#X connect 49 1 24 0; +#X connect 50 0 40 1; +#X connect 51 0 45 0; +#X connect 51 1 43 0; +#X connect 52 0 1 0; +#X connect 53 0 1 0; +#X connect 54 0 1 0; +#X connect 55 0 1 0; +#X connect 56 0 1 0;