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