From 9eabe9bad6616437cac6f53a1dcaaa3dc60876f9 Mon Sep 17 00:00:00 2001
From: Robert Izzard <r.izzard@surrey.ac.uk>
Date: Wed, 7 Jul 2021 13:28:30 +0100
Subject: [PATCH] switch from using wordexp() to our own string splitter

updated docs
---
 doc/binary_c2.lyx                       |  55 +++++++++-
 doc/binary_grid2.lyx                    | 128 +++++++++++++++++++++++-
 src/binary_c_code_options.h             |   9 ++
 src/setup/new_system.c                  |  27 +++--
 src/setup/parse_arguments_from_string.c |  21 +++-
 src/setup/version.c                     |   1 +
 src/string/string_prototypes.h          |   7 +-
 src/string/string_split.c               |   4 +
 src/string/string_split_preserve.c      |  33 ++++++
 9 files changed, 267 insertions(+), 18 deletions(-)
 create mode 100644 src/string/string_split_preserve.c

diff --git a/doc/binary_c2.lyx b/doc/binary_c2.lyx
index 34422bf7b..071ab0fc3 100644
--- a/doc/binary_c2.lyx
+++ b/doc/binary_c2.lyx
@@ -1434,7 +1434,7 @@ status open
 
 \begin_layout Plain Layout
 
-export LD_LIBRARY_PATH=$HOME/lib
+export LD_LIBRARY_PATH=$HOME/lib:$BINARY_C/src
 \end_layout
 
 \begin_layout Plain Layout
@@ -12299,6 +12299,59 @@ filename "binary_grid2.lyx"
 \end_inset
 
 
+\end_layout
+
+\begin_layout Section
+Making populations of stars with 
+\begin_inset Formula $\binarycpython$
+\end_inset
+
+
+\end_layout
+
+\begin_layout Standard
+\begin_inset CommandInset label
+LatexCommand label
+name "subsec:Running-a-grid-python"
+
+\end_inset
+
+Please see instructions at 
+\end_layout
+
+\begin_layout Itemize
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+https://gitlab.eps.surrey.ac.uk/ri0005/binary_c-python
+\end_layout
+
+\end_inset
+
+
+\end_layout
+
+\begin_layout Itemize
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+https://pypi.org/project/binarycpython/
+\end_layout
+
+\end_inset
+
+
+\end_layout
+
+\begin_layout Standard
+\begin_inset Newpage pagebreak
+\end_inset
+
+
 \end_layout
 
 \begin_layout Section
diff --git a/doc/binary_grid2.lyx b/doc/binary_grid2.lyx
index 5f5e8e93d..9cb20a254 100644
--- a/doc/binary_grid2.lyx
+++ b/doc/binary_grid2.lyx
@@ -2826,7 +2826,11 @@ grid script
 \emph default
 and coupling your population synthesis to 
 \emph on
-binary_c/nucsyn
+
+\begin_inset Formula $\binaryc$
+\end_inset
+
+
 \end_layout
 
 \begin_layout Standard
@@ -2911,7 +2915,121 @@ xxx
 \end_inset
 
 
-\begin_inset Newline newline
+\end_layout
+
+\begin_layout Subsubsection
+Loading the 
+\begin_inset Formula $\binaryc$
+\end_inset
+
+ library 
+\end_layout
+
+\begin_layout Standard
+When using 
+\begin_inset Formula $\binarygrid$
+\end_inset
+
+ you need to ensure the binary_c shared library is loaded.
+ Usually, this means you have to set the environment variable 
+\begin_inset Flex Envvar
+status open
+
+\begin_layout Plain Layout
+LD_LIBRARY_PATH
+\end_layout
+
+\end_inset
+
+ (or 
+\begin_inset Flex Envvar
+status open
+
+\begin_layout Plain Layout
+DYLD_LIBRARY_PATH
+\end_layout
+
+\end_inset
+
+ on 
+\begin_inset Flex OS
+status open
+
+\begin_layout Plain Layout
+OSX
+\end_layout
+
+\end_inset
+
+) to point to the location where the library is installed, usually 
+\begin_inset Flex File
+status open
+
+\begin_layout Plain Layout
+$BINARY_C/src
+\end_layout
+
+\end_inset
+
+.
+ If this fails to work, try the following using 
+\begin_inset Flex Envvar
+status open
+
+\begin_layout Plain Layout
+LD_PRELOAD
+\end_layout
+
+\end_inset
+
+ (or 
+\begin_inset Flex Envvar
+status open
+
+\begin_layout Plain Layout
+DYLD_PRELOAD
+\end_layout
+
+\end_inset
+
+ on 
+\begin_inset Flex OS
+status open
+
+\begin_layout Plain Layout
+OSX
+\end_layout
+
+\end_inset
+
+, see Sec.
+\begin_inset space ~
+\end_inset
+
+
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "subsec:binaryc-on-MacOSX"
+plural "false"
+caps "false"
+noprefix "false"
+
+\end_inset
+
+ for Mac-specific instructions) from in the 
+\begin_inset Formula $\binaryc$
+\end_inset
+
+ directory:
+\begin_inset listings
+inline false
+status open
+
+\begin_layout Plain Layout
+
+LD_PRELOAD=./src/libbinary_c.so <script>
+\end_layout
+
 \end_inset
 
 
@@ -2920,7 +3038,11 @@ xxx
 \begin_layout Subsubsection
 Logging in 
 \emph on
-binary_c
+
+\begin_inset Formula $\binaryc$
+\end_inset
+
+
 \end_layout
 
 \begin_layout Standard
diff --git a/src/binary_c_code_options.h b/src/binary_c_code_options.h
index 4ba204728..b78728692 100644
--- a/src/binary_c_code_options.h
+++ b/src/binary_c_code_options.h
@@ -1225,4 +1225,13 @@ void Print_trace(void);
 #define Fallthrough /* do nothing */
 #endif
 
+/*
+ * If USE_SPLIT_COMMANDLINE is TRUE, we used
+ * split_commandline, which calls wordexp(), to
+ * analyse command-line strings. This performs
+ * shell expansion, so is slow, and is usually
+ * not required.
+ */
+//#define USE_SPLIT_COMMANDLINE
+
 #endif //BINARY_C_CODE_OPTIONS_H
diff --git a/src/setup/new_system.c b/src/setup/new_system.c
index 352bd780c..15af72e48 100644
--- a/src/setup/new_system.c
+++ b/src/setup/new_system.c
@@ -83,30 +83,35 @@ void new_system(struct stardata_t ** new_stardata,
         /*
          * Split given arg string
          */
-        //char ** const argv_system = split_commandline(*argv,&argc_system);
-        size_t argc_system_size;
         int argc_system;
+#ifdef USE_SPLIT_COMMANDLINE
+        char ** const argv_system = split_commandline(*argv,&argc_system);
+#else
+
+        size_t alloced;
         char ** argv_system = NULL;
         char * argvc = *argv;
-
-        string_split(argvc,
-                     &argv_system,
-                     ' ',
-                     1024,
-                     &argc_system_size,
-                     TRUE);
-        argc_system = (int)argc_system_size;
+        argc_system = (int)string_split(argvc,
+                                        &argv_system,
+                                        ' ',
+                                        1024,
+                                        &alloced,
+                                        TRUE);
         if(argv_system==NULL)
         {
             Exit_binary_c_no_stardata(BINARY_C_WRONG_ARGUMENT,
                                       "Command line split failed: argv_system==NULL from command line string \"%s\"\n",*argv);
         }
+#endif // USE_SPLIT_COMMANDLINE
         parse_arguments(1,
                         argc_system,
                         argv_system,
                         *new_stardata);
-        //split_commandline_free(argv_system,argc_system);
+#ifdef USE_SPLIT_COMMANDLINE
+        split_commandline_free(argv_system,argc_system);
+#else
         Safe_free(argv_system);
+#endif
         dprint(*new_stardata,"scanned %d args\n",argc_system);
     }
     else if(argc>=0)
diff --git a/src/setup/parse_arguments_from_string.c b/src/setup/parse_arguments_from_string.c
index 0fd3c0218..5eb047f77 100644
--- a/src/setup/parse_arguments_from_string.c
+++ b/src/setup/parse_arguments_from_string.c
@@ -8,12 +8,29 @@ void parse_arguments_from_string(const char * RESTRICT const argstring,
 {
 
     /*
-     * Split the string into the argv and argc arrays, then 
+     * Split the string into the argv and argc arrays, then
      * free the memory in those arrays.
      */
+    char ** argv = NULL;
     Dprint("split string into args\n");
-    char ** argv = split_commandline(argstring, argc);
+#ifdef USE_SPLIT_COMMANDLINE
+    /*
+     * This is slower, but performs shell expansion
+     */
+    argv = split_commandline(argstring, argc);
     Dprint("parse %d args from split string\n",*argc);
     parse_arguments(1,*argc,argv,stardata);
     split_commandline_free(argv,*argc);
+#else
+    size_t alloced;
+    *argc = (int)string_split_preserve(argstring,
+                                       &argv,
+                                       ' ',
+                                       1024,
+                                       &alloced,
+                                       TRUE);
+    Dprint("parse %d args from split string\n",*argc);
+    parse_arguments(1,*argc,argv,stardata);
+    Safe_free(argv);
+#endif
 }
diff --git a/src/setup/version.c b/src/setup/version.c
index 4fb360fe3..33649ba1d 100644
--- a/src/setup/version.c
+++ b/src/setup/version.c
@@ -1133,6 +1133,7 @@ void version(struct stardata_t * RESTRICT const stardata)
     Macrotest(__APPLE__);
     Macrotest(__arm__);
     Macrotest(__i386__);
+    Macrotest(USE_SPLIT_COMMANDLINE);
 #ifdef ALIGNSIZE
     Printf("Memory is aligned to %d bytes (set in ALIGNSIZE)\n",ALIGNSIZE);
 #else
diff --git a/src/string/string_prototypes.h b/src/string/string_prototypes.h
index 95ae67e0c..a4a65e48d 100644
--- a/src/string/string_prototypes.h
+++ b/src/string/string_prototypes.h
@@ -35,7 +35,12 @@ size_t string_split(const char * const RESTRICT string,
                     const size_t prealloc,
                     size_t * const alloced,
                     const Boolean shrink);
-
+size_t string_split_preserve(const char * const RESTRICT string,
+                             char *** const RESTRICT array,
+                             const char delimiter,
+                             const size_t prealloc,
+                             size_t * const alloced,
+                             const Boolean shrink);
 
 int strtoi(const char * const RESTRICT s, char **endptr, const int base);
 short int strtoshort(const char * const RESTRICT s, char **endptr, const int base);
diff --git a/src/string/string_split.c b/src/string/string_split.c
index 1870a6eee..b72b5333d 100644
--- a/src/string/string_split.c
+++ b/src/string/string_split.c
@@ -18,6 +18,10 @@ No_empty_translation_unit_warning;
  * You can even use prealloc to maintain the size of *array passed
  * in, if it's alloc'd once, and the alloc size never changes,
  * you never have to make it again.
+ *
+ * Because we use strtok_r, the string passed in is modified.
+ * If you do not want to modify the string, use string_split_preserve()
+ * instead.
  */
 
 
diff --git a/src/string/string_split_preserve.c b/src/string/string_split_preserve.c
new file mode 100644
index 000000000..13f516fae
--- /dev/null
+++ b/src/string/string_split_preserve.c
@@ -0,0 +1,33 @@
+#include "../binary_c.h"
+No_empty_translation_unit_warning;
+
+size_t string_split_preserve(const char * const RESTRICT string,
+                             char *** const RESTRICT array,
+                             const char delimiter,
+                             const size_t prealloc,
+                             size_t * const alloced,
+                             const Boolean shrink)
+{
+    /*
+     * Like string_split, but copies the string
+     * passed in and works on the copy, thus does not
+     * change the string.
+     */
+    char * string_copy = strdup(string);
+    size_t s;
+    if(string_copy != NULL)
+    {
+        s = string_split(string_copy,
+                         array,
+                         delimiter,
+                         prealloc,
+                         alloced,
+                         shrink);
+        Safe_free(string_copy);
+    }
+    else
+    {
+        s = 0;
+    }
+    return s;
+}
-- 
GitLab