2002-09-19 Martin Baulig <martin@gnome.org>
[mono.git] / mcs / mcs / driver.cs
index 51224fe7d1ff2dba335bd8fcf3e7b7fd291157fc..33c575812db183dd66372a22f5f1e5261e5ed767 100755 (executable)
@@ -15,6 +15,7 @@ namespace Mono.CSharp
        using System.Reflection.Emit;
        using System.Collections;
        using System.IO;
+       using System.Text;
        using System.Globalization;
        using Mono.Languages;
 
@@ -72,6 +73,7 @@ namespace Mono.CSharp
                // A list of resource files
                //
                static ArrayList resources;
+               static ArrayList embedded_resources;
                
                //
                // An array of the defines from the command line
@@ -82,13 +84,27 @@ namespace Mono.CSharp
                // Output file
                //
                static string output_file = null;
-               
+
                //
                // Last time we took the time
                //
-               static DateTime last_time;
-               static void ShowTime (string msg)
+               static DateTime last_time, first_time;
+
+               //
+               // Encoding: ISO-Latin1 is 28591
+               //
+               static Encoding encoding = Encoding.GetEncoding (28591);
+
+               //
+               // Whether the user has specified a different encoder manually
+               //
+               static bool using_default_encoder = true;
+               
+               public static void ShowTime (string msg)
                {
+                       if (!timestamps)
+                               return;
+
                        DateTime now = DateTime.Now;
                        TimeSpan span = now - last_time;
                        last_time = now;
@@ -97,6 +113,20 @@ namespace Mono.CSharp
                                "[{0:00}:{1:000}] {2}",
                                (int) span.TotalSeconds, span.Milliseconds, msg);
                }
+
+               public static void ShowTotalTime (string msg)
+               {
+                       if (!timestamps)
+                               return;
+
+                       DateTime now = DateTime.Now;
+                       TimeSpan span = now - first_time;
+                       last_time = now;
+
+                       Console.WriteLine (
+                               "[{0:00}:{1:000}] {2}",
+                               (int) span.TotalSeconds, span.Milliseconds, msg);
+               }              
               
                static void tokenize_file (string input_file)
                {
@@ -110,7 +140,8 @@ namespace Mono.CSharp
                        }
 
                        using (input){
-                               Tokenizer lexer = new Tokenizer (input, input_file, defines);
+                               StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
+                               Tokenizer lexer = new Tokenizer (reader, input_file, defines);
                                int token, tokens = 0, errors = 0;
 
                                while ((token = lexer.token ()) != Token.EOF){
@@ -138,7 +169,9 @@ namespace Mono.CSharp
                                return;
                        }
 
-                       parser = new CSharpParser (input_file, input, defines);
+                       StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
+                               
+                       parser = new CSharpParser (reader, input_file, defines);
                        parser.yacc_verbose = yacc_verbose;
                        try {
                                parser.parse ();
@@ -154,46 +187,57 @@ namespace Mono.CSharp
                        Console.WriteLine (
                                "Mono C# compiler, (C) 2001 Ximian, Inc.\n" +
                                "mcs [options] source-files\n" +
-                               "   --about          About the Mono C# compiler\n" +
-                               "   --checked        Set default context to checked\n" +
-                               "   --define SYM     Defines the symbol SYM\n" +
-                               "   --debug          Generate debugging information\n" + 
-                               "   -g               Generate debugging information\n" +
-                               "   --debug-args X   Specify additional arguments for the\n" +
-                               "                    symbol writer.\n" +
-                               "   --fatal          Makes errors fatal\n" +
-                               "   -L PATH          Adds PATH to the assembly link path\n" +
-                               "   --noconfig       Disables implicit references to assemblies\n" +
-                               "   --nostdlib       Does not load core libraries\n" +
-                               "   --nowarn XXX     Ignores warning number XXX\n" +
-                               "   -o FNAME         Specifies output file\n" +
-                               "   -g, --debug      Write symbolic debugging information to FILE-debug.s\n" +
-                               "   --parse          Only parses the source file\n" +
-                               "   --expect-error X Expect that error X will be encountered\n" +
-                               "   --recurse SPEC   Recursively compiles the files in SPEC ([dir]/file)\n" + 
-                               "   --resource FILE  Addds FILE as a resource\n" + 
-                               "   --stacktrace     Shows stack trace at error location\n" +
-                               "   --target KIND    Specifies the target (KIND is one of: exe, winexe, " +
-                                                    "library, module)\n" +
-                               "   --timestamp      Displays time stamps of various compiler events\n" +
-                               "   --unsafe         Allows unsafe code\n" +
-                               "   --werror         Treat warnings as errors\n" +
-                               "   --wlevel LEVEL   Sets warning level (the highest is 4, the default)\n" +
-                               "   -r               References an assembly\n" +
-                               "   -v               Verbose parsing (for debugging the parser)\n" +
-                                "   @file            Read response file for more options");
+                               "   --about            About the Mono C# compiler\n" +
+                               "   -checked[+|-]      Set default context to checked\n" +
+                               "   -codepage:ID       Sets code page to the one in ID\n" +
+                               "                      (number, `utf8' or `reset')" +
+                               "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
+                               "   -debug[+-]         Generate debugging information\n" + 
+                               "   -g                 Generate debugging information\n" +
+                               "   --debug-args X     Specify additional arguments for the\n" +
+                               "                      symbol writer.\n" +
+                               "   --fatal            Makes errors fatal\n" +
+                               "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
+                               "   -main:class        Specified the class that contains the entry point\n" +
+                               "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
+                               "   -nostdlib[+|-]     Does not load core libraries\n" +
+                               "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
+                               "   -out:FNAME         Specifies output file\n" +
+                               "   --parse            Only parses the source file\n" +
+                               "   --expect-error X   Expect that error X will be encountered\n" +
+                               "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
+                               "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
+                               "   --stacktrace       Shows stack trace at error location\n" +
+                               "   -target:KIND       Specifies the target (KIND is one of: exe, winexe, " +
+                                                      "library, module), (short: /t:)\n" +
+                               "   --timestamp        Displays time stamps of various compiler events\n" +
+                               "   -unsafe[+|-]       Allows unsafe code\n" +
+                               "   -warnaserror[+|-]  Treat warnings as errors\n" +
+                               "   -warn:LEVEL        Sets warning level (the highest is 4, the default)\n" +
+                               "   -v                 Verbose parsing (for debugging the parser)\n" +
+                               "\n" +
+                               "Resources:" +
+                               "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
+                               "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
+                               
+#if MCS_DEBUG                                         
+                               "   --mcs-debug X      Sets MCS debugging level to X\n" +
+#endif                                                
+                                "   @file              Read response file for more options\n\n" +
+                               "Options can be of the form -option or /option");
                }
 
                static void About ()
                {
                        Console.WriteLine (
-                               "The Mono C# compiler is (C) 2001 Ximian, Inc.\n\n" +
+                               "The Mono C# compiler is (C) 2001, 2002 Ximian, Inc.\n\n" +
                                "The compiler source code is released under the terms of the GNU GPL\n\n" +
 
                                "For more information on Mono, visit the project Web site\n" +
                                "   http://www.go-mono.com\n\n" +
 
-                               "The compiler was written by Miguel de Icaza and Ravi Pratap");
+                               "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
+                       Environment.Exit (0);
                }
                
                public static int Main (string[] args)
@@ -290,11 +334,36 @@ namespace Mono.CSharp
                                return null;
                        }
 
+                       StringBuilder sb = new StringBuilder ();
+                       
                        while ((line = f.ReadLine ()) != null){
-                               string [] line_args = line.Split (new char [] { ' ' });
+                               int t = line.Length;
 
-                               foreach (string arg in line_args)
-                                       args.Add (arg);
+                               for (int i = 0; i < t; i++){
+                                       char c = line [i];
+                                       
+                                       if (c == '"' || c == '\''){
+                                               char end = c;
+                                               
+                                               for (i++; i < t; i++){
+                                                       c = line [i];
+
+                                                       if (c == end)
+                                                               break;
+                                                       sb.Append (c);
+                                               }
+                                       } else if (c == ' '){
+                                               if (sb.Length > 0){
+                                                       args.Add (sb.ToString ());
+                                                       sb.Length = 0;
+                                               }
+                                       } else
+                                               sb.Append (c);
+                               }
+                               if (sb.Length > 0){
+                                       args.Add (sb.ToString ());
+                                       sb.Length = 0;
+                               }
                        }
 
                        string [] ret_value = new string [args.Count];
@@ -556,10 +625,11 @@ namespace Mono.CSharp
                                Report.Stacktrace = true;
                                return true;
                                
-                       case "--resource":
+                       case "--linkresource":
+                       case "--linkres":
                                if ((i + 1) >= args.Length){
                                        Usage ();
-                                       Console.WriteLine("Missing argument to --resource"); 
+                                       Console.WriteLine("Missing argument to --linkres"); 
                                        Environment.Exit (1);
                                }
                                if (resources == null)
@@ -568,6 +638,19 @@ namespace Mono.CSharp
                                resources.Add (args [++i]);
                                return true;
                                
+                       case "--resource":
+                       case "--res":
+                               if ((i + 1) >= args.Length){
+                                       Usage ();
+                                       Console.WriteLine("Missing argument to --resource"); 
+                                       Environment.Exit (1);
+                               }
+                               if (embedded_resources == null)
+                                       embedded_resources = new ArrayList ();
+                               
+                               embedded_resources.Add (args [++i]);
+                               return true;
+                               
                        case "--target":
                                if ((i + 1) >= args.Length){
                                        Environment.Exit (1);
@@ -655,6 +738,22 @@ namespace Mono.CSharp
 
                                SetWarningLevel (args [++i]);
                                return true;
+
+#if MCS_DEBUG
+                       case "--mcs-debug":
+                               if ((i + 1) >= args.Length){
+                                       Console.WriteLine ("--mcs-debug requires an argument");
+                                       Environment.Exit (1);
+                               }
+
+                               try {
+                                       Report.DebugFlags = Int32.Parse (args [++i]);
+                               } catch {
+                                       Console.WriteLine ("Invalid argument to --mcs-debug");
+                                       Environment.Exit (1);
+                               }
+                               return true;
+#endif
                                
                        case "--about":
                                About ();
@@ -670,7 +769,7 @@ namespace Mono.CSharp
                                
                        case "--timestamp":
                                timestamps = true;
-                               last_time = DateTime.Now;
+                               last_time = first_time = DateTime.Now;
                                debug_arglist.Add ("timestamp");
                                return true;
                                
@@ -690,11 +789,9 @@ namespace Mono.CSharp
                        case "--noconfig":
                                load_default_config = false;
                                return true;
-                               
-                       default:
-                               Report.Warning(666, "Unknown option: " + arg);
-                               return true;
                        }
+
+                       return false;
                }
 
                //
@@ -747,7 +844,7 @@ namespace Mono.CSharp
                                }
                                return true;
 
-                       case "/out:":
+                       case "/out":
                                if (value == ""){
                                        Usage ();
                                        Environment.Exit (1);
@@ -772,13 +869,38 @@ namespace Mono.CSharp
                                        Usage ();
                                        Environment.Exit (1);
                                }
-                               
-                               defs = value.Split (new Char [] {';'});
-                               foreach (string d in defs)
+
+                               defs = value.Split (new Char [] {';', ','});
+                               foreach (string d in defs){
                                        defines.Add (d);
+                               }
                                return true;
                        }
 
+                       case "/linkres":
+                       case "/linkresource":
+                               if (value == ""){
+                                       Console.WriteLine ("{0} requires an argument", arg);
+                                       Environment.Exit (1);
+                               }
+                               if (resources == null)
+                                       resources = new ArrayList ();
+                               
+                               resources.Add (value);
+                               return true;
+                               
+                       case "/res":
+                       case "/resource":
+                               if (value == ""){
+                                       Console.WriteLine ("{0} requires an argument", arg);
+                                       Environment.Exit (1);
+                               }
+                               if (embedded_resources == null)
+                                       embedded_resources = new ArrayList ();
+                               
+                               embedded_resources.Add (value);
+                               return true;
+                               
                        case "/recurse":
                                if (value == ""){
                                        Console.WriteLine ("/recurse requires an argument");
@@ -790,7 +912,7 @@ namespace Mono.CSharp
                        case "/r":
                        case "/reference":
                                if (value == ""){
-                                       Console.WriteLine ("/recurse requires an argument");
+                                       Console.WriteLine ("/reference requires an argument");
                                        Environment.Exit (1);
                                }
                                references.Add (value);
@@ -799,8 +921,8 @@ namespace Mono.CSharp
                        case "/lib": {
                                string [] libdirs;
                                
-                               if (value = ""){
-                                       Usage ();       
+                               if (value == ""){
+                                       Console.WriteLine ("/lib requires an argument");
                                        Environment.Exit (1);
                                }
 
@@ -850,7 +972,7 @@ namespace Mono.CSharp
                                string [] warns;
 
                                if (value == ""){
-                                       Usage ();
+                                       Console.WriteLine ("/nowarn requires an argument");
                                        Environment.Exit (1);
                                }
                                
@@ -882,7 +1004,7 @@ namespace Mono.CSharp
                        case "/main":
                        case "/m":
                                if (value == ""){
-                                       Usage ();
+                                       Console.WriteLine ("/main requires an argument");                                       
                                        Environment.Exit (1);
                                }
                                RootContext.MainClass = value;
@@ -897,6 +1019,33 @@ namespace Mono.CSharp
                                RootContext.StdLib = true;
                                return true;
 
+                       case "/codepage":
+                               int cp = -1;
+
+                               if (value == "utf8")
+                                       cp = (new UTF8Encoding()).WindowsCodePage;
+                               if (value == "reset"){
+                                       cp = 28591;
+                                       using_default_encoder = true;
+                               }
+                               
+                               try {
+                                       cp = Int32.Parse (value);
+                               } catch { }
+                               
+                               if (cp == -1){
+                                       Console.WriteLine ("Invalid code-page requested");
+                                       Usage ();
+                               }
+
+                               try {
+                                       encoding = Encoding.GetEncoding (cp);
+                                       using_default_encoder = false;
+                               } catch {
+                                       Console.WriteLine ("Code page: {0} not supported", cp);
+                               }
+                               return true;
+
                        }
                        return false;
                }
@@ -973,10 +1122,16 @@ namespace Mono.CSharp
                                        if (arg.StartsWith ("-")){
                                                if (UnixParseOption (arg, ref args, ref i))
                                                        continue;
+
+                                               // Try a -CSCOPTION
+                                               string csc_opt = "/" + arg.Substring (1);
+                                               if (CSCParseOption (csc_opt, ref args, ref i))
+                                                       continue;
                                        } else {
-                                               if (arg.StartsWith ("/"))
+                                               if (arg.StartsWith ("/")){
                                                        if (CSCParseOption (arg, ref args, ref i))
                                                                continue;
+                                               }
                                        }
                                }
 
@@ -1071,6 +1226,7 @@ namespace Mono.CSharp
                        if (!RootContext.StdLib)
                                RootContext.BootCorlib_PopulateCoreTypes ();
                        RootContext.PopulateTypes ();
+                       RootContext.DefineTypes ();
                        
                        TypeManager.InitCodeHelpers ();
                                
@@ -1083,6 +1239,7 @@ namespace Mono.CSharp
                        //
                        if (timestamps)
                                ShowTime ("Emitting code");
+                       ShowTotalTime ("Total so far");
                        RootContext.EmitCode ();
                        if (timestamps)
                                ShowTime ("   done");
@@ -1093,6 +1250,10 @@ namespace Mono.CSharp
 
                        if (timestamps)
                                ShowTime ("Closing types");
+
+                       if (RootContext.WarningLevel >= 4)
+                               if (!Namespace.VerifyUsing ())
+                                       return false;
                        
                        RootContext.CloseTypes ();
 
@@ -1109,7 +1270,8 @@ namespace Mono.CSharp
                                MethodInfo ep = RootContext.EntryPoint;
 
                                if (ep == null){
-                                       Report.Error (5001, "Program " + output_file +
+                                       if (Report.Errors == 0)
+                                               Report.Error (5001, "Program " + output_file +
                                                              " does not have an entry point defined");
                                        return false;
                                }
@@ -1121,14 +1283,51 @@ namespace Mono.CSharp
                        // Add the resources
                        //
                        if (resources != null){
-                               foreach (string file in resources)
-                                       CodeGen.AssemblyBuilder.AddResourceFile (file, file);
+                               foreach (string spec in resources){
+                                       string file, res;
+                                       int cp;
+                                       
+                                       cp = spec.IndexOf (',');
+                                       if (cp != -1){
+                                               file = spec.Substring (0, cp);
+                                               res = spec.Substring (cp + 1);
+                                       } else
+                                               file = res = spec;
+
+                                       CodeGen.AssemblyBuilder.AddResourceFile (res, file);
+                               }
+                       }
+                       
+                       if (embedded_resources != null){
+                               object[] margs = new object [2];
+                               Type[] argst = new Type [2];
+                               argst [0] = argst [1] = typeof (string);
+                               MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", argst);
+                               if (embed_res == null) {
+                                       Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
+                               } else {
+                                       foreach (string spec in embedded_resources) {
+                                               int cp;
+
+                                               cp = spec.IndexOf (',');
+                                               if (cp != -1){
+                                                       margs [0] = spec.Substring (cp + 1);
+                                                       margs [1] = spec.Substring (0, cp);
+                                               } else
+                                                       margs [0] = margs [1] = spec;
+                                               embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
+                                       }
+                               }
                        }
                        
                        CodeGen.Save (output_file);
-                       if (timestamps)
+                       if (timestamps) {
                                ShowTime ("Saved output");
+                               ShowTotalTime ("Total");
+                       }
 
+                       Timer.ShowTimers ();
+                       
                        if (want_debugging_support) {
                                CodeGen.SaveSymbols ();
                                if (timestamps)