]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CCode/Source/GenAcpiTable/GenAcpiTable.c
Add checking code for GenAcpiTable tools.
[mirror_edk2.git] / Tools / CCode / Source / GenAcpiTable / GenAcpiTable.c
1 /*++
2
3 Copyright (c) 2004-2006 Intel Corporation. All rights reserved
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 GenAcpiTable.c
15
16 Abstract:
17
18 A utility that extracts the .DATA section from a PE/COFF image.
19
20 --*/
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include <Common/UefiBaseTypes.h>
27 #include <Common/EfiImage.h> // for PE32 structure definitions
28
29 #include "CommonLib.h"
30 #include "EfiUtilityMsgs.h"
31
32 //
33 // Acpi Table definition
34 //
35 #include "Acpi.h"
36 #include "Acpi1_0.h"
37 #include "Acpi2_0.h"
38 #include "Acpi3_0.h"
39 #include "MemoryMappedConfigurationSpaceAccessTable.h"
40
41 //
42 // Version of this utility
43 //
44 #define UTILITY_NAME "GenAcpiTable"
45 #define UTILITY_MAJOR_VERSION 0
46 #define UTILITY_MINOR_VERSION 11
47
48 //
49 // Define the max length of a filename
50 //
51 #define MAX_PATH 256
52 #define DEFAULT_OUTPUT_EXTENSION ".acpi"
53
54 //
55 // Use this to track our command-line options and globals
56 //
57 struct {
58 INT8 OutFileName[MAX_PATH];
59 INT8 InFileName[MAX_PATH];
60 } mOptions;
61
62 //
63 // Use these to convert from machine type value to a named type
64 //
65 typedef struct {
66 UINT16 Value;
67 INT8 *Name;
68 } STRING_LOOKUP;
69
70 static STRING_LOOKUP mMachineTypes[] = {
71 EFI_IMAGE_MACHINE_IA32,
72 "IA32",
73 EFI_IMAGE_MACHINE_IA64,
74 "IA64",
75 EFI_IMAGE_MACHINE_EBC,
76 "EBC",
77 0,
78 NULL
79 };
80
81 static STRING_LOOKUP mSubsystemTypes[] = {
82 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
83 "EFI application",
84 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,
85 "EFI boot service driver",
86 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,
87 "EFI runtime driver",
88 0,
89 NULL
90 };
91 //
92 // Function prototypes
93 //
94 static
95 void
96 Version (
97 VOID
98 );
99
100 static
101 void
102 Usage (
103 VOID
104 );
105
106 static
107 STATUS
108 ParseCommandLine (
109 int Argc,
110 char *Argv[]
111 );
112
113 static
114 STATUS
115 CheckAcpiTable (
116 VOID *AcpiTable,
117 UINT32 Length
118 );
119
120 static
121 STATUS
122 CheckPE32File (
123 INT8 *FileName,
124 FILE *Fptr,
125 UINT16 *MachineType,
126 UINT16 *SubSystem
127 );
128
129 static
130 STATUS
131 ProcessFile (
132 INT8 *InFileName,
133 INT8 *OutFileName
134 );
135
136 static
137 void
138 DumpImage (
139 INT8 *FileName
140 );
141
142 main (
143 int Argc,
144 char *Argv[]
145 )
146 /*++
147
148 Routine Description:
149
150
151 Arguments:
152
153 Argc - standard C main() argument count
154
155 Argv - standard C main() argument list
156
157 Returns:
158
159 0 success
160 non-zero otherwise
161
162 --*/
163 // GC_TODO: ] - add argument and description to function comment
164 {
165 UINT32 Status;
166
167 SetUtilityName (UTILITY_NAME);
168 //
169 // Parse the command line arguments
170 //
171 if (ParseCommandLine (Argc, Argv)) {
172 return STATUS_ERROR;
173 }
174 //
175 // Make sure we don't have the same filename for input and output files
176 //
177 if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {
178 Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");
179 goto Finish;
180 }
181 //
182 // Process the file
183 //
184 ProcessFile (mOptions.InFileName, mOptions.OutFileName);
185 Finish:
186 Status = GetUtilityStatus ();
187 return Status;
188 }
189
190 static
191 STATUS
192 ProcessFile (
193 INT8 *InFileName,
194 INT8 *OutFileName
195 )
196 /*++
197
198 Routine Description:
199
200 Process a PE32 EFI file.
201
202 Arguments:
203
204 InFileName - Name of the PE32 EFI file to process.
205 OutFileName - Name of the output file for the processed data.
206
207 Returns:
208
209 0 - successful
210
211 --*/
212 {
213 STATUS Status;
214 UINTN Index;
215 FILE *InFptr;
216 FILE *OutFptr;
217 UINT16 MachineType;
218 UINT16 SubSystem;
219 UINT32 PESigOffset;
220 EFI_IMAGE_FILE_HEADER FileHeader;
221 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
222 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
223 EFI_IMAGE_SECTION_HEADER SectionHeader;
224 UINT8 *Buffer;
225 long SaveFilePosition;
226
227 InFptr = NULL;
228 OutFptr = NULL;
229 Buffer = NULL;
230 Status = STATUS_ERROR;
231 //
232 // Try to open the input file
233 //
234 if ((InFptr = fopen (InFileName, "rb")) == NULL) {
235 Error (NULL, 0, 0, InFileName, "failed to open input file for reading");
236 return STATUS_ERROR;
237 }
238 //
239 // Double-check the file to make sure it's what we expect it to be
240 //
241 if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {
242 goto Finish;
243 }
244 //
245 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit
246 // offset (from the start of the file) to the PE signature, which always
247 // follows the MSDOS stub. The PE signature is immediately followed by the
248 // COFF file header.
249 //
250 //
251 if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {
252 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);
253 goto Finish;
254 }
255
256 if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {
257 Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");
258 goto Finish;
259 }
260
261 if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {
262 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");
263 goto Finish;
264 }
265 //
266 // We should now be at the COFF file header. Read it in and verify it's
267 // of an image type we support.
268 //
269 if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {
270 Error (NULL, 0, 0, InFileName, "failed to read file header from image");
271 goto Finish;
272 }
273
274 if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64) && (FileHeader.Machine != EFI_IMAGE_MACHINE_X64)) {
275 Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);
276 goto Finish;
277 }
278 //
279 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+
280 //
281 SaveFilePosition = ftell (InFptr);
282 if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {
283 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");
284 goto Finish;
285 }
286
287 if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
288 if (fseek (InFptr, SaveFilePosition, SEEK_SET) != 0) {
289 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");
290 goto Finish;
291 }
292
293 if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {
294 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");
295 goto Finish;
296 }
297 }
298 //
299 // Search for the ".data" section
300 //
301 for (Index = 0; Index < FileHeader.NumberOfSections; Index++) {
302 if (fread (&SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER), 1, InFptr) != 1) {
303 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");
304 goto Finish;
305 }
306
307 if (strcmp (SectionHeader.Name, ".data") == 0 || strcmp (SectionHeader.Name, ".sdata") == 0) {
308 if (fseek (InFptr, SectionHeader.PointerToRawData, SEEK_SET) != 0) {
309 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");
310 goto Finish;
311 }
312
313 Buffer = (UINT8 *) malloc (SectionHeader.Misc.VirtualSize);
314 if (Buffer == NULL) {
315 Status = EFI_OUT_OF_RESOURCES;
316 goto Finish;
317 }
318 if (fread (Buffer, SectionHeader.Misc.VirtualSize, 1, InFptr) != 1) {
319 Error (NULL, 0, 0, InFileName, "failed to .data section");
320 goto Finish;
321 }
322
323 //
324 // Check Acpi Table
325 //
326 if (CheckAcpiTable (Buffer, SectionHeader.Misc.VirtualSize) != STATUS_SUCCESS) {
327 Error (NULL, 0, 0, InFileName, "failed to check ACPI table");
328 goto Finish;
329 }
330
331 //
332 // Now open our output file
333 //
334 if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {
335 Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");
336 goto Finish;
337 }
338
339 if (fwrite (Buffer, SectionHeader.Misc.VirtualSize, 1, OutFptr) != 1) {
340 Error (NULL, 0, 0, OutFileName, "failed to write .data section");
341 goto Finish;
342 }
343
344 Status = STATUS_SUCCESS;
345 goto Finish;
346 }
347 }
348
349 Status = STATUS_ERROR;
350
351 Finish:
352 if (InFptr != NULL) {
353 fclose (InFptr);
354 }
355 //
356 // Close the output file. If there was an error, delete the output file so
357 // that a subsequent build will rebuild it.
358 //
359 if (OutFptr != NULL) {
360 fclose (OutFptr);
361 if (GetUtilityStatus () == STATUS_ERROR) {
362 remove (OutFileName);
363 }
364 }
365
366 //
367 // Free up our buffer
368 //
369 if (Buffer != NULL) {
370 free (Buffer);
371 }
372
373 return Status;
374 }
375
376 static
377 STATUS
378 CheckAcpiTable (
379 VOID *AcpiTable,
380 UINT32 Length
381 )
382 /*++
383
384 Routine Description:
385
386 Check Acpi Table
387
388 Arguments:
389
390 AcpiTable Buffer for AcpiSection
391 Length AcpiSection Length
392
393 Returns:
394
395 0 success
396 non-zero otherwise
397
398 --*/
399 {
400 EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader;
401 EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
402 UINT32 ExpectedLength;
403
404 AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable;
405
406 //
407 // Generic check for AcpiTable length.
408 //
409 if (AcpiHeader->Length > Length) {
410 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass AcpiTable Length check");
411 return STATUS_ERROR;
412 }
413
414 //
415 // Currently, we only check must-have tables: FADT, FACS, DSDT,
416 // and some important tables: MADT, MCFG.
417 //
418 switch (AcpiHeader->Signature) {
419
420 //
421 // "FACP" Fixed ACPI Description Table
422 //
423 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
424 switch (AcpiHeader->Revision) {
425 case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
426 ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE);
427 break;
428 case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
429 ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE);
430 break;
431 case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
432 ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE);
433 break;
434 default:
435 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP revision check");
436 return STATUS_ERROR;
437 }
438 if (ExpectedLength != AcpiHeader->Length) {
439 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP Length check");
440 return STATUS_ERROR;
441 }
442 break;
443
444 //
445 // "FACS" Firmware ACPI Control Structure
446 //
447 case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
448 Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable;
449 if ((Facs->Version != 0) &&
450 (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
451 (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){
452 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS version check");
453 return STATUS_ERROR;
454 }
455 if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&
456 (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&
457 (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) {
458 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS Length check");
459 return STATUS_ERROR;
460 }
461 break;
462
463 //
464 // "DSDT" Differentiated System Description Table
465 //
466 case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
467 if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) {
468 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT revision check");
469 return STATUS_ERROR;
470 }
471 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {
472 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT Length check");
473 return STATUS_ERROR;
474 }
475 break;
476
477 //
478 // "APIC" Multiple APIC Description Table
479 //
480 case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
481 if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&
482 (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&
483 (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) {
484 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC revision check");
485 return STATUS_ERROR;
486 }
487 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) {
488 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC Length check");
489 return STATUS_ERROR;
490 }
491 break;
492
493 //
494 // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table
495 //
496 case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
497 if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {
498 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG revision check");
499 return STATUS_ERROR;
500 }
501 if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) {
502 Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG Length check");
503 return STATUS_ERROR;
504 }
505 break;
506
507 //
508 // Other table pass check
509 //
510 default:
511 break;
512 }
513
514 return STATUS_SUCCESS;
515 }
516
517 static
518 STATUS
519 CheckPE32File (
520 INT8 *FileName,
521 FILE *Fptr,
522 UINT16 *MachineType,
523 UINT16 *SubSystem
524 )
525 /*++
526
527 Routine Description:
528
529 GC_TODO: Add function description
530
531 Arguments:
532
533 FileName - GC_TODO: add argument description
534 Fptr - GC_TODO: add argument description
535 MachineType - GC_TODO: add argument description
536 SubSystem - GC_TODO: add argument description
537
538 Returns:
539
540 GC_TODO: add return values
541
542 --*/
543 {
544 /*++
545
546 Routine Description:
547
548 Given a file pointer to a supposed PE32 image file, verify that it is indeed a
549 PE32 image file, and then return the machine type in the supplied pointer.
550
551 Arguments:
552
553 Fptr File pointer to the already-opened PE32 file
554 MachineType Location to stuff the machine type of the PE32 file. This is needed
555 because the image may be Itanium-based, IA32, or EBC.
556
557 Returns:
558
559 0 success
560 non-zero otherwise
561
562 --*/
563 EFI_IMAGE_DOS_HEADER DosHeader;
564 EFI_IMAGE_FILE_HEADER FileHdr;
565 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;
566 UINT32 PESig;
567 STATUS Status;
568
569 Status = STATUS_ERROR;
570 //
571 // Position to the start of the file
572 //
573 fseek (Fptr, 0, SEEK_SET);
574 //
575 // Read the DOS header
576 //
577 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
578 Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");
579 goto Finish;
580 }
581 //
582 // Check the magic number (0x5A4D)
583 //
584 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
585 Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");
586 goto Finish;
587 }
588 //
589 // Position into the file and check the PE signature
590 //
591 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);
592 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {
593 Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");
594 goto Finish;
595 }
596 //
597 // Check the PE signature in the header "PE\0\0"
598 //
599 if (PESig != EFI_IMAGE_NT_SIGNATURE) {
600 Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");
601 goto Finish;
602 }
603 //
604 // Read the file header
605 //
606 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {
607 Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");
608 goto Finish;
609 }
610 //
611 // Read the optional header so we can get the subsystem
612 //
613 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {
614 Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");
615 goto Finish;
616 }
617
618 *SubSystem = OptionalHdr.Subsystem;
619 //
620 // Good to go
621 //
622 Status = STATUS_SUCCESS;
623 Finish:
624 fseek (Fptr, 0, SEEK_SET);
625 return Status;
626 }
627
628 static
629 int
630 ParseCommandLine (
631 int Argc,
632 char *Argv[]
633 )
634 /*++
635
636 Routine Description:
637
638 Given the Argc/Argv program arguments, and a pointer to an options structure,
639 parse the command-line options and check their validity.
640
641
642 Arguments:
643
644 Argc - standard C main() argument count
645 Argv - standard C main() argument list
646
647 Returns:
648
649 STATUS_SUCCESS success
650 non-zero otherwise
651
652 --*/
653 // GC_TODO: ] - add argument and description to function comment
654 {
655 //
656 // Clear out the options
657 //
658 memset ((char *) &mOptions, 0, sizeof (mOptions));
659 //
660 // Skip over the program name
661 //
662 Argc--;
663 Argv++;
664
665 if (Argc < 1) {
666 Usage();
667 return STATUS_ERROR;
668 }
669
670 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
671 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
672 Usage();
673 return STATUS_ERROR;
674 }
675
676 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {
677 Version();
678 return STATUS_ERROR;
679 }
680
681 if (Argc != 2) {
682 Usage ();
683 return STATUS_ERROR;
684 }
685
686 strcpy (mOptions.InFileName, Argv[0]);
687 //
688 // Next argument
689 //
690 Argv++;
691 Argc--;
692
693 strcpy (mOptions.OutFileName, Argv[0]);
694
695 return STATUS_SUCCESS;
696 }
697
698 static
699 void
700 Version (
701 VOID
702 )
703 {
704 printf ("%s v%d.%d -EDK Utility for generating ACPI Table image from an EFI PE32 image.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
705 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
706 }
707
708
709 static
710 void
711 Usage (
712 VOID
713 )
714 /*++
715
716 Routine Description:
717
718 Print usage information for this utility.
719
720 Arguments:
721
722 None.
723
724 Returns:
725
726 Nothing.
727
728 --*/
729 {
730 int Index;
731 static const char *Msg[] = {
732 "\nUsage: "UTILITY_NAME " {-h|--help|-?|/?|-V|--version} InFileName OutFileName",
733 " where:",
734 " InFileName - name of the input PE32 file",
735 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,
736 NULL
737 };
738
739 Version();
740 for (Index = 0; Msg[Index] != NULL; Index++) {
741 fprintf (stdout, "%s\n", Msg[Index]);
742 }
743 }