diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9d293c59bed95ba8d1c32dd1253ca2f5d08b13f7..aac825245144652278e0d006106456361a5ffbcd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -79,7 +79,7 @@ ubuntu_14.04_i386_deb:
      - echo "" | sudo -S DEBIAN_FRONTEND=noninteractive dpkg --force-all -i pd-l2ork*.deb > /dev/null
      - cd scripts
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio -send "init dollarzero \$0" regression_control.pd
-     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio scripts/regression_tilde.pd
+     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio regression_tilde.pd
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio external-tests.pd
    artifacts:
      name: "$CI_RUNNER_DESCRIPTION"
@@ -102,7 +102,7 @@ ubuntu_14.04_x86_64_deb:
      - echo "" | sudo -S DEBIAN_FRONTEND=noninteractive dpkg --force-all -i pd-l2ork*.deb > /dev/null
      - cd scripts
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio -send "init dollarzero \$0" regression_control.pd
-     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio scripts/regression_tilde.pd
+     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio regression_tilde.pd
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio external-tests.pd
    artifacts:
      name: "$CI_RUNNER_DESCRIPTION"
@@ -125,7 +125,7 @@ ubuntu_16.04_x86_64_deb:
      - echo "" | sudo -S DEBIAN_FRONTEND=noninteractive dpkg --force-all -i pd-l2ork*.deb > /dev/null
      - cd scripts
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio -send "init dollarzero \$0" regression_control.pd
-     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio scripts/regression_tilde.pd
+     - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio regression_tilde.pd
      - valgrind pd-l2ork -noprefs -nostdpath -nogui -nrt -noaudio external-tests.pd
    artifacts:
      name: "$CI_RUNNER_DESCRIPTION"
diff --git a/pd/src/x_connective.c b/pd/src/x_connective.c
index 2e61671dcb9802030c7657e506a822c148e5c137..76850ed09c383f9a3d80b013e459e5ab79f3733f 100644
--- a/pd/src/x_connective.c
+++ b/pd/src/x_connective.c
@@ -1449,21 +1449,25 @@ 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* _formatscan(const char*str, t_printtype*typ)
 {
     int infmt=0;
-    char *str;
-    if (!x->x_format) return;
-    x->x_accept = A_NULL;
-    for (str=x->x_format->s_name; *str; str++)
+    for (; *str; str++)
     {
         if (!infmt && *str=='%')
         {
@@ -1472,31 +1476,78 @@ static void makefilename_scanformat(t_makefilename *x)
         }
         if (infmt)
         {
+            if (*str=='%')
+            {
+                infmt=0;
+                continue;
+            }
             if (strchr("-.#0123456789",*str)!=0)
                 continue;
             if (*str=='s')
             {
-                x->x_accept = A_SYMBOL;
-                x->x_intconvert = 0;
-                break;
+                *typ = STRING;
+                return str;
             }
             if (strchr("fgGeE",*str)!=0)
             {
-                x->x_accept = A_FLOAT;
-                x->x_intconvert = 0;
-                break;
+                *typ = FLOAT;
+                return str;
             }
             if (strchr("xXdiouc",*str)!=0)
             {
-                x->x_accept = A_FLOAT;
-                x->x_intconvert = 1;
-                break;
+                *typ = INT;
+                return str;
             }
-            infmt=0;
+            if (strchr("p",*str)!=0)
+            {
+                *typ = POINTER;
+                return str;
+            }
+        }
+    }
+    *typ = NONE;
+    return str;
+}
+
+static void makefilename_scanformat(t_makefilename *x)
+{
+    const char *str;
+    t_printtype typ;
+    if (!x->x_format) return;
+    str = x->x_format->s_name;
+    str = _formatscan(str, &typ);
+    x->x_accept = typ;
+    if (str && (typ != NONE))
+    {
+            /* try again, to see if there's another format specifier
+               (which we forbid) */
+        str = _formatscan(str, &typ);
+        if (NONE != typ)
+        {
+            pd_error(x, "makefilename: invalid format string '%s' "
+                        "(too many format specifiers)", x->x_format->s_name);
+            x->x_format = 0;
+            return;
         }
     }
 }
 
+static void makefilename_printf(t_makefilename *x, char *buf,
+    const char *fmt, ...)
+{
+    int size_minus_one;
+    va_list ap;
+    va_start(ap, fmt);
+    size_minus_one = vsnprintf(buf, MAXPDSTRING, fmt, ap);
+    va_end(ap);
+    if (size_minus_one >= MAXPDSTRING)
+    {
+        pd_error(x, "makefilename: truncating output greater than %d bytes",
+            MAXPDSTRING);
+        buf[MAXPDSTRING-1] = '\0';
+    }
+}
+
 static void *makefilename_new(t_symbol *s)
 {
     t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
@@ -1504,8 +1555,7 @@ 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);
 }
@@ -1513,31 +1563,89 @@ static void *makefilename_new(t_symbol *s)
 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 NONE:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
+        break;
+    case INT: case POINTER:
+        makefilename_printf(x, buf, x->x_format->s_name, (int)f);
+        break;
+    case FLOAT:
+        makefilename_printf(x, buf, x->x_format->s_name, f);
+        break;
+    case STRING:
     {
         char buf2[MAXPDSTRING];
-        sprintf(buf2, "%g", f);
-        sprintf(buf, x->x_format->s_name, buf2);
+        makefilename_printf(x, buf2, "%g", f);
+        makefilename_printf(x, buf, x->x_format->s_name, buf2);
+        break;
+    }
+    default:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
     }
     if (buf[0]!=0)
-    outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
+        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 (!x->x_format)
+    {
+        pd_error(x, "makefilename: no format specifier given");
+        return;
+    }
+    switch (x->x_accept)
+    {
+    case STRING: case POINTER:
+        makefilename_printf(x, buf, x->x_format->s_name, s->s_name);
+        break;
+    case INT:
+        makefilename_printf(x, buf, x->x_format->s_name, 0);
+        break;
+    case FLOAT:
+        makefilename_printf(x, buf, x->x_format->s_name, 0.);
+        break;
+    case NONE:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
+        break;
+    default:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
+    }
+    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_printf(x, buf, x->x_format->s_name, 0);
+        break;
+    case FLOAT:
+        makefilename_printf(x, buf, x->x_format->s_name, 0.);
+        break;
+    case NONE:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
+        break;
+    default:
+        makefilename_printf(x, buf, "%s", x->x_format->s_name);
+    }
     if (buf[0]!=0)
-    outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
+        outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
 }
 
 static void makefilename_set(t_makefilename *x, t_symbol *s)
@@ -1553,6 +1661,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);
 }