* driver.cs (BadAssembly): Handle all the ugliness of DefineDynamicAssembly.
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004, 2005 Novell, Inc
10 //
11
12 namespace Mono.CSharp
13 {
14         using System;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Collections;
18         using System.Collections.Specialized;
19         using System.IO;
20         using System.Text;
21         using System.Globalization;
22         using System.Diagnostics;
23
24         public enum Target {
25                 Library, Exe, Module, WinExe
26         };
27         
28         /// <summary>
29         ///    The compiler driver.
30         /// </summary>
31         public class Driver
32         {
33                 
34                 //
35                 // Assemblies references to be linked.   Initialized with
36                 // mscorlib.dll here.
37                 static ArrayList references;
38
39                 //
40                 // If any of these fail, we ignore the problem.  This is so
41                 // that we can list all the assemblies in Windows and not fail
42                 // if they are missing on Linux.
43                 //
44                 static ArrayList soft_references;
45
46                 // 
47                 // External aliases for assemblies.
48                 //
49                 static Hashtable external_aliases;
50
51                 //
52                 // Modules to be linked
53                 //
54                 static ArrayList modules;
55
56                 // Lookup paths
57                 static ArrayList link_paths;
58
59                 // Whether we want to only run the tokenizer
60                 static bool tokenize = false;
61                 
62                 static string first_source;
63
64                 static bool want_debugging_support = false;
65
66                 static bool parse_only = false;
67                 static bool timestamps = false;
68                 static bool pause = false;
69                 static bool show_counters = false;
70                 
71                 //
72                 // Whether to load the initial config file (what CSC.RSP has by default)
73                 // 
74                 static bool load_default_config = true;
75
76                 //
77                 // A list of resource files
78                 //
79                 static Resources embedded_resources;
80                 static string win32ResourceFile;
81                 static string win32IconFile;
82
83                 //
84                 // An array of the defines from the command line
85                 //
86                 static ArrayList defines;
87
88                 //
89                 // Output file
90                 //
91                 static string output_file = null;
92
93                 //
94                 // Last time we took the time
95                 //
96                 static DateTime last_time, first_time;
97
98                 //
99                 // Encoding.
100                 //
101                 static Encoding encoding;
102
103                 static public void Reset ()
104                 {
105                         want_debugging_support = false;
106                         parse_only = false;
107                         timestamps = false;
108                         pause = false;
109                         show_counters = false;
110                         load_default_config = true;
111                         embedded_resources = null;
112                         win32ResourceFile = win32IconFile = null;
113                         defines = null;
114                         output_file = null;
115                         encoding = null;
116                         first_source = null;
117                 }
118
119                 public static void ShowTime (string msg)
120                 {
121                         if (!timestamps)
122                                 return;
123
124                         DateTime now = DateTime.Now;
125                         TimeSpan span = now - last_time;
126                         last_time = now;
127
128                         Console.WriteLine (
129                                 "[{0:00}:{1:000}] {2}",
130                                 (int) span.TotalSeconds, span.Milliseconds, msg);
131                 }
132
133                 public static void ShowTotalTime (string msg)
134                 {
135                         if (!timestamps)
136                                 return;
137
138                         DateTime now = DateTime.Now;
139                         TimeSpan span = now - first_time;
140                         last_time = now;
141
142                         Console.WriteLine (
143                                 "[{0:00}:{1:000}] {2}",
144                                 (int) span.TotalSeconds, span.Milliseconds, msg);
145                 }              
146                
147                 static void tokenize_file (SourceFile file)
148                 {
149                         Stream input;
150
151                         try {
152                                 input = File.OpenRead (file.Name);
153                         } catch {
154                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
155                                 return;
156                         }
157
158                         using (input){
159                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
160                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
161                                 int token, tokens = 0, errors = 0;
162
163                                 while ((token = lexer.token ()) != Token.EOF){
164                                         tokens++;
165                                         if (token == Token.ERROR)
166                                                 errors++;
167                                 }
168                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
169                         }
170                         
171                         return;
172                 }
173
174                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
175                 static void parse (SourceFile file)
176                 {
177                         CSharpParser parser;
178                         Stream input;
179
180                         try {
181                                 input = File.OpenRead (file.Name);
182                         } catch {
183                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
184                                 return;
185                         }
186
187                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
188
189                         // Check 'MZ' header
190                         if (reader.Read () == 77 && reader.Read () == 90) {
191                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
192                                 input.Close ();
193                                 return;
194                         }
195
196                         reader.Position = 0;
197                         parser = new CSharpParser (reader, file, defines);
198                         parser.ErrorOutput = Report.Stderr;
199                         try {
200                                 parser.parse ();
201                         } catch (Exception ex) {
202                                 Report.Error(666, "Compilation aborted: " + ex);
203                         } finally {
204                                 input.Close ();
205                         }
206                 }
207
208                 static void OtherFlags ()
209                 {
210                         Console.WriteLine (
211                                 "Other flags in the compiler\n" +
212                                 "   --fatal            Makes errors fatal\n" +
213                                 "   --parse            Only parses the source file\n" +
214                                 "   --stacktrace       Shows stack trace at error location\n" +
215                                 "   --timestamp        Displays time stamps of various compiler events\n" +
216                                 "   --expect-error X   Expect that error X will be encountered\n" +
217                                 "   -2                 Enables experimental C# features\n" +
218                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
219                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
220                 }
221                 
222                 static void Usage ()
223                 {
224                         Console.WriteLine (
225                                 "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" +
226                                 "mcs [options] source-files\n" +
227                                 "   --about            About the Mono C# compiler\n" +
228                                 "   -addmodule:MODULE  Adds the module to the generated assembly\n" + 
229                                 "   -checked[+|-]      Set default context to checked\n" +
230                                 "   -codepage:ID       Sets code page to the one in ID (number, utf8, reset)\n" +
231                                 "   -clscheck[+|-]     Disables CLS Compliance verifications" + Environment.NewLine +
232                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
233                                 "   -debug[+|-], -g    Generate debugging information\n" + 
234                                 "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
235                                 "   -doc:FILE          XML Documentation file to generate\n" + 
236                                 "   -keycontainer:NAME The key pair container used to strongname the assembly\n" +
237                                 "   -keyfile:FILE      The strongname key file used to strongname the assembly\n" +
238                                 "   -langversion:TEXT  Specifies language version modes: ISO-1 or Default\n" + 
239                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
240                                 "   -main:class        Specified the class that contains the entry point\n" +
241                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
242                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
243                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
244                                 "   -optimize[+|-]     Enables code optimalizations\n" + 
245                                 "   -out:FNAME         Specifies output file\n" +
246                                 "   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
247                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
248                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
249                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
250                                 "                      library, module), (short: /t:)\n" +
251                                 "   -unsafe[+|-]       Allows unsafe code\n" +
252                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
253                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default is 2)\n" +
254                                 "   -help2             Show other help flags\n" + 
255                                 "\n" +
256                                 "Resources:\n" +
257                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
258                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
259                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
260                                 "   -win32icon:FILE         Use this icon for the output\n" +
261                                 "   @file                   Read response file for more options\n\n" +
262                                 "Options can be of the form -option or /option");
263                 }
264
265                 static void TargetUsage ()
266                 {
267                         Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
268                 }
269                 
270                 static void About ()
271                 {
272                         Console.WriteLine (
273                                 "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" +
274                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
275
276                                 "For more information on Mono, visit the project Web site\n" +
277                                 "   http://www.go-mono.com\n\n" +
278
279                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
280                         Environment.Exit (0);
281                 }
282
283                 public static int counter1, counter2;
284                 
285                 public static int Main (string[] args)
286                 {
287 #if GMCS_SOURCE
288                         RootContext.Version = LanguageVersion.Default;
289 #endif
290                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
291
292                         bool ok = MainDriver (args);
293                         
294                         if (ok && Report.Errors == 0) {
295                                 if (Report.Warnings > 0) {
296                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
297                                 }
298                                 if (show_counters){
299                                         Console.WriteLine ("Counter1: " + counter1);
300                                         Console.WriteLine ("Counter2: " + counter2);
301                                 }
302                                 if (pause)
303                                         Console.ReadLine ();
304                                 return 0;
305                         } else {
306                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
307                                         Report.Errors, Report.Warnings);
308                                 return 1;
309                         }
310                 }
311
312                 static public void LoadAssembly (string assembly, bool soft)
313                 {
314                         LoadAssembly (assembly, null, soft);
315                 }
316
317                 static void Error6 (string name, string log)
318                 {
319                         if (log != null && log.Length > 0)
320                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
321                         Report.Error (6, "cannot find metadata file `{0}'", name);
322                 }
323
324                 static void Error9 (string type, string filename, string log)
325                 {
326                         if (log != null && log.Length > 0)
327                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
328                         Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
329                 }
330
331                 static void BadAssembly (string filename, string log)
332                 {
333                         MethodInfo adder_method = AssemblyClass.AddModule_Method;
334
335                         if (adder_method != null) {
336                                 AssemblyName an = new AssemblyName ();
337                                 an.Name = ".temp";
338                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
339                                 try {
340                                         object m = null;
341                                         try {
342                                                 m = adder_method.Invoke (ab, new object [] { filename });
343                                         } catch (TargetInvocationException ex) {
344                                                 throw ex.InnerException;
345                                         }
346
347                                         if (m != null) {
348                                                 Report.Error (1509, "referenced file `{0}' is not an assembly; try using the '-addmodule' option", filename);
349                                                 return;
350                                         }
351                                 } catch (FileNotFoundException) {
352                                         // did the file get deleted during compilation? who cares? swallow the exception
353                                 } catch (BadImageFormatException) {
354                                         // swallow exception
355                                 } catch (FileLoadException) {
356                                         // swallow exception
357                                 }
358                         }
359                         Error9 ("assembly", filename, log);
360                 }
361
362                 static public void LoadAssembly (string assembly, string alias, bool soft)
363                 {
364                         Assembly a = null;
365                         string total_log = "";
366
367                         try {
368                                 try {
369                                         char[] path_chars = { '/', '\\' };
370
371                                         if (assembly.IndexOfAny (path_chars) != -1) {
372                                                 a = Assembly.LoadFrom (assembly);
373                                         } else {
374                                                 string ass = assembly;
375                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
376                                                         ass = assembly.Substring (0, assembly.Length - 4);
377                                                 a = Assembly.Load (ass);
378                                         }
379                                 } catch (FileNotFoundException) {
380                                         bool err = !soft;
381                                         foreach (string dir in link_paths) {
382                                                 string full_path = Path.Combine (dir, assembly);
383                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
384                                                         full_path += ".dll";
385
386                                                 try {
387                                                         a = Assembly.LoadFrom (full_path);
388                                                         err = false;
389                                                         break;
390                                                 } catch (FileNotFoundException ff) {
391                                                         total_log += ff.FusionLog;
392                                                 }
393                                         }
394                                         if (err) {
395                                                 Error6 (assembly, total_log);
396                                                 return;
397                                         }
398                                 }
399
400                                 // Extern aliased refs require special handling
401                                 if (alias == null)
402                                         RootNamespace.Global.AddAssemblyReference (a);
403                                 else
404                                         RootNamespace.DefineRootNamespace (alias, a);
405
406                         } catch (BadImageFormatException f) {
407                                 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
408                                 BadAssembly (f.FileName, f.FusionLog);
409                         } catch (FileLoadException f) {
410                                 // ... while .NET 1.1 throws this
411                                 BadAssembly (f.FileName, f.FusionLog);
412                         }
413                 }
414
415                 static public void LoadModule (string module)
416                 {
417                         Module m = null;
418                         string total_log = "";
419
420                         try {
421                                 try {
422                                         m = CodeGen.Assembly.AddModule (module);
423                                 } catch (FileNotFoundException) {
424                                         bool err = true;
425                                         foreach (string dir in link_paths) {
426                                                 string full_path = Path.Combine (dir, module);
427                                                 if (!module.EndsWith (".netmodule"))
428                                                         full_path += ".netmodule";
429
430                                                 try {
431                                                         m = CodeGen.Assembly.AddModule (full_path);
432                                                         err = false;
433                                                         break;
434                                                 } catch (FileNotFoundException ff) {
435                                                         total_log += ff.FusionLog;
436                                                 }
437                                         }
438                                         if (err) {
439                                                 Error6 (module, total_log);
440                                                 return;
441                                         }
442                                 }
443
444                                 RootNamespace.Global.AddModuleReference (m);
445
446                         } catch (BadImageFormatException f) {
447                                 Error9 ("module", f.FileName, f.FusionLog);
448                         } catch (FileLoadException f) {
449                                 Error9 ("module", f.FileName, f.FusionLog);
450                         }
451                 }
452
453                 /// <summary>
454                 ///   Loads all assemblies referenced on the command line
455                 /// </summary>
456                 static public void LoadReferences ()
457                 {
458                         foreach (string r in references)
459                                 LoadAssembly (r, false);
460
461                         foreach (string r in soft_references)
462                                 LoadAssembly (r, true);
463
464                         foreach (DictionaryEntry entry in external_aliases)
465                                 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
466                         
467                         return;
468                 }
469
470                 static void SetupDefaultDefines ()
471                 {
472                         defines = new ArrayList ();
473                         defines.Add ("__MonoCS__");
474                 }
475
476                 static string [] LoadArgs (string file)
477                 {
478                         StreamReader f;
479                         ArrayList args = new ArrayList ();
480                         string line;
481                         try {
482                                 f = new StreamReader (file);
483                         } catch {
484                                 return null;
485                         }
486
487                         StringBuilder sb = new StringBuilder ();
488                         
489                         while ((line = f.ReadLine ()) != null){
490                                 int t = line.Length;
491
492                                 for (int i = 0; i < t; i++){
493                                         char c = line [i];
494                                         
495                                         if (c == '"' || c == '\''){
496                                                 char end = c;
497                                                 
498                                                 for (i++; i < t; i++){
499                                                         c = line [i];
500
501                                                         if (c == end)
502                                                                 break;
503                                                         sb.Append (c);
504                                                 }
505                                         } else if (c == ' '){
506                                                 if (sb.Length > 0){
507                                                         args.Add (sb.ToString ());
508                                                         sb.Length = 0;
509                                                 }
510                                         } else
511                                                 sb.Append (c);
512                                 }
513                                 if (sb.Length > 0){
514                                         args.Add (sb.ToString ());
515                                         sb.Length = 0;
516                                 }
517                         }
518
519                         string [] ret_value = new string [args.Count];
520                         args.CopyTo (ret_value, 0);
521
522                         return ret_value;
523                 }
524
525                 //
526                 // Returns the directory where the system assemblies are installed
527                 //
528                 static string GetSystemDir ()
529                 {
530                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
531                 }
532
533                 //
534                 // Given a path specification, splits the path from the file/pattern
535                 //
536                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
537                 {
538                         int p = spec.LastIndexOf ('/');
539                         if (p != -1){
540                                 //
541                                 // Windows does not like /file.cs, switch that to:
542                                 // "\", "file.cs"
543                                 //
544                                 if (p == 0){
545                                         path = "\\";
546                                         pattern = spec.Substring (1);
547                                 } else {
548                                         path = spec.Substring (0, p);
549                                         pattern = spec.Substring (p + 1);
550                                 }
551                                 return;
552                         }
553
554                         p = spec.LastIndexOf ('\\');
555                         if (p != -1){
556                                 path = spec.Substring (0, p);
557                                 pattern = spec.Substring (p + 1);
558                                 return;
559                         }
560
561                         path = ".";
562                         pattern = spec;
563                 }
564
565                 static void ProcessFile (string f)
566                 {
567                         if (first_source == null)
568                                 first_source = f;
569
570                         Location.AddFile (f);
571                 }
572
573                 static void ProcessFiles ()
574                 {
575                         Location.Initialize ();
576
577                         foreach (SourceFile file in Location.SourceFiles) {
578                                 if (tokenize) {
579                                         tokenize_file (file);
580                                 } else {
581                                         parse (file);
582                                 }
583                         }
584                 }
585
586                 static void CompileFiles (string spec, bool recurse)
587                 {
588                         string path, pattern;
589
590                         SplitPathAndPattern (spec, out path, out pattern);
591                         if (pattern.IndexOf ('*') == -1){
592                                 ProcessFile (spec);
593                                 return;
594                         }
595
596                         string [] files = null;
597                         try {
598                                 files = Directory.GetFiles (path, pattern);
599                         } catch (System.IO.DirectoryNotFoundException) {
600                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
601                                 return;
602                         } catch (System.IO.IOException){
603                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
604                                 return;
605                         }
606                         foreach (string f in files) {
607                                 ProcessFile (f);
608                         }
609
610                         if (!recurse)
611                                 return;
612                         
613                         string [] dirs = null;
614
615                         try {
616                                 dirs = Directory.GetDirectories (path);
617                         } catch {
618                         }
619                         
620                         foreach (string d in dirs) {
621                                         
622                                 // Don't include path in this string, as each
623                                 // directory entry already does
624                                 CompileFiles (d + "/" + pattern, true);
625                         }
626                 }
627
628                 static void DefineDefaultConfig ()
629                 {
630                         //
631                         // For now the "default config" is harcoded into the compiler
632                         // we can move this outside later
633                         //
634                         string [] default_config = {
635                                 "System",
636                                 "System.Xml",
637 #if false
638                                 //
639                                 // Is it worth pre-loading all this stuff?
640                                 //
641                                 "Accessibility",
642                                 "System.Configuration.Install",
643                                 "System.Data",
644                                 "System.Design",
645                                 "System.DirectoryServices",
646                                 "System.Drawing.Design",
647                                 "System.Drawing",
648                                 "System.EnterpriseServices",
649                                 "System.Management",
650                                 "System.Messaging",
651                                 "System.Runtime.Remoting",
652                                 "System.Runtime.Serialization.Formatters.Soap",
653                                 "System.Security",
654                                 "System.ServiceProcess",
655                                 "System.Web",
656                                 "System.Web.RegularExpressions",
657                                 "System.Web.Services",
658                                 "System.Windows.Forms"
659 #endif
660                         };
661                         
662                         int p = 0;
663                         foreach (string def in default_config)
664                                 soft_references.Insert (p++, def);
665                 }
666
667                 public static string OutputFile
668                 {
669                         set {
670                                 output_file = value;
671                         }
672                         get {
673                                 return Path.GetFileName (output_file);
674                         }
675                 }
676
677                 static void SetWarningLevel (string s)
678                 {
679                         int level = -1;
680
681                         try {
682                                 level = Int32.Parse (s);
683                         } catch {
684                         }
685                         if (level < 0 || level > 4){
686                                 Report.Error (1900, "Warning level must be in the range 0-4");
687                                 return;
688                         }
689                         RootContext.WarningLevel = level;
690                 }
691
692                 static void SetupV2 ()
693                 {
694                         RootContext.Version = LanguageVersion.Default;
695                         defines.Add ("__V2__");
696                 }
697                 
698                 static void Version ()
699                 {
700                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
701                         Console.WriteLine ("Mono C# compiler version {0}", version);
702                         Environment.Exit (0);
703                 }
704                 
705                 //
706                 // Currently handles the Unix-like command line options, but will be
707                 // deprecated in favor of the CSCParseOption, which will also handle the
708                 // options that start with a dash in the future.
709                 //
710                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
711                 {
712                         switch (arg){
713                         case "-v":
714                                 CSharpParser.yacc_verbose_flag++;
715                                 return true;
716
717                         case "--version":
718                                 Version ();
719                                 return true;
720                                 
721                         case "--parse":
722                                 parse_only = true;
723                                 return true;
724                                 
725                         case "--main": case "-m":
726                                 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
727                                 if ((i + 1) >= args.Length){
728                                         Usage ();
729                                         Environment.Exit (1);
730                                 }
731                                 RootContext.MainClass = args [++i];
732                                 return true;
733                                 
734                         case "--unsafe":
735                                 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
736                                 RootContext.Unsafe = true;
737                                 return true;
738                                 
739                         case "/?": case "/h": case "/help":
740                         case "--help":
741                                 Usage ();
742                                 Environment.Exit (0);
743                                 return true;
744
745                         case "--define":
746                                 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
747                                 if ((i + 1) >= args.Length){
748                                         Usage ();
749                                         Environment.Exit (1);
750                                 }
751                                 defines.Add (args [++i]);
752                                 return true;
753
754                         case "--show-counters":
755                                 show_counters = true;
756                                 return true;
757                                 
758                         case "--expect-error": {
759                                 int code = 0;
760                                 
761                                 try {
762                                         code = Int32.Parse (
763                                                 args [++i], NumberStyles.AllowLeadingSign);
764                                         Report.ExpectedError = code;
765                                 } catch {
766                                         Report.Error (-14, "Invalid number specified");
767                                 } 
768                                 return true;
769                         }
770                                 
771                         case "--tokenize": 
772                                 tokenize = true;
773                                 return true;
774                                 
775                         case "-o": 
776                         case "--output":
777                                 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
778                                 if ((i + 1) >= args.Length){
779                                         Usage ();
780                                         Environment.Exit (1);
781                                 }
782                                 OutputFile = args [++i];
783                                 return true;
784
785                         case "--checked":
786                                 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
787                                 RootContext.Checked = true;
788                                 return true;
789                                 
790                         case "--stacktrace":
791                                 Report.Stacktrace = true;
792                                 return true;
793                                 
794                         case "--linkresource":
795                         case "--linkres":
796                                 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
797                                 if ((i + 1) >= args.Length){
798                                         Usage ();
799                                         Report.Error (5, "Missing argument to --linkres"); 
800                                         Environment.Exit (1);
801                                 }
802                                 if (embedded_resources == null)
803                                         embedded_resources = new Resources ();
804                                 
805                                 embedded_resources.Add (false, args [++i], args [i]);
806                                 return true;
807                                 
808                         case "--resource":
809                         case "--res":
810                                 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
811                                 if ((i + 1) >= args.Length){
812                                         Usage ();
813                                         Report.Error (5, "Missing argument to --resource"); 
814                                         Environment.Exit (1);
815                                 }
816                                 if (embedded_resources == null)
817                                         embedded_resources = new Resources ();
818                                 
819                                 embedded_resources.Add (true, args [++i], args [i]);
820                                 return true;
821                                 
822                         case "--target":
823                                 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
824                                 if ((i + 1) >= args.Length){
825                                         Environment.Exit (1);
826                                         return true;
827                                 }
828                                 
829                                 string type = args [++i];
830                                 switch (type){
831                                 case "library":
832                                         RootContext.Target = Target.Library;
833                                         RootContext.TargetExt = ".dll";
834                                         break;
835                                         
836                                 case "exe":
837                                         RootContext.Target = Target.Exe;
838                                         break;
839                                         
840                                 case "winexe":
841                                         RootContext.Target = Target.WinExe;
842                                         break;
843                                         
844                                 case "module":
845                                         RootContext.Target = Target.Module;
846                                         RootContext.TargetExt = ".dll";
847                                         break;
848                                 default:
849                                         TargetUsage ();
850                                         break;
851                                 }
852                                 return true;
853                                 
854                         case "-r":
855                                 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
856                                 if ((i + 1) >= args.Length){
857                                         Usage ();
858                                         Environment.Exit (1);
859                                 }
860                                 
861                                 string val = args [++i];
862                                 int idx = val.IndexOf ('=');
863                                 if (idx > -1) {
864                                         string alias = val.Substring (0, idx);
865                                         string assembly = val.Substring (idx + 1);
866                                         AddExternAlias (alias, assembly);
867                                         return true;
868                                 }
869
870                                 references.Add (val);
871                                 return true;
872                                 
873                         case "-L":
874                                 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
875                                 if ((i + 1) >= args.Length){
876                                         Usage ();       
877                                         Environment.Exit (1);
878                                 }
879                                 link_paths.Add (args [++i]);
880                                 return true;
881                                 
882                         case "--nostdlib":
883                                 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
884                                 RootContext.StdLib = false;
885                                 return true;
886                                 
887                         case "--fatal":
888                                 Report.Fatal = true;
889                                 return true;
890                                 
891                         case "--werror":
892                                 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
893                                 Report.WarningsAreErrors = true;
894                                 return true;
895
896                         case "--nowarn":
897                                 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
898                                 if ((i + 1) >= args.Length){
899                                         Usage ();
900                                         Environment.Exit (1);
901                                 }
902                                 int warn = 0;
903                                 
904                                 try {
905                                         warn = Int32.Parse (args [++i]);
906                                 } catch {
907                                         Usage ();
908                                         Environment.Exit (1);
909                                 }
910                                 Report.SetIgnoreWarning (warn);
911                                 return true;
912                                 
913                         case "--wlevel":
914                                 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
915                                 if ((i + 1) >= args.Length){
916                                         Report.Error (
917                                                 1900,
918                                                 "--wlevel requires a value from 0 to 4");
919                                         Environment.Exit (1);
920                                 }
921
922                                 SetWarningLevel (args [++i]);
923                                 return true;
924
925                         case "--mcs-debug":
926                                 if ((i + 1) >= args.Length){
927                                         Report.Error (5, "--mcs-debug requires an argument");
928                                         Environment.Exit (1);
929                                 }
930
931                                 try {
932                                         Report.DebugFlags = Int32.Parse (args [++i]);
933                                 } catch {
934                                         Report.Error (5, "Invalid argument to --mcs-debug");
935                                         Environment.Exit (1);
936                                 }
937                                 return true;
938                                 
939                         case "--about":
940                                 About ();
941                                 return true;
942                                 
943                         case "--recurse":
944                                 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
945                                 if ((i + 1) >= args.Length){
946                                         Report.Error (5, "--recurse requires an argument");
947                                         Environment.Exit (1);
948                                 }
949                                 CompileFiles (args [++i], true); 
950                                 return true;
951                                 
952                         case "--timestamp":
953                                 timestamps = true;
954                                 last_time = first_time = DateTime.Now;
955                                 return true;
956
957                         case "--pause":
958                                 pause = true;
959                                 return true;
960                                 
961                         case "--debug": case "-g":
962                                 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
963                                 want_debugging_support = true;
964                                 return true;
965                                 
966                         case "--noconfig":
967                                 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
968                                 load_default_config = false;
969                                 return true;
970                         }
971
972                         return false;
973                 }
974
975                 //
976                 // This parses the -arg and /arg options to the compiler, even if the strings
977                 // in the following text use "/arg" on the strings.
978                 //
979                 static bool CSCParseOption (string option, ref string [] args, ref int i)
980                 {
981                         int idx = option.IndexOf (':');
982                         string arg, value;
983
984                         if (idx == -1){
985                                 arg = option;
986                                 value = "";
987                         } else {
988                                 arg = option.Substring (0, idx);
989
990                                 value = option.Substring (idx + 1);
991                         }
992
993                         switch (arg){
994                         case "/nologo":
995                                 return true;
996
997                         case "/t":
998                         case "/target":
999                                 switch (value){
1000                                 case "exe":
1001                                         RootContext.Target = Target.Exe;
1002                                         break;
1003
1004                                 case "winexe":
1005                                         RootContext.Target = Target.WinExe;
1006                                         break;
1007
1008                                 case "library":
1009                                         RootContext.Target = Target.Library;
1010                                         RootContext.TargetExt = ".dll";
1011                                         break;
1012
1013                                 case "module":
1014                                         RootContext.Target = Target.Module;
1015                                         RootContext.TargetExt = ".netmodule";
1016                                         break;
1017
1018                                 default:
1019                                         TargetUsage ();
1020                                         break;
1021                                 }
1022                                 return true;
1023
1024                         case "/out":
1025                                 if (value.Length == 0){
1026                                         Usage ();
1027                                         Environment.Exit (1);
1028                                 }
1029                                 OutputFile = value;
1030                                 return true;
1031
1032                         case "/optimize":
1033                         case "/optimize+":
1034                                 RootContext.Optimize = true;
1035                                 return true;
1036
1037                         case "/optimize-":
1038                                 RootContext.Optimize = false;
1039                                 return true;
1040
1041                         case "/incremental":
1042                         case "/incremental+":
1043                         case "/incremental-":
1044                                 // nothing.
1045                                 return true;
1046
1047                         case "/d":
1048                         case "/define": {
1049                                 string [] defs;
1050
1051                                 if (value.Length == 0){
1052                                         Usage ();
1053                                         Environment.Exit (1);
1054                                 }
1055
1056                                 defs = value.Split (new Char [] {';', ','});
1057                                 foreach (string d in defs){
1058                                         defines.Add (d);
1059                                 }
1060                                 return true;
1061                         }
1062
1063                         case "/bugreport":
1064                                 //
1065                                 // We should collect data, runtime, etc and store in the file specified
1066                                 //
1067                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1068                                 return true;
1069
1070                         case "/pkg": {
1071                                 string packages;
1072
1073                                 if (value.Length == 0){
1074                                         Usage ();
1075                                         Environment.Exit (1);
1076                                 }
1077                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1078                                 
1079                                 ProcessStartInfo pi = new ProcessStartInfo ();
1080                                 pi.FileName = "pkg-config";
1081                                 pi.RedirectStandardOutput = true;
1082                                 pi.UseShellExecute = false;
1083                                 pi.Arguments = "--libs " + packages;
1084                                 Process p = null;
1085                                 try {
1086                                         p = Process.Start (pi);
1087                                 } catch (Exception e) {
1088                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1089                                         Environment.Exit (1);
1090                                 }
1091
1092                                 if (p.StandardOutput == null){
1093                                         Report.Warning (-27, 1, "Specified package did not return any information");
1094                                         return true;
1095                                 }
1096                                 string pkgout = p.StandardOutput.ReadToEnd ();
1097                                 p.WaitForExit ();
1098                                 if (p.ExitCode != 0) {
1099                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1100                                         Environment.Exit (1);
1101                                 }
1102
1103                                 if (pkgout != null){
1104                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1105                                                 Split (new Char [] { ' ', '\t'});
1106                                         args = AddArgs (args, xargs);
1107                                 }
1108                                 
1109                                 p.Close ();
1110                                 return true;
1111                         }
1112                                 
1113                         case "/linkres":
1114                         case "/linkresource":
1115                         case "/res":
1116                         case "/resource":
1117                                 if (embedded_resources == null)
1118                                         embedded_resources = new Resources ();
1119
1120                                 bool embeded = arg.StartsWith ("/r");
1121                                 string[] s = value.Split (',');
1122                                 switch (s.Length) {
1123                                         case 1:
1124                                                 if (s[0].Length == 0)
1125                                                         goto default;
1126                                                 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1127                                                 break;
1128                                         case 2:
1129                                                 embedded_resources.Add (embeded, s [0], s [1]);
1130                                                 break;
1131                                         case 3:
1132                                                 if (s [2] != "public" && s [2] != "private") {
1133                                                         Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1134                                                         return true;
1135                                                 }
1136                                                 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1137                                                 break;
1138                                         default:
1139                                                 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1140                                                 break;
1141                                 }
1142
1143                                 return true;
1144                                 
1145                         case "/recurse":
1146                                 if (value.Length == 0){
1147                                         Report.Error (5, "-recurse requires an argument");
1148                                         Environment.Exit (1);
1149                                 }
1150                                 CompileFiles (value, true); 
1151                                 return true;
1152
1153                         case "/r":
1154                         case "/reference": {
1155                                 if (value.Length == 0){
1156                                         Report.Error (5, "-reference requires an argument");
1157                                         Environment.Exit (1);
1158                                 }
1159
1160                                 string [] refs = value.Split (new char [] { ';', ',' });
1161                                 foreach (string r in refs){
1162                                         string val = r;
1163                                         int index = val.IndexOf ("=");
1164                                         if (index > -1) {
1165                                                 string alias = r.Substring (0, index);
1166                                                 string assembly = r.Substring (index + 1);
1167                                                 AddExternAlias (alias, assembly);
1168                                                 return true;
1169                                         }
1170                                         
1171                                         references.Add (val);
1172                                 }
1173                                 return true;
1174                         }
1175                         case "/addmodule": {
1176                                 if (value.Length == 0){
1177                                         Report.Error (5, arg + " requires an argument");
1178                                         Environment.Exit (1);
1179                                 }
1180
1181                                 string [] refs = value.Split (new char [] { ';', ',' });
1182                                 foreach (string r in refs){
1183                                         modules.Add (r);
1184                                 }
1185                                 return true;
1186                         }
1187                         case "/win32res": {
1188                                 if (value.Length == 0) {
1189                                         Report.Error (5, arg + " requires an argument");
1190                                         Environment.Exit (1);
1191                                 }
1192
1193                                 win32ResourceFile = value;
1194                                 return true;
1195                         }
1196                         case "/win32icon": {
1197                                 if (value.Length == 0) {
1198                                         Report.Error (5, arg + " requires an argument");
1199                                         Environment.Exit (1);
1200                                 }
1201
1202                                 win32IconFile = value;
1203                                 return true;
1204                         }
1205                         case "/doc": {
1206                                 if (value.Length == 0){
1207                                         Report.Error (2006, arg + " requires an argument");
1208                                         Environment.Exit (1);
1209                                 }
1210                                 RootContext.Documentation = new Documentation (value);
1211                                 return true;
1212                         }
1213                         case "/lib": {
1214                                 string [] libdirs;
1215                                 
1216                                 if (value.Length == 0){
1217                                         Report.Error (5, "/lib requires an argument");
1218                                         Environment.Exit (1);
1219                                 }
1220
1221                                 libdirs = value.Split (new Char [] { ',' });
1222                                 foreach (string dir in libdirs)
1223                                         link_paths.Add (dir);
1224                                 return true;
1225                         }
1226
1227                         case "/debug-":
1228                                 want_debugging_support = false;
1229                                 return true;
1230                                 
1231                         case "/debug":
1232                         case "/debug+":
1233                                 want_debugging_support = true;
1234                                 return true;
1235
1236                         case "/checked":
1237                         case "/checked+":
1238                                 RootContext.Checked = true;
1239                                 return true;
1240
1241                         case "/checked-":
1242                                 RootContext.Checked = false;
1243                                 return true;
1244
1245                         case "/clscheck":
1246                         case "/clscheck+":
1247                                 return true;
1248
1249                         case "/clscheck-":
1250                                 RootContext.VerifyClsCompliance = false;
1251                                 return true;
1252
1253                         case "/unsafe":
1254                         case "/unsafe+":
1255                                 RootContext.Unsafe = true;
1256                                 return true;
1257
1258                         case "/unsafe-":
1259                                 RootContext.Unsafe = false;
1260                                 return true;
1261
1262                         case "/warnaserror":
1263                         case "/warnaserror+":
1264                                 Report.WarningsAreErrors = true;
1265                                 return true;
1266
1267                         case "/warnaserror-":
1268                                 Report.WarningsAreErrors = false;
1269                                 return true;
1270
1271                         case "/warn":
1272                                 SetWarningLevel (value);
1273                                 return true;
1274
1275                         case "/nowarn": {
1276                                 string [] warns;
1277
1278                                 if (value.Length == 0){
1279                                         Report.Error (5, "/nowarn requires an argument");
1280                                         Environment.Exit (1);
1281                                 }
1282                                 
1283                                 warns = value.Split (new Char [] {','});
1284                                 foreach (string wc in warns){
1285                                         try {
1286                                                 int warn = Int32.Parse (wc);
1287                                                 if (warn < 1) {
1288                                                         throw new ArgumentOutOfRangeException("warn");
1289                                                 }
1290                                                 Report.SetIgnoreWarning (warn);
1291                                         } catch {
1292                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1293                                         }
1294                                 }
1295                                 return true;
1296                         }
1297
1298                         case "/noconfig-":
1299                                 load_default_config = true;
1300                                 return true;
1301                                 
1302                         case "/noconfig":
1303                         case "/noconfig+":
1304                                 load_default_config = false;
1305                                 return true;
1306
1307                         case "/help2":
1308                                 OtherFlags ();
1309                                 Environment.Exit(0);
1310                                 return true;
1311                                 
1312                         case "/help":
1313                         case "/?":
1314                                 Usage ();
1315                                 Environment.Exit (0);
1316                                 return true;
1317
1318                         case "/main":
1319                         case "/m":
1320                                 if (value.Length == 0){
1321                                         Report.Error (5, arg + " requires an argument");                                        
1322                                         Environment.Exit (1);
1323                                 }
1324                                 RootContext.MainClass = value;
1325                                 return true;
1326
1327                         case "/nostdlib":
1328                         case "/nostdlib+":
1329                                 RootContext.StdLib = false;
1330                                 return true;
1331
1332                         case "/nostdlib-":
1333                                 RootContext.StdLib = true;
1334                                 return true;
1335
1336                         case "/fullpaths":
1337                                 return true;
1338
1339                         case "/keyfile":
1340                                 if (value == String.Empty) {
1341                                         Report.Error (5, arg + " requires an argument");
1342                                         Environment.Exit (1);
1343                                 }
1344                                 RootContext.StrongNameKeyFile = value;
1345                                 return true;
1346                         case "/keycontainer":
1347                                 if (value == String.Empty) {
1348                                         Report.Error (5, arg + " requires an argument");
1349                                         Environment.Exit (1);
1350                                 }
1351                                 RootContext.StrongNameKeyContainer = value;
1352                                 return true;
1353                         case "/delaysign+":
1354                                 RootContext.StrongNameDelaySign = true;
1355                                 return true;
1356                         case "/delaysign-":
1357                                 RootContext.StrongNameDelaySign = false;
1358                                 return true;
1359
1360                         case "/v2":
1361                         case "/2":
1362                                 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1363                                 SetupV2 ();
1364                                 return true;
1365                                 
1366                         case "/langversion":
1367                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1368                                         case "iso-1":
1369                                                 RootContext.Version = LanguageVersion.ISO_1;
1370                                                 return true;
1371
1372                                         case "default":
1373                                                 SetupV2 ();
1374                                                 return true;
1375                                 }
1376                                 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
1377                                 return true;
1378
1379                         case "/codepage":
1380                                 switch (value) {
1381                                 case "utf8":
1382                                         encoding = new UTF8Encoding();
1383                                         break;
1384                                 case "reset":
1385                                         encoding = Encoding.Default;
1386                                         break;
1387                                 default:
1388                                         try {
1389                                                 encoding = Encoding.GetEncoding (
1390                                                 Int32.Parse (value));
1391                                         } catch {
1392                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1393                                         }
1394                                         break;
1395                                 }
1396                                 return true;
1397                         }
1398
1399                         return false;
1400                 }
1401
1402                 static void Error_WrongOption (string option)
1403                 {
1404                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1405                 }
1406
1407                 static string [] AddArgs (string [] args, string [] extra_args)
1408                 {
1409                         string [] new_args;
1410                         new_args = new string [extra_args.Length + args.Length];
1411
1412                         // if args contains '--' we have to take that into account
1413                         // split args into first half and second half based on '--'
1414                         // and add the extra_args before --
1415                         int split_position = Array.IndexOf (args, "--");
1416                         if (split_position != -1)
1417                         {
1418                                 Array.Copy (args, new_args, split_position);
1419                                 extra_args.CopyTo (new_args, split_position);
1420                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1421                         }
1422                         else
1423                         {
1424                                 args.CopyTo (new_args, 0);
1425                                 extra_args.CopyTo (new_args, args.Length);
1426                         }
1427
1428                         return new_args;
1429                 }
1430
1431                 static void AddExternAlias (string identifier, string assembly)
1432                 {
1433                         if (assembly.Length == 0) {
1434                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1435                                 return;
1436                         }
1437
1438                         if (!IsExternAliasValid (identifier)) {
1439                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1440                                 return;
1441                         }
1442                         
1443                         // Could here hashtable throw an exception?
1444                         external_aliases [identifier] = assembly;
1445                 }
1446                 
1447                 static bool IsExternAliasValid (string identifier)
1448                 {
1449                         if (identifier.Length == 0)
1450                                 return false;
1451                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1452                                 return false;
1453
1454                         for (int i = 1; i < identifier.Length; i++) {
1455                                 char c = identifier [i];
1456                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1457                                         continue;
1458
1459                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1460                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1461                                                 category != UnicodeCategory.SpacingCombiningMark ||
1462                                                 category != UnicodeCategory.ConnectorPunctuation)
1463                                         return false;
1464                         }
1465                         
1466                         return true;
1467                 }
1468                 
1469                 /// <summary>
1470                 ///    Parses the arguments, and drives the compilation
1471                 ///    process.
1472                 /// </summary>
1473                 ///
1474                 /// <remarks>
1475                 ///    TODO: Mostly structured to debug the compiler
1476                 ///    now, needs to be turned into a real driver soon.
1477                 /// </remarks>
1478                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1479                 internal static bool MainDriver (string [] args)
1480                 {
1481                         int i;
1482                         bool parsing_options = true;
1483
1484                         encoding = Encoding.Default;
1485
1486                         references = new ArrayList ();
1487                         external_aliases = new Hashtable ();
1488                         soft_references = new ArrayList ();
1489                         modules = new ArrayList ();
1490                         link_paths = new ArrayList ();
1491
1492                         SetupDefaultDefines ();
1493                         
1494                         //
1495                         // Setup defaults
1496                         //
1497                         // This is not required because Assembly.Load knows about this
1498                         // path.
1499                         //
1500
1501                         Hashtable response_file_list = null;
1502
1503                         for (i = 0; i < args.Length; i++){
1504                                 string arg = args [i];
1505                                 if (arg.Length == 0)
1506                                         continue;
1507
1508                                 if (arg.StartsWith ("@")){
1509                                         string [] extra_args;
1510                                         string response_file = arg.Substring (1);
1511
1512                                         if (response_file_list == null)
1513                                                 response_file_list = new Hashtable ();
1514                                         
1515                                         if (response_file_list.Contains (response_file)){
1516                                                 Report.Error (
1517                                                         1515, "Response file `" + response_file +
1518                                                         "' specified multiple times");
1519                                                 Environment.Exit (1);
1520                                         }
1521                                         
1522                                         response_file_list.Add (response_file, response_file);
1523                                                     
1524                                         extra_args = LoadArgs (response_file);
1525                                         if (extra_args == null){
1526                                                 Report.Error (2011, "Unable to open response file: " +
1527                                                               response_file);
1528                                                 return false;
1529                                         }
1530
1531                                         args = AddArgs (args, extra_args);
1532                                         continue;
1533                                 }
1534
1535                                 if (parsing_options){
1536                                         if (arg == "--"){
1537                                                 parsing_options = false;
1538                                                 continue;
1539                                         }
1540                                         
1541                                         if (arg.StartsWith ("-")){
1542                                                 if (UnixParseOption (arg, ref args, ref i))
1543                                                         continue;
1544
1545                                                 // Try a -CSCOPTION
1546                                                 string csc_opt = "/" + arg.Substring (1);
1547                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1548                                                         continue;
1549
1550                                                 Error_WrongOption (arg);
1551                                                 return false;
1552                                         } else {
1553                                                 if (arg [0] == '/'){
1554                                                         if (CSCParseOption (arg, ref args, ref i))
1555                                                                 continue;
1556
1557                                                         // Need to skip `/home/test.cs' however /test.cs is considered as error
1558                                                         if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
1559                                                                 Error_WrongOption (arg);
1560                                                                 return false;
1561                                                         }
1562                                                 }
1563                                         }
1564                                 }
1565
1566                                 CompileFiles (arg, false); 
1567                         }
1568
1569                         ProcessFiles ();
1570
1571                         if (tokenize)
1572                                 return true;
1573
1574                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1575                                 throw new InternalErrorException ("who set it?");
1576
1577                         //
1578                         // If we are an exe, require a source file for the entry point
1579                         //
1580                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
1581                                 if (first_source == null){
1582                                         Report.Error (2008, "No files to compile were specified");
1583                                         return false;
1584                                 }
1585
1586                         }
1587
1588                         //
1589                         // If there is nothing to put in the assembly, and we are not a library
1590                         //
1591                         if (first_source == null && embedded_resources == null){
1592                                 Report.Error (2008, "No files to compile were specified");
1593                                 return false;
1594                         }
1595
1596                         if (Report.Errors > 0)
1597                                 return false;
1598                         
1599                         if (parse_only)
1600                                 return true;
1601
1602                         //
1603                         // Load Core Library for default compilation
1604                         //
1605                         if (RootContext.StdLib)
1606                                 references.Insert (0, "mscorlib");
1607
1608                         if (load_default_config)
1609                                 DefineDefaultConfig ();
1610
1611                         if (Report.Errors > 0){
1612                                 return false;
1613                         }
1614
1615                         //
1616                         // Load assemblies required
1617                         //
1618                         if (timestamps)
1619                                 ShowTime ("Loading references");
1620                         link_paths.Add (GetSystemDir ());
1621                         link_paths.Add (Directory.GetCurrentDirectory ());
1622                         LoadReferences ();
1623                         
1624                         if (timestamps)
1625                                 ShowTime ("   References loaded");
1626                         
1627                         if (Report.Errors > 0){
1628                                 return false;
1629                         }
1630
1631                         //
1632                         // Quick hack
1633                         //
1634                         if (output_file == null){
1635                                 if (first_source == null){
1636                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1637                                         return false;
1638                                 }
1639                                         
1640                                 int pos = first_source.LastIndexOf ('.');
1641
1642                                 if (pos > 0)
1643                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1644                                 else
1645                                         output_file = first_source + RootContext.TargetExt;
1646                         }
1647
1648                         if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1649                                 return false;
1650
1651                         if (RootContext.Target == Target.Module) {
1652                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1653                                 if (module_only == null) {
1654                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1655                                         Environment.Exit (1);
1656                                 }
1657
1658                                 MethodInfo set_method = module_only.GetSetMethod (true);
1659                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1660                         }
1661
1662                         RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1663
1664                         if (modules.Count > 0) {
1665                                 foreach (string module in modules)
1666                                         LoadModule (module);
1667                         }
1668                         
1669                         //
1670                         // Before emitting, we need to get the core
1671                         // types emitted from the user defined types
1672                         // or from the system ones.
1673                         //
1674                         if (timestamps)
1675                                 ShowTime ("Initializing Core Types");
1676                         if (!RootContext.StdLib){
1677                                 RootContext.ResolveCore ();
1678                                 if (Report.Errors > 0)
1679                                         return false;
1680                         }
1681                         
1682                         TypeManager.InitCoreTypes ();
1683                         if (timestamps)
1684                                 ShowTime ("   Core Types done");
1685
1686                         CodeGen.Module.Resolve ();
1687
1688                         //
1689                         // The second pass of the compiler
1690                         //
1691                         if (timestamps)
1692                                 ShowTime ("Resolving tree");
1693                         RootContext.ResolveTree ();
1694
1695                         if (Report.Errors > 0)
1696                                 return false;
1697                         if (timestamps)
1698                                 ShowTime ("Populate tree");
1699                         if (!RootContext.StdLib)
1700                                 RootContext.BootCorlib_PopulateCoreTypes ();
1701                         RootContext.PopulateTypes ();
1702
1703                         TypeManager.InitCodeHelpers ();
1704
1705                         RootContext.DefineTypes ();
1706                         
1707                         if (Report.Errors == 0 &&
1708                                 RootContext.Documentation != null &&
1709                                 !RootContext.Documentation.OutputDocComment (
1710                                         output_file))
1711                                 return false;
1712
1713                         //
1714                         // Verify using aliases now
1715                         //
1716                         NamespaceEntry.VerifyAllUsing ();
1717                         
1718                         if (Report.Errors > 0){
1719                                 return false;
1720                         }
1721
1722                         CodeGen.Assembly.Resolve ();
1723                         
1724                         if (RootContext.VerifyClsCompliance) {
1725                                 if (CodeGen.Assembly.IsClsCompliant) {
1726                                         AttributeTester.VerifyModulesClsCompliance ();
1727                                         TypeManager.LoadAllImportedTypes ();
1728                                 }
1729                         }
1730                         if (Report.Errors > 0)
1731                                 return false;
1732                         
1733                         //
1734                         // The code generator
1735                         //
1736                         if (timestamps)
1737                                 ShowTime ("Emitting code");
1738                         ShowTotalTime ("Total so far");
1739                         RootContext.EmitCode ();
1740                         if (timestamps)
1741                                 ShowTime ("   done");
1742
1743                         if (Report.Errors > 0){
1744                                 return false;
1745                         }
1746
1747                         if (timestamps)
1748                                 ShowTime ("Closing types");
1749
1750                         RootContext.CloseTypes ();
1751
1752                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1753
1754                         switch (RootContext.Target) {
1755                         case Target.Library:
1756                         case Target.Module:
1757                                 k = PEFileKinds.Dll; break;
1758                         case Target.Exe:
1759                                 k = PEFileKinds.ConsoleApplication; break;
1760                         case Target.WinExe:
1761                                 k = PEFileKinds.WindowApplication; break;
1762                         }
1763
1764                         if (RootContext.NeedsEntryPoint) {
1765                                 MethodInfo ep = RootContext.EntryPoint;
1766
1767                                 if (ep == null) {
1768                                         if (RootContext.MainClass != null) {
1769                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1770                                                 if (main_cont == null) {
1771                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1772                                                         return false;
1773                                                 }
1774
1775                                                 if (!(main_cont is ClassOrStruct)) {
1776                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1777                                                         return false;
1778                                                 }
1779
1780                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1781                                                 return false;
1782                                         }
1783
1784                                         if (Report.Errors == 0)
1785                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1786                                                         output_file);
1787                                         return false;
1788                                 }
1789
1790                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1791                         } else if (RootContext.MainClass != null) {
1792                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1793                         }
1794
1795                         if (embedded_resources != null){
1796                                 if (RootContext.Target == Target.Module) {
1797                                         Report.Error (1507, "Cannot link resource file when building a module");
1798                                         return false;
1799                                 }
1800
1801                                 embedded_resources.Emit ();
1802                         }
1803
1804                         //
1805                         // Add Win32 resources
1806                         //
1807
1808                         CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1809
1810                         if (win32ResourceFile != null) {
1811                                 try {
1812                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1813                                 }
1814                                 catch (ArgumentException) {
1815                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1816                                 }
1817                         }
1818
1819                         if (win32IconFile != null) {
1820                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1821                                 if (define_icon == null) {
1822                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1823                                 }
1824                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1825                         }
1826
1827                         if (Report.Errors > 0)
1828                                 return false;
1829                         
1830                         CodeGen.Save (output_file);
1831                         if (timestamps) {
1832                                 ShowTime ("Saved output");
1833                                 ShowTotalTime ("Total");
1834                         }
1835
1836                         Timer.ShowTimers ();
1837                         
1838                         if (Report.ExpectedError != 0) {
1839                                 if (Report.Errors == 0) {
1840                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1841                                                 "No other errors reported.");
1842                                         
1843                                         Environment.Exit (2);
1844                                 } else {
1845                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1846                                                 "However, other errors were reported.");
1847                                         
1848                                         Environment.Exit (1);
1849                                 }
1850                                 
1851                                 
1852                                 return false;
1853                         }
1854
1855 #if DEBUGME
1856                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1857                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1858 #endif
1859                         return (Report.Errors == 0);
1860                 }
1861         }
1862
1863         class Resources
1864         {
1865                 interface IResource
1866                 {
1867                         void Emit ();
1868                         string FileName { get; }
1869                 }
1870
1871                 class EmbededResource : IResource
1872                 {
1873                         static MethodInfo embed_res;
1874
1875                         static EmbededResource () {
1876                                 Type[] argst = new Type [] { 
1877                                                                                            typeof (string), typeof (string), typeof (ResourceAttributes)
1878                                                                                    };
1879
1880                                 embed_res = typeof (AssemblyBuilder).GetMethod (
1881                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1882                                         null, CallingConventions.Any, argst, null);
1883                                 
1884                                 if (embed_res == null) {
1885                                         Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1886                                 }
1887                         }
1888
1889                         readonly object[] args;
1890
1891                         public EmbededResource (string name, string file, bool isPrivate)
1892                         {
1893                                 args = new object [3];
1894                                 args [0] = name;
1895                                 args [1] = file;
1896                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1897                         }
1898
1899                         public void Emit()
1900                         {
1901                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1902                         }
1903
1904                         public string FileName {
1905                                 get {
1906                                         return (string)args [1];
1907                                 }
1908                         }
1909                 }
1910
1911                 class LinkedResource : IResource
1912                 {
1913                         readonly string file;
1914                         readonly string name;
1915                         readonly ResourceAttributes attribute;
1916
1917                         public LinkedResource (string name, string file, bool isPrivate)
1918                         {
1919                                 this.name = name;
1920                                 this.file = file;
1921                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1922                         }
1923
1924                         public void Emit ()
1925                         {
1926                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1927                         }
1928
1929                         public string FileName {
1930                                 get {
1931                                         return file;
1932                                 }
1933                         }
1934                 }
1935
1936
1937                 IDictionary embedded_resources = new HybridDictionary ();
1938
1939                 public void Add (bool embeded, string file, string name)
1940                 {
1941                         Add (embeded, file, name, false);
1942                 }
1943
1944                 public void Add (bool embeded, string file, string name, bool isPrivate)
1945                 {
1946                         if (embedded_resources.Contains (name)) {
1947                                 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1948                                 return;
1949                         }
1950                         IResource r = embeded ? 
1951                                 (IResource) new EmbededResource (name, file, isPrivate) : 
1952                                 new LinkedResource (name, file, isPrivate);
1953
1954                         embedded_resources.Add (name, r);
1955                 }
1956
1957                 public void Emit ()
1958                 {
1959                         foreach (IResource r in embedded_resources.Values) {
1960                                 if (!File.Exists (r.FileName)) {
1961                                         Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1962                                         continue;
1963                                 }
1964                                 
1965                                 r.Emit ();
1966                         }
1967                 }
1968         }
1969
1970         //
1971         // This is the only public entry point
1972         //
1973         public class CompilerCallableEntryPoint : MarshalByRefObject {
1974                 public static bool InvokeCompiler (string [] args, TextWriter error)
1975                 {
1976                         Report.Stderr = error;
1977                         try {
1978                                 return Driver.MainDriver (args) && Report.Errors == 0;
1979                         }
1980                         finally {
1981                                 Report.Stderr = Console.Error;
1982                                 Reset ();
1983                         }
1984                 }
1985
1986                 public static int[] AllWarningNumbers {
1987                         get {
1988                                 return Report.AllWarnings;
1989                         }
1990                 }
1991                 
1992                 static void Reset ()
1993                 {
1994                         Driver.Reset ();
1995                         Location.Reset ();
1996                         RootContext.Reset ();
1997                         Report.Reset ();
1998                         TypeManager.Reset ();
1999                         TypeHandle.Reset ();
2000                         RootNamespace.Reset ();
2001                         NamespaceEntry.Reset ();
2002                         CodeGen.Reset ();
2003                         Attribute.Reset ();
2004                         AttributeTester.Reset ();
2005                 }
2006         }
2007 }