--- D:\DevProject\SemiTwistDTools\rdmd.d	2010-09-23 21:10:00.000000000 -0400
+++ D:\DevProject\SemiTwistDTools\rdmd_fix_misc.d	2010-09-24 16:51:53.000000000 -0400
@@ -1,9 +1,9 @@
 // Written in the D programming language.
 
-import std.algorithm, std.c.stdlib, std.contracts, std.date,
+import std.algorithm, std.c.stdlib, std.exception, std.date,
     std.file, std.getopt,
     std.md5, std.path, std.process, std.regexp,
     std.stdio, std.string, std.typetuple;
 
 version (Posix)
 {
@@ -43,15 +43,20 @@
             // -ofmyfile passed
             exe = value[1 .. $];
         }
         else if (value[0] == 'd')
         {
             // -odmydir passed
-            // add a trailing path separator to clarify it's a dir
-            exe = std.path.join(value[1 .. $], "");
-            assert(std.algorithm.endsWith(exe, std.path.sep[]));
+            if(!exe) // Don't let -od override -of
+            {
+                // add a trailing path separator to clarify it's a dir
+                exe = value[1 .. $];
+                if(!std.algorithm.endsWith(exe, std.path.sep[]))
+                    exe ~= std.path.sep[];
+                assert(std.algorithm.endsWith(exe, std.path.sep[]));
+            }
         }
         else if (value[0] == '-')
         {
             // -o- passed
             enforce(false, "Option -o- currently not supported by rdmd");
         }
@@ -69,21 +74,24 @@
             if (!b.length) continue;
             if (!system(b~" http://www.digitalmars.com/d/2.0/rdmd.html"))
                 return;
         }
     }
 
+    auto programPos = indexOfProgram(args);
+    // Insert "--" to tell getopts when to stop
+    args = args[0..programPos] ~ "--" ~ ( (programPos<args.length)? args[programPos..$] : [] );
+
     bool bailout;    // bailout set by functions called in getopt if
                      // program should exit
     string[] loop;       // set by --loop
     bool addStubMain;// set by --main
     string[] eval;     // set by --eval
     getopt(args,
             std.getopt.config.caseSensitive,
             std.getopt.config.passThrough,
-            std.getopt.config.stopOnFirstNonOption,
             "build-only", &buildOnly,
             "chatty", &chatty,
             "dry-run", &dryRun,
             "force", &force,
             "help", (string) { writeln(helpString); bailout = true; },
             "main", &addStubMain,
@@ -106,29 +114,25 @@
     {
         return .eval(importWorld ~ "void main(char[][] args) {\n"
                 ~ join(eval, "\n") ~ ";\n}");
     }
     
     // Parse the program line - first find the program to run
-    uint programPos = 1;
-    for (;; ++programPos)
-    {
-        if (programPos == args.length)
-        {
-            write(helpString);
-            return 1;
-        }
-        if (args[programPos].length && args[programPos][0] != '-') break;
+    programPos = indexOfProgram(args);
+    if(programPos == args.length)
+    {
+        write(helpString);
+        return 1;
     }
     const
         root = /*rel2abs*/(chomp(args[programPos], ".d") ~ ".d"),
         exeBasename = basename(root, ".d"),
-        exeDirname = dirname(root),
-        programArgs = args[programPos + 1 .. $];
+        exeDirname = dirname(root);
+    auto programArgs = args[programPos + 1 .. $];
     args = args[0 .. programPos];
-    const compilerFlags = args[1 .. programPos];
+    const compilerFlags = args[1 .. programPos-1];
 
     // Compute the object directory and ensure it exists
     invariant objDir = getObjPath(root, compilerFlags);
     if (!dryRun)        // only make a fuss about objDir on a real run
     {
         exists(objDir)
@@ -174,13 +178,45 @@
         invariant result = rebuild(root, exe, objDir, myModules, compilerFlags,
                                    addStubMain);
         if (result) return result;
     }
 
     // run
-    return buildOnly ? 0 : execv(exe, [ exe ] ~ programArgs);
+    version(Windows)
+    {
+        foreach(ref arg; programArgs)
+            arg = shellQuote(arg);
+        return buildOnly ? 0 : system(([ exe ] ~ programArgs).join(" "));
+    }
+    else
+        return buildOnly ? 0 : execv(exe, [ exe ] ~ programArgs);
+}
+
+size_t indexOfProgram(ref string[] args)
+{
+    foreach(i, arg; args)
+    {
+        if(i == 0)
+            continue;
+            
+        if(arg.length > 0 && arg[0] != '-' && arg[0] != '@')
+        {
+            if(
+                !arg.endsWith(".obj") &&
+                !arg.endsWith(".o") &&
+                !arg.endsWith(".lib") &&
+                !arg.endsWith(".a") &&
+                !arg.endsWith(".def")
+            )
+            {
+                return i;
+            }
+        }
+    }
+    
+    return args.length;
 }
 
 bool inALibrary(in string source, in string object)
 {
     // Heuristics: if source starts with "std.", it's in a library
     return std.string.startsWith(source, "std.")
@@ -241,15 +277,16 @@
 // object file.
 
 private int rebuild(string root, string fullExe,
         string objDir, in string[string] myModules,
         in string[] compilerFlags, bool addStubMain)
 {
-    auto todo = compiler~" "~join(compilerFlags, " ")
+    auto todo = " "~join(compilerFlags, " ")
         ~" -of"~shellQuote(fullExe)
         ~" -od"~shellQuote(objDir)
+        ~" -I"~shellQuote(dirname(root))
         ~" "~shellQuote(root)~" ";
     foreach (k; map!(shellQuote)(myModules.keys)) {
         todo ~= k ~ " ";
     }
 
     // Need to add the pesky void main(){}?
@@ -257,12 +294,25 @@
     {
         auto stubMain = std.path.join(myOwnTmpDir, "stubmain.d");
         std.file.write(stubMain, "void main(){}");
         todo ~= stubMain;
     }
     
+    // Different shells and OS functions have different limits,
+    // but 1024 seems to be the smallest maximum outside of MS-DOS.
+    enum maxLength = 1024;
+    if(todo.length + compiler.length >= maxLength)
+    {
+        auto rspName = std.path.join(myOwnTmpDir,
+                "rdmd." ~ hash(root, compilerFlags) ~ ".rsp");
+
+        std.file.write(rspName, todo);
+        todo = " " ~ shellQuote("@"~rspName);
+    }
+
+    todo = compiler ~ todo;
     invariant result = run(todo);
     if (result) 
     {
         // build failed
         return result;
     }
@@ -298,12 +348,13 @@
     // myModules maps module source paths to corresponding .o names
     string[string] myModules;// = [ rootModule : d2obj(rootModule) ];
     // Must collect dependencies
     invariant depsGetter = /*"cd "~shellQuote(rootDir)~" && "
                              ~*/compiler~" "~join(compilerFlags, " ")
         ~" -v -o- "~shellQuote(rootModule)
+        ~" -I"~shellQuote(rootDir)
         ~" >"~depsFilename;
     if (chatty) writeln(depsGetter);
     immutable depsExitCode = system(depsGetter);
     if (depsExitCode)
     {
         // if (exists(depsFilename))
@@ -320,24 +371,32 @@
     foreach (string line; lines(depsReader))
     {
         if (!pattern.test(line)) continue;
         invariant moduleName = pattern[1], moduleSrc = pattern[2];
         if (inALibrary(moduleName, moduleSrc)) continue;
         invariant moduleObj = d2obj(moduleSrc);
-        myModules[/*rel2abs*/join(rootDir, moduleSrc)] = moduleObj;
+        myModules[moduleSrc] = moduleObj;
     }
 
     return myModules;
 }
 
-/*private*/ string shellQuote(string filename)
+/*private*/ string shellQuote(string arg)
 {
     // This may have to change under windows
     version (Windows) enum quotechar = '"';
     else enum quotechar = '\'';
-    return quotechar ~ filename ~ quotechar;
+    version (Windows)
+    {
+        // Escape trailing backslash, so it doesn't escape the ending quote.
+        // Backslashes elsewhere should NOT be escaped.
+        if(arg.length > 0 && arg[$-1] == '\\')
+            arg ~= '\\';
+        arg = arg.replace(`"`, `\"`);
+    }
+    return quotechar ~ arg ~ quotechar;
 }
 
 private bool isNewer(string source, string target)
 {
     return force || lastModified(source) >= lastModified(target, d_time.min);
 }
