[MLton-commit] r6699

Wesley Terpstra wesley at mlton.org
Mon Aug 11 16:11:25 PDT 2008


As reported by Nicolas Bertolotti, the escape function for shell arguments was
broken on MinGW. This patch corrects it. It might still be broken on cygwin.


----------------------------------------------------------------------

U   mlton/trunk/basis-library/mlton/process.sml
A   mlton/trunk/regression/spawn.ok
A   mlton/trunk/regression/spawn.sml

----------------------------------------------------------------------

Modified: mlton/trunk/basis-library/mlton/process.sml
===================================================================
--- mlton/trunk/basis-library/mlton/process.sml	2008-08-08 16:03:08 UTC (rev 6698)
+++ mlton/trunk/basis-library/mlton/process.sml	2008-08-11 23:11:23 UTC (rev 6699)
@@ -251,13 +251,40 @@
                end
           | SOME pid => pid (* parent *)
 
-      val dquote = "\""
-      fun cmdEscape y = 
-         concat [dquote,
+      fun strContains seps s =
+        CharVector.exists (Char.contains seps) s
+      (* In MinGW, a string must be escaped if it contains " \t" or is "".
+       * Escaping means adds "s on the front and end. Any quotes inside
+       * must be escaped with \. Any \s already in the string must be
+       * doubled ONLY when they precede a " or the end of string.
+       *)
+      fun mingwEscape (l, 0) = l
+        | mingwEscape (l, i) = mingwEscape (#"\\"::l, i-1)
+      fun mingwFold (#"\\", (l, escapeCount)) = (#"\\"::l, escapeCount+1)
+        | mingwFold (#"\"", (l, escapeCount)) = 
+            (#"\"" :: mingwEscape (#"\\"::l, escapeCount), 0)
+        | mingwFold (x, (l, _)) = (x :: l, 0)
+      val mingwQuote = mingwEscape o CharVector.foldl mingwFold ([#"\""], 0)
+      fun mingwEscape y =
+         if not (strContains " \t\"" y) andalso y<>"" then y else
+         String.implode (List.rev (#"\"" :: mingwQuote y))
+
+      (* In cygwin, according to what I read, \ should always become \\.
+       * Furthermore, more characters cause escaping as compared to MinGW. 
+       * From what I read, " should become "", not \", but I leave the old
+       * behaviour alone until someone runs the spawn regression.
+       *)
+      fun cygwinEscape y = 
+         if not (strContains " \t\"\r\n\f'" y) andalso y<>"" then y else
+         concat ["\"",
                  String.translate
                  (fn #"\"" => "\\\"" | #"\\" => "\\\\" | x => String.str x) y,
-                 dquote]
+                 "\""]
 
+      val cmdEscape = 
+         if MLton.Platform.OS.host = MLton.Platform.OS.MinGW
+         then mingwEscape else cygwinEscape
+
       fun create (cmd, args, env, stdin, stdout, stderr) =
          SysCall.simpleResult'
          ({errVal = C_PId.castFromFixedInt ~1}, fn () =>

Added: mlton/trunk/regression/spawn.ok
===================================================================
--- mlton/trunk/regression/spawn.ok	2008-08-08 16:03:08 UTC (rev 6698)
+++ mlton/trunk/regression/spawn.ok	2008-08-11 23:11:23 UTC (rev 6699)
@@ -0,0 +1 @@
+OK!

Added: mlton/trunk/regression/spawn.sml
===================================================================
--- mlton/trunk/regression/spawn.sml	2008-08-08 16:03:08 UTC (rev 6698)
+++ mlton/trunk/regression/spawn.sml	2008-08-11 23:11:23 UTC (rev 6699)
@@ -0,0 +1,34 @@
+val tests = [
+  "\"hello\\\"",
+  "c:\\foo.bah",
+  "",
+  "hi\\",
+  "hi\"",
+  "evil\narg",
+  "evil\targ",
+  "evil arg",
+  "evil\rarg",
+  "evil\farg",
+  "\"bar\\",
+  "\\bah",
+  "bah \\bar",
+  "bah\\bar",
+  "bah\\\\",
+  "ba h\\\\",
+  "holy\"smoke",
+  "holy \"smoke" ]
+
+val args = CommandLine.arguments ()
+
+fun loop ([], []) = print "OK!\n"
+  | loop (x::r, y::s) = 
+      (if x <> y then print ("FAIL: "^x^":"^y^"\n") else (); loop (r, s))
+  | loop (_, _) = print "Wrong argument count\n"
+
+open Posix.Process
+open MLton.Process
+val () =
+  if List.length args = 0
+  then ignore (waitpid (W_CHILD (spawn { path = "spawn", args = "spawn"::tests }), []))
+  else loop (tests, args)
+ 




More information about the MLton-commit mailing list