From b0d0df6b50bf3fc62958e32bd3560661dfbc03ba Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jon.w.wilkes@gmail.com>
Date: Wed, 8 Nov 2017 21:19:55 -0500
Subject: [PATCH] update stdout to Vanilla's
 eed18dd4b57000d0ebfe9d75b76b0c94609d45de so that it works with pd~

Fix bug in which stdout didn't catch on that it should send to parent pd~
in binary; this was caused by different startup order when pd~ was started
with or without GUI (it failed when non-GUI, binary mode).
---
 pd/extra/stdout/GNUmakefile.am |  34 +++++++---
 pd/extra/stdout/stdout-help.pd |  29 ++++++--
 pd/extra/stdout/stdout.c       | 118 ++++++++++++++++++++++++++++++++-
 3 files changed, 162 insertions(+), 19 deletions(-)

diff --git a/pd/extra/stdout/GNUmakefile.am b/pd/extra/stdout/GNUmakefile.am
index cc2a517f0..72c585ff7 100644
--- a/pd/extra/stdout/GNUmakefile.am
+++ b/pd/extra/stdout/GNUmakefile.am
@@ -1,28 +1,40 @@
-## Makefile.am -- Process this file with automake to produce Makefile.in
+#########################################
+##### Defaults & Paths #####
 
 NAME=stdout
 
 external_LTLIBRARIES = stdout.la
-SOURCES =  stdout.c
-PATCHES =  stdout-help.pd
+SOURCES = stdout.c
+PATCHES = stdout-help.pd
 OTHERDATA = 
 
-###############################
+EXTRA_DIST = makefile
+
+#########################################
+##### Files, Binaries, & Libs #####
+
 # you shouldn't need to add anything below here
 dist_external_DATA = $(PATCHES) $(OTHERDATA)
 
 AUTOMAKE_OPTIONS = foreign
-AM_CPPFLAGS	 = -I$(top_srcdir)/src -DPD
-AM_CFLAGS = @ARCH_CFLAGS@
+AM_CFLAGS = @EXTERNAL_CFLAGS@
+AM_CPPFLAGS	+= -I$(top_srcdir)/src -DPD
 AM_LIBS = $(LIBM)
-AM_LDFLAGS = -module -avoid-version -shared @ARCH_LDFLAGS@ -shrext .@EXTERNAL_EXTENSION@ -L$(top_srcdir)/src
+AM_LDFLAGS = -module -avoid-version -shared @EXTERNAL_LDFLAGS@ \
+    -shrext .@EXTERNAL_EXTENSION@ -L$(top_builddir)/src
 
 externaldir = $(pkglibdir)/extra/$(NAME)
 
-
-if MINGW
-AM_LIBS += -lpd
-endif
+#########################################
+##### Targets #####
 
 libtool: $(LIBTOOL_DEPS)
 	$(SHELL) ./config.status --recheck
+
+# create convenience link for running locally
+all-local:
+	rm -f *.@EXTERNAL_EXTENSION@
+	-$(LN_S) $(wildcard .libs/*.@EXTERNAL_EXTENSION@) ./
+
+clean-local:
+	rm -f *.@EXTERNAL_EXTENSION@
diff --git a/pd/extra/stdout/stdout-help.pd b/pd/extra/stdout/stdout-help.pd
index 91edbc417..4d7f3ebb4 100644
--- a/pd/extra/stdout/stdout-help.pd
+++ b/pd/extra/stdout/stdout-help.pd
@@ -1,19 +1,38 @@
-#N canvas 121 60 488 321 12;
+#N canvas 124 51 758 493 12;
 #X msg 126 203 walk the dog;
 #X msg 117 156 1;
 #X obj 117 240 stdout;
-#X text 269 287 updated for Pd version 0.42;
 #X obj 14 13 stdout;
 #X text 67 14 - write messages to standard output;
 #X msg 122 179 1 2;
-#X obj 119 291 pd~;
-#X text 44 291 see also:;
+#X obj 119 431 pd~;
+#X text 44 431 see also:;
 #X text 34 39 Sends messages to Pd's standard output. This is useful
 in conjunction with the pd~ object \, which starts a pd sub-process.
 Messages sent to the sub-process standard output appear on the output
 of the pd~ object in the owning process. This might also be useful
 in other situations. Note that there's no corresponding "stdin" object
 - there seems to be no one canonical way such a thing should act.;
+#X msg 256 203 walk the dog;
+#X msg 247 156 1;
+#X msg 252 179 1 2;
+#X text 269 427 updated for Pd version 0.48;
+#X obj 247 240 stdout -cr;
+#X msg 383 178 100 111 117 98 108 101 32 32 115 112 97 99 101 44 32
+80 100 10, f 32;
+#X obj 383 240 stdout -b;
+#X text 45 307 special flags:;
+#X text 76 332 -cr: omit trailing semicolon in output (like [print])
+;
+#X text 79 352 -b \, -binary: binary mode;
+#X text 79 392 -nf \, -noflush: do not fflush the output after each
+message;
+#X text 79 372 -f \, -flush: fflush the output after each message (default
+on W32), f 65;
 #X connect 0 0 2 0;
 #X connect 1 0 2 0;
-#X connect 6 0 2 0;
+#X connect 5 0 2 0;
+#X connect 9 0 13 0;
+#X connect 10 0 13 0;
+#X connect 11 0 13 0;
+#X connect 14 0 15 0;
diff --git a/pd/extra/stdout/stdout.c b/pd/extra/stdout/stdout.c
index 5cd52f25c..3798aa44f 100644
--- a/pd/extra/stdout/stdout.c
+++ b/pd/extra/stdout/stdout.c
@@ -9,20 +9,124 @@
 #include <string.h>
 static t_class *stdout_class;
 
+#define MODE_DEFAULT 0  /* default, FUDI style */
+#define MODE_CR 1       /* newline-terminate messages and omit semicolons */
+#define MODE_BIN 2      /* binary messages supplied bytewise from patch */
+#define MODE_PDTILDE 3  /* binary atoms for subprocess of pd~ object */
+
 typedef struct _stdout
 {
     t_object x_obj;
+    int x_mode; /* 0=FUDI; 1=printf (no terminating semicolon); -1=binary */
+    int x_flush; /* fflush() stdout after each message */
 } t_stdout;
 
-static void *stdout_new(t_float fnonrepeat)
+static void *stdout_new(t_symbol*s, int argc, t_atom*argv)
 {
     t_stdout *x = (t_stdout *)pd_new(stdout_class);
+        /* for some reason in MS windows we have to flush standard out here -
+        otherwise these outputs get out of order from the ones from pdsched.c
+        over in ../pd~.  I'm guessing mingw (with its different C runtime
+        support) will handle this correctly and so am only ifdeffing this on
+        Microsoft C compiler.  It's an efficiency hit, possibly a serious
+        one. */
+#ifdef _MSC_VER
+    x->x_flush = 1;
+#endif
+
+    while(argc--)
+    {
+        s = atom_getsymbol(argv++);
+        if (gensym("-cr") == s)
+        {
+                /* No-semicolon mode */
+            x->x_mode = MODE_CR;
+        }
+        else if ((gensym("-b") == s) || (gensym("-binary") == s))
+        {
+                /* Binary mode:
+                   no extra characters (semicolons, CR,...) is appended
+                 */
+            x->x_mode = MODE_BIN;
+        }
+        else if ((gensym("-f") == s) || (gensym("-flush") == s))
+        {
+            x->x_flush = 1;
+        }
+        else if ((gensym("-nf") == s) || (gensym("-noflush") == s))
+        {
+            x->x_flush = 0;
+        }
+        else if (gensym("") != s)
+        {
+                /* unknown mode; ignore it */
+        }
+    }
+    if (gensym("#pd_binary_stdio")->s_thing)
+        x->x_mode = MODE_PDTILDE;
     return (x);
 }
 
+static void stdout_binary(t_stdout *x, int argc, t_atom *argv)
+{
+#define BUFSIZE 65535
+    char buf[BUFSIZE];
+    int i;
+    if (argc>BUFSIZE)
+        argc = BUFSIZE;
+    for (i=0; i<argc; i++)
+        ((unsigned char *)buf)[i] = atom_getfloatarg(i, argc, argv);
+    buf[i>BUFSIZE?BUFSIZE:i] = 0;
+    fwrite(buf, 1, argc, stdout);
+
+    if (x->x_flush || !argc)
+        fflush(stdout);
+}
+
+static void pd_tilde_putfloat(float f, FILE *fd)
+{
+    putc(A_FLOAT, fd);
+    fwrite(&f, sizeof(f), 1, fd);
+}
+
+static void pd_tilde_putsymbol(t_symbol *s, FILE *fd)
+{
+    char *sp = s->s_name;
+    putc(A_SYMBOL, fd);
+    do
+        putc(*sp, fd);
+    while (*sp++);
+}
+
 static void stdout_anything(t_stdout *x, t_symbol *s, int argc, t_atom *argv)
 {
     char msgbuf[MAXPDSTRING], *sp, *ep = msgbuf+MAXPDSTRING;
+    if (x->x_mode == MODE_BIN)
+    {
+        if ((gensym("list") == s) || (gensym("float") == s) ||
+            (gensym("bang") == s))
+                stdout_binary(x, argc, argv);
+        else
+            pd_error(x,
+ "stdout: only 'list' messages allowed in binary mode (got '%s')",
+                s->s_name);
+        return;
+    }
+    else if (x->x_mode == MODE_PDTILDE)
+    {
+        pd_tilde_putsymbol(s, stdout);
+        for (; argc--; argv++)
+        {
+            if (argv->a_type == A_FLOAT)
+                pd_tilde_putfloat(argv->a_w.w_float, stdout);
+            else if (argv->a_type == A_SYMBOL)
+                pd_tilde_putsymbol(argv->a_w.w_symbol, stdout);
+        }
+        putc(A_SEMI, stdout);
+        if (x->x_flush)
+            fflush(stdout);
+        return;
+    }
     msgbuf[0] = 0;
     strncpy(msgbuf, s->s_name, MAXPDSTRING);
     msgbuf[MAXPDSTRING-1] = 0;
@@ -34,7 +138,15 @@ static void stdout_anything(t_stdout *x, t_symbol *s, int argc, t_atom *argv)
         atom_string(argv++, sp, ep-sp);
         sp += strlen(sp);
     }
-    printf("%s;\n", msgbuf);
+    switch(x->x_mode) {
+    case MODE_CR:
+        printf("%s\n", msgbuf);
+        break;
+    default:
+        printf("%s;\n", msgbuf);
+    }
+    if (x->x_flush)
+        fflush(stdout);
 }
 
 static void stdout_free(t_stdout *x)
@@ -45,6 +157,6 @@ static void stdout_free(t_stdout *x)
 void stdout_setup(void)
 {
     stdout_class = class_new(gensym("stdout"), (t_newmethod)stdout_new,
-        (t_method)stdout_free, sizeof(t_stdout), 0, 0);
+        (t_method)stdout_free, sizeof(t_stdout), 0, A_GIMME, 0);
     class_addanything(stdout_class, stdout_anything);
 }
-- 
GitLab