[mcs] Accept and ignore command line args supported by csc that we don't
[mono.git] / mcs / mcs / settings.cs
1 //
2 // settings.cs: All compiler settings
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //            Ravi Pratap  (ravi@ximian.com)
6 //            Marek Safar  (marek.safar@gmail.com)
7 //
8 //
9 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 //
11 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
12 // Copyright 2004-2008 Novell, Inc
13 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
14 //
15
16 using System.Collections.Generic;
17 using System.IO;
18 using System.Text;
19 using System.Globalization;
20 using System;
21
22 namespace Mono.CSharp {
23
24         public enum LanguageVersion
25         {
26                 ISO_1 = 1,
27                 ISO_2 = 2,
28                 V_3 = 3,
29                 V_4 = 4,
30                 V_5 = 5,
31                 V_6 = 6,
32                 Experimental = 100,
33
34                 Default = LanguageVersion.V_6,
35         }
36
37         public enum RuntimeVersion
38         {
39                 v1,
40                 v2,
41                 v4
42         }
43
44         public enum Target
45         {
46                 Library, Exe, Module, WinExe
47         }
48
49         public enum Platform
50         {
51                 AnyCPU,
52                 AnyCPU32Preferred,
53                 Arm,
54                 X86,
55                 X64,
56                 IA64
57         }
58
59         public class CompilerSettings
60         {
61                 public Target Target;
62                 public Platform Platform;
63                 public string TargetExt;
64                 public bool VerifyClsCompliance;
65                 public bool Optimize;
66                 public LanguageVersion Version;
67                 public bool EnhancedWarnings;
68                 public bool LoadDefaultReferences;
69                 public string SdkVersion;
70
71                 public string StrongNameKeyFile;
72                 public string StrongNameKeyContainer;
73                 public bool StrongNameDelaySign;
74
75                 public int TabSize;
76
77                 public bool WarningsAreErrors;
78                 public int WarningLevel;
79
80                 //
81                 // Assemblies references to be loaded
82                 //
83                 public List<string> AssemblyReferences;
84
85                 // 
86                 // External aliases for assemblies
87                 //
88                 public List<Tuple<string, string>> AssemblyReferencesAliases;
89
90                 public List<KeyValuePair<string, string>> PathMap;
91
92                 //
93                 // Modules to be embedded
94                 //
95                 public List<string> Modules;
96
97                 //
98                 // Lookup paths for referenced assemblies
99                 //
100                 public List<string> ReferencesLookupPaths;
101
102                 //
103                 // Encoding.
104                 //
105                 public Encoding Encoding;
106
107                 //
108                 // If set, enable XML documentation generation
109                 //
110                 public string DocumentationFile;
111
112                 public string MainClass;
113
114                 //
115                 // Output file
116                 //
117                 public string OutputFile;
118
119                 // 
120                 // The default compiler checked state
121                 //
122                 public bool Checked;
123
124                 //
125                 // If true, the compiler is operating in statement mode,
126                 // this currently turns local variable declaration into
127                 // static variables of a class
128                 //
129                 public bool StatementMode;      // TODO: SUPER UGLY
130                 
131                 //
132                 // Whether to allow Unsafe code
133                 //
134                 public bool Unsafe;
135
136                 public string Win32ResourceFile;
137                 public string Win32IconFile;
138
139                 //
140                 // A list of resource files for embedding
141                 //
142                 public List<AssemblyResource> Resources;
143
144                 public bool GenerateDebugInfo;
145
146                 #region Compiler debug flags only
147                 public bool ParseOnly, TokenizeOnly, Timestamps;
148                 public int DebugFlags;
149                 public int VerboseParserFlag;
150                 public int FatalCounter;
151                 public bool Stacktrace;
152                 public bool BreakOnInternalError;
153                 #endregion
154
155                 public List<string> GetResourceStrings;
156
157                 public bool ShowFullPaths;
158
159                 //
160                 // Whether we are being linked against the standard libraries.
161                 // This is only used to tell whether `System.Object' should
162                 // have a base class or not.
163                 //
164                 public bool StdLib;
165
166                 public RuntimeVersion StdLibRuntimeVersion;
167
168                 public string RuntimeMetadataVersion;
169
170                 public bool WriteMetadataOnly;
171
172                 readonly List<string> conditional_symbols;
173
174                 readonly List<SourceFile> source_files;
175
176                 List<int> warnings_as_error;
177                 List<int> warnings_only;
178                 HashSet<int> warning_ignore_table;
179
180                 public CompilerSettings ()
181                 {
182                         StdLib = true;
183                         Target = Target.Exe;
184                         TargetExt = ".exe";
185                         Platform = Platform.AnyCPU;
186                         Version = LanguageVersion.Default;
187                         VerifyClsCompliance = true;
188                         Encoding = Encoding.UTF8;
189                         LoadDefaultReferences = true;
190                         StdLibRuntimeVersion = RuntimeVersion.v4;
191                         WarningLevel = 4;
192
193                         // Default to 1 or mdb files would be platform speficic
194                         TabSize = 1;
195
196                         AssemblyReferences = new List<string> ();
197                         AssemblyReferencesAliases = new List<Tuple<string, string>> ();
198                         Modules = new List<string> ();
199                         ReferencesLookupPaths = new List<string> ();
200
201                         conditional_symbols = new List<string> ();
202                         //
203                         // Add default mcs define
204                         //
205                         conditional_symbols.Add ("__MonoCS__");
206
207                         source_files = new List<SourceFile> ();
208                 }
209
210                 #region Properties
211
212                 public SourceFile FirstSourceFile {
213                         get {
214                                 return source_files.Count > 0 ? source_files [0] : null;
215                         }
216                 }
217
218                 public bool HasKeyFileOrContainer {
219                         get {
220                                 return StrongNameKeyFile != null || StrongNameKeyContainer != null;
221                         }
222                 }
223
224                 public bool NeedsEntryPoint {
225                         get {
226                                 return Target == Target.Exe || Target == Target.WinExe;
227                         }
228                 }
229
230                 public List<SourceFile> SourceFiles {
231                         get {
232                                 return source_files;
233                         }
234                 }
235
236                 #endregion
237
238                 public void AddConditionalSymbol (string symbol)
239                 {
240                         if (!conditional_symbols.Contains (symbol))
241                                 conditional_symbols.Add (symbol);
242                 }
243
244                 public void AddWarningAsError (int id)
245                 {
246                         if (warnings_as_error == null)
247                                 warnings_as_error = new List<int> ();
248
249                         warnings_as_error.Add (id);
250                 }
251
252                 public void AddWarningOnly (int id)
253                 {
254                         if (warnings_only == null)
255                                 warnings_only = new List<int> ();
256
257                         warnings_only.Add (id);
258                 }
259
260                 public bool IsConditionalSymbolDefined (string symbol)
261                 {
262                         return conditional_symbols.Contains (symbol);
263                 }
264
265                 public bool IsWarningAsError (int code)
266                 {
267                         bool is_error = WarningsAreErrors;
268
269                         // Check specific list
270                         if (warnings_as_error != null)
271                                 is_error |= warnings_as_error.Contains (code);
272
273                         // Ignore excluded warnings
274                         if (warnings_only != null && warnings_only.Contains (code))
275                                 is_error = false;
276
277                         return is_error;
278                 }
279
280                 public bool IsWarningEnabled (int code, int level)
281                 {
282                         if (WarningLevel < level)
283                                 return false;
284
285                         return !IsWarningDisabledGlobally (code);
286                 }
287
288                 public bool IsWarningDisabledGlobally (int code)
289                 {
290                         return warning_ignore_table != null && warning_ignore_table.Contains (code);
291                 }
292
293                 public void SetIgnoreWarning (int code)
294                 {
295                         if (warning_ignore_table == null)
296                                 warning_ignore_table = new HashSet<int> ();
297
298                         warning_ignore_table.Add (code);
299                 }
300         }
301
302         public class CommandLineParser
303         {
304                 enum ParseResult
305                 {
306                         Success,
307                         Error,
308                         Stop,
309                         UnknownOption
310                 }
311
312                 static readonly char[] argument_value_separator = { ';', ',' };
313                 static readonly char[] numeric_value_separator = { ';', ',', ' ' };
314
315                 readonly TextWriter output;
316                 readonly Report report;
317                 bool stop_argument;
318
319                 Dictionary<string, int> source_file_index;
320
321                 public event Func<string[], int, int> UnknownOptionHandler;
322
323                 CompilerSettings parser_settings;
324
325                 public CommandLineParser (TextWriter errorOutput)
326                         : this (errorOutput, Console.Out)
327                 {
328                 }
329
330                 public CommandLineParser (TextWriter errorOutput, TextWriter messagesOutput)
331                 {
332                         var rp = new StreamReportPrinter (errorOutput);
333
334                         parser_settings = new CompilerSettings ();
335                         report = new Report (new CompilerContext (parser_settings, rp), rp);
336                         this.output = messagesOutput;
337                 }
338
339                 public bool HasBeenStopped {
340                         get {
341                                 return stop_argument;
342                         }
343                 }
344
345                 void About ()
346                 {
347                         output.WriteLine (
348                                 "The Mono C# compiler is Copyright 2001-2011, Novell, Inc.\n\n" +
349                                 "The compiler source code is released under the terms of the \n" +
350                                 "MIT X11 or GNU GPL licenses\n\n" +
351
352                                 "For more information on Mono, visit the project Web site\n" +
353                                 "   http://www.mono-project.com\n\n" +
354
355                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
356                 }
357
358                 public CompilerSettings ParseArguments (string[] args)
359                 {
360                         CompilerSettings settings = new CompilerSettings ();
361                         if (!ParseArguments (settings, args))
362                                 return null;
363
364                         return settings;
365                 }
366
367                 public bool ParseArguments (CompilerSettings settings, string[] args)
368                 {
369                         if (settings == null)
370                                 throw new ArgumentNullException ("settings");
371
372                         List<string> response_file_list = null;
373                         bool parsing_options = true;
374                         stop_argument = false;
375                         source_file_index = new Dictionary<string, int> ();
376
377                         for (int i = 0; i < args.Length; i++) {
378                                 string arg = args[i];
379                                 if (arg.Length == 0)
380                                         continue;
381
382                                 if (arg[0] == '@') {
383                                         string[] extra_args;
384                                         string response_file = arg.Substring (1);
385
386                                         if (response_file_list == null)
387                                                 response_file_list = new List<string> ();
388
389                                         if (response_file_list.Contains (response_file)) {
390                                                 report.Error (1515, "Response file `{0}' specified multiple times", response_file);
391                                                 return false;
392                                         }
393
394                                         response_file_list.Add (response_file);
395
396                                         extra_args = LoadArgs (response_file);
397                                         if (extra_args == null) {
398                                                 report.Error (2011, "Unable to open response file: " + response_file);
399                                                 return false;
400                                         }
401
402                                         args = AddArgs (args, extra_args);
403                                         continue;
404                                 }
405
406                                 if (parsing_options) {
407                                         if (arg == "--") {
408                                                 parsing_options = false;
409                                                 continue;
410                                         }
411
412                                         bool dash_opt = arg[0] == '-';
413                                         bool slash_opt = arg[0] == '/';
414                                         if (dash_opt) {
415                                                 switch (ParseOptionUnix (arg, ref args, ref i, settings)) {
416                                                 case ParseResult.Error:
417                                                 case ParseResult.Success:
418                                                         continue;
419                                                 case ParseResult.Stop:
420                                                         stop_argument = true;
421                                                         return true;
422                                                 case ParseResult.UnknownOption:
423                                                         if (UnknownOptionHandler != null) {
424                                                                 var ret = UnknownOptionHandler (args, i);
425                                                                 if (ret != -1) {
426                                                                         i = ret;
427                                                                         continue;
428                                                                 }
429                                                         }
430                                                         break;
431                                                 }
432                                         }
433
434                                         if (dash_opt || slash_opt) {
435                                                 // Try a -CSCOPTION
436                                                 string csc_opt = dash_opt ? "/" + arg.Substring (1) : arg;
437                                                 switch (ParseOption (csc_opt, ref args, settings)) {
438                                                 case ParseResult.Error:
439                                                 case ParseResult.Success:
440                                                         continue;
441                                                 case ParseResult.UnknownOption:
442                                                         // Need to skip `/home/test.cs' however /test.cs is considered as error
443                                                         if ((slash_opt && arg.Length > 3 && arg.IndexOf ('/', 2) > 0))
444                                                                 break;
445
446                                                         if (UnknownOptionHandler != null) {
447                                                                 var ret = UnknownOptionHandler (args, i);
448                                                                 if (ret != -1) {
449                                                                         i = ret;
450                                                                         continue;
451                                                                 }
452                                                         }
453
454                                                         Error_WrongOption (arg);
455                                                         return false;
456
457                                                 case ParseResult.Stop:
458                                                         stop_argument = true;
459                                                         return true;
460                                                 }
461                                         }
462                                 }
463
464                                 ProcessSourceFiles (arg, false, settings.SourceFiles);
465                         }
466
467                         return report.Errors == 0;
468                 }
469
470                 void ProcessSourceFiles (string spec, bool recurse, List<SourceFile> sourceFiles)
471                 {
472                         string path, pattern;
473
474                         SplitPathAndPattern (spec, out path, out pattern);
475                         if (pattern.IndexOf ('*') == -1) {
476                                 AddSourceFile (spec, sourceFiles);
477                                 return;
478                         }
479
480                         string[] files;
481                         try {
482                                 files = Directory.GetFiles (path, pattern);
483                         } catch (System.IO.DirectoryNotFoundException) {
484                                 report.Error (2001, "Source file `" + spec + "' could not be found");
485                                 return;
486                         } catch (System.IO.IOException) {
487                                 report.Error (2001, "Source file `" + spec + "' could not be found");
488                                 return;
489                         }
490                         foreach (string f in files) {
491                                 AddSourceFile (f, sourceFiles);
492                         }
493
494                         if (!recurse)
495                                 return;
496
497                         string[] dirs = null;
498
499                         try {
500                                 dirs = Directory.GetDirectories (path);
501                         } catch {
502                         }
503
504                         foreach (string d in dirs) {
505
506                                 // Don't include path in this string, as each
507                                 // directory entry already does
508                                 ProcessSourceFiles (d + "/" + pattern, true, sourceFiles);
509                         }
510                 }
511
512                 static string[] AddArgs (string[] args, string[] extra_args)
513                 {
514                         string[] new_args;
515                         new_args = new string[extra_args.Length + args.Length];
516
517                         // if args contains '--' we have to take that into account
518                         // split args into first half and second half based on '--'
519                         // and add the extra_args before --
520                         int split_position = Array.IndexOf (args, "--");
521                         if (split_position != -1) {
522                                 Array.Copy (args, new_args, split_position);
523                                 extra_args.CopyTo (new_args, split_position);
524                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
525                         } else {
526                                 args.CopyTo (new_args, 0);
527                                 extra_args.CopyTo (new_args, args.Length);
528                         }
529
530                         return new_args;
531                 }
532
533                 void AddAssemblyReference (string alias, string assembly, CompilerSettings settings)
534                 {
535                         if (assembly.Length == 0) {
536                                 report.Error (1680, "Invalid reference alias `{0}='. Missing filename", alias);
537                                 return;
538                         }
539
540                         if (!IsExternAliasValid (alias)) {
541                                 report.Error (1679, "Invalid extern alias for -reference. Alias `{0}' is not a valid identifier", alias);
542                                 return;
543                         }
544
545                         settings.AssemblyReferencesAliases.Add (Tuple.Create (alias, assembly));
546                 }
547
548                 void AddResource (AssemblyResource res, CompilerSettings settings)
549                 {
550                         if (settings.Resources == null) {
551                                 settings.Resources = new List<AssemblyResource> ();
552                                 settings.Resources.Add (res);
553                                 return;
554                         }
555
556                         if (settings.Resources.Contains (res)) {
557                                 report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", res.Name);
558                                 return;
559                         }
560
561                         settings.Resources.Add (res);
562                 }
563
564                 void AddSourceFile (string fileName, List<SourceFile> sourceFiles)
565                 {
566                         string path = Path.GetFullPath (fileName);
567
568                         int index;
569                         if (source_file_index.TryGetValue (path, out index)) {
570                                 string other_name = sourceFiles[index - 1].Name;
571                                 if (fileName.Equals (other_name))
572                                         report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
573                                 else
574                                         report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", fileName, other_name, path);
575
576                                 return;
577                         }
578
579                         var unit = new SourceFile (fileName, path, sourceFiles.Count + 1);
580                         sourceFiles.Add (unit);
581                         source_file_index.Add (path, unit.Index);
582                 }
583
584                 public bool ProcessWarningsList (string text, Action<int> action)
585                 {
586                         bool valid = true;
587                         foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) {
588                                 var warning = wid;
589                                 if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S')
590                                         warning = warning.Substring (2);
591
592                                 int id;
593                                 if (!int.TryParse (warning, NumberStyles.AllowLeadingWhite, CultureInfo.InvariantCulture, out id)) {
594                                         continue;
595                                 }
596
597                                 if (report.CheckWarningCode (id, Location.Null)) {
598                                         action (id);
599                                 } else {
600                                         report.Error (1904, "`{0}' is not a valid warning number", wid);
601                                         valid = false;
602                                 }
603                         }
604
605                         return valid;
606                 }
607
608                 void Error_RequiresArgument (string option)
609                 {
610                         report.Error (2006, "Missing argument for `{0}' option", option);
611                 }
612
613                 void Error_RequiresFileName (string option)
614                 {
615                         report.Error (2005, "Missing file specification for `{0}' option", option);
616                 }
617
618                 void Error_WrongOption (string option)
619                 {
620                         report.Error (2007, "Unrecognized command-line option: `{0}'", option);
621                 }
622
623                 static bool IsExternAliasValid (string identifier)
624                 {
625                         return Tokenizer.IsValidIdentifier (identifier);
626                 }
627
628                 static string[] LoadArgs (string file)
629                 {
630                         StreamReader f;
631                         var args = new List<string> ();
632                         string line;
633                         try {
634                                 f = new StreamReader (file);
635                         } catch {
636                                 return null;
637                         }
638
639                         StringBuilder sb = new StringBuilder ();
640
641                         while ((line = f.ReadLine ()) != null) {
642                                 int t = line.Length;
643
644                                 for (int i = 0; i < t; i++) {
645                                         char c = line[i];
646
647                                         if (c == '"' || c == '\'') {
648                                                 char end = c;
649
650                                                 for (i++; i < t; i++) {
651                                                         c = line[i];
652
653                                                         if (c == end)
654                                                                 break;
655                                                         sb.Append (c);
656                                                 }
657                                         } else if (c == ' ') {
658                                                 if (sb.Length > 0) {
659                                                         args.Add (sb.ToString ());
660                                                         sb.Length = 0;
661                                                 }
662                                         } else
663                                                 sb.Append (c);
664                                 }
665                                 if (sb.Length > 0) {
666                                         args.Add (sb.ToString ());
667                                         sb.Length = 0;
668                                 }
669                         }
670
671                         return args.ToArray ();
672                 }
673
674                 void OtherFlags ()
675                 {
676                         output.WriteLine (
677                                 "Other flags in the compiler\n" +
678                                 "   --fatal[=COUNT]    Makes error after COUNT fatal\n" +
679                                 "   --lint             Enhanced warnings\n" +
680                                 "   --metadata-only    Produced assembly will contain metadata only\n" +
681                                 "   --parse            Only parses the source file\n" +
682                                 "   --runtime:VERSION  Sets mscorlib.dll metadata version: v1, v2, v4\n" +
683                                 "   --stacktrace       Shows stack trace at error location\n" +
684                                 "   --timestamp        Displays time stamps of various compiler events\n" +
685                                 "   -v                 Verbose parsing (for debugging the parser)\n" +
686                                 "   --mcs-debug X      Sets MCS debugging level to X\n" +
687                                 "   --break-on-ice     Breaks compilation on internal compiler error");
688                 }
689
690                 //
691                 // This parses the -arg and /arg options to the compiler, even if the strings
692                 // in the following text use "/arg" on the strings.
693                 //
694                 ParseResult ParseOption (string option, ref string[] args, CompilerSettings settings)
695                 {
696                         int idx = option.IndexOf (':');
697                         string arg, value;
698
699                         if (idx == -1) {
700                                 arg = option;
701                                 value = "";
702                         } else {
703                                 arg = option.Substring (0, idx);
704
705                                 value = option.Substring (idx + 1);
706                         }
707
708                         switch (arg.ToLowerInvariant ()) {
709                         case "/nologo":
710                                 return ParseResult.Success;
711
712                         case "/t":
713                         case "/target":
714                                 switch (value) {
715                                 case "exe":
716                                         settings.Target = Target.Exe;
717                                         break;
718
719                                 case "winexe":
720                                         settings.Target = Target.WinExe;
721                                         break;
722
723                                 case "library":
724                                         settings.Target = Target.Library;
725                                         settings.TargetExt = ".dll";
726                                         break;
727
728                                 case "module":
729                                         settings.Target = Target.Module;
730                                         settings.TargetExt = ".netmodule";
731                                         break;
732
733                                 default:
734                                         report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
735                                         return ParseResult.Error;
736                                 }
737                                 return ParseResult.Success;
738
739                         case "/out":
740                                 if (value.Length == 0) {
741                                         Error_RequiresFileName (option);
742                                         return ParseResult.Error;
743                                 }
744                                 settings.OutputFile = value;
745                                 return ParseResult.Success;
746
747                         case "/o":
748                         case "/o+":
749                         case "/optimize":
750                         case "/optimize+":
751                                 settings.Optimize = true;
752                                 return ParseResult.Success;
753
754                         case "/o-":
755                         case "/optimize-":
756                                 settings.Optimize = false;
757                                 return ParseResult.Success;
758
759                         // TODO: Not supported by csc 3.5+
760                         case "/incremental":
761                         case "/incremental+":
762                         case "/incremental-":
763                                 // nothing.
764                                 return ParseResult.Success;
765
766                         case "/d":
767                         case "/define": {
768                                         if (value.Length == 0) {
769                                                 Error_RequiresArgument (option);
770                                                 return ParseResult.Error;
771                                         }
772
773                                         foreach (string d in value.Split (argument_value_separator)) {
774                                                 string conditional = d.Trim ();
775                                                 if (!Tokenizer.IsValidIdentifier (conditional)) {
776                                                         report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
777                                                         continue;
778                                                 }
779
780                                                 settings.AddConditionalSymbol (conditional);
781                                         }
782                                         return ParseResult.Success;
783                                 }
784
785                         case "/bugreport":
786                                 //
787                                 // We should collect data, runtime, etc and store in the file specified
788                                 //
789                                 output.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
790                                 return ParseResult.Success;
791
792                         case "/pkg": {
793                                         string packages;
794
795                                         if (value.Length == 0) {
796                                                 Error_RequiresArgument (option);
797                                                 return ParseResult.Error;
798                                         }
799                                         packages = String.Join (" ", value.Split (new Char[] { ';', ',', '\n', '\r' }));
800                                         string pkgout = Driver.GetPackageFlags (packages, report);
801
802                                         if (pkgout == null)
803                                                 return ParseResult.Error;
804
805                                         string[] xargs = pkgout.Trim (new Char[] { ' ', '\n', '\r', '\t' }).Split (new Char[] { ' ', '\t' });
806                                         args = AddArgs (args, xargs);
807                                         return ParseResult.Success;
808                                 }
809
810                         case "/linkres":
811                         case "/linkresource":
812                         case "/res":
813                         case "/resource":
814                                 AssemblyResource res = null;
815                                 string[] s = value.Split (argument_value_separator, StringSplitOptions.RemoveEmptyEntries);
816                                 switch (s.Length) {
817                                 case 1:
818                                         if (s[0].Length == 0)
819                                                 goto default;
820                                         res = new AssemblyResource (s[0], Path.GetFileName (s[0]));
821                                         break;
822                                 case 2:
823                                         res = new AssemblyResource (s[0], s[1]);
824                                         break;
825                                 case 3:
826                                         if (s[2] != "public" && s[2] != "private") {
827                                                 report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s[2]);
828                                                 return ParseResult.Error;
829                                         }
830                                         res = new AssemblyResource (s[0], s[1], s[2] == "private");
831                                         break;
832                                 default:
833                                         report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
834                                         return ParseResult.Error;
835                                 }
836
837                                 if (res != null) {
838                                         res.IsEmbeded = arg[1] == 'r' || arg[1] == 'R';
839                                         AddResource (res, settings);
840                                 }
841
842                                 return ParseResult.Success;
843
844                         case "/recurse":
845                                 if (value.Length == 0) {
846                                         Error_RequiresFileName (option);
847                                         return ParseResult.Error;
848                                 }
849                                 ProcessSourceFiles (value, true, settings.SourceFiles);
850                                 return ParseResult.Success;
851
852                         case "/r":
853                         case "/reference": {
854                                         if (value.Length == 0) {
855                                                 Error_RequiresFileName (option);
856                                                 return ParseResult.Error;
857                                         }
858
859                                         string[] refs = value.Split (argument_value_separator);
860                                         foreach (string r in refs) {
861                                                 if (r.Length == 0)
862                                                         continue;
863
864                                                 string val = r;
865                                                 int index = val.IndexOf ('=');
866                                                 if (index > -1) {
867                                                         string alias = r.Substring (0, index);
868                                                         string assembly = r.Substring (index + 1);
869                                                         AddAssemblyReference (alias, assembly, settings);
870                                                         if (refs.Length != 1) {
871                                                                 report.Error (2034, "Cannot specify multiple aliases using single /reference option");
872                                                                 return ParseResult.Error;
873                                                         }
874                                                 } else {
875                                                         settings.AssemblyReferences.Add (val);
876                                                 }
877                                         }
878                                         return ParseResult.Success;
879                                 }
880                         case "/addmodule": {
881                                         if (value.Length == 0) {
882                                                 Error_RequiresFileName (option);
883                                                 return ParseResult.Error;
884                                         }
885
886                                         string[] refs = value.Split (argument_value_separator);
887                                         foreach (string r in refs) {
888                                                 settings.Modules.Add (r);
889                                         }
890                                         return ParseResult.Success;
891                                 }
892                         case "/win32res": {
893                                         if (value.Length == 0) {
894                                                 Error_RequiresFileName (option);
895                                                 return ParseResult.Error;
896                                         }
897
898                                         if (settings.Win32IconFile != null)
899                                                 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
900
901                                         settings.Win32ResourceFile = value;
902                                         return ParseResult.Success;
903                                 }
904                         case "/win32icon": {
905                                         if (value.Length == 0) {
906                                                 Error_RequiresFileName (option);
907                                                 return ParseResult.Error;
908                                         }
909
910                                         if (settings.Win32ResourceFile != null)
911                                                 report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
912
913                                         settings.Win32IconFile = value;
914                                         return ParseResult.Success;
915                                 }
916                         case "/doc": {
917                                         if (value.Length == 0) {
918                                                 Error_RequiresFileName (option);
919                                                 return ParseResult.Error;
920                                         }
921
922                                         settings.DocumentationFile = value;
923                                         return ParseResult.Success;
924                                 }
925                         case "/lib": {
926                                         string[] libdirs;
927
928                                         if (value.Length == 0) {
929                                                 return ParseResult.Error;
930                                         }
931
932                                         libdirs = value.Split (argument_value_separator);
933                                         foreach (string dir in libdirs)
934                                                 settings.ReferencesLookupPaths.Add (dir);
935                                         return ParseResult.Success;
936                                 }
937
938                         case "/debug-":
939                                 settings.GenerateDebugInfo = false;
940                                 return ParseResult.Success;
941
942                         case "/debug":
943                                 if (value.Equals ("full", StringComparison.OrdinalIgnoreCase) || value.Equals ("pdbonly", StringComparison.OrdinalIgnoreCase) || idx < 0) {
944                                         settings.GenerateDebugInfo = true;
945                                         return ParseResult.Success;
946                                 }
947
948                                 if (value.Length > 0) {
949                                         report.Error (1902, "Invalid debug option `{0}'. Valid options are `full' or `pdbonly'", value);
950                                 } else {
951                                         Error_RequiresArgument (option);
952                                 }
953
954                                 return ParseResult.Error;
955
956                         case "/debug+":
957                                 settings.GenerateDebugInfo = true;
958                                 return ParseResult.Success;
959
960                         case "/checked":
961                         case "/checked+":
962                                 settings.Checked = true;
963                                 return ParseResult.Success;
964
965                         case "/checked-":
966                                 settings.Checked = false;
967                                 return ParseResult.Success;
968
969                         case "/clscheck":
970                         case "/clscheck+":
971                                 settings.VerifyClsCompliance = true;
972                                 return ParseResult.Success;
973
974                         case "/clscheck-":
975                                 settings.VerifyClsCompliance = false;
976                                 return ParseResult.Success;
977
978                         case "/unsafe":
979                         case "/unsafe+":
980                                 settings.Unsafe = true;
981                                 return ParseResult.Success;
982
983                         case "/unsafe-":
984                                 settings.Unsafe = false;
985                                 return ParseResult.Success;
986
987                         case "/warnaserror":
988                         case "/warnaserror+":
989                                 if (value.Length == 0) {
990                                         settings.WarningsAreErrors = true;
991                                         parser_settings.WarningsAreErrors = true;
992                                 } else {
993                                         if (!ProcessWarningsList (value, settings.AddWarningAsError))
994                                                 return ParseResult.Error;
995                                 }
996                                 return ParseResult.Success;
997
998                         case "/warnaserror-":
999                                 if (value.Length == 0) {
1000                                         settings.WarningsAreErrors = false;
1001                                 } else {
1002                                         if (!ProcessWarningsList (value, settings.AddWarningOnly))
1003                                                 return ParseResult.Error;
1004                                 }
1005                                 return ParseResult.Success;
1006
1007                         case "/warn":
1008                         case "/w":
1009                                 if (value.Length == 0) {
1010                                         Error_RequiresArgument (option);
1011                                         return ParseResult.Error;
1012                                 }
1013
1014                                 SetWarningLevel (value, settings);
1015                                 return ParseResult.Success;
1016
1017                         case "/nowarn":
1018                                 if (value.Length == 0) {
1019                                         Error_RequiresArgument (option);
1020                                         return ParseResult.Error;
1021                                 }
1022
1023                                 if (!ProcessWarningsList (value, settings.SetIgnoreWarning))
1024                                         return ParseResult.Error;
1025
1026                                 return ParseResult.Success;
1027
1028                         case "/noconfig":
1029                                 settings.LoadDefaultReferences = false;
1030                                 return ParseResult.Success;
1031
1032                         case "/platform":
1033                                 if (value.Length == 0) {
1034                                         Error_RequiresArgument (option);
1035                                         return ParseResult.Error;
1036                                 }
1037
1038                                 switch (value.ToLowerInvariant ()) {
1039                                 case "arm":
1040                                         settings.Platform = Platform.Arm;
1041                                         break;
1042                                 case "anycpu":
1043                                         settings.Platform = Platform.AnyCPU;
1044                                         break;
1045                                 case "x86":
1046                                         settings.Platform = Platform.X86;
1047                                         break;
1048                                 case "x64":
1049                                         settings.Platform = Platform.X64;
1050                                         break;
1051                                 case "itanium":
1052                                         settings.Platform = Platform.IA64;
1053                                         break;
1054                                 case "anycpu32bitpreferred":
1055                                         settings.Platform = Platform.AnyCPU32Preferred;
1056                                         break;
1057                                 default:
1058                                         report.Error (1672, "Invalid -platform option `{0}'. Valid options are `anycpu', `anycpu32bitpreferred', `arm', `x86', `x64' or `itanium'",
1059                                                 value);
1060                                         return ParseResult.Error;
1061                                 }
1062
1063                                 return ParseResult.Success;
1064
1065                         case "/sdk":
1066                                 if (value.Length == 0) {
1067                                         Error_RequiresArgument (option);
1068                                         return ParseResult.Error;
1069                                 }
1070
1071                                 settings.SdkVersion = value;
1072                                 return ParseResult.Success;
1073
1074                         // We just ignore this.
1075                         case "/errorreport":
1076                         case "/filealign":
1077                                 if (value.Length == 0) {
1078                                         Error_RequiresArgument (option);
1079                                         return ParseResult.Error;
1080                                 }
1081
1082                                 return ParseResult.Success;
1083
1084                         case "/helpinternal":
1085                                 OtherFlags ();
1086                                 return ParseResult.Stop;
1087
1088                         case "/help":
1089                         case "/?":
1090                                 Usage ();
1091                                 return ParseResult.Stop;
1092
1093                         case "/main":
1094                         case "/m":
1095                                 if (value.Length == 0) {
1096                                         Error_RequiresArgument (option);
1097                                         return ParseResult.Error;
1098                                 }
1099                                 settings.MainClass = value;
1100                                 return ParseResult.Success;
1101
1102                         case "/nostdlib":
1103                         case "/nostdlib+":
1104                                 settings.StdLib = false;
1105                                 return ParseResult.Success;
1106
1107                         case "/nostdlib-":
1108                                 settings.StdLib = true;
1109                                 return ParseResult.Success;
1110
1111                         case "/fullpaths":
1112                                 settings.ShowFullPaths = true;
1113                                 return ParseResult.Success;
1114
1115                         case "/keyfile":
1116                                 if (value.Length == 0) {
1117                                         Error_RequiresFileName (option);
1118                                         return ParseResult.Error;
1119                                 }
1120
1121                                 settings.StrongNameKeyFile = value;
1122                                 return ParseResult.Success;
1123
1124                         case "/keycontainer":
1125                                 if (value.Length == 0) {
1126                                         Error_RequiresArgument (option);
1127                                         return ParseResult.Error;
1128                                 }
1129
1130                                 settings.StrongNameKeyContainer = value;
1131                                 return ParseResult.Success;
1132
1133                         case "/delaysign+":
1134                         case "/delaysign":
1135                                 settings.StrongNameDelaySign = true;
1136                                 return ParseResult.Success;
1137
1138                         case "/delaysign-":
1139                                 settings.StrongNameDelaySign = false;
1140                                 return ParseResult.Success;
1141
1142                         case "/langversion":
1143                                 if (value.Length == 0) {
1144                                         Error_RequiresArgument (option);
1145                                         return ParseResult.Error;
1146                                 }
1147
1148                                 switch (value.ToLowerInvariant ()) {
1149                                 case "iso-1":
1150                                 case "1":
1151                                         settings.Version = LanguageVersion.ISO_1;
1152                                         return ParseResult.Success;
1153                                 case "default":
1154                                         settings.Version = LanguageVersion.Default;
1155                                         return ParseResult.Success;
1156                                 case "2":
1157                                 case "iso-2":
1158                                         settings.Version = LanguageVersion.ISO_2;
1159                                         return ParseResult.Success;
1160                                 case "3":
1161                                         settings.Version = LanguageVersion.V_3;
1162                                         return ParseResult.Success;
1163                                 case "4":
1164                                         settings.Version = LanguageVersion.V_4;
1165                                         return ParseResult.Success;
1166                                 case "5":
1167                                         settings.Version = LanguageVersion.V_5;
1168                                         return ParseResult.Success;
1169                                 case "6":
1170                                         settings.Version = LanguageVersion.V_6;
1171                                         return ParseResult.Success;
1172                                 case "experimental":
1173                                         settings.Version = LanguageVersion.Experimental;
1174                                         return ParseResult.Success;
1175                                 case "future":
1176                                         report.Warning (8000, 1, "Language version `future' is no longer supported");
1177                                         goto case "6";
1178                                 }
1179
1180                                 report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', Default or value in range 1 to 6", value);
1181                                 return ParseResult.Error;
1182
1183                         case "/codepage":
1184                                 if (value.Length == 0) {
1185                                         Error_RequiresArgument (option);
1186                                         return ParseResult.Error;
1187                                 }
1188
1189                                 switch (value) {
1190                                 case "utf8":
1191                                         settings.Encoding = Encoding.UTF8;
1192                                         break;
1193                                 case "reset":
1194                                         settings.Encoding = Encoding.Default;
1195                                         break;
1196                                 default:
1197                                         try {
1198                                                 settings.Encoding = Encoding.GetEncoding (int.Parse (value));
1199                                         } catch {
1200                                                 report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1201                                         }
1202                                         return ParseResult.Error;
1203                                 }
1204                                 return ParseResult.Success;
1205
1206                         case "runtimemetadataversion":
1207                                 if (value.Length == 0) {
1208                                         Error_RequiresArgument (option);
1209                                         return ParseResult.Error;
1210                                 }
1211
1212                                 settings.RuntimeMetadataVersion = value;
1213                                 return ParseResult.Success;
1214
1215                         case "/pathmap":
1216                                 if (value.Length == 0) {
1217                                         return ParseResult.Success;
1218                                 }
1219
1220                                 foreach (var pair in value.Split (',')) {
1221                                         var kv = pair.Split ('=');
1222                                         if (kv.Length != 2) {
1223                                                 report.Error (8101, "The pathmap option was incorrectly formatted");
1224                                                 return ParseResult.Error;
1225                                         }
1226
1227                                         if (settings.PathMap == null)
1228                                                 settings.PathMap = new List<KeyValuePair<string, string>> ();
1229
1230                                         var key = kv [0].TrimEnd (Path.DirectorySeparatorChar);
1231                                         var path = kv [1].TrimEnd (Path.DirectorySeparatorChar);
1232                                         if (key.Length == 0 || path.Length == 0)
1233                                                 report.Error (8101, "The pathmap option was incorrectly formatted");
1234
1235                                         settings.PathMap.Add (new KeyValuePair<string, string> (key, path));
1236                                 }
1237
1238                                 return ParseResult.Success;
1239
1240                         // csc options that we don't support
1241                         case "/analyzer":
1242                         case "/appconfig":
1243                         case "/baseaddress":
1244                         case "/deterministic":
1245                         case "/deterministic+":
1246                         case "/deterministic-":
1247                         case "/errorendlocation":
1248                         case "/errorlog":
1249                         case "/features":
1250                         case "/highentropyva":
1251                         case "/highentropyva+":
1252                         case "/highentropyva-":
1253                         case "/link":
1254                         case "/moduleassemblyname":
1255                         case "/nowin32manifest":
1256                         case "/pdb":
1257                         case "/preferreduilang":
1258                         case "/publicsign":
1259                         case "/publicsign+":
1260                         case "/publicsign-":
1261                         case "/reportanalyzer":
1262                         case "/ruleset":
1263                         case "/sqmsessionguid":
1264                         case "/subsystemversion":
1265                         case "/utf8output":
1266                         case "/win32manifest":
1267                                 return ParseResult.Success;
1268
1269                         default:
1270                                 return ParseResult.UnknownOption;
1271                         }
1272                 }
1273
1274                 //
1275                 // Currently handles the Unix-like command line options, but will be
1276                 // deprecated in favor of the CSCParseOption, which will also handle the
1277                 // options that start with a dash in the future.
1278                 //
1279                 ParseResult ParseOptionUnix (string arg, ref string[] args, ref int i, CompilerSettings settings)
1280                 {
1281                         switch (arg){
1282                         case "-v":
1283                                 settings.VerboseParserFlag++;
1284                                 return ParseResult.Success;
1285
1286                         case "--version":
1287                                 Version ();
1288                                 return ParseResult.Stop;
1289                                 
1290                         case "--parse":
1291                                 settings.ParseOnly = true;
1292                                 return ParseResult.Success;
1293                                 
1294                         case "--main": case "-m":
1295                                 report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
1296                                 if ((i + 1) >= args.Length){
1297                                         Error_RequiresArgument (arg);
1298                                         return ParseResult.Error;
1299                                 }
1300                                 settings.MainClass = args[++i];
1301                                 return ParseResult.Success;
1302                                 
1303                         case "--unsafe":
1304                                 report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
1305                                 settings.Unsafe = true;
1306                                 return ParseResult.Success;
1307                                 
1308                         case "/?": case "/h": case "/help":
1309                         case "--help":
1310                                 Usage ();
1311                                 return ParseResult.Stop;
1312
1313                         case "--define":
1314                                 report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
1315                                 if ((i + 1) >= args.Length){
1316                                         Error_RequiresArgument (arg);
1317                                         return ParseResult.Error;
1318                                 }
1319
1320                                 settings.AddConditionalSymbol (args [++i]);
1321                                 return ParseResult.Success;
1322
1323                         case "--tokenize":
1324                                 settings.TokenizeOnly = true;
1325                                 return ParseResult.Success;
1326                                 
1327                         case "-o": 
1328                         case "--output":
1329                                 report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
1330                                 if ((i + 1) >= args.Length){
1331                                         Error_RequiresArgument (arg);
1332                                         return ParseResult.Error;
1333                                 }
1334                                 settings.OutputFile = args[++i];
1335                                 return ParseResult.Success;
1336
1337                         case "--checked":
1338                                 report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
1339                                 settings.Checked = true;
1340                                 return ParseResult.Success;
1341                                 
1342                         case "--stacktrace":
1343                                 settings.Stacktrace = true;
1344                                 return ParseResult.Success;
1345                                 
1346                         case "--linkresource":
1347                         case "--linkres":
1348                                 report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
1349                                 if ((i + 1) >= args.Length){
1350                                         Error_RequiresArgument (arg);
1351                                         return ParseResult.Error;
1352                                 }
1353
1354                                 AddResource (new AssemblyResource (args[++i], args[i]), settings);
1355                                 return ParseResult.Success;
1356                                 
1357                         case "--resource":
1358                         case "--res":
1359                                 report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
1360                                 if ((i + 1) >= args.Length){
1361                                         Error_RequiresArgument (arg);
1362                                         return ParseResult.Error;
1363                                 }
1364
1365                                 AddResource (new AssemblyResource (args[++i], args[i], true), settings);
1366                                 return ParseResult.Success;
1367                                 
1368                         case "--target":
1369                                 report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
1370                                 if ((i + 1) >= args.Length){
1371                                         Error_RequiresArgument (arg);
1372                                         return ParseResult.Error;
1373                                 }
1374                                 
1375                                 string type = args [++i];
1376                                 switch (type){
1377                                 case "library":
1378                                         settings.Target = Target.Library;
1379                                         settings.TargetExt = ".dll";
1380                                         break;
1381                                         
1382                                 case "exe":
1383                                         settings.Target = Target.Exe;
1384                                         break;
1385                                         
1386                                 case "winexe":
1387                                         settings.Target = Target.WinExe;
1388                                         break;
1389                                         
1390                                 case "module":
1391                                         settings.Target = Target.Module;
1392                                         settings.TargetExt = ".dll";
1393                                         break;
1394                                 default:
1395                                         report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
1396                                         break;
1397                                 }
1398                                 return ParseResult.Success;
1399                                 
1400                         case "-r":
1401                                 report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
1402                                 if ((i + 1) >= args.Length){
1403                                         Error_RequiresArgument (arg);
1404                                         return ParseResult.Error;
1405                                 }
1406                                 
1407                                 string val = args [++i];
1408                                 int idx = val.IndexOf ('=');
1409                                 if (idx > -1) {
1410                                         string alias = val.Substring (0, idx);
1411                                         string assembly = val.Substring (idx + 1);
1412                                         AddAssemblyReference (alias, assembly, settings);
1413                                         return ParseResult.Success;
1414                                 }
1415
1416                                 settings.AssemblyReferences.Add (val);
1417                                 return ParseResult.Success;
1418                                 
1419                         case "-L":
1420                                 report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
1421                                 if ((i + 1) >= args.Length){
1422                                         Error_RequiresArgument (arg);
1423                                         return ParseResult.Error;
1424                                 }
1425                                 settings.ReferencesLookupPaths.Add (args [++i]);
1426                                 return ParseResult.Success;
1427
1428                         case "--lint":
1429                                 settings.EnhancedWarnings = true;
1430                                 return ParseResult.Success;
1431                                 
1432                         case "--nostdlib":
1433                                 report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
1434                                 settings.StdLib = false;
1435                                 return ParseResult.Success;
1436                                 
1437                         case "--nowarn":
1438                                 report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
1439                                 if ((i + 1) >= args.Length){
1440                                         Error_RequiresArgument (arg);
1441                                         return ParseResult.Error;
1442                                 }
1443                                 int warn = 0;
1444                                 
1445                                 try {
1446                                         warn = int.Parse (args [++i]);
1447                                 } catch {
1448                                         Usage ();
1449                                         Environment.Exit (1);
1450                                 }
1451                                 settings.SetIgnoreWarning (warn);
1452                                 return ParseResult.Success;
1453
1454                         case "--wlevel":
1455                                 report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1456                                 if ((i + 1) >= args.Length){
1457                                         Error_RequiresArgument (arg);
1458                                         return ParseResult.Error;
1459                                 }
1460
1461                                 SetWarningLevel (args [++i], settings);
1462                                 return ParseResult.Success;
1463
1464                         case "--mcs-debug":
1465                                 if ((i + 1) >= args.Length){
1466                                         Error_RequiresArgument (arg);
1467                                         return ParseResult.Error;
1468                                 }
1469
1470                                 try {
1471                                         settings.DebugFlags = int.Parse (args [++i]);
1472                                 } catch {
1473                                         Error_RequiresArgument (arg);
1474                                         return ParseResult.Error;
1475                                 }
1476
1477                                 return ParseResult.Success;
1478                                 
1479                         case "--about":
1480                                 About ();
1481                                 return ParseResult.Stop;
1482                                 
1483                         case "--recurse":
1484                                 report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1485                                 if ((i + 1) >= args.Length){
1486                                         Error_RequiresArgument (arg);
1487                                         return ParseResult.Error;
1488                                 }
1489                                 ProcessSourceFiles (args [++i], true, settings.SourceFiles);
1490                                 return ParseResult.Success;
1491                                 
1492                         case "--timestamp":
1493                                 settings.Timestamps = true;
1494                                 return ParseResult.Success;
1495
1496                         case "--debug": case "-g":
1497                                 report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1498                                 settings.GenerateDebugInfo = true;
1499                                 return ParseResult.Success;
1500                                 
1501                         case "--noconfig":
1502                                 report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1503                                 settings.LoadDefaultReferences = false;
1504                                 return ParseResult.Success;
1505
1506                         case "--metadata-only":
1507                                 settings.WriteMetadataOnly = true;
1508                                 return ParseResult.Success;
1509
1510                         case "--break-on-ice":
1511                                 settings.BreakOnInternalError = true;
1512                                 return ParseResult.Success;
1513
1514                         default:
1515                                 if (arg.StartsWith ("--fatal", StringComparison.Ordinal)) {
1516                                         int fatal = 1;
1517                                         if (arg.StartsWith ("--fatal=", StringComparison.Ordinal))
1518                                                 int.TryParse (arg.Substring (8), out fatal);
1519
1520                                         settings.FatalCounter = fatal;
1521                                         return ParseResult.Success;
1522                                 }
1523                                 if (arg.StartsWith ("--runtime:", StringComparison.Ordinal)) {
1524                                         string version = arg.Substring (10);
1525
1526                                         switch (version) {
1527                                         case "v1":
1528                                         case "V1":
1529                                                 settings.StdLibRuntimeVersion = RuntimeVersion.v1;
1530                                                 break;
1531                                         case "v2":
1532                                         case "V2":
1533                                                 settings.StdLibRuntimeVersion = RuntimeVersion.v2;
1534                                                 break;
1535                                         case "v4":
1536                                         case "V4":
1537                                                 settings.StdLibRuntimeVersion = RuntimeVersion.v4;
1538                                                 break;
1539                                         }
1540                                         return ParseResult.Success;
1541                                 }
1542
1543                                 if (arg.StartsWith ("--getresourcestrings:", StringComparison.Ordinal)) {
1544                                         string file = arg.Substring (21).Trim ();
1545                                         if (file.Length < 1) {
1546                                                 Error_RequiresArgument (arg);
1547                                                 return ParseResult.Error;
1548                                         }
1549
1550                                         if (settings.GetResourceStrings == null)
1551                                                 settings.GetResourceStrings = new List<string> ();
1552
1553                                         settings.GetResourceStrings.Add (file);
1554                                         return ParseResult.Success;
1555                                 }
1556
1557                                 return ParseResult.UnknownOption;
1558                         }
1559                 }
1560
1561                 void SetWarningLevel (string s, CompilerSettings settings)
1562                 {
1563                         int level = -1;
1564
1565                         try {
1566                                 level = int.Parse (s);
1567                         } catch {
1568                         }
1569                         if (level < 0 || level > 4) {
1570                                 report.Error (1900, "Warning level must be in the range 0-4");
1571                                 return;
1572                         }
1573                         settings.WarningLevel = level;
1574                 }
1575
1576                 //
1577                 // Given a path specification, splits the path from the file/pattern
1578                 //
1579                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
1580                 {
1581                         int p = spec.LastIndexOf ('/');
1582                         if (p != -1) {
1583                                 //
1584                                 // Windows does not like /file.cs, switch that to:
1585                                 // "\", "file.cs"
1586                                 //
1587                                 if (p == 0) {
1588                                         path = "\\";
1589                                         pattern = spec.Substring (1);
1590                                 } else {
1591                                         path = spec.Substring (0, p);
1592                                         pattern = spec.Substring (p + 1);
1593                                 }
1594                                 return;
1595                         }
1596
1597                         p = spec.LastIndexOf ('\\');
1598                         if (p != -1) {
1599                                 path = spec.Substring (0, p);
1600                                 pattern = spec.Substring (p + 1);
1601                                 return;
1602                         }
1603
1604                         path = ".";
1605                         pattern = spec;
1606                 }
1607
1608                 void Usage ()
1609                 {
1610                         output.WriteLine (
1611                                 "Mono C# compiler, Copyright 2001-2011 Novell, Inc., Copyright 2011-2012 Xamarin, Inc\n" +
1612                                 "mcs [options] source-files\n" +
1613                                 "   --about              About the Mono C# compiler\n" +
1614                                 "   -addmodule:M1[,Mn]   Adds the module to the generated assembly\n" +
1615                                 "   -checked[+|-]        Sets default aritmetic overflow context\n" +
1616                                 "   -clscheck[+|-]       Disables CLS Compliance verifications\n" +
1617                                 "   -codepage:ID         Sets code page to the one in ID (number, utf8, reset)\n" +
1618                                 "   -define:S1[;S2]      Defines one or more conditional symbols (short: -d)\n" +
1619                                 "   -debug[+|-], -g      Generate debugging information\n" +
1620                                 "   -delaysign[+|-]      Only insert the public key into the assembly (no signing)\n" +
1621                                 "   -doc:FILE            Process documentation comments to XML file\n" +
1622                                 "   -fullpaths           Any issued error or warning uses absolute file path\n" +
1623                                 "   -help                Lists all compiler options (short: -?)\n" +
1624                                 "   -keycontainer:NAME   The key pair container used to sign the output assembly\n" +
1625                                 "   -keyfile:FILE        The key file used to strongname the ouput assembly\n" +
1626                                 "   -langversion:TEXT    Specifies language version: ISO-1, ISO-2, 3, 4, 5, 6, Default or Experimental\n" +
1627                                 "   -lib:PATH1[,PATHn]   Specifies the location of referenced assemblies\n" +
1628                                 "   -main:CLASS          Specifies the class with the Main method (short: -m)\n" +
1629                                 "   -noconfig            Disables implicitly referenced assemblies\n" +
1630                                 "   -nostdlib[+|-]       Does not reference mscorlib.dll library\n" +
1631                                 "   -nowarn:W1[,Wn]      Suppress one or more compiler warnings\n" +
1632                                 "   -optimize[+|-]       Enables advanced compiler optimizations (short: -o)\n" +
1633                                 "   -out:FILE            Specifies output assembly name\n" +
1634                                 "   -pathmap:K=V[,Kn=Vn] Sets a mapping for source path names used in generated output\n" +
1635                                 "   -pkg:P1[,Pn]         References packages P1..Pn\n" +
1636                                 "   -platform:ARCH       Specifies the target platform of the output assembly\n" +
1637                                 "                        ARCH can be one of: anycpu, anycpu32bitpreferred, arm,\n" +
1638                                 "                        x86, x64 or itanium. The default is anycpu.\n" +
1639                                 "   -recurse:SPEC        Recursively compiles files according to SPEC pattern\n" +
1640                                 "   -reference:A1[,An]   Imports metadata from the specified assembly (short: -r)\n" +
1641                                 "   -reference:ALIAS=A   Imports metadata using specified extern alias (short: -r)\n" +
1642                                 "   -sdk:VERSION         Specifies SDK version of referenced assemblies\n" +
1643                                 "                        VERSION can be one of: 2, 4, 4.5 (default) or a custom value\n" +
1644                                 "   -target:KIND         Specifies the format of the output assembly (short: -t)\n" +
1645                                 "                        KIND can be one of: exe, winexe, library, module\n" +
1646                                 "   -unsafe[+|-]         Allows to compile code which uses unsafe keyword\n" +
1647                                 "   -warnaserror[+|-]    Treats all warnings as errors\n" +
1648                                 "   -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
1649                                 "   -warn:0-4            Sets warning level, the default is 4 (short -w:)\n" +
1650                                 "   -helpinternal        Shows internal and advanced compiler options\n" +
1651                                 "\n" +
1652                                 "Resources:\n" +
1653                                 "   -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
1654                                 "   -resource:FILE[,ID]     Embed FILE as a resource (short: -res)\n" +
1655                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
1656                                 "   -win32icon:FILE         Use this icon for the output\n" +
1657                                                                 "   @file                   Read response file for more options\n\n" +
1658                                 "Options can be of the form -option or /option");
1659                 }
1660
1661                 void Version ()
1662                 {
1663                         string version = System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType.Assembly.GetName ().Version.ToString ();
1664                         output.WriteLine ("Mono C# compiler version {0}", version);
1665                 }
1666         }
1667
1668         public class RootContext
1669         {
1670                 //
1671                 // Contains the parsed tree
1672                 //
1673                 static ModuleContainer root;
1674
1675                 static public ModuleContainer ToplevelTypes {
1676                         get { return root; }
1677                         set { root = value; }
1678                 }
1679         }
1680 }