* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / tools / al / Al.cs
1 //
2 // Mono.AssemblyLinker.AssemblyLinker
3 //
4 // Author(s):
5 //   Zoltan Varga (vargaz@freemail.hu)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
10
11 using System;
12 using System.IO;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Security.Cryptography;
17 using System.Text;
18 using System.Configuration.Assemblies;
19
20 using Mono.Security.Cryptography;
21
22 namespace Mono.AssemblyLinker
23 {
24         class ModuleInfo {
25                 public string fileName;
26                 public string target;
27         }
28
29         class ResourceInfo {
30                 public string name;
31                 public string fileName;
32                 public string target;
33                 public bool isEmbedded;
34                 public bool isPrivate;
35         }
36
37         enum Target {
38                 Dll,
39                 Exe,
40                 Win
41         }
42
43         public class AssemblyLinker {
44
45                 ArrayList inputFiles = new ArrayList ();
46                 ArrayList resources = new ArrayList ();
47                 ArrayList cattrs = new ArrayList ();
48                 bool fullPaths;
49                 string outFile;
50                 string entryPoint;
51                 string win32IconFile;
52                 string win32ResFile;
53                 string templateFile;
54                 bool isTemplateFile = false;
55                 Target target;
56                 bool delaysign;
57                 string keyfile;
58                 string keyname;
59
60                 public static int Main (String[] args) {
61                         return new AssemblyLinker ().DynMain (args);
62                 }
63
64                 private int DynMain (String[] args) {
65                         ParseArgs (args);
66
67                         DoIt ();
68
69                         return 0;
70                 }
71
72                 static bool IsStrongNamed (Assembly assembly)
73                 {
74                         object[] attrs = assembly.GetCustomAttributes (true);
75                         foreach (object o in attrs) 
76                         {
77                                 if (o is AssemblyKeyFileAttribute)
78                                         return true;
79                                 else if (o is AssemblyKeyNameAttribute)
80                                         return true;
81                         }
82                         return false;
83                 }
84
85                 private void ParseArgs (string[] args) 
86                 {
87
88                         ArrayList flat_args = new ArrayList ();
89
90                         // Process response files
91                         Hashtable response_files = new Hashtable ();
92                         foreach (string str in args) {
93                                 if (str [0] != '@') {
94                                         flat_args.Add (str);
95                                         continue;
96                                 }
97
98                                 if (str.Length == 1)
99                                         ReportMissingFileSpec ("@");
100
101                                 string resfile_name = Path.GetFullPath (str.Substring (1));
102                                 if (response_files.ContainsKey (resfile_name))
103                                         Report (1006, "Response file '" + resfile_name + "' was already included");
104                                 response_files [resfile_name] = resfile_name;
105                                 LoadArgs (resfile_name, flat_args);
106                         }
107
108                         if (flat_args.Count == 0)
109                                 Usage ();
110
111                         foreach (string str in flat_args) {
112                                 if ((str [0] != '-') && (str [0] != '/')) {
113                                         string[] parts = str.Split (',');
114                                         ModuleInfo mod = new ModuleInfo ();
115                                         mod.fileName = parts [0];
116                                         if (parts.Length > 1)
117                                                 mod.target = parts [1];
118                                         inputFiles.Add (mod);
119                                         continue;
120                                 }
121
122                                 string arg;
123                                 string opt = GetCommand (str, out arg);
124
125                                 ResourceInfo res;
126                                 switch (opt) {
127                                 case "help":
128                                 case "?":
129                                         Usage ();
130                                         break;
131
132                                 case "embed": {
133                                         if (arg == null)
134                                                 ReportMissingFileSpec (opt);
135                                         res = new ResourceInfo ();
136                                         res.isEmbedded = true;
137                                         String[] parts = arg.Split (',');
138                                         res.fileName = parts [0];
139                                         if (parts.Length > 1)
140                                                 res.name = parts [1];
141                                         if (parts.Length > 2) {
142                                                 switch (parts [2]) {
143                                                 case "public":
144                                                         break;
145                                                 case "private":
146                                                         res.isPrivate = true;
147                                                         break;
148                                                 default:
149                                                         ReportInvalidArgument (opt, parts [2]);
150                                                         break;
151                                                 }
152                                         }
153                                         resources.Add (res);
154                                         break;
155                                 }
156
157                                 case "link": {
158                                         if (arg == null)
159                                                 ReportMissingFileSpec (opt);
160                                         res = new ResourceInfo ();
161                                         String[] parts = arg.Split (',');
162                                         res.fileName = parts [0];
163                                         if (parts.Length > 1)
164                                                 res.name = parts [1];
165                                         if (parts.Length > 2)
166                                                 res.target = parts [2];
167                                         if (parts.Length > 3) {
168                                                 switch (parts [3]) {
169                                                 case "public":
170                                                         break;
171                                                 case "private":
172                                                         res.isPrivate = true;
173                                                         break;
174                                                 default:
175                                                         ReportInvalidArgument (opt, parts [3]);
176                                                         break;
177                                                 }
178                                         }
179                                         resources.Add (res);
180                                         break;
181                                 }
182
183                                 case "algid":
184                                         if (arg == null)
185                                                 ReportMissingArgument (opt);
186                                         try {
187                                                 string realArg = arg;
188                                                 if (realArg.StartsWith ("0x"))
189                                                         realArg = realArg.Substring (2);
190                                                 uint val = Convert.ToUInt32 (realArg, 16);
191                                                 AddCattr (typeof (AssemblyAlgorithmIdAttribute), typeof (uint), val);
192                                         }
193                                         catch (Exception) {
194                                                 ReportInvalidArgument (opt, arg);
195                                         }
196                                         break;
197
198                                 case "base":
199                                         ReportNotImplemented (opt);
200                                         break;
201
202                                 case "baseaddress":
203                                         ReportNotImplemented (opt);
204                                         break;
205
206                                 case "bugreport":
207                                         ReportNotImplemented (opt);
208                                         break;
209
210                                 case "comp":
211                                 case "company":
212                                         if (arg == null)
213                                                 ReportMissingText (opt);
214                                         AddCattr (typeof (AssemblyCompanyAttribute), arg);
215                                         break;
216
217                                 case "config":
218                                 case "configuration":
219                                         if (arg == null)
220                                                 ReportMissingText (opt);
221                                         AddCattr (typeof (AssemblyConfigurationAttribute), arg);
222                                         break;
223
224                                 case "copy":
225                                 case "copyright":
226                                         if (arg == null)
227                                                 ReportMissingText (opt);
228                                         AddCattr (typeof (AssemblyCopyrightAttribute), arg);
229                                         break;
230
231                                 case "c":
232                                 case "culture":
233                                         if (arg == null)
234                                                 ReportMissingText (opt);
235                                         AddCattr (typeof (AssemblyCultureAttribute), arg);
236                                         break;
237
238                                 case "delay":
239                                 case "delaysign":
240                                 case "delay+":
241                                 case "delaysign+":
242                                         AddCattr (typeof (AssemblyDelaySignAttribute), typeof (bool), true);
243                                         delaysign = true;
244                                         break;
245
246                                 case "delay-":
247                                 case "delaysign-":
248                                         delaysign = false;
249                                         break;
250
251                                 case "descr":
252                                 case "description":
253                                         if (arg == null)
254                                                 ReportMissingText (opt);
255                                         AddCattr (typeof (AssemblyDescriptionAttribute), arg);
256                                         break;
257
258                                 case "e":
259                                 case "evidence":
260                                         if (arg == null)
261                                                 ReportMissingFileSpec (opt);
262                                         res = new ResourceInfo ();
263                                         res.name = "Security.Evidence";
264                                         res.fileName = arg;
265                                         res.isEmbedded = true;
266                                         res.isPrivate = true;
267                                         resources.Add (res);
268                                         break;
269
270                                 case "fileversion":
271                                         if (arg == null)
272                                                 ReportMissingText (opt);
273
274                                         AddCattr (typeof (AssemblyFileVersionAttribute), arg);
275                                         break;
276
277                                 case "flags":
278                                         if (arg == null)
279                                                 ReportMissingArgument (opt);
280                                         try {
281                                                 string realArg = arg;
282                                                 if (realArg.StartsWith ("0x"))
283                                                         realArg = realArg.Substring (2);
284                                                 uint val = Convert.ToUInt32 (realArg, 16);
285                                                 AddCattr (typeof (AssemblyFlagsAttribute), typeof (uint), val);
286                                         }
287                                         catch (Exception) {
288                                                 ReportInvalidArgument (opt, arg);
289                                         }
290                                         break;
291
292                                 case "fullpaths":
293                                         fullPaths = true;
294                                         break;
295
296                                 case "keyf":
297                                 case "keyfile":
298                                         if (arg == null)
299                                                 ReportMissingText (opt);
300                                         AddCattr (typeof (AssemblyKeyFileAttribute), arg);
301                                         keyfile = arg;
302                                         break;
303                                         
304                                 case "keyn":
305                                 case "keyname":
306                                         if (arg == null)
307                                                 ReportMissingText (opt);
308                                         AddCattr (typeof (AssemblyKeyNameAttribute), arg);
309                                         keyname = arg;
310                                         break;
311
312                                 case "main":
313                                         if (arg == null)
314                                                 ReportMissingText (opt);
315                                         entryPoint = arg;
316                                         break;
317
318                                 case "nologo":
319                                         break;
320
321                                 case "out":
322                                         if (arg == null)
323                                                 ReportMissingFileSpec (opt);
324                                         outFile = arg;
325                                         break;
326
327                                 case "prod":
328                                 case "product":
329                                         if (arg == null)
330                                                 ReportMissingText (opt);
331                                         AddCattr (typeof (AssemblyProductAttribute), arg);
332                                         break;
333
334                                 case "productv":
335                                 case "productversion":
336                                         if (arg == null)
337                                                 ReportMissingText (opt);
338                                         AddCattr (typeof (AssemblyInformationalVersionAttribute), arg);
339                                         break;
340
341                                 case "t":
342                                 case "target":
343                                         if (arg == null)
344                                                 ReportMissingText (opt);
345                                         switch (arg) {
346                                         case "lib":
347                                         case "library":
348                                                 target = Target.Dll;
349                                                 break;
350                                         case "exe":
351                                                 target = Target.Exe;
352                                                 break;
353                                         case "win":
354                                         case "winexe":
355                                                 Report (0, "target:win is not implemented");
356                                                 break;
357                                         default:
358                                                 ReportInvalidArgument (opt, arg);
359                                                 break;
360                                         }
361                                         break;
362
363                                 case "template":
364                                         if (arg == null)
365                                                 ReportMissingFileSpec (opt);
366                                         isTemplateFile = true;
367                                         templateFile = arg;
368                                         break;
369
370                                 case "title":
371                                         if (arg == null)
372                                                 ReportMissingText (opt);
373                                         AddCattr (typeof (AssemblyTitleAttribute), arg);
374                                         break;
375
376                                 case "trade":
377                                 case "trademark":
378                                         if (arg == null)
379                                                 ReportMissingText (opt);
380                                         AddCattr (typeof (AssemblyTrademarkAttribute), arg);
381                                         break;
382
383                                 case "v":
384                                 case "version":
385                                         // This option conflicts with the standard UNIX meaning
386                                         if (arg == null) {
387                                                 Version ();
388                                                 break;
389                                         }
390                                         AddCattr (typeof (AssemblyVersionAttribute), arg);
391                                         break;
392
393                                 case "win32icon":
394                                         if (arg == null)
395                                                 ReportMissingFileSpec (opt);
396                                         win32IconFile = arg;
397                                         break;
398
399                                 case "win32res":
400                                         if (arg == null)
401                                                 ReportMissingFileSpec (opt);
402                                         win32ResFile = arg;
403                                         break;
404
405                                 default:
406                                         Report (1013, String.Format ("Unrecognized command line option: '{0}'", opt));
407                                         break;
408                                 }
409                         }
410
411                         if ((inputFiles.Count == 0) && (resources.Count == 0))
412                                 Report (1016, "No valid input files were specified");
413
414                         if (outFile == null)
415                                 Report (1017, "No target filename was specified");
416
417                         if (target == Target.Dll && (entryPoint != null))
418                                 Report (1035, "Libraries cannot have an entry point");
419
420                         if (target == Target.Exe && (entryPoint == null))
421                                 Report (1036, "Entry point required for executable applications");                                              
422                 }
423
424                 private string GetCommand (string str, out string command_arg) {
425                         if ((str [0] == '-') && (str.Length > 1) && (str [1] == '-'))
426                                 str = str.Substring (1);
427
428                         int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
429                         string command = str.Substring (1,
430                                                                                         end_index == -1 ? str.Length - 1 : end_index - 1);
431                         
432                         if (end_index != -1) {
433                                 command_arg = str.Substring (end_index+1);
434                                 if (command_arg == String.Empty)
435                                         command_arg = null;
436                         } else {
437                                 command_arg = null;
438                         }
439                                 
440                         return command.ToLower ();
441                 }
442
443                 private void AddCattr (Type attrType, Type arg, object value) {
444                         cattrs.Add (new CustomAttributeBuilder (attrType.GetConstructor (new Type [] { arg }), new object [] { value }));
445                 }
446
447                 private void AddCattr (Type attrType, object value) {
448                         AddCattr (attrType, typeof (string), value);
449                 }
450
451                 private void AddResource (ResourceInfo res) {
452                         foreach (ResourceInfo res2 in resources) {
453                                 if (res.name == res2.name) {
454
455                                 }
456                         }
457                         resources.Add (res);
458                 }
459
460                 private void PrintVersion () {
461                         Console.WriteLine ("Mono Assembly Linker (al.exe) version " + Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
462                 }
463
464                 private void Version () {
465                         PrintVersion ();
466                         Environment.Exit (0);
467                 }
468
469                 private void Usage () {
470                         PrintVersion ();
471                         
472                         foreach (string s in usage)
473                                 Console.WriteLine (s);
474                         Environment.Exit (0);
475                 }
476
477                 private void Report (int errorNum, string msg) {
478                         Console.WriteLine (String.Format ("ALINK: error A{0:0000}: {1}", errorNum, msg));
479                         Environment.Exit (1);
480                 }
481
482                 private void ReportWarning (int errorNum, string msg) {
483                         Console.WriteLine (String.Format ("ALINK: warning A{0:0000}: {1}", errorNum, msg));
484                 }
485
486                 private void ReportInvalidArgument (string option, string value) {
487                         Report (1012, String.Format ("'{0}' is not a valid setting for option '{1}'", value, option));
488                 }
489
490                 private void ReportMissingArgument (string option) {
491                         Report (1003, String.Format ("Compiler option '{0}' must be followed by an argument", option));
492                 }
493
494                 private void ReportNotImplemented (string option) {
495                         Report (0, String.Format ("Compiler option '{0}' is not implemented", option));
496                 }
497
498                 private void ReportMissingFileSpec (string option) {
499                         Report (1008, String.Format ("Missing file specification for '{0}' command-line option", option));
500                 }
501
502                 private void ReportMissingText (string option) {
503                         Report (1010, String.Format ("Missing ':<text>' for '{0}' option", option));
504                 }
505
506                 // copied from /mcs/mcs/codegen.cs
507                 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob) 
508                 {
509                         // check for possible ECMA key
510                         if (strongNameBlob.Length == 16) {
511                                 // will be rejected if not "the" ECMA key
512                                 an.SetPublicKey (strongNameBlob);
513                         } else {
514                                 // take it, with or without, a private key
515                                 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
516                                 // and make sure we only feed the public part to Sys.Ref
517                                 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
518                                         
519                                 // AssemblyName.SetPublicKey requires an additional header
520                                 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
521
522                                 byte[] encodedPublicKey = new byte [12 + publickey.Length];
523                                 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
524                                 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
525                                 an.SetPublicKey (encodedPublicKey);
526                         }
527                 }
528
529                 private void SetKeyPair (AssemblyName aname)
530                 {
531                         if (keyfile != null) {
532                                 if (!File.Exists (keyfile)) {
533                                         Report (1044, String.Format ("Couldn't open '{0}' key file.", keyfile));
534                                 }
535
536                                 using (FileStream fs = File.OpenRead (keyfile)) {
537                                         byte[] data = new byte [fs.Length];
538                                         try {
539                                                 fs.Read (data, 0, data.Length);
540
541                                                 if (delaysign) {
542                                                         SetPublicKey (aname, data);
543                                                 } else {
544                                                         CryptoConvert.FromCapiPrivateKeyBlob (data);
545                                                         aname.KeyPair = new StrongNameKeyPair (data);
546                                                 }
547                                         }
548                                         catch (CryptographicException) {
549                                                 if (!delaysign) {
550                                                         if (data.Length == 16) {
551                                                                 // error # is different for ECMA key
552                                                                 Report (1019, "Could not strongname the assembly. " + 
553                                                                         "ECMA key can only be used to delay-sign assemblies");
554                                                         } else {
555                                                                 Report (1028, String.Format ("Key file {0}' is missing it's private key " +
556                                                                         "or couldn't be decoded.", keyfile));
557                                                         }
558                                                 } else {
559                                                         Report (1044, String.Format ("Couldn't decode '{0}' key file.", keyfile));
560                                                 }
561                                         }
562                                         fs.Close ();
563                                 }
564                         } else if (keyname != null) {
565                                 // delay-sign doesn't apply to key containers
566                                 aname.KeyPair = new StrongNameKeyPair (keyname);
567                         }
568                 }
569                 
570                 private void DoIt () {
571                         AssemblyName aname = new AssemblyName ();
572                         aname.Name = Path.GetFileNameWithoutExtension (outFile);
573                         SetKeyPair (aname);
574
575                         string fileName = Path.GetFileName (outFile);
576
577                         AssemblyBuilder ab;
578                         
579                         /*
580                          * Emit Manifest
581                          * */
582
583                         if(isTemplateFile) {
584                                 
585                                 byte[] pk;
586                                 AssemblyName myAssm = new AssemblyName();
587                                 myAssm.Name = Path.GetFileNameWithoutExtension (templateFile);
588                                 Assembly assembly = Assembly.Load(myAssm);
589         
590                                 if (!IsStrongNamed(assembly)){
591                                         Report (1055, String.Format ("Assembly specified does not have Strong Name '{0}'","template"));
592                       }
593                                 pk = assembly.GetName().GetPublicKey();
594
595                                 aname.SetPublicKey(pk);
596                                 aname.HashAlgorithm = assembly.GetName().HashAlgorithm;
597                                 aname.Version = assembly.GetName().Version;
598                                 aname.HashAlgorithm = assembly.GetName().HashAlgorithm;
599                         }
600
601                         if (fileName != outFile)
602                                 ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
603                         else
604                                 ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
605
606                         foreach (CustomAttributeBuilder cb in cattrs)
607                                 ab.SetCustomAttribute (cb);
608
609                         /*
610                          * Emit modules
611                          */
612
613                         foreach (ModuleInfo mod in inputFiles) {
614                                 MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
615                                 if (mi == null)
616                                         Report (0, "Cannot add modules on this runtime: try the Mono runtime instead.");
617
618                                 if (mod.target != null) {
619                                         File.Copy (mod.fileName, mod.target, true);
620                                         mod.fileName = mod.target;
621                                 }
622
623                                 bool isAssembly = false;
624                                 try {
625                                         AssemblyName.GetAssemblyName (mod.fileName);
626                                         isAssembly = true;
627                                 }
628                                 catch (Exception) {
629                                 }
630
631                                 if (isAssembly)
632                                         ReportWarning (1020, "Ignoring included assembly '" + mod.fileName + "'");
633                                 else
634                                         mi.Invoke (ab, new object [] { mod.fileName });
635                         }
636
637                         /*
638                          * Set entry point
639                          */
640
641                         if (entryPoint != null) {
642                                 string mainClass = entryPoint.Substring (0, entryPoint.LastIndexOf ('.'));
643                                 string mainMethod = entryPoint.Substring (entryPoint.LastIndexOf ('.') + 1);
644
645                                 MethodInfo mainMethodInfo = null;
646
647                                 try {
648                                         Type mainType = ab.GetType (mainClass);
649                                         if (mainType != null)
650                                                 mainMethodInfo = mainType.GetMethod (mainMethod);
651                                 }
652                                 catch (Exception ex) {
653                                         Console.WriteLine (ex);
654                                 }
655                                 if (mainMethodInfo != null)
656                                         ab.SetEntryPoint (mainMethodInfo);
657                                 else
658                                         Report (1037, "Unable to find the entry point method '" + entryPoint + "'");
659                         }
660
661                         /*
662                          * Emit resources
663                          */
664
665                         ab.DefineVersionInfoResource ();
666
667                         if (win32IconFile != null) {
668                                 try {
669                                         MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
670                                         if (mi == null)
671                                                 Report (0, "Cannot embed win32 icons on this runtime: try the Mono runtime instead.");
672                                         mi.Invoke (ab, new object [] {  win32IconFile });
673                                 }
674                                 catch (Exception ex) {
675                                         Report (1031, "Error reading icon '" + win32IconFile + "' --" + ex);
676                                 }
677                         }
678
679                         if (win32ResFile != null) {
680                                 try {
681                                         ab.DefineUnmanagedResource (win32ResFile);
682                                 }
683                                 catch (Exception ex) {
684                                         Report (1019, "Metadata failure creating assembly -- " + ex);
685                                 }
686                         }
687
688                         foreach (ResourceInfo res in resources) {
689                                 if (res.name == null)
690                                         res.name = Path.GetFileName (res.fileName);
691
692                                 foreach (ResourceInfo res2 in resources)
693                                         if ((res != res2) && (res.name == res2.name))
694                                                 Report (1046, String.Format ("Resource identifier '{0}' has already been used in this assembly", res.name));
695
696                                 if (res.isEmbedded) {
697                                         MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
698                                                 null, CallingConventions.Any, new Type [] { typeof (string), typeof (string) }, null);
699                                         if (mi == null)
700                                                 Report (0, "Cannot embed resources on this runtime: try the Mono runtime instead.");
701                                         mi.Invoke (ab, new object [] { res.name, res.fileName });
702                                 }
703                                 else {
704                                         if (res.target != null) {
705                                                 File.Copy (res.fileName, res.target, true);
706                                                 res.fileName = res.target;
707                                         }
708
709                                         ab.AddResourceFile (res.name, res.fileName,
710                                                         res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
711                                 }
712                         }
713
714                         try {
715                                 ab.Save (fileName);
716                         }
717                         catch (Exception ex) {
718                                 Report (1019, "Metadata failure creating assembly -- " + ex);
719                         }
720                 }
721
722                 private void LoadArgs (string file, ArrayList args) {
723                         StreamReader f = null;
724                         string line;
725                         try {
726                                 f = new StreamReader (file);
727
728                                 StringBuilder sb = new StringBuilder ();
729                         
730                                 while ((line = f.ReadLine ()) != null){
731                                         int t = line.Length;
732
733                                         for (int i = 0; i < t; i++){
734                                                 char c = line [i];
735                                                 
736                                                 if (c == '"' || c == '\''){
737                                                         char end = c;
738                                                         
739                                                         for (i++; i < t; i++){
740                                                                 c = line [i];
741
742                                                                 if (c == end)
743                                                                         break;
744                                                                 sb.Append (c);
745                                                         }
746                                                 } else if (c == ' '){
747                                                         if (sb.Length > 0){
748                                                                 args.Add (sb.ToString ());
749                                                                 sb.Length = 0;
750                                                         }
751                                                 } else
752                                                         sb.Append (c);
753                                         }
754                                         if (sb.Length > 0){
755                                                 args.Add (sb.ToString ());
756                                                 sb.Length = 0;
757                                         }
758                                 }
759                         } catch (Exception ex) {
760                                 Report (1007, "Error opening response file '" + file + "' -- '" + ex.Message + "'");
761                         } finally {
762                                 if (f != null)
763                                         f.Close ();
764                         }
765                 }
766
767                 string[] usage = {
768                         "Usage: al [options] [sources]",
769                         "Options: ('/out' must be specified)",
770                         "",
771                         "  /? or /help               Display this usage message",
772                         "  @<filename>               Read response file for more options",
773                         "  /algid:<id>               Algorithm used to hash files (in hexadecimal)",
774                         "  /base[address]:<addr>     Base address for the library",
775                         "  /bugreport:<filename>     Create a 'Bug Report' file",
776                         "  /comp[any]:<text>         Company name",
777                         "  /config[uration]:<text>   Configuration string",
778                         "  /copy[right]:<text>       Copyright message",
779                         "  /c[ulture]:<text>         Supported culture",
780                         "  /delay[sign][+|-]         Delay sign this assembly",
781                         "  /descr[iption]:<text>     Description",
782                         "  /e[vidence]:<filename>    Security evidence file to embed",
783                         "  /fileversion:<version>    Optional Win32 version (overrides assembly version)",
784                         "  /flags:<flags>            Assembly flags  (in hexadecimal)",
785                         "  /fullpaths                Display files using fully-qualified filenames",
786                         "  /keyf[ile]:<filename>     File containing key to sign the assembly",
787                         "  /keyn[ame]:<text>         Key container name of key to sign assembly",
788                         "  /main:<method>            Specifies the method name of the entry point",
789                         "  /nologo                   Suppress the startup banner and copyright message",
790                         "  /out:<filename>           Output file name for the assembly manifest",
791                         "  /prod[uct]:<text>         Product name",
792                         "  /productv[ersion]:<text>  Product version",
793                         "  /t[arget]:lib[rary]       Create a library",
794                         "  /t[arget]:exe             Create a console executable",
795                         "  /t[arget]:win[exe]        Create a Windows executable",
796                         "  /template:<filename>      Specifies an assembly to get default options from",
797                         "  /title:<text>             Title",
798                         "  /trade[mark]:<text>       Trademark message",
799                         "  /v[ersion]:<version>      Version (use * to auto-generate remaining numbers)",
800                         "  /win32icon:<filename>     Use this icon for the output",
801                         "  /win32res:<filename>      Specifies the Win32 resource file",
802                         "",
803                         "Sources: (at least one source input is required)",
804                         "  <filename>[,<targetfile>] add file to assembly",
805                         "  /embed[resource]:<filename>[,<name>[,Private]]",
806                         "                            embed the file as a resource in the assembly",
807                         "  /link[resource]:<filename>[,<name>[,<targetfile>[,Private]]]",
808                         "                            link the file as a resource to the assembly",
809                 };
810
811         }
812 }