From 1f016c21cfd30ba1d602727cc316f239bbae7f48 Mon Sep 17 00:00:00 2001
From: Miller Puckette <msp@ucsd.edu>
Date: Mon, 14 Jan 2008 18:16:19 -0800
Subject: [PATCH] took various small patches

---
 doc/5.reference/swap-help.pd    |   61 +-
 doc/5.reference/trigger-help.pd |    2 +-
 src/m_class.c                   |    6 +-
 src/m_pd.h                      |    3 +-
 src/s_inter.c                   |    6 +-
 src/s_main.c                    |    2 +-
 src/s_main.c.orig               | 1013 +++++++++++++++++++++++++++++++
 src/s_path.c                    |   34 +-
 src/s_path.c.orig               |  580 ++++++++++++++++++
 src/x_connective.c              |    2 +-
 10 files changed, 1667 insertions(+), 42 deletions(-)
 create mode 100644 src/s_main.c.orig
 create mode 100644 src/s_path.c.orig

diff --git a/doc/5.reference/swap-help.pd b/doc/5.reference/swap-help.pd
index 987a58441..039e5659e 100644
--- a/doc/5.reference/swap-help.pd
+++ b/doc/5.reference/swap-help.pd
@@ -1,20 +1,41 @@
-#N canvas 376 130 488 326 12;
-#X msg 67 124 bang;
-#X floatatom 67 252;
-#X floatatom 79 154;
-#X floatatom 118 194;
-#X obj 66 15 swap;
-#X text 114 16 - SWAP TWO NUMBERS \, RESPECTING RIGHT-TO-LEFT ORDER;
-#X text 284 309 updated for Pd version 0.27;
-#X text 12 42 The swap object stores numbers from its left inlet to output on its right inlet -- after repeating its right hand input out the left.;
-#X text 112 123 outputs 2 stored values;
-#X obj 67 226 swap 6.5;
-#X text 110 154 sets second value and outputs both;
-#X text 150 195 sets first value;
-#X text 142 226 creation argument initializes first value;
-#X floatatom 118 254;
-#X connect 0 0 9 0;
-#X connect 2 0 9 0;
-#X connect 3 0 9 1;
-#X connect 9 0 1 0;
-#X connect 9 1 13 0;
+#N canvas 475 187 615 593 12;
+#X msg 72 167 bang;
+#X floatatom 72 292 0 0 0 0 - - -;
+#X floatatom 84 200 0 0 0 0 - - -;
+#X floatatom 139 237 0 0 0 0 - - -;
+#X obj 33 15 swap;
+#X text 81 16 - SWAP TWO NUMBERS \, RESPECTING RIGHT-TO-LEFT ORDER
+;
+#X text 117 166 outputs 2 stored values;
+#X obj 72 266 swap 6.5;
+#X text 115 200 sets second value and outputs both;
+#X text 171 238 sets first value;
+#X text 157 266 creation argument initializes first value;
+#X floatatom 139 291 0 0 0 0 - - -;
+#X obj 139 331 print right;
+#X obj 72 367 print left;
+#X text 43 427 A common use of swap is to reverse the operands in arithmetic
+objects like this:;
+#X obj 72 491 swap;
+#X obj 72 519 -;
+#X floatatom 72 541 5 0 0 0 - - -;
+#X floatatom 103 469 3 0 0 0 - - -;
+#X floatatom 72 469 3 0 0 0 - - -;
+#X text 291 549 updated for Pd version 0.41;
+#X text 32 52 The swap object swaps the positions of two incoming numbers.
+The number coming in through the right inlet will be sent to the left
+outlet and the number coming in left will come out right. Only the
+left inlet is hot and triggers output on both outlets. Output order
+is right to left as in [trigger].;
+#X connect 0 0 7 0;
+#X connect 1 0 13 0;
+#X connect 2 0 7 0;
+#X connect 3 0 7 1;
+#X connect 7 0 1 0;
+#X connect 7 1 11 0;
+#X connect 11 0 12 0;
+#X connect 15 0 16 0;
+#X connect 15 1 16 1;
+#X connect 16 0 17 0;
+#X connect 18 0 15 1;
+#X connect 19 0 15 0;
diff --git a/doc/5.reference/trigger-help.pd b/doc/5.reference/trigger-help.pd
index a32d5defc..3fae71128 100644
--- a/doc/5.reference/trigger-help.pd
+++ b/doc/5.reference/trigger-help.pd
@@ -14,7 +14,7 @@
 #X text 39 59 The trigger object outputs its input from right to left
 \, converting to the types indicated by its creation arguments. There
 is also a "pointer" argument type (see the pointer object.);
-#X obj 381 293 t f b l s a;
+#X obj 381 293 t f b s l a;
 #X msg 466 167 dog my cats;
 #X obj 466 199 trigger bang anything;
 #X obj 374 242 print x5;
diff --git a/src/m_class.c b/src/m_class.c
index 622fbd2da..ab0b86bed 100644
--- a/src/m_class.c
+++ b/src/m_class.c
@@ -459,12 +459,12 @@ t_propertiesfn class_getpropertiesfn(t_class *c)
 
 static t_symbol *symhash[HASHSIZE];
 
-t_symbol *dogensym(char *s, t_symbol *oldsym)
+t_symbol *dogensym(const char *s, t_symbol *oldsym)
 {
     t_symbol **sym1, *sym2;
     unsigned int hash1 = 0,  hash2 = 0;
     int length = 0;
-    char *s2 = s;
+    const char *s2 = s;
     while (*s2)
     {
         hash1 += *s2;
@@ -491,7 +491,7 @@ t_symbol *dogensym(char *s, t_symbol *oldsym)
     return (sym2);
 }
 
-t_symbol *gensym(char *s)
+t_symbol *gensym(const char *s)
 {
     return(dogensym(s, 0));
 }
diff --git a/src/m_pd.h b/src/m_pd.h
index c92ba837c..25d811279 100644
--- a/src/m_pd.h
+++ b/src/m_pd.h
@@ -225,7 +225,7 @@ EXTERN t_symbol s_;
 /* --------- prototypes from the central message system ----------- */
 EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
 EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
-EXTERN t_symbol *gensym(char *s);
+EXTERN t_symbol *gensym(const char *s);
 EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
 EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
 EXTERN void nullfn(void);
@@ -417,6 +417,7 @@ EXTERN char *class_gethelpname(t_class *c);
 EXTERN void class_setdrawcommand(t_class *c);
 EXTERN int class_isdrawcommand(t_class *c);
 EXTERN void class_domainsignalin(t_class *c, int onset);
+EXTERN void class_set_extern_dir(t_symbol *s);
 #define CLASS_MAINSIGNALIN(c, type, field) \
     class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
 
diff --git a/src/s_inter.c b/src/s_inter.c
index 816e6207a..85a5af306 100644
--- a/src/s_inter.c
+++ b/src/s_inter.c
@@ -250,12 +250,14 @@ static void sys_huphandler(int n)
 void sys_setalarm(int microsec)
 {
     struct itimerval gonzo;
+    int sec = (int)(microsec/1000000);
+    microsec %= 1000000;
 #if 0
-    fprintf(stderr, "timer %d\n", microsec);
+    fprintf(stderr, "timer %d:%d\n", sec, microsec);
 #endif
     gonzo.it_interval.tv_sec = 0;
     gonzo.it_interval.tv_usec = 0;
-    gonzo.it_value.tv_sec = 0;
+    gonzo.it_value.tv_sec = sec;
     gonzo.it_value.tv_usec = microsec;
     if (microsec)
         sys_signal(SIGALRM, sys_alarmhandler);
diff --git a/src/s_main.c b/src/s_main.c
index 52795cfef..3002937f1 100644
--- a/src/s_main.c
+++ b/src/s_main.c
@@ -295,7 +295,7 @@ int sys_main(int argc, char **argv)
         HINSTANCE ntdll;
         char filename[MAXPDSTRING];
 
-        sprintf(filename, "%s.dll", sys_externalschedlibname);
+        snprintf(filename, sizeof(filename), "%s.dll", sys_externalschedlibname);
         sys_bashfilename(filename, filename);
         ntdll = LoadLibrary(filename);
         if (!ntdll)
diff --git a/src/s_main.c.orig b/src/s_main.c.orig
new file mode 100644
index 000000000..52795cfef
--- /dev/null
+++ b/src/s_main.c.orig
@@ -0,0 +1,1013 @@
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#include "m_pd.h"
+#include "m_imp.h"
+#include "s_stuff.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+char *pd_version;
+char pd_compiletime[] = __TIME__;
+char pd_compiledate[] = __DATE__;
+
+void pd_init(void);
+int sys_argparse(int argc, char **argv);
+void sys_findprogdir(char *progname);
+int sys_startgui(const char *guipath);
+int sys_rcfile(void);
+int m_mainloop(void);
+void sys_addhelppath(char *p);
+#ifdef USEAPI_ALSA
+void alsa_adddev(char *name);
+#endif
+
+int sys_debuglevel;
+int sys_verbose;
+int sys_noloadbang;
+int sys_nogui;
+int sys_hipriority = -1;    /* -1 = don't care; 0 = no; 1 = yes */
+int sys_guisetportnumber;   /* if started from the GUI, this is the port # */
+int sys_nosleep = 0;  /* skip all "sleep" calls and spin instead */
+
+char *sys_guicmd;
+t_symbol *sys_libdir;
+static t_symbol *sys_guidir;
+static t_namelist *sys_openlist;
+static t_namelist *sys_messagelist;
+static int sys_version;
+int sys_oldtclversion;      /* hack to warn g_rtext.c about old text sel */
+
+int sys_nmidiout = -1;
+int sys_nmidiin = -1;
+int sys_midiindevlist[MAXMIDIINDEV] = {1};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
+
+char sys_font[100] = 
+#ifdef MSW
+    "Courier";
+#else
+    "Courier";
+#endif
+char sys_fontweight[] = "bold  "; /* currently only used for iemguis */
+static int sys_main_srate;
+static int sys_main_advance;
+static int sys_main_callback;
+static int sys_listplease;
+
+int sys_externalschedlib;
+char sys_externalschedlibname[MAXPDSTRING];
+int sys_extraflags;
+char sys_extraflagsstring[MAXPDSTRING];
+
+
+    /* here the "-1" counts signify that the corresponding vector hasn't been
+    specified in command line arguments; sys_set_audio_settings will detect it
+    and fill things in. */
+static int sys_nsoundin = -1;
+static int sys_nsoundout = -1;
+static int sys_soundindevlist[MAXAUDIOINDEV];
+static int sys_soundoutdevlist[MAXAUDIOOUTDEV];
+
+static int sys_nchin = -1;
+static int sys_nchout = -1;
+static int sys_chinlist[MAXAUDIOINDEV];
+static int sys_choutlist[MAXAUDIOOUTDEV];
+
+t_sample* get_sys_soundout() { return sys_soundout; }
+t_sample* get_sys_soundin() { return sys_soundin; }
+int* get_sys_main_advance() { return &sys_main_advance; }
+double* get_sys_time_per_dsp_tick() { return &sys_time_per_dsp_tick; }
+int* get_sys_schedblocksize() { return &sys_schedblocksize; }
+double* get_sys_time() { return &sys_time; }
+t_float* get_sys_dacsr() { return &sys_dacsr; }
+int* get_sys_sleepgrain() { return &sys_sleepgrain; }
+int* get_sys_schedadvance() { return &sys_schedadvance; }
+
+typedef struct _fontinfo
+{
+    int fi_fontsize;
+    int fi_maxwidth;
+    int fi_maxheight;
+    int fi_hostfontsize;
+    int fi_width;
+    int fi_height;
+} t_fontinfo;
+
+    /* these give the nominal point size and maximum height of the characters
+    in the six fonts.  */
+
+static t_fontinfo sys_fontlist[] = {
+    {8, 6, 10, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
+    {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
+#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
+
+/* here are the actual font size structs on msp's systems:
+MSW:
+font 8 5 9 8 5 11
+font 10 7 13 10 6 13
+font 12 9 16 14 8 16
+font 16 10 20 16 10 18
+font 24 15 25 16 10 18
+font 36 25 42 36 22 41
+
+linux:
+font 8 5 9 8 5 9
+font 10 7 13 12 7 13
+font 12 9 16 14 9 15
+font 16 10 20 16 10 19
+font 24 15 25 24 15 24
+font 36 25 42 36 22 41
+*/
+
+static t_fontinfo *sys_findfont(int fontsize)
+{
+    unsigned int i;
+    t_fontinfo *fi;
+    for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
+        if (fontsize < fi[1].fi_fontsize) return (fi);
+    return (sys_fontlist + (NFONT-1));
+}
+
+int sys_nearestfontsize(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_fontsize);
+}
+
+int sys_hostfontsize(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_hostfontsize);
+}
+
+int sys_fontwidth(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_width);
+}
+
+int sys_fontheight(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_height);
+}
+
+int sys_defaultfont;
+#define DEFAULTFONT 10
+
+static void openit(const char *dirname, const char *filename)
+{
+    char dirbuf[MAXPDSTRING], *nameptr;
+    int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
+        MAXPDSTRING, 0);
+    if (fd >= 0)
+    {
+        close (fd);
+        glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
+    }
+    else
+        error("%s: can't open", filename);
+}
+
+/* this is called from the gui process.  The first argument is the cwd, and
+succeeding args give the widths and heights of known fonts.  We wait until 
+these are known to open files and send messages specified on the command line.
+We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
+from; for instance we could be some kind of RT embedded system.  However, to
+really make this make sense we would have to implement
+open(), read(), etc, calls to be served somehow from the GUI too. */
+
+void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+    char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
+    t_namelist *nl;
+    unsigned int i;
+    int j;
+    int nhostfont = (argc-2)/3;
+    sys_oldtclversion = atom_getfloatarg(1, argc, argv);
+    if (argc != 2 + 3 * nhostfont) bug("glob_initfromgui");
+    for (i = 0; i < NFONT; i++)
+    {
+        int best = 0;
+        int wantheight = sys_fontlist[i].fi_maxheight;
+        int wantwidth = sys_fontlist[i].fi_maxwidth;
+        for (j = 1; j < nhostfont; j++)
+        {
+            if (atom_getintarg(3 * j + 4, argc, argv) <= wantheight &&
+                atom_getintarg(3 * j + 3, argc, argv) <= wantwidth)
+                    best = j;
+        }
+            /* best is now the host font index for the desired font index i. */
+        sys_fontlist[i].fi_hostfontsize =
+            atom_getintarg(3 * best + 2, argc, argv);
+        sys_fontlist[i].fi_width = atom_getintarg(3 * best + 3, argc, argv);
+        sys_fontlist[i].fi_height = atom_getintarg(3 * best + 4, argc, argv);
+    }
+#if 0
+    for (i = 0; i < 6; i++)
+        fprintf(stderr, "font (%d %d %d) -> (%d %d %d)\n",
+            sys_fontlist[i].fi_fontsize,
+            sys_fontlist[i].fi_maxwidth,
+            sys_fontlist[i].fi_maxheight,
+            sys_fontlist[i].fi_hostfontsize,
+            sys_fontlist[i].fi_width,
+            sys_fontlist[i].fi_height);
+#endif
+        /* load dynamic libraries specified with "-lib" args */
+    for  (nl = sys_externlist; nl; nl = nl->nl_next)
+        if (!sys_load_lib(0, nl->nl_string))
+            post("%s: can't load library", nl->nl_string);
+        /* open patches specifies with "-open" args */
+    for  (nl = sys_openlist; nl; nl = nl->nl_next)
+        openit(cwd, nl->nl_string);
+    namelist_free(sys_openlist);
+    sys_openlist = 0;
+        /* send messages specified with "-send" args */
+    for  (nl = sys_messagelist; nl; nl = nl->nl_next)
+    {
+        t_binbuf *b = binbuf_new();
+        binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
+        binbuf_eval(b, 0, 0, 0);
+        binbuf_free(b);
+    }
+    namelist_free(sys_messagelist);
+    sys_messagelist = 0;
+}
+
+static void sys_afterargparse(void);
+
+static void pd_makeversion(void)
+{
+    char foo[100];
+    sprintf(foo,  "Pd version %d.%d-%d%s\n",PD_MAJOR_VERSION,
+        PD_MINOR_VERSION,PD_BUGFIX_VERSION,PD_TEST_VERSION);
+    pd_version = malloc(strlen(foo)+1);
+    strcpy(pd_version, foo);
+}
+
+/* this is called from main() in s_entry.c */
+int sys_main(int argc, char **argv)
+{
+    int i, noprefs;
+    sys_externalschedlib = 0;
+    sys_extraflags = 0;
+#ifdef PD_DEBUG
+    fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
+#endif
+    pd_init();                                  /* start the message system */
+    sys_findprogdir(argv[0]);                   /* set sys_progname, guipath */
+    for (i = noprefs = 0; i < argc; i++)        /* prescan args for noprefs */
+        if (!strcmp(argv[i], "-noprefs"))
+            noprefs = 1;
+    if (!noprefs)
+        sys_loadpreferences();                  /* load default settings */
+#ifndef MSW
+    sys_rcfile();                               /* parse the startup file */
+#endif
+    if (sys_argparse(argc-1, argv+1))           /* parse cmd line */
+        return (1);
+    sys_afterargparse();                    /* post-argparse settings */
+        /* build version string from defines in m_pd.h */
+    pd_makeversion();
+    if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
+        pd_version, pd_compiletime, pd_compiledate);
+    if (sys_version)    /* if we were just asked our version, exit here. */
+        return (0);
+    if (sys_startgui(sys_guidir->s_name))       /* start the gui */
+        return(1);
+    if (sys_externalschedlib)
+    {
+#ifdef MSW
+        typedef int (*t_externalschedlibmain)(char *);
+        t_externalschedlibmain externalmainfunc;
+        HINSTANCE ntdll;
+        char filename[MAXPDSTRING];
+
+        sprintf(filename, "%s.dll", sys_externalschedlibname);
+        sys_bashfilename(filename, filename);
+        ntdll = LoadLibrary(filename);
+        if (!ntdll)
+        {
+              post("%s: couldn't load external scheduler lib ", filename);
+              return (0);
+        }
+        externalmainfunc = (t_externalschedlibmain)GetProcAddress(ntdll,
+                                                                  "main");
+        return((*externalmainfunc)(sys_extraflagsstring));
+#else
+        return (0);
+#endif
+    }
+    else
+    {
+            /* open audio and MIDI */
+        sys_reopen_midi();
+        sys_reopen_audio();
+            /* run scheduler until it quits */
+        return (m_mainloop());
+    }
+}
+
+static char *(usagemessage[]) = {
+"usage: pd [-flags] [file]...\n",
+"\naudio configuration flags:\n",
+"-r <n>           -- specify sample rate\n",
+"-audioindev ...  -- audio in devices; e.g., \"1,3\" for first and third\n",
+"-audiooutdev ... -- audio out devices (same)\n",
+"-audiodev ...    -- specify input and output together\n",
+"-inchannels ...  -- audio input channels (by device, like \"2\" or \"16,8\")\n",
+"-outchannels ... -- number of audio out channels (same)\n",
+"-channels ...    -- specify both input and output channels\n",
+"-audiobuf <n>    -- specify size of audio buffer in msec\n",
+"-blocksize <n>   -- specify audio I/O block size in sample frames\n",
+"-sleepgrain <n>  -- specify number of milliseconds to sleep when idle\n",
+"-nodac           -- suppress audio output\n",
+"-noadc           -- suppress audio input\n",
+"-noaudio         -- suppress audio input and output (-nosound is synonym) \n",
+"-listdev         -- list audio and MIDI devices\n",
+
+#ifdef USEAPI_OSS
+"-oss             -- use OSS audio API\n",
+"-32bit           ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
+#endif
+
+#ifdef USEAPI_ALSA
+"-alsa            -- use ALSA audio API\n",
+"-alsaadd <name>  -- add an ALSA device name to list\n",
+#endif
+
+#ifdef USEAPI_JACK
+"-jack            -- use JACK audio API\n",
+#endif
+
+#ifdef USEAPI_PORTAUDIO
+#ifdef MSW
+"-asio            -- use ASIO audio driver (via Portaudio)\n",
+"-pa              -- synonym for -asio\n",
+#else
+"-pa              -- use Portaudio API\n",
+#endif
+#endif
+
+#ifdef USEAPI_MMIO
+"-mmio            -- use MMIO audio API (default for Windows)\n",
+#endif
+"      (default audio API for this platform:  ", API_DEFSTRING, ")\n\n",
+
+"\nMIDI configuration flags:\n",
+"-midiindev ...   -- midi in device list; e.g., \"1,3\" for first and third\n",
+"-midioutdev ...  -- midi out device list, same format\n",
+"-mididev ...     -- specify -midioutdev and -midiindev together\n",
+"-nomidiin        -- suppress MIDI input\n",
+"-nomidiout       -- suppress MIDI output\n",
+"-nomidi          -- suppress MIDI input and output\n",
+#ifdef USEAPI_ALSA
+"-alsamidi        -- use ALSA midi API\n",
+#endif
+
+
+"\nother flags:\n",
+"-path <path>     -- add to file search path\n",
+"-nostdpath       -- don't search standard (\"extra\") directory\n",
+"-stdpath         -- search standard directory (true by default)\n",
+"-helppath <path> -- add to help file search path\n",
+"-open <file>     -- open file(s) on startup\n",
+"-lib <file>      -- load object library(s)\n",
+"-font-size <n>     -- specify default font size in points\n",
+"-font-face <name>  -- specify default font\n",
+"-font-weight <name>-- specify default font weight (normal or bold)\n",
+"-verbose         -- extra printout on startup and when searching for files\n",
+"-version         -- don't run Pd; just print out which version it is \n",
+"-d <n>           -- specify debug level\n",
+"-noloadbang      -- suppress all loadbangs\n",
+"-stderr          -- send printout to standard error instead of GUI\n",
+"-nogui           -- suppress starting the GUI\n",
+"-guiport <n>     -- connect to pre-existing GUI over port <n>\n",
+"-guicmd \"cmd...\" -- start alternatve GUI program (e.g., remote via ssh)\n",
+"-send \"msg...\"   -- send a message at startup, after patches are loaded\n",
+"-noprefs         -- suppress loading preferences on startup\n",
+#ifdef UNISTD
+"-rt or -realtime -- use real-time priority\n",
+"-nrt             -- don't use real-time priority\n",
+#endif
+"-nosleep         -- spin, don't sleep (may lower latency on multi-CPUs)\n",
+};
+
+static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
+{
+    int n = 0;
+    while (n < max)
+    {
+        if (!*str) break;
+        else
+        {
+            char *endp;
+            vecp[n] = strtol(str, &endp, 10);
+            if (endp == str)
+                break;
+            n++;
+            if (!endp)
+                break;
+            str = endp + 1;
+        }
+    }
+    *np = n;
+}
+
+static int sys_getmultidevchannels(int n, int *devlist)
+{
+    int sum = 0;
+    if (n<0)return(-1);
+    if (n==0)return 0;
+    while(n--)sum+=*devlist++;
+    return sum;
+}
+
+
+    /* this routine tries to figure out where to find the auxilliary files
+    Pd will need to run.  This is either done by looking at the command line
+    invokation for Pd, or if that fails, by consulting the variable
+    INSTALL_PREFIX.  In MSW, we don't try to use INSTALL_PREFIX. */
+void sys_findprogdir(char *progname)
+{
+    char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
+    char *lastslash; 
+#ifdef UNISTD
+    struct stat statbuf;
+#endif
+
+    /* find out by what string Pd was invoked; put answer in "sbuf". */
+#ifdef MSW
+    GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
+    sbuf2[MAXPDSTRING-1] = 0;
+    sys_unbashfilename(sbuf2, sbuf);
+#endif /* MSW */
+#ifdef UNISTD
+    strncpy(sbuf, progname, MAXPDSTRING);
+    sbuf[MAXPDSTRING-1] = 0;
+#endif
+    lastslash = strrchr(sbuf, '/');
+    if (lastslash)
+    {
+            /* bash last slash to zero so that sbuf is directory pd was in,
+                e.g., ~/pd/bin */
+        *lastslash = 0; 
+            /* go back to the parent from there, e.g., ~/pd */
+        lastslash = strrchr(sbuf, '/');
+        if (lastslash)
+        {
+            strncpy(sbuf2, sbuf, lastslash-sbuf);
+            sbuf2[lastslash-sbuf] = 0;
+        }
+        else strcpy(sbuf2, "..");
+    }
+    else
+    {
+            /* no slashes found.  Try INSTALL_PREFIX. */
+#ifdef INSTALL_PREFIX
+        strcpy(sbuf2, INSTALL_PREFIX);
+#else
+        strcpy(sbuf2, ".");
+#endif
+    }
+        /* now we believe sbuf2 holds the parent directory of the directory
+        pd was found in.  We now want to infer the "lib" directory and the
+        "gui" directory.  In "simple" unix installations, the layout is
+            .../bin/pd
+            .../bin/pd-gui
+            .../doc
+        and in "complicated" unix installations, it's:
+            .../bin/pd
+            .../lib/pd/bin/pd-gui
+            .../lib/pd/doc
+        To decide which, we stat .../lib/pd; if that exists, we assume it's
+        the complicated layout.  In MSW, it's the "simple" layout, but
+        the gui program is straight wish80:
+            .../bin/pd
+            .../bin/wish80.exe
+            .../doc
+        */
+#ifdef MSW
+    sys_libdir = gensym(sbuf2);
+    sys_guidir = &s_;   /* in MSW the guipath just depends on the libdir */
+#else
+    strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/lib/pd");
+    if (stat(sbuf, &statbuf) >= 0)
+    {
+            /* complicated layout: lib dir is the one we just stat-ed above */
+        sys_libdir = gensym(sbuf);
+            /* gui lives in .../lib/pd/bin */
+        strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+        sbuf[MAXPDSTRING-30] = 0;
+        strcat(sbuf, "/lib/pd/bin");
+        sys_guidir = gensym(sbuf);
+    }
+    else
+    {
+            /* simple layout: lib dir is the parent */
+        sys_libdir = gensym(sbuf2);
+            /* gui lives in .../bin */
+        strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+        sbuf[MAXPDSTRING-30] = 0;
+        strcat(sbuf, "/bin");
+        sys_guidir = gensym(sbuf);
+    }
+#endif
+}
+
+#ifdef MSW
+static int sys_mmio = 1;
+#else
+static int sys_mmio = 0;
+#endif
+
+int sys_argparse(int argc, char **argv)
+{
+    char sbuf[MAXPDSTRING];
+    int i;
+    while ((argc > 0) && **argv == '-')
+    {
+        if (!strcmp(*argv, "-r") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_main_srate) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-inchannels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchin,
+                sys_chinlist, MAXAUDIOINDEV, argv[1]);
+
+          if (!sys_nchin)
+              goto usage;
+
+          argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-outchannels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchout, sys_choutlist,
+                MAXAUDIOOUTDEV, argv[1]);
+
+          if (!sys_nchout)
+            goto usage;
+
+          argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-channels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
+                argv[1]);
+            sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV,
+                argv[1]);
+
+            if (!sys_nchout)
+              goto usage;
+
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf") && (argc > 1))
+        {
+            sys_main_advance = atoi(argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-callback"))
+        {
+            sys_main_callback = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-blocksize"))
+        {
+            sys_setblocksize(atoi(argv[1]));
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-sleepgrain") && (argc > 1))
+        {
+            sys_sleepgrain = 1000 * atof(argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-nodac"))
+        {
+            sys_nsoundout=0;
+            sys_nchout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-noadc"))
+        {
+            sys_nsoundin=0;
+            sys_nchin = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
+        {
+            sys_nsoundin=sys_nsoundout = 0;
+            sys_nchin = sys_nchout = 0;
+            argc--; argv++;
+        }
+#ifdef USEAPI_OSS
+        else if (!strcmp(*argv, "-oss"))
+        {
+            sys_set_audio_api(API_OSS);
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-32bit"))
+        {
+            sys_set_audio_api(API_OSS);
+            oss_set32bit();
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_ALSA
+        else if (!strcmp(*argv, "-alsa"))
+        {
+            sys_set_audio_api(API_ALSA);
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-alsaadd") && (argc > 1))
+        {
+            if (argc > 1)
+                alsa_adddev(argv[1]);
+            else goto usage;
+            argc -= 2; argv +=2;
+        }
+        else if (!strcmp(*argv, "-alsamidi"))
+        {
+          sys_set_midi_api(API_ALSA);
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_JACK
+        else if (!strcmp(*argv, "-jack"))
+        {
+            sys_set_audio_api(API_JACK);
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_PORTAUDIO
+        else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")
+#ifdef MSW
+            || !strcmp(*argv, "-asio")
+#endif
+            )
+        {
+            sys_set_audio_api(API_PORTAUDIO);
+            sys_mmio = 0;
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_MMIO
+        else if (!strcmp(*argv, "-mmio"))
+        {
+            sys_set_audio_api(API_MMIO);
+            sys_mmio = 1;
+            argc--; argv++;
+        }
+#endif
+        else if (!strcmp(*argv, "-nomidiin"))
+        {
+            sys_nmidiin = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nomidiout"))
+        {
+            sys_nmidiout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nomidi"))
+        {
+            sys_nmidiin = sys_nmidiout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-midiindev"))
+        {
+            sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+                argv[1]);
+            if (!sys_nmidiin)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-midioutdev") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+                argv[1]);
+            if (!sys_nmidiout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-mididev") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+                argv[1]);
+            sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+                argv[1]);
+            if (!sys_nmidiout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-path") && (argc > 1))
+        {
+            sys_searchpath = namelist_append_files(sys_searchpath, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-nostdpath"))
+        {
+            sys_usestdpath = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-stdpath"))
+        {
+            sys_usestdpath = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-helppath"))
+        {
+            sys_helppath = namelist_append_files(sys_helppath, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-open") && argc > 1)
+        {
+            sys_openlist = namelist_append_files(sys_openlist, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-lib") && argc > 1)
+        {
+            sys_externlist = namelist_append_files(sys_externlist, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if ((!strcmp(*argv, "-font-size") || !strcmp(*argv, "-font"))
+            && argc > 1)
+        {
+            sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
+            argc -= 2;
+            argv += 2;
+        }
+        else if ((!strcmp(*argv, "-font-face") || !strcmp(*argv, "-typeface"))
+            && argc > 1)
+        {
+            strncpy(sys_font,*(argv+1),sizeof(sys_font)-1);
+            sys_font[sizeof(sys_font)-1] = 0;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-font-weight") && argc > 1)
+        {
+            strncpy(sys_fontweight,*(argv+1),sizeof(sys_fontweight)-1);
+            sys_fontweight[sizeof(sys_fontweight)-1] = 0;
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-verbose"))
+        {
+            sys_verbose++;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-version"))
+        {
+            sys_version = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-d") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-noloadbang"))
+        {
+            sys_noloadbang = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nogui"))
+        {
+            sys_printtostderr = sys_nogui = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-guiport") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_guisetportnumber) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-stderr"))
+        {
+            sys_printtostderr = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-guicmd") && argc > 1)
+        {
+            sys_guicmd = argv[1];
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-send") && argc > 1)
+        {
+            sys_messagelist = namelist_append(sys_messagelist, argv[1], 1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-listdev"))
+        {
+            sys_listplease = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-schedlib"))
+        {
+            sys_externalschedlib = 1;
+            strncpy(sys_externalschedlibname, argv[1],
+                sizeof(sys_externalschedlibname) - 1);
+            argv += 2;
+            argc -= 2;
+        }
+        else if (!strcmp(*argv, "-extraflags"))
+        {
+            sys_extraflags = 1;
+            strncpy(sys_extraflagsstring, argv[1],
+                sizeof(sys_extraflagsstring) - 1);
+            argv += 2;
+            argc -= 2;
+        }
+#ifdef UNISTD
+        else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
+        {
+            sys_hipriority = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nrt"))
+        {
+            sys_hipriority = 0;
+            argc--; argv++;
+        }
+#endif
+        else if (!strcmp(*argv, "-nosleep"))
+        {
+            sys_nosleep = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-soundindev") ||
+            !strcmp(*argv, "-audioindev"))
+        {
+            sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+                MAXAUDIOINDEV, argv[1]);
+            if (!sys_nsoundin)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-soundoutdev") ||
+            !strcmp(*argv, "-audiooutdev"))
+        {
+            sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+                MAXAUDIOOUTDEV, argv[1]);
+            if (!sys_nsoundout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if ((!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
+                 && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+                MAXAUDIOINDEV, argv[1]);
+            sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+                MAXAUDIOOUTDEV, argv[1]);
+            if (!sys_nsoundout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-noprefs")) /* did this earlier */
+            argc--, argv++;
+        else
+        {
+            unsigned int i;
+        usage:
+            for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
+                fprintf(stderr, "%s", usagemessage[i]);
+            return (1);
+        }
+    }
+    if (!sys_defaultfont)
+        sys_defaultfont = DEFAULTFONT;
+    for (; argc > 0; argc--, argv++) 
+        sys_openlist = namelist_append_files(sys_openlist, *argv);
+
+
+    return (0);
+}
+
+int sys_getblksize(void)
+{
+    return (DEFDACBLKSIZE);
+}
+
+    /* stuff to do, once, after calling sys_argparse() -- which may itself
+    be called more than once (first from "settings, second from .pdrc, then
+    from command-line arguments */
+static void sys_afterargparse(void)
+{
+    char sbuf[MAXPDSTRING];
+    int i;
+    int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
+    int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
+    int nchindev, nchoutdev, rate, advance, callback;
+    int nmidiindev = 0, midiindev[MAXMIDIINDEV];
+    int nmidioutdev = 0, midioutdev[MAXMIDIOUTDEV];
+            /* add "extra" library to path */
+    strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/extra");
+    sys_setextrapath(sbuf);
+            /* add "doc/5.reference" library to helppath */
+    strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/doc/5.reference");
+    sys_helppath = namelist_append_files(sys_helppath, sbuf);
+        /* correct to make audio and MIDI device lists zero based.  On
+        MMIO, however, "1" really means the second device (the first one
+        is "mapper" which is was not included when the command args were
+        set up, so we leave it that way for compatibility. */
+    if (!sys_mmio)
+    {
+        for (i = 0; i < sys_nsoundin; i++)
+            sys_soundindevlist[i]--;
+        for (i = 0; i < sys_nsoundout; i++)
+            sys_soundoutdevlist[i]--;
+    }
+    for (i = 0; i < sys_nmidiin; i++)
+        sys_midiindevlist[i]--;
+    for (i = 0; i < sys_nmidiout; i++)
+        sys_midioutdevlist[i]--;
+    if (sys_listplease)
+        sys_listdevs();
+        
+            /* get the current audio parameters.  These are set
+            by the preferences mechanism (sys_loadpreferences()) or
+            else are the default.  Overwrite them with any results
+            of argument parsing, and store them again. */
+    sys_get_audio_params(&naudioindev, audioindev, chindev,
+        &naudiooutdev, audiooutdev, choutdev, &rate, &advance, &callback);
+    if (sys_nchin >= 0)
+    {
+        nchindev = sys_nchin;
+        for (i = 0; i < nchindev; i++)
+            chindev[i] = sys_chinlist[i];
+    }
+    else nchindev = naudioindev;
+    if (sys_nsoundin >= 0)
+    {
+        naudioindev = sys_nsoundin;
+        for (i = 0; i < naudioindev; i++)
+            audioindev[i] = sys_soundindevlist[i];
+    }
+    
+    if (sys_nchout >= 0)
+    {
+        nchoutdev = sys_nchout;
+        for (i = 0; i < nchoutdev; i++)
+            choutdev[i] = sys_choutlist[i];
+    }
+    else nchoutdev = naudiooutdev;
+    if (sys_nsoundout >= 0)
+    {
+        naudiooutdev = sys_nsoundout;
+        for (i = 0; i < naudiooutdev; i++)
+            audiooutdev[i] = sys_soundoutdevlist[i];
+    }
+    sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+    if (sys_nmidiin >= 0)
+    {
+        post("sys_nmidiin %d, nmidiindev %d", sys_nmidiin, nmidiindev);
+        nmidiindev = sys_nmidiin;
+        for (i = 0; i < nmidiindev; i++)
+            midiindev[i] = sys_midiindevlist[i];
+    }
+    if (sys_nmidiout >= 0)
+    {
+        nmidioutdev = sys_nmidiout;
+        for (i = 0; i < nmidioutdev; i++)
+            midioutdev[i] = sys_midioutdevlist[i];
+    }
+    if (sys_main_advance)
+        advance = sys_main_advance;
+    if (sys_main_srate)
+        rate = sys_main_srate;
+    if (sys_main_callback)
+        callback = sys_main_callback;
+    sys_set_audio_settings(naudioindev, audioindev, nchindev, chindev,
+        naudiooutdev, audiooutdev, nchoutdev, choutdev, rate, advance, 
+        callback);
+    sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0);
+}
+
+static void sys_addreferencepath(void)
+{
+    char sbuf[MAXPDSTRING];
+}
diff --git a/src/s_path.c b/src/s_path.c
index 0d9728619..f96ea872f 100644
--- a/src/s_path.c
+++ b/src/s_path.c
@@ -71,21 +71,29 @@ void sys_unbashfilename(const char *from, char *to)
 
 /*******************  Utility functions used below ******************/
 
-/* copy until delimiter and return position after delimiter in string */
-/* if it was the last substring, return NULL */
-
-static const char* strtokcpy(char *to, const char *from, int delim)
+/*!
+ * \brief copy until delimiter
+ * 
+ * \arg to destination buffer
+ * \arg to_len destination buffer length
+ * \arg from source buffer
+ * \arg delim string delimiter to stop copying on
+ *
+ * \return position after delimiter in string.  If it was the last
+ *         substring, return NULL.
+ */
+static const char *strtokcpy(char *to, size_t to_len, const char *from, char delim)
 {
-    int size = 0;
+    unsigned int i = 0;
+
+	for (; i < (to_len - 1) && from[i] && from[i] != delim; i++)
+		to[i] = from[i];
+	to[i] = '\0';
 
-    while (from[size] != (char)delim && from[size] != '\0')
-        size++;
+	if (i && from[i] != '\0')
+		return from + i + 1;
 
-    strncpy(to,from,size);
-    to[size] = '\0';
-    if (from[size] == '\0') return NULL;
-    if (size) return from+size+1;
-    else return NULL;
+	return NULL;
 }
 
 /* add a single item to a namelist.  If "allowdup" is true, duplicates
@@ -133,7 +141,7 @@ t_namelist *namelist_append_files(t_namelist *listwas, const char *s)
     npos = s;
     do
     {
-        npos = strtokcpy(temp, npos, SEPARATOR);
+        npos = strtokcpy(temp, sizeof(temp), npos, SEPARATOR);
         if (! *temp) continue;
         nl = namelist_append(nl, temp, 0);
     }
diff --git a/src/s_path.c.orig b/src/s_path.c.orig
new file mode 100644
index 000000000..0d9728619
--- /dev/null
+++ b/src/s_path.c.orig
@@ -0,0 +1,580 @@
+/* Copyright (c) 1999 Guenter Geiger and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+/*
+ * This file implements the loader for linux, which includes
+ * a little bit of path handling.
+ *
+ * Generalized by MSP to provide an open_via_path function
+ * and lists of files for all purposes.
+ */ 
+
+/* #define DEBUG(x) x */
+#define DEBUG(x)
+
+#include <stdlib.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+
+#include <string.h>
+#include "m_pd.h"
+#include "m_imp.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef _LARGEFILE64_SOURCE
+# define open  open64
+# define lseek lseek64
+# define fstat fstat64
+# define stat  stat64
+#endif
+
+t_namelist *sys_externlist;
+t_namelist *sys_searchpath;
+t_namelist *sys_helppath;
+
+    /* change '/' characters to the system's native file separator */
+void sys_bashfilename(const char *from, char *to)
+{
+    char c;
+    while (c = *from++)
+    {
+#ifdef MSW
+        if (c == '/') c = '\\';
+#endif
+        *to++ = c;
+    }
+    *to = 0;
+}
+
+    /* change the system's native file separator to '/' characters  */
+void sys_unbashfilename(const char *from, char *to)
+{
+    char c;
+    while (c = *from++)
+    {
+#ifdef MSW
+        if (c == '\\') c = '/';
+#endif
+        *to++ = c;
+    }
+    *to = 0;
+}
+
+/*******************  Utility functions used below ******************/
+
+/* copy until delimiter and return position after delimiter in string */
+/* if it was the last substring, return NULL */
+
+static const char* strtokcpy(char *to, const char *from, int delim)
+{
+    int size = 0;
+
+    while (from[size] != (char)delim && from[size] != '\0')
+        size++;
+
+    strncpy(to,from,size);
+    to[size] = '\0';
+    if (from[size] == '\0') return NULL;
+    if (size) return from+size+1;
+    else return NULL;
+}
+
+/* add a single item to a namelist.  If "allowdup" is true, duplicates
+may be added; othewise they're dropped.  */
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup)
+{
+    t_namelist *nl, *nl2;
+    nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
+    nl2->nl_next = 0;
+    nl2->nl_string = (char *)getbytes(strlen(s) + 1);
+    strcpy(nl2->nl_string, s);
+    sys_unbashfilename(nl2->nl_string, nl2->nl_string);
+    if (!listwas)
+        return (nl2);
+    else
+    {
+        for (nl = listwas; ;)
+        {
+            if (!allowdup && !strcmp(nl->nl_string, s))
+                return (listwas);
+            if (!nl->nl_next)
+                break;
+            nl = nl->nl_next;
+        }
+        nl->nl_next = nl2;
+    }
+    return (listwas);
+}
+
+/* add a colon-separated list of names to a namelist */
+
+#ifdef MSW
+#define SEPARATOR ';'   /* in MSW the natural separator is semicolon instead */
+#else
+#define SEPARATOR ':'
+#endif
+
+t_namelist *namelist_append_files(t_namelist *listwas, const char *s)
+{
+    const char *npos;
+    char temp[MAXPDSTRING];
+    t_namelist *nl = listwas, *rtn = listwas;
+    
+    npos = s;
+    do
+    {
+        npos = strtokcpy(temp, npos, SEPARATOR);
+        if (! *temp) continue;
+        nl = namelist_append(nl, temp, 0);
+    }
+        while (npos);
+    return (nl);
+}
+
+void namelist_free(t_namelist *listwas)
+{
+    t_namelist *nl, *nl2;
+    for (nl = listwas; nl; nl = nl2)
+    {
+        nl2 = nl->nl_next;
+        t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
+        t_freebytes(nl, sizeof(*nl));
+    }
+}
+
+char *namelist_get(t_namelist *namelist, int n)
+{
+    int i;
+    t_namelist *nl;
+    for (i = 0, nl = namelist; i < n && nl; i++, nl = nl->nl_next)
+        ;
+    return (nl ? nl->nl_string : 0);
+}
+
+static t_namelist *pd_extrapath;
+
+int sys_usestdpath = 1;
+
+void sys_setextrapath(const char *p)
+{
+    namelist_free(pd_extrapath);
+    pd_extrapath = namelist_append(0, p, 0);
+}
+
+#ifdef MSW
+#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
+#else
+#define MSWOPENFLAG(bin) 0
+#endif
+
+    /* try to open a file in the directory "dir", named "name""ext",
+    for reading.  "Name" may have slashes.  The directory is copied to
+    "dirresult" which must be at least "size" bytes.  "nameresult" is set
+    to point to the filename (copied elsewhere into the same buffer). 
+    The "bin" flag requests opening for binary (which only makes a difference
+    on Windows). */
+
+int sys_trytoopenone(const char *dir, const char *name, const char* ext,
+    char *dirresult, char **nameresult, unsigned int size, int bin)
+{
+    int fd;
+    if (strlen(dir) + strlen(name) + strlen(ext) + 4 > size)
+        return (-1);
+    strcpy(dirresult, dir);
+    if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
+        strcat(dirresult, "/");
+    strcat(dirresult, name);
+    strcat(dirresult, ext);
+    sys_bashfilename(dirresult, dirresult);
+
+    DEBUG(post("looking for %s",dirresult));
+        /* see if we can open the file for reading */
+    if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
+    {
+            /* in unix, further check that it's not a directory */
+#ifdef UNISTD
+        struct stat statbuf;
+        int ok =  ((fstat(fd, &statbuf) >= 0) &&
+            !S_ISDIR(statbuf.st_mode));
+        if (!ok)
+        {
+            if (sys_verbose) post("tried %s; stat failed or directory",
+                dirresult);
+            close (fd);
+            fd = -1;
+        }
+        else
+#endif
+        {
+            char *slash;
+            if (sys_verbose) post("tried %s and succeeded", dirresult);
+            sys_unbashfilename(dirresult, dirresult);
+            slash = strrchr(dirresult, '/');
+            if (slash)
+            {
+                *slash = 0;
+                *nameresult = slash + 1;
+            }
+            else *nameresult = dirresult;
+
+            return (fd);  
+        }
+    }
+    else
+    {
+        if (sys_verbose) post("tried %s and failed", dirresult);
+    }
+    return (-1);
+}
+
+    /* check if we were given an absolute pathname, if so try to open it
+    and return 1 to signal the caller to cancel any path searches */
+int sys_open_absolute(const char *name, const char* ext,
+    char *dirresult, char **nameresult, unsigned int size, int bin, int *fdp)
+{
+    if (name[0] == '/' 
+#ifdef MSW
+        || (name[1] == ':' && name[2] == '/')
+#endif
+            )
+    {
+        char dirbuf[MAXPDSTRING];
+        int dirlen = (strrchr(name, '/') - name);
+        if (dirlen > MAXPDSTRING-1) 
+            dirlen = MAXPDSTRING-1;
+        strncpy(dirbuf, name, dirlen);
+        dirbuf[dirlen] = 0;
+        *fdp = sys_trytoopenone(dirbuf, name+(dirlen+1), ext,
+            dirresult, nameresult, size, bin);
+        return (1);
+    }
+    else return (0);
+}
+
+/* search for a file in a specified directory, then along the globally
+defined search path, using ext as filename extension.  The
+fd is returned, the directory ends up in the "dirresult" which must be at
+least "size" bytes.  "nameresult" is set to point to the filename, which
+ends up in the same buffer as dirresult.  Exception:
+if the 'name' starts with a slash or a letter, colon, and slash in MSW,
+there is no search and instead we just try to open the file literally.  */
+
+/* see also canvas_open() which, in addition, searches down the
+canvas-specific path. */
+
+static int do_open_via_path(const char *dir, const char *name,
+    const char *ext, char *dirresult, char **nameresult, unsigned int size,
+    int bin, t_namelist *searchpath)
+{
+    t_namelist *nl;
+    int fd = -1;
+
+        /* first check if "name" is absolute (and if so, try to open) */
+    if (sys_open_absolute(name, ext, dirresult, nameresult, size, bin, &fd))
+        return (fd);
+    
+        /* otherwise "name" is relative; try the directory "dir" first. */
+    if ((fd = sys_trytoopenone(dir, name, ext,
+        dirresult, nameresult, size, bin)) >= 0)
+            return (fd);
+
+        /* next go through the search path */
+    for (nl = searchpath; nl; nl = nl->nl_next)
+        if ((fd = sys_trytoopenone(nl->nl_string, name, ext,
+            dirresult, nameresult, size, bin)) >= 0)
+                return (fd);
+
+        /* next look in "extra" */
+    if (sys_usestdpath &&
+        (fd = sys_trytoopenone(pd_extrapath->nl_string, name, ext,
+            dirresult, nameresult, size, bin)) >= 0)
+                return (fd);
+
+    *dirresult = 0;
+    *nameresult = dirresult;
+    return (-1);
+}
+
+    /* open via path, using the global search path. */
+int open_via_path(const char *dir, const char *name, const char *ext,
+    char *dirresult, char **nameresult, unsigned int size, int bin)
+{
+    return (do_open_via_path(dir, name, ext, dirresult, nameresult,
+        size, bin, sys_searchpath));
+}
+
+    /* Open a help file using the help search path.  We expect the ".pd"
+    suffix here, even though we have to tear it back off for one of the
+    search attempts. */
+void open_via_helppath(const char *name, const char *dir)
+{
+    char realname[MAXPDSTRING], dirbuf[MAXPDSTRING], *basename;
+        /* make up a silly "dir" if none is supplied */
+    const char *usedir = (*dir ? dir : "./");
+    int fd;
+
+        /* 1. "objectname-help.pd" */
+    strncpy(realname, name, MAXPDSTRING-10);
+    realname[MAXPDSTRING-10] = 0;
+    if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd"))
+        realname[strlen(realname)-3] = 0;
+    strcat(realname, "-help.pd");
+    if ((fd = do_open_via_path(dir, realname, "", dirbuf, &basename, 
+        MAXPDSTRING, 0, sys_helppath)) >= 0)
+            goto gotone;
+
+        /* 2. "help-objectname.pd" */
+    strcpy(realname, "help-");
+    strncat(realname, name, MAXPDSTRING-10);
+    realname[MAXPDSTRING-1] = 0;
+    if ((fd = do_open_via_path(dir, realname, "", dirbuf, &basename, 
+        MAXPDSTRING, 0, sys_helppath)) >= 0)
+            goto gotone;
+
+        /* 3. "objectname.pd" */
+    if ((fd = do_open_via_path(dir, name, "", dirbuf, &basename, 
+        MAXPDSTRING, 0, sys_helppath)) >= 0)
+            goto gotone;
+    post("sorry, couldn't find help patch for \"%s\"", name);
+    return;
+gotone:
+    close (fd);
+    glob_evalfile(0, gensym((char*)basename), gensym(dirbuf));
+}
+
+
+/* Startup file reading for linux and __APPLE__.  As of 0.38 this will be
+deprecated in favor of the "settings" mechanism */
+
+int sys_argparse(int argc, char **argv);
+
+#ifndef MSW
+
+#define STARTUPNAME ".pdrc"
+#define NUMARGS 1000
+
+int sys_rcfile(void)
+{
+    FILE* file;
+    int i;
+    int k;
+    int rcargc;
+    char* rcargv[NUMARGS];
+    char* buffer;
+    char  fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
+    int retval = 1; /* that's what we will return at the end; for now, let's think it'll be an error */
+ 
+    /* initialize rc-arg-array so we can safely clean up at the end */
+    for (i = 1; i < NUMARGS-1; i++)
+      rcargv[i]=0;
+
+
+    /* parse a startup file */
+    
+    *fname = '\0'; 
+
+    strncat(fname, home? home : ".", MAXPDSTRING-10);
+    strcat(fname, "/");
+
+    strcat(fname, STARTUPNAME);
+
+    if (!(file = fopen(fname, "r")))
+        return 1;
+
+    post("reading startup file: %s", fname);
+
+    rcargv[0] = ".";    /* this no longer matters to sys_argparse() */
+
+    for (i = 1; i < NUMARGS-1; i++)
+    {
+        if (fscanf(file, "%999s", buf) < 0)
+            break;
+        buf[1000] = 0;
+        if (!(rcargv[i] = malloc(strlen(buf) + 1)))
+            goto cleanup;
+        strcpy(rcargv[i], buf);
+    }
+    if (i >= NUMARGS-1)
+        fprintf(stderr, "startup file too long; extra args dropped\n");
+    rcargv[i] = 0;
+
+    rcargc = i;
+
+    /* parse the options */
+
+    fclose(file);
+    if (sys_verbose)
+    {
+        if (rcargv)
+        {
+            post("startup args from RC file:");
+            for (i = 1; i < rcargc; i++)
+                post("%s", rcargv[i]);
+        }
+        else post("no RC file arguments found");
+    }
+    if (sys_argparse(rcargc-1, rcargv+1))
+    {
+        post("error parsing RC arguments");
+        goto cleanup;
+    }
+
+    retval=0; /* we made it without an error */
+
+
+ cleanup: /* prevent memleak */
+    for (i = 1; i < NUMARGS-1; i++)
+      if(rcargv[i])free(rcargv[i]);
+    
+    return(retval);
+}
+#endif /* MSW */
+
+void sys_doflags( void)
+{
+    int i, beginstring = 0, state = 0, len = strlen(sys_flags->s_name);
+    int rcargc = 0;
+    char *rcargv[MAXPDSTRING];
+    if (len > MAXPDSTRING)
+    {
+        post("flags: %s: too long", sys_flags->s_name);
+        return;
+    }
+    for (i = 0; i < len+1; i++)
+    {
+        int c = sys_flags->s_name[i];
+        if (state == 0)
+        {
+            if (c && !isspace(c))
+            {
+                beginstring = i;
+                state = 1;
+            }
+        }
+        else
+        {
+            if (!c || isspace(c))
+            {
+                char *foo = malloc(i - beginstring + 1);
+                if (!foo)
+                    return;
+                strncpy(foo, sys_flags->s_name + beginstring, i - beginstring);
+                foo[i - beginstring] = 0;
+                rcargv[rcargc] = foo;
+                rcargc++;
+                if (rcargc >= MAXPDSTRING)
+                    break;
+                state = 0;
+            }
+        }
+    }
+    if (sys_argparse(rcargc, rcargv))
+        post("error parsing startup arguments");
+}
+
+/* undo pdtl_encodedialog.  This allows dialogs to send spaces, commas,
+    dollars, and semis down here. */
+t_symbol *sys_decodedialog(t_symbol *s)
+{
+    char buf[MAXPDSTRING], *sp = s->s_name;
+    int i;
+    if (*sp != '+')
+        bug("sys_decodedialog: %s", sp);
+    else sp++;
+    for (i = 0; i < MAXPDSTRING-1; i++, sp++)
+    {
+        if (!sp[0])
+            break;
+        if (sp[0] == '+')
+        {
+            if (sp[1] == '_')
+                buf[i] = ' ', sp++;
+            else if (sp[1] == '+')
+                buf[i] = '+', sp++;
+            else if (sp[1] == 'c')
+                buf[i] = ',', sp++;
+            else if (sp[1] == 's')
+                buf[i] = ';', sp++;
+            else if (sp[1] == 'd')
+                buf[i] = '$', sp++;
+            else buf[i] = sp[0];
+        }
+        else buf[i] = sp[0];
+    }
+    buf[i] = 0;
+    return (gensym(buf));
+}
+
+
+    /* start a search path dialog window */
+void glob_start_path_dialog(t_pd *dummy)
+{
+    char buf[MAXPDSTRING];
+    int i;
+    t_namelist *nl;
+
+    sys_vgui("pd_set pd_path \"\"\n");
+    for (nl = sys_searchpath, i = 0; nl; nl = nl->nl_next, i++)
+        sys_vgui("lappend pd_path \"%s\"\n", nl->nl_string);
+    sprintf(buf, "pdtk_path_dialog %%s %d %d\n", sys_usestdpath, sys_verbose);
+    gfxstub_new(&glob_pdobject, (void *)glob_start_path_dialog, buf);
+}
+
+    /* new values from dialog window */
+void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+    int i;
+    namelist_free(sys_searchpath);
+    sys_searchpath = 0;
+    sys_usestdpath = atom_getintarg(0, argc, argv);
+    sys_verbose = atom_getintarg(1, argc, argv);
+    for (i = 0; i < argc-2; i++)
+    {
+        t_symbol *s = sys_decodedialog(atom_getsymbolarg(i+2, argc, argv));
+        if (*s->s_name)
+            sys_searchpath = namelist_append_files(sys_searchpath, s->s_name);
+    }
+}
+
+    /* start a startup dialog window */
+void glob_start_startup_dialog(t_pd *dummy)
+{
+    char buf[MAXPDSTRING];
+    int i;
+    t_namelist *nl;
+
+    sys_vgui("pd_set pd_startup \"\"\n");
+    for (nl = sys_externlist, i = 0; nl; nl = nl->nl_next, i++)
+        sys_vgui("lappend pd_startup \"%s\"\n", nl->nl_string);
+    sprintf(buf, "pdtk_startup_dialog %%s %d \"%s\"\n", sys_defeatrt,
+        sys_flags->s_name);
+    gfxstub_new(&glob_pdobject, (void *)glob_start_startup_dialog, buf);
+}
+
+    /* new values from dialog window */
+void glob_startup_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+    int i;
+    namelist_free(sys_externlist);
+    sys_externlist = 0;
+    sys_defeatrt = atom_getintarg(0, argc, argv);
+    sys_flags = sys_decodedialog(atom_getsymbolarg(1, argc, argv));
+    for (i = 0; i < argc-2; i++)
+    {
+        t_symbol *s = sys_decodedialog(atom_getsymbolarg(i+2, argc, argv));
+        if (*s->s_name)
+            sys_externlist = namelist_append_files(sys_externlist, s->s_name);
+    }
+}
+
+
diff --git a/src/x_connective.c b/src/x_connective.c
index 2f291f506..8687154ea 100644
--- a/src/x_connective.c
+++ b/src/x_connective.c
@@ -1232,7 +1232,7 @@ static void makefilename_scanformat(t_makefilename *x)
                 x->x_intconvert = 0;
                 break;
             }
-            if (strchr("xXdiou",*str)!=0) {
+            if (strchr("xXdiouc",*str)!=0) {
                 x->x_accept = A_FLOAT;
                 x->x_intconvert = 1;
                 break;
-- 
GitLab