Initial import of the Generic MCS tree.
[mono.git] / mcs / gmcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 //
10
11 namespace Mono.CSharp
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using System.Text;
19         using System.Globalization;
20
21         enum Target {
22                 Library, Exe, Module, WinExe
23         };
24         
25         /// <summary>
26         ///    The compiler driver.
27         /// </summary>
28         public class Driver
29         {
30                 
31                 //
32                 // Assemblies references to be linked.   Initialized with
33                 // mscorlib.dll here.
34                 static ArrayList references;
35
36                 //
37                 // If any of these fail, we ignore the problem.  This is so
38                 // that we can list all the assemblies in Windows and not fail
39                 // if they are missing on Linux.
40                 //
41                 static ArrayList soft_references;
42
43                 // Lookup paths
44                 static ArrayList link_paths;
45
46                 // Whether we want Yacc to output its progress
47                 static bool yacc_verbose = false;
48
49                 // Whether we want to only run the tokenizer
50                 static bool tokenize = false;
51                 
52                 static string first_source;
53
54                 static Target target = Target.Exe;
55                 static string target_ext = ".exe";
56
57                 static bool want_debugging_support = false;
58
59                 static bool parse_only = false;
60                 static bool timestamps = false;
61                 static bool pause = false;
62                 static bool show_counters = false;
63                 
64                 //
65                 // Whether to load the initial config file (what CSC.RSP has by default)
66                 // 
67                 static bool load_default_config = true;
68
69                 static Hashtable response_file_list;
70
71                 //
72                 // A list of resource files
73                 //
74                 static ArrayList resources;
75                 static ArrayList embedded_resources;
76                 
77                 //
78                 // An array of the defines from the command line
79                 //
80                 static ArrayList defines;
81
82                 //
83                 // Output file
84                 //
85                 static string output_file = null;
86
87                 //
88                 // Last time we took the time
89                 //
90                 static DateTime last_time, first_time;
91
92                 //
93                 // Encoding: ISO-Latin1 is 28591
94                 //
95                 static Encoding encoding;
96
97                 //
98                 // Whether the user has specified a different encoder manually
99                 //
100                 static bool using_default_encoder = true;
101                 
102                 public static void ShowTime (string msg)
103                 {
104                         if (!timestamps)
105                                 return;
106
107                         DateTime now = DateTime.Now;
108                         TimeSpan span = now - last_time;
109                         last_time = now;
110
111                         Console.WriteLine (
112                                 "[{0:00}:{1:000}] {2}",
113                                 (int) span.TotalSeconds, span.Milliseconds, msg);
114
115                         if (pause)
116                                 Console.ReadLine ();
117                 }
118
119                 public static void ShowTotalTime (string msg)
120                 {
121                         if (!timestamps)
122                                 return;
123
124                         DateTime now = DateTime.Now;
125                         TimeSpan span = now - first_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                 static void tokenize_file (SourceFile file)
134                 {
135                         Stream input;
136
137                         try {
138                                 input = File.OpenRead (file.Name);
139                         } catch {
140                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
141                                 return;
142                         }
143
144                         using (input){
145                                 StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
146                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
147                                 int token, tokens = 0, errors = 0;
148
149                                 while ((token = lexer.token ()) != Token.EOF){
150                                         Location l = lexer.Location;
151                                         tokens++;
152                                         if (token == Token.ERROR)
153                                                 errors++;
154                                 }
155                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
156                         }
157                         
158                         return;
159                 }
160
161                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
162                 static void parse (SourceFile file)
163                 {
164                         CSharpParser parser;
165                         Stream input;
166
167                         try {
168                                 input = File.OpenRead (file.Name);
169                         } catch {
170                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
171                                 return;
172                         }
173
174                         StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
175                                 
176                         parser = new CSharpParser (reader, file, defines);
177                         parser.yacc_verbose_flag = yacc_verbose;
178                         try {
179                                 parser.parse ();
180                         } catch (Exception ex) {
181                                 Report.Error(666, "Compilation aborted: " + ex);
182                         } finally {
183                                 input.Close ();
184                         }
185                 }
186                 
187                 static void Usage ()
188                 {
189                         Console.WriteLine (
190                                 "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
191                                 "mcs [options] source-files\n" +
192                                 "   --about            About the Mono C# compiler\n" +
193                                 "   -checked[+|-]      Set default context to checked\n" +
194                                 "   -codepage:ID       Sets code page to the one in ID\n" +
195                                 "                      (number, `utf8' or `reset')\n" +
196                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
197                                 "   -debug[+-]         Generate debugging information\n" + 
198                                 "   -doc:FILE          XML Documentation file to generate\n" + 
199                                 "   -g                 Generate debugging information\n" +
200                                 "   --fatal            Makes errors fatal\n" +
201                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
202                                 "   -main:class        Specified the class that contains the entry point\n" +
203                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
204                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
205                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
206                                 "   -out:FNAME         Specifies output file\n" +
207                                 "   --parse            Only parses the source file\n" +
208                                 "   --expect-error X   Expect that error X will be encountered\n" +
209                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
210                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
211                                 "   --stacktrace       Shows stack trace at error location\n" +
212                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
213                                 "                      library, module), (short: /t:)\n" +
214                                 "   --timestamp        Displays time stamps of various compiler events\n" +
215                                 "   -unsafe[+|-]       Allows unsafe code\n" +
216                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
217                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default)\n" +
218                                 "   -v                 Verbose parsing (for debugging the parser)\n" +
219                                 "\n" +
220                                 "Resources:\n" +
221                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
222                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
223                                 "   --mcs-debug X      Sets MCS debugging level to X\n" +
224                                 "   @file              Read response file for more options\n\n" +
225                                 "Options can be of the form -option or /option");
226                 }
227
228                 static void TargetUsage ()
229                 {
230                         Report.Error (2019, "Valid options for -target: are exe, winexe, library or module");
231                 }
232                 
233                 static void About ()
234                 {
235                         Console.WriteLine (
236                                 "The Mono C# compiler is (C) 2001, 2002, 2003 Ximian, Inc.\n\n" +
237                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
238
239                                 "For more information on Mono, visit the project Web site\n" +
240                                 "   http://www.go-mono.com\n\n" +
241
242                                 "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
243                         Environment.Exit (0);
244                 }
245
246                 public static int counter1, counter2;
247                 
248                 public static int Main (string[] args)
249                 {
250                         bool ok = MainDriver (args);
251                         
252                         if (ok && Report.Errors == 0) {
253                                 Console.Write("Compilation succeeded");
254                                 if (Report.Warnings > 0) {
255                                         Console.Write(" - {0} warning(s)", Report.Warnings);
256                                 }
257                                 Console.WriteLine();
258                                 if (show_counters){
259                                         Console.WriteLine ("Counter1: " + counter1);
260                                         Console.WriteLine ("Counter2: " + counter2);
261                                 }
262                                 return 0;
263                         } else {
264                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
265                                         Report.Errors, Report.Warnings);
266                                 return 1;
267                         }
268                 }
269
270                 static public void LoadAssembly (string assembly, bool soft)
271                 {
272                         Assembly a;
273                         string total_log = "";
274
275                         try {
276                                 char[] path_chars = { '/', '\\', '.' };
277
278                                 if (assembly.IndexOfAny (path_chars) != -1) {
279                                         a = Assembly.LoadFrom (assembly);
280                                 } else {
281                                         a = Assembly.Load (assembly);
282                                 }
283                                 TypeManager.AddAssembly (a);
284
285                         } catch (FileNotFoundException){
286                                 foreach (string dir in link_paths){
287                                         string full_path = Path.Combine (dir, assembly);
288                                         if (!assembly.EndsWith (".dll"))
289                                                 full_path += ".dll";
290
291                                         try {
292                                                 a = Assembly.LoadFrom (full_path);
293                                                 TypeManager.AddAssembly (a);
294                                                 return;
295                                         } catch (FileNotFoundException ff) {
296                                                 total_log += ff.FusionLog;
297                                                 continue;
298                                         }
299                                 }
300                                 if (!soft) {
301                                         Report.Error (6, "Cannot find assembly `" + assembly + "'" );
302                                         Console.WriteLine ("Log: \n" + total_log);
303                                 }
304                         } catch (BadImageFormatException f) {
305                                 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
306                         } catch (FileLoadException f){
307                                 Report.Error(6, "Cannot load assembly " + f.FusionLog);
308                         } catch (ArgumentNullException){
309                                 Report.Error(6, "Cannot load assembly (null argument)");
310                         }
311                 }
312
313                 /// <summary>
314                 ///   Loads all assemblies referenced on the command line
315                 /// </summary>
316                 static public void LoadReferences ()
317                 {
318                         foreach (string r in references)
319                                 LoadAssembly (r, false);
320
321                         foreach (string r in soft_references)
322                                 LoadAssembly (r, true);
323                         
324                         return;
325                 }
326
327                 static void SetupDefaultDefines ()
328                 {
329                         defines = new ArrayList ();
330                         defines.Add ("__MonoCS__");
331                 }
332
333                 static string [] LoadArgs (string file)
334                 {
335                         StreamReader f;
336                         ArrayList args = new ArrayList ();
337                         string line;
338                         try {
339                                 f = new StreamReader (file);
340                         } catch {
341                                 return null;
342                         }
343
344                         StringBuilder sb = new StringBuilder ();
345                         
346                         while ((line = f.ReadLine ()) != null){
347                                 int t = line.Length;
348
349                                 for (int i = 0; i < t; i++){
350                                         char c = line [i];
351                                         
352                                         if (c == '"' || c == '\''){
353                                                 char end = c;
354                                                 
355                                                 for (i++; i < t; i++){
356                                                         c = line [i];
357
358                                                         if (c == end)
359                                                                 break;
360                                                         sb.Append (c);
361                                                 }
362                                         } else if (c == ' '){
363                                                 if (sb.Length > 0){
364                                                         args.Add (sb.ToString ());
365                                                         sb.Length = 0;
366                                                 }
367                                         } else
368                                                 sb.Append (c);
369                                 }
370                                 if (sb.Length > 0){
371                                         args.Add (sb.ToString ());
372                                         sb.Length = 0;
373                                 }
374                         }
375
376                         string [] ret_value = new string [args.Count];
377                         args.CopyTo (ret_value, 0);
378
379                         return ret_value;
380                 }
381
382                 //
383                 // Returns the directory where the system assemblies are installed
384                 //
385                 static string GetSystemDir ()
386                 {
387                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
388
389                         foreach (Assembly a in assemblies){
390                                 string codebase = a.Location;
391                                 if (codebase.EndsWith ("corlib.dll")){
392                                         return codebase.Substring (0, codebase.LastIndexOf (System.IO.Path.DirectorySeparatorChar));
393                                 }
394                         }
395
396                         Report.Error (-15, "Can not compute my system path");
397                         return "";
398                 }
399
400                 //
401                 // Given a path specification, splits the path from the file/pattern
402                 //
403                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
404                 {
405                         int p = spec.LastIndexOf ("/");
406                         if (p != -1){
407                                 //
408                                 // Windows does not like /file.cs, switch that to:
409                                 // "\", "file.cs"
410                                 //
411                                 if (p == 0){
412                                         path = "\\";
413                                         pattern = spec.Substring (1);
414                                 } else {
415                                         path = spec.Substring (0, p);
416                                         pattern = spec.Substring (p + 1);
417                                 }
418                                 return;
419                         }
420
421                         p = spec.LastIndexOf ("\\");
422                         if (p != -1){
423                                 path = spec.Substring (0, p);
424                                 pattern = spec.Substring (p + 1);
425                                 return;
426                         }
427
428                         path = ".";
429                         pattern = spec;
430                 }
431
432                 static void ProcessFile (string f)
433                 {
434                         if (first_source == null)
435                                 first_source = f;
436
437                         Location.AddFile (f);
438                 }
439
440                 static void ProcessFiles ()
441                 {
442                         Location.Initialize ();
443
444                         foreach (SourceFile file in Location.SourceFiles) {
445                                 if (tokenize) {
446                                         tokenize_file (file);
447                                 } else {
448                                         parse (file);
449                                 }
450                         }
451                 }
452
453                 static void CompileFiles (string spec, bool recurse)
454                 {
455                         string path, pattern;
456
457                         SplitPathAndPattern (spec, out path, out pattern);
458                         if (pattern.IndexOf ("*") == -1){
459                                 ProcessFile (spec);
460                                 return;
461                         }
462
463                         string [] files = null;
464                         try {
465                                 files = Directory.GetFiles (path, pattern);
466                         } catch (System.IO.DirectoryNotFoundException) {
467                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
468                                 return;
469                         } catch (System.IO.IOException){
470                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
471                                 return;
472                         }
473                         foreach (string f in files) {
474                                 ProcessFile (f);
475                         }
476
477                         if (!recurse)
478                                 return;
479                         
480                         string [] dirs = null;
481
482                         try {
483                                 dirs = Directory.GetDirectories (path);
484                         } catch {
485                         }
486                         
487                         foreach (string d in dirs) {
488                                         
489                                 // Don't include path in this string, as each
490                                 // directory entry already does
491                                 CompileFiles (d + "/" + pattern, true);
492                         }
493                 }
494
495                 static void DefineDefaultConfig ()
496                 {
497                         //
498                         // For now the "default config" is harcoded into the compiler
499                         // we can move this outside later
500                         //
501                         string [] default_config = {
502                                 "System",
503                                 "System.Xml",
504 #if false
505                                 //
506                                 // Is it worth pre-loading all this stuff?
507                                 //
508                                 "Accessibility",
509                                 "System.Configuration.Install",
510                                 "System.Data",
511                                 "System.Design",
512                                 "System.DirectoryServices",
513                                 "System.Drawing.Design",
514                                 "System.Drawing",
515                                 "System.EnterpriseServices",
516                                 "System.Management",
517                                 "System.Messaging",
518                                 "System.Runtime.Remoting",
519                                 "System.Runtime.Serialization.Formatters.Soap",
520                                 "System.Security",
521                                 "System.ServiceProcess",
522                                 "System.Web",
523                                 "System.Web.RegularExpressions",
524                                 "System.Web.Services",
525                                 "System.Windows.Forms"
526 #endif
527                         };
528                         
529                         int p = 0;
530                         foreach (string def in default_config)
531                                 soft_references.Insert (p++, def);
532                 }
533
534                 static void SetOutputFile (string name)
535                 {
536                         output_file = name;
537                 }
538
539                 static void SetWarningLevel (string s)
540                 {
541                         int level = 0;
542
543                         try {
544                                 level = Int32.Parse (s);
545                         } catch {
546                                 Report.Error (
547                                         1900,
548                                         "--wlevel requires an value from 0 to 4");
549                                 Environment.Exit (1);
550                         }
551                         if (level < 0 || level > 4){
552                                 Report.Error (1900, "Warning level must be 0 to 4");
553                                 Environment.Exit (1);
554                         } else
555                                 RootContext.WarningLevel = level;
556                 }
557
558                 static void SetupV2 ()
559                 {
560                         RootContext.V2 = true;
561                         defines.Add ("__V2__");
562                 }
563                 
564                 static void Version ()
565                 {
566                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
567                         Console.WriteLine ("Mono C# compiler version {0}", version);
568                         Environment.Exit (0);
569                 }
570                 
571                 //
572                 // Currently handles the Unix-like command line options, but will be
573                 // deprecated in favor of the CSCParseOption, which will also handle the
574                 // options that start with a dash in the future.
575                 //
576                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
577                 {
578                         switch (arg){
579                         case "-v":
580                                 yacc_verbose = true;
581                                 return true;
582
583                         case "--version":
584                                 Version ();
585                                 return true;
586                                 
587                         case "--parse":
588                                 parse_only = true;
589                                 return true;
590                                 
591                         case "--main": case "-m":
592                                 if ((i + 1) >= args.Length){
593                                         Usage ();
594                                         Environment.Exit (1);
595                                 }
596                                 RootContext.MainClass = args [++i];
597                                 return true;
598                                 
599                         case "--unsafe":
600                                 RootContext.Unsafe = true;
601                                 return true;
602                                 
603                         case "/?": case "/h": case "/help":
604                         case "--help":
605                                 Usage ();
606                                 Environment.Exit (0);
607                                 return true;
608                                 
609                         case "--define":
610                                 if ((i + 1) >= args.Length){
611                                         Usage ();
612                                         Environment.Exit (1);
613                                 }
614                                 defines.Add (args [++i]);
615                                 return true;
616
617                         case "--show-counters":
618                                 show_counters = true;
619                                 return true;
620                                 
621                         case "--expect-error": {
622                                 int code = 0;
623                                 
624                                 try {
625                                         code = Int32.Parse (
626                                                 args [++i], NumberStyles.AllowLeadingSign);
627                                         Report.ExpectedError = code;
628                                 } catch {
629                                         Report.Error (-14, "Invalid number specified");
630                                 } 
631                                 return true;
632                         }
633                                 
634                         case "--tokenize": 
635                                 tokenize = true;
636                                 return true;
637                                 
638                         case "-o": 
639                         case "--output":
640                                 if ((i + 1) >= args.Length){
641                                         Usage ();
642                                         Environment.Exit (1);
643                                 }
644                                 SetOutputFile (args [++i]);
645                                 return true;
646                                 
647                         case "--checked":
648                                 RootContext.Checked = true;
649                                 return true;
650                                 
651                         case "--stacktrace":
652                                 Report.Stacktrace = true;
653                                 return true;
654                                 
655                         case "--linkresource":
656                         case "--linkres":
657                                 if ((i + 1) >= args.Length){
658                                         Usage ();
659                                         Report.Error (5, "Missing argument to --linkres"); 
660                                         Environment.Exit (1);
661                                 }
662                                 if (resources == null)
663                                         resources = new ArrayList ();
664                                 
665                                 resources.Add (args [++i]);
666                                 return true;
667                                 
668                         case "--resource":
669                         case "--res":
670                                 if ((i + 1) >= args.Length){
671                                         Usage ();
672                                         Report.Error (5, "Missing argument to --resource"); 
673                                         Environment.Exit (1);
674                                 }
675                                 if (embedded_resources == null)
676                                         embedded_resources = new ArrayList ();
677                                 
678                                 embedded_resources.Add (args [++i]);
679                                 return true;
680                                 
681                         case "--target":
682                                 if ((i + 1) >= args.Length){
683                                         Environment.Exit (1);
684                                         return true;
685                                 }
686                                 
687                                 string type = args [++i];
688                                 switch (type){
689                                 case "library":
690                                         target = Target.Library;
691                                         target_ext = ".dll";
692                                         break;
693                                         
694                                 case "exe":
695                                         target = Target.Exe;
696                                         break;
697                                         
698                                 case "winexe":
699                                         target = Target.WinExe;
700                                         break;
701                                         
702                                 case "module":
703                                         target = Target.Module;
704                                         target_ext = ".dll";
705                                         break;
706                                 default:
707                                         TargetUsage ();
708                                         Environment.Exit (1);
709                                         break;
710                                 }
711                                 return true;
712                                 
713                         case "-r":
714                                 if ((i + 1) >= args.Length){
715                                         Usage ();
716                                         Environment.Exit (1);
717                                 }
718                                 
719                                 references.Add (args [++i]);
720                                 return true;
721                                 
722                         case "-L":
723                                 if ((i + 1) >= args.Length){
724                                         Usage ();       
725                                         Environment.Exit (1);
726                                 }
727                                 link_paths.Add (args [++i]);
728                                 return true;
729                                 
730                         case "--nostdlib":
731                                 RootContext.StdLib = false;
732                                 return true;
733                                 
734                         case "--fatal":
735                                 Report.Fatal = true;
736                                 return true;
737                                 
738                         case "--werror":
739                                 Report.WarningsAreErrors = true;
740                                 return true;
741                                 
742                         case "--nowarn":
743                                 if ((i + 1) >= args.Length){
744                                         Usage ();
745                                         Environment.Exit (1);
746                                 }
747                                 int warn = 0;
748                                 
749                                 try {
750                                         warn = Int32.Parse (args [++i]);
751                                 } catch {
752                                         Usage ();
753                                         Environment.Exit (1);
754                                 }
755                                 Report.SetIgnoreWarning (warn);
756                                 return true;
757                                 
758                         case "--wlevel":
759                                 if ((i + 1) >= args.Length){
760                                         Report.Error (
761                                                 1900,
762                                                 "--wlevel requires an value from 0 to 4");
763                                         Environment.Exit (1);
764                                 }
765
766                                 SetWarningLevel (args [++i]);
767                                 return true;
768
769                         case "--mcs-debug":
770                                 if ((i + 1) >= args.Length){
771                                         Report.Error (5, "--mcs-debug requires an argument");
772                                         Environment.Exit (1);
773                                 }
774
775                                 try {
776                                         Report.DebugFlags = Int32.Parse (args [++i]);
777                                 } catch {
778                                         Report.Error (5, "Invalid argument to --mcs-debug");
779                                         Environment.Exit (1);
780                                 }
781                                 return true;
782                                 
783                         case "--about":
784                                 About ();
785                                 return true;
786                                 
787                         case "--recurse":
788                                 if ((i + 1) >= args.Length){
789                                         Report.Error (5, "--recurse requires an argument");
790                                         Environment.Exit (1);
791                                 }
792                                 CompileFiles (args [++i], true); 
793                                 return true;
794                                 
795                         case "--timestamp":
796                                 timestamps = true;
797                                 last_time = first_time = DateTime.Now;
798                                 return true;
799
800                         case "--pause":
801                                 pause = true;
802                                 return true;
803                                 
804                         case "--debug": case "-g":
805                                 want_debugging_support = true;
806                                 return true;
807                                 
808                         case "--noconfig":
809                                 load_default_config = false;
810                                 return true;
811                         }
812
813                         return false;
814                 }
815
816                 //
817                 // Currently it is very basic option parsing, but eventually, this will
818                 // be the complete option parser
819                 //
820                 static bool CSCParseOption (string option, ref string [] args, ref int i)
821                 {
822                         int idx = option.IndexOf (":");
823                         string arg, value;
824
825                         if (idx == -1){
826                                 arg = option;
827                                 value = "";
828                         } else {
829                                 arg = option.Substring (0, idx);
830
831                                 value = option.Substring (idx + 1);
832                         }
833
834                         switch (arg){
835                         case "/nologo":
836                                 return true;
837
838                         case "/t":
839                         case "/target":
840                                 switch (value){
841                                 case "exe":
842                                         target = Target.Exe;
843                                         break;
844
845                                 case "winexe":
846                                         target = Target.WinExe;
847                                         break;
848
849                                 case "library":
850                                         target = Target.Library;
851                                         target_ext = ".dll";
852                                         break;
853
854                                 case "module":
855                                         target = Target.Module;
856                                         target_ext = ".netmodule";
857                                         break;
858
859                                 default:
860                                         TargetUsage ();
861                                         Environment.Exit (1);
862                                         break;
863                                 }
864                                 return true;
865
866                         case "/out":
867                                 if (value == ""){
868                                         Usage ();
869                                         Environment.Exit (1);
870                                 }
871                                 SetOutputFile (value);
872                                 return true;
873
874                         case "/optimize":
875                         case "/optimize+":
876                         case "/optimize-":
877                         case "/incremental":
878                         case "/incremental+":
879                         case "/incremental-":
880                                 // nothing.
881                                 return true;
882
883                         case "/d":
884                         case "/define": {
885                                 string [] defs;
886
887                                 if (value == ""){
888                                         Usage ();
889                                         Environment.Exit (1);
890                                 }
891
892                                 defs = value.Split (new Char [] {';', ','});
893                                 foreach (string d in defs){
894                                         defines.Add (d);
895                                 }
896                                 return true;
897                         }
898
899                         case "/linkres":
900                         case "/linkresource":
901                                 if (value == ""){
902                                         Report.Error (5, arg + " requires an argument");
903                                         Environment.Exit (1);
904                                 }
905                                 if (resources == null)
906                                         resources = new ArrayList ();
907                                 
908                                 resources.Add (value);
909                                 return true;
910                                 
911                         case "/res":
912                         case "/resource":
913                                 if (value == ""){
914                                         Report.Error (5, arg + " requires an argument");
915                                         Environment.Exit (1);
916                                 }
917                                 if (embedded_resources == null)
918                                         embedded_resources = new ArrayList ();
919                                 
920                                 embedded_resources.Add (value);
921                                 return true;
922                                 
923                         case "/recurse":
924                                 if (value == ""){
925                                         Report.Error (5, "/recurse requires an argument");
926                                         Environment.Exit (1);
927                                 }
928                                 CompileFiles (value, true); 
929                                 return true;
930
931                         case "/r":
932                         case "/reference": {
933                                 if (value == ""){
934                                         Report.Error (5, arg + " requires an argument");
935                                         Environment.Exit (1);
936                                 }
937
938                                 string [] refs = value.Split (new char [] { ';', ',' });
939                                 foreach (string r in refs){
940                                         references.Add (r);
941                                 }
942                                 return true;
943                         }
944                         case "/doc": {
945                                 if (value == ""){
946                                         Report.Error (5, arg + " requires an argument");
947                                         Environment.Exit (1);
948                                 }
949                                 // TODO handle the /doc argument to generate xml doc
950                                 return true;
951                         }
952                         case "/lib": {
953                                 string [] libdirs;
954                                 
955                                 if (value == ""){
956                                         Report.Error (5, "/lib requires an argument");
957                                         Environment.Exit (1);
958                                 }
959
960                                 libdirs = value.Split (new Char [] { ',' });
961                                 foreach (string dir in libdirs)
962                                         link_paths.Add (dir);
963                                 return true;
964                         }
965                                 
966                         case "/debug":
967                         case "/debug+":
968                                 want_debugging_support = true;
969                                 return true;
970
971                         case "/checked":
972                         case "/checked+":
973                                 RootContext.Checked = true;
974                                 return true;
975
976                         case "/checked-":
977                                 RootContext.Checked = false;
978                                 return true;
979
980                         case "/unsafe":
981                         case "/unsafe+":
982                                 RootContext.Unsafe = true;
983                                 return true;
984
985                         case "/unsafe-":
986                                 RootContext.Unsafe = false;
987                                 return true;
988
989                         case "/warnaserror":
990                         case "/warnaserror+":
991                                 Report.WarningsAreErrors = true;
992                                 return true;
993
994                         case "/warnaserror-":
995                                 Report.WarningsAreErrors = false;
996                                 return true;
997
998                         case "/warn":
999                                 SetWarningLevel (value);
1000                                 return true;
1001
1002                         case "/nowarn": {
1003                                 string [] warns;
1004
1005                                 if (value == ""){
1006                                         Report.Error (5, "/nowarn requires an argument");
1007                                         Environment.Exit (1);
1008                                 }
1009                                 
1010                                 warns = value.Split (new Char [] {','});
1011                                 foreach (string wc in warns){
1012                                         int warn = 0;
1013                                         
1014                                         try {
1015                                                 warn = Int32.Parse (wc);
1016                                         } catch {
1017                                                 Usage ();
1018                                                 Environment.Exit (1);
1019                                         }
1020                                         Report.SetIgnoreWarning (warn);
1021                                 }
1022                                 return true;
1023                         }
1024
1025                         case "/noconfig-":
1026                                 load_default_config = true;
1027                                 return true;
1028                                 
1029                         case "/noconfig":
1030                         case "/noconfig+":
1031                                 load_default_config = false;
1032                                 return true;
1033
1034                         case "/help":
1035                         case "/?":
1036                                 Usage ();
1037                                 Environment.Exit (0);
1038                                 return true;
1039
1040                         case "/main":
1041                         case "/m":
1042                                 if (value == ""){
1043                                         Report.Error (5, arg + " requires an argument");                                        
1044                                         Environment.Exit (1);
1045                                 }
1046                                 RootContext.MainClass = value;
1047                                 return true;
1048
1049                         case "/nostdlib":
1050                         case "/nostdlib+":
1051                                 RootContext.StdLib = false;
1052                                 return true;
1053
1054                         case "/nostdlib-":
1055                                 RootContext.StdLib = true;
1056                                 return true;
1057
1058                         case "/fullpaths":
1059                                 return true;
1060
1061                         case "/win32icon":
1062                                 Report.Error (5, "/win32icon is currently not supported");
1063                                 return true;
1064                                 
1065                         case "/v2":
1066                                 SetupV2 ();
1067                                 return true;
1068                                 
1069                         case "/codepage":
1070                                 int cp = -1;
1071
1072                                 if (value == "utf8"){
1073                                         encoding = new UTF8Encoding();
1074                                         using_default_encoder = false;
1075                                         return true;
1076                                 }
1077                                 if (value == "reset"){
1078                                         //
1079                                         // 28591 is the code page for ISO-8859-1 encoding.
1080                                         //
1081                                         cp = 28591;
1082                                         using_default_encoder = true;
1083                                 }
1084                                 
1085                                 try {
1086                                         cp = Int32.Parse (value);
1087                                 } catch { }
1088                                 
1089                                 if (cp == -1){
1090                                         Console.WriteLine ("Invalid code-page requested");
1091                                         Usage ();
1092                                 }
1093
1094                                 try {
1095                                         encoding = Encoding.GetEncoding (cp);
1096                                         using_default_encoder = false;
1097                                 } catch {
1098                                         Console.WriteLine ("Code page: {0} not supported", cp);
1099                                 }
1100                                 return true;
1101
1102                         }
1103                         return false;
1104                 }
1105                 
1106                 /// <summary>
1107                 ///    Parses the arguments, and drives the compilation
1108                 ///    process.
1109                 /// </summary>
1110                 ///
1111                 /// <remarks>
1112                 ///    TODO: Mostly structured to debug the compiler
1113                 ///    now, needs to be turned into a real driver soon.
1114                 /// </remarks>
1115                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1116                 static bool MainDriver (string [] args)
1117                 {
1118                         int i;
1119                         bool parsing_options = true;
1120
1121                         Console.WriteLine ("Mono C# Compiler {0} for Generics",
1122                                            Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
1123                         try {
1124                                 encoding = Encoding.GetEncoding (28591);
1125                         } catch {
1126                                 Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
1127                                 encoding = Encoding.GetEncoding (1252);
1128                         }
1129                         
1130                         references = new ArrayList ();
1131                         soft_references = new ArrayList ();
1132                         link_paths = new ArrayList ();
1133
1134                         SetupDefaultDefines ();
1135                         
1136                         //
1137                         // Setup defaults
1138                         //
1139                         // This is not required because Assembly.Load knows about this
1140                         // path.
1141                         //
1142
1143                         int argc = args.Length;
1144                         for (i = 0; i < argc; i++){
1145                                 string arg = args [i];
1146
1147                                 if (arg.StartsWith ("@")){
1148                                         string [] new_args, extra_args;
1149                                         string response_file = arg.Substring (1);
1150
1151                                         if (response_file_list == null)
1152                                                 response_file_list = new Hashtable ();
1153                                         
1154                                         if (response_file_list.Contains (response_file)){
1155                                                 Report.Error (
1156                                                         1515, "Response file `" + response_file +
1157                                                         "' specified multiple times");
1158                                                 Environment.Exit (1);
1159                                         }
1160                                         
1161                                         response_file_list.Add (response_file, response_file);
1162                                                     
1163                                         extra_args = LoadArgs (response_file);
1164                                         if (extra_args == null){
1165                                                 Report.Error (2011, "Unable to open response file: " +
1166                                                               response_file);
1167                                                 return false;
1168                                         }
1169
1170                                         new_args = new string [extra_args.Length + argc];
1171                                         args.CopyTo (new_args, 0);
1172                                         extra_args.CopyTo (new_args, argc);
1173                                         args = new_args;
1174                                         argc = new_args.Length;
1175                                         continue;
1176                                 }
1177
1178                                 if (parsing_options){
1179                                         if (arg == "--"){
1180                                                 parsing_options = false;
1181                                                 continue;
1182                                         }
1183                                         
1184                                         if (arg.StartsWith ("-")){
1185                                                 if (UnixParseOption (arg, ref args, ref i))
1186                                                         continue;
1187
1188                                                 // Try a -CSCOPTION
1189                                                 string csc_opt = "/" + arg.Substring (1);
1190                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1191                                                         continue;
1192                                         } else {
1193                                                 if (arg.StartsWith ("/")){
1194                                                         if (CSCParseOption (arg, ref args, ref i))
1195                                                                 continue;
1196                                                 }
1197                                         }
1198                                 }
1199
1200                                 CompileFiles (arg, false); 
1201                         }
1202
1203                         ProcessFiles ();
1204
1205                         if (tokenize)
1206                                 return true;
1207                         
1208                         if (first_source == null){
1209                                 Report.Error (2008, "No files to compile were specified");
1210                                 return false;
1211                         }
1212
1213                         if (Report.Errors > 0)
1214                                 return false;
1215                         
1216                         if (parse_only)
1217                                 return true;
1218                         
1219                         //
1220                         // Load Core Library for default compilation
1221                         //
1222                         if (RootContext.StdLib)
1223                                 references.Insert (0, "mscorlib");
1224
1225                         if (load_default_config)
1226                                 DefineDefaultConfig ();
1227
1228                         if (Report.Errors > 0){
1229                                 return false;
1230                         }
1231
1232                         //
1233                         // Load assemblies required
1234                         //
1235                         if (timestamps)
1236                                 ShowTime ("Loading references");
1237                         link_paths.Add (GetSystemDir ());
1238                         LoadReferences ();
1239                         
1240                         if (timestamps)
1241                                 ShowTime ("   References loaded");
1242                         
1243                         if (Report.Errors > 0){
1244                                 return false;
1245                         }
1246
1247                         //
1248                         // Quick hack
1249                         //
1250                         if (output_file == null){
1251                                 int pos = first_source.LastIndexOf (".");
1252
1253                                 if (pos > 0)
1254                                         output_file = first_source.Substring (0, pos) + target_ext;
1255                                 else
1256                                         output_file = first_source + target_ext;
1257                         }
1258
1259                         CodeGen.Init (output_file, output_file, want_debugging_support);
1260
1261                         TypeManager.AddModule (CodeGen.ModuleBuilder);
1262
1263                         DateTime start = DateTime.Now;
1264                         TypeManager.ComputeNamespaces ();
1265                         DateTime end = DateTime.Now;
1266                         
1267                         //
1268                         // Before emitting, we need to get the core
1269                         // types emitted from the user defined types
1270                         // or from the system ones.
1271                         //
1272                         if (timestamps)
1273                                 ShowTime ("Initializing Core Types");
1274                         if (!RootContext.StdLib){
1275                                 RootContext.ResolveCore ();
1276                                 if (Report.Errors > 0)
1277                                         return false;
1278                         }
1279                         
1280                         TypeManager.InitCoreTypes ();
1281                         if (timestamps)
1282                                 ShowTime ("   Core Types done");
1283
1284                         //
1285                         // The second pass of the compiler
1286                         //
1287                         if (timestamps)
1288                                 ShowTime ("Resolving tree");
1289                         RootContext.ResolveTree ();
1290                         if (timestamps)
1291                                 ShowTime ("Populate tree");
1292                         if (!RootContext.StdLib)
1293                                 RootContext.BootCorlib_PopulateCoreTypes ();
1294                         RootContext.PopulateTypes ();
1295                         RootContext.DefineTypes ();
1296                         
1297                         TypeManager.InitCodeHelpers ();
1298
1299                         //
1300                         // Verify using aliases now
1301                         //
1302                         Namespace.VerifyUsing ();
1303                         
1304                         if (Report.Errors > 0){
1305                                 return false;
1306                         }
1307                         
1308                         //
1309                         // The code generator
1310                         //
1311                         if (timestamps)
1312                                 ShowTime ("Emitting code");
1313                         ShowTotalTime ("Total so far");
1314                         RootContext.EmitCode ();
1315                         if (timestamps)
1316                                 ShowTime ("   done");
1317
1318                         if (Report.Errors > 0){
1319                                 return false;
1320                         }
1321
1322                         if (timestamps)
1323                                 ShowTime ("Closing types");
1324
1325                         RootContext.CloseTypes ();
1326
1327                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1328                                 
1329                         if (target == Target.Library || target == Target.Module){
1330                                 k = PEFileKinds.Dll;
1331
1332                                 if (RootContext.MainClass != null)
1333                                         Report.Error (2017, "Can not specify -main: when building module or library");
1334                         } else if (target == Target.Exe)
1335                                 k = PEFileKinds.ConsoleApplication;
1336                         else if (target == Target.WinExe)
1337                                 k = PEFileKinds.WindowApplication;
1338
1339                         if (target == Target.Exe || target == Target.WinExe){
1340                                 MethodInfo ep = RootContext.EntryPoint;
1341
1342                                 if (ep == null){
1343                                         if (Report.Errors == 0)
1344                                                 Report.Error (5001, "Program " + output_file +
1345                                                               " does not have an entry point defined");
1346                                         return false;
1347                                 }
1348                                 
1349                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
1350                         }
1351
1352                         //
1353                         // Add the resources
1354                         //
1355                         if (resources != null){
1356                                 foreach (string spec in resources){
1357                                         string file, res;
1358                                         int cp;
1359                                         
1360                                         cp = spec.IndexOf (',');
1361                                         if (cp != -1){
1362                                                 file = spec.Substring (0, cp);
1363                                                 res = spec.Substring (cp + 1);
1364                                         } else
1365                                                 file = res = spec;
1366
1367                                         CodeGen.AssemblyBuilder.AddResourceFile (res, file);
1368                                 }
1369                         }
1370                         
1371                         if (embedded_resources != null){
1372                                 object[] margs = new object [2];
1373                                 Type[] argst = new Type [2];
1374                                 argst [0] = argst [1] = typeof (string);
1375                                 MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", argst);
1376                                 if (embed_res == null) {
1377                                         Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
1378                                 } else {
1379                                         foreach (string spec in embedded_resources) {
1380                                                 int cp;
1381
1382                                                 cp = spec.IndexOf (',');
1383                                                 if (cp != -1){
1384                                                         margs [0] = spec.Substring (cp + 1);
1385                                                         margs [1] = spec.Substring (0, cp);
1386                                                 } else
1387                                                         margs [0] = margs [1] = spec;
1388
1389                                                 if (File.Exists ((string) margs [1]))
1390                                                         embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
1391                                                 else {
1392                                                         Report.Error (1566, "Can not find the resource " + margs [1]);
1393                                                 }
1394                                         }
1395                                 }
1396                         }
1397
1398                         if (Report.Errors > 0)
1399                                 return false;
1400                         
1401                         CodeGen.Save (output_file);
1402                         if (timestamps) {
1403                                 ShowTime ("Saved output");
1404                                 ShowTotalTime ("Total");
1405                         }
1406
1407                         Timer.ShowTimers ();
1408                         
1409                         if (Report.ExpectedError != 0){
1410                                 Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
1411                                 Environment.Exit (1);
1412                                 return false;
1413                         }
1414
1415 #if DEBUGME
1416                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1417                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1418 #endif
1419                         return (Report.Errors == 0);
1420                 }
1421
1422         }
1423 }