1 /******************************************************************************
2  *
3  * Module Name: asfile - Main module for the acpi source processor utility
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpisrc.h"
45 #include "acapps.h"
46 
47 /* Local prototypes */
48 
49 void
50 AsDoWildcard (
51     ACPI_CONVERSION_TABLE   *ConversionTable,
52     char                    *SourcePath,
53     char                    *TargetPath,
54     int                     MaxPathLength,
55     int                     FileType,
56     char                    *WildcardSpec);
57 
58 BOOLEAN
59 AsDetectLoneLineFeeds (
60     char                    *Filename,
61     char                    *Buffer);
62 
63 static ACPI_INLINE int
64 AsMaxInt (int a, int b)
65 {
66     return (a > b ? a : b);
67 }
68 
69 
70 /******************************************************************************
71  *
72  * FUNCTION:    AsDoWildcard
73  *
74  * DESCRIPTION: Process files via wildcards
75  *
76  ******************************************************************************/
77 
78 void
79 AsDoWildcard (
80     ACPI_CONVERSION_TABLE   *ConversionTable,
81     char                    *SourcePath,
82     char                    *TargetPath,
83     int                     MaxPathLength,
84     int                     FileType,
85     char                    *WildcardSpec)
86 {
87     void                    *DirInfo;
88     char                    *Filename;
89     char                    *SourceDirPath;
90     char                    *TargetDirPath;
91     char                    RequestedFileType;
92 
93 
94     if (FileType == FILE_TYPE_DIRECTORY)
95     {
96         RequestedFileType = REQUEST_DIR_ONLY;
97     }
98     else
99     {
100         RequestedFileType = REQUEST_FILE_ONLY;
101     }
102 
103     VERBOSE_PRINT (("Checking for %s source files in directory \"%s\"\n",
104             WildcardSpec, SourcePath));
105 
106     /* Open the directory for wildcard search */
107 
108     DirInfo = AcpiOsOpenDirectory (SourcePath, WildcardSpec, RequestedFileType);
109     if (DirInfo)
110     {
111         /*
112          * Get all of the files that match both the
113          * wildcard and the requested file type
114          */
115         while ((Filename = AcpiOsGetNextFilename (DirInfo)))
116         {
117             /* Looking for directory files, must check file type */
118 
119             switch (RequestedFileType)
120             {
121             case REQUEST_DIR_ONLY:
122 
123                 /* If we actually have a dir, process the subtree */
124 
125                 if (!AsCheckForDirectory (SourcePath, TargetPath, Filename,
126                         &SourceDirPath, &TargetDirPath))
127                 {
128                     VERBOSE_PRINT (("Subdirectory: %s\n", Filename));
129 
130                     AsProcessTree (ConversionTable, SourceDirPath, TargetDirPath);
131                     free (SourceDirPath);
132                     free (TargetDirPath);
133                 }
134                 break;
135 
136             case REQUEST_FILE_ONLY:
137 
138                 /* Otherwise, this is a file, not a directory */
139 
140                 VERBOSE_PRINT (("File: %s\n", Filename));
141 
142                 AsProcessOneFile (ConversionTable, SourcePath, TargetPath,
143                         MaxPathLength, Filename, FileType);
144                 break;
145 
146             default:
147 
148                 break;
149             }
150         }
151 
152         /* Cleanup */
153 
154         AcpiOsCloseDirectory (DirInfo);
155     }
156 }
157 
158 
159 /******************************************************************************
160  *
161  * FUNCTION:    AsProcessTree
162  *
163  * DESCRIPTION: Process the directory tree. Files with the extension ".C" and
164  *              ".H" are processed as the tree is traversed.
165  *
166  ******************************************************************************/
167 
168 ACPI_NATIVE_INT
169 AsProcessTree (
170     ACPI_CONVERSION_TABLE   *ConversionTable,
171     char                    *SourcePath,
172     char                    *TargetPath)
173 {
174     int                     MaxPathLength;
175 
176 
177     MaxPathLength = AsMaxInt (strlen (SourcePath), strlen (TargetPath));
178 
179     if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT))
180     {
181         if (ConversionTable->Flags & FLG_LOWERCASE_DIRNAMES)
182         {
183             AcpiUtStrlwr (TargetPath);
184         }
185 
186         VERBOSE_PRINT (("Creating Directory \"%s\"\n", TargetPath));
187         if (mkdir (TargetPath))
188         {
189             if (errno != EEXIST)
190             {
191                 printf ("Could not create target directory\n");
192                 return (-1);
193             }
194         }
195     }
196 
197     /* Do the C source files */
198 
199     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
200             FILE_TYPE_SOURCE, "*.c");
201 
202     /* Do the C header files */
203 
204     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
205             FILE_TYPE_HEADER, "*.h");
206 
207     /* Do the Lex file(s) */
208 
209     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
210             FILE_TYPE_SOURCE, "*.l");
211 
212     /* Do the yacc file(s) */
213 
214     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
215             FILE_TYPE_SOURCE, "*.y");
216 
217     /* Do any ASL files */
218 
219     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
220             FILE_TYPE_HEADER, "*.asl");
221 
222     /* Do any subdirectories */
223 
224     AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
225             FILE_TYPE_DIRECTORY, "*");
226 
227     return (0);
228 }
229 
230 
231 /******************************************************************************
232  *
233  * FUNCTION:    AsDetectLoneLineFeeds
234  *
235  * DESCRIPTION: Find LF without CR.
236  *
237  ******************************************************************************/
238 
239 BOOLEAN
240 AsDetectLoneLineFeeds (
241     char                    *Filename,
242     char                    *Buffer)
243 {
244     UINT32                  i = 1;
245     UINT32                  LfCount = 0;
246     UINT32                  LineCount = 0;
247 
248 
249     if (!Buffer[0])
250     {
251         return (FALSE);
252     }
253 
254     while (Buffer[i])
255     {
256         if (Buffer[i] == 0x0A)
257         {
258             if (Buffer[i-1] != 0x0D)
259             {
260                 LfCount++;
261             }
262             LineCount++;
263         }
264         i++;
265     }
266 
267     if (LfCount)
268     {
269         if (LineCount == LfCount)
270         {
271             if (!Gbl_IgnoreLoneLineFeeds)
272             {
273                 printf ("%s: ****File has UNIX format**** (LF only, not CR/LF) %u lines\n",
274                     Filename, LfCount);
275             }
276         }
277         else
278         {
279             printf ("%s: %u lone linefeeds in file\n", Filename, LfCount);
280         }
281         return (TRUE);
282     }
283 
284     return (FALSE);
285 }
286 
287 
288 /******************************************************************************
289  *
290  * FUNCTION:    AsConvertFile
291  *
292  * DESCRIPTION: Perform the requested transforms on the file buffer (as
293  *              determined by the ConversionTable and the FileType).
294  *
295  ******************************************************************************/
296 
297 void
298 AsConvertFile (
299     ACPI_CONVERSION_TABLE   *ConversionTable,
300     char                    *FileBuffer,
301     char                    *Filename,
302     ACPI_NATIVE_INT         FileType)
303 {
304     UINT32                  i;
305     UINT32                  Functions;
306     ACPI_STRING_TABLE       *StringTable;
307     ACPI_IDENTIFIER_TABLE   *ConditionalTable;
308     ACPI_IDENTIFIER_TABLE   *LineTable;
309     ACPI_TYPED_IDENTIFIER_TABLE *StructTable;
310     ACPI_IDENTIFIER_TABLE   *SpecialMacroTable;
311 
312 
313     switch (FileType)
314     {
315     case FILE_TYPE_SOURCE:
316 
317         Functions           = ConversionTable->SourceFunctions;
318         StringTable         = ConversionTable->SourceStringTable;
319         LineTable           = ConversionTable->SourceLineTable;
320         ConditionalTable    = ConversionTable->SourceConditionalTable;
321         StructTable         = ConversionTable->SourceStructTable;
322         SpecialMacroTable   = ConversionTable->SourceSpecialMacroTable;
323        break;
324 
325     case FILE_TYPE_HEADER:
326 
327         Functions           = ConversionTable->HeaderFunctions;
328         StringTable         = ConversionTable->HeaderStringTable;
329         LineTable           = ConversionTable->HeaderLineTable;
330         ConditionalTable    = ConversionTable->HeaderConditionalTable;
331         StructTable         = ConversionTable->HeaderStructTable;
332         SpecialMacroTable   = ConversionTable->HeaderSpecialMacroTable;
333         break;
334 
335     case FILE_TYPE_PATCH:
336 
337         Functions           = ConversionTable->PatchFunctions;
338         StringTable         = ConversionTable->PatchStringTable;
339         LineTable           = ConversionTable->PatchLineTable;
340         ConditionalTable    = ConversionTable->PatchConditionalTable;
341         StructTable         = ConversionTable->PatchStructTable;
342         SpecialMacroTable   = ConversionTable->PatchSpecialMacroTable;
343         break;
344 
345     default:
346 
347         printf ("Unknown file type, cannot process\n");
348         return;
349     }
350 
351 
352     Gbl_StructDefs = strstr (FileBuffer, "/* acpisrc:StructDefs");
353     Gbl_Files++;
354     VERBOSE_PRINT (("Processing %u bytes\n",
355         (unsigned int) strlen (FileBuffer)));
356 
357     if (Gbl_Cleanup)
358     {
359         AsRemoveExtraLines (FileBuffer, Filename);
360         AsRemoveSpacesAfterPeriod (FileBuffer, Filename);
361     }
362 
363     if (ConversionTable->LowerCaseTable)
364     {
365         for (i = 0; ConversionTable->LowerCaseTable[i].Identifier; i++)
366         {
367             AsLowerCaseString (ConversionTable->LowerCaseTable[i].Identifier,
368                                 FileBuffer);
369         }
370     }
371 
372     /* Process all the string replacements */
373 
374     if (StringTable)
375     {
376         for (i = 0; StringTable[i].Target; i++)
377         {
378             AsReplaceString (StringTable[i].Target, StringTable[i].Replacement,
379                     StringTable[i].Type, FileBuffer);
380         }
381     }
382 
383     if (LineTable)
384     {
385         for (i = 0; LineTable[i].Identifier; i++)
386         {
387             AsRemoveLine (FileBuffer, LineTable[i].Identifier);
388         }
389     }
390 
391     if (ConditionalTable)
392     {
393         for (i = 0; ConditionalTable[i].Identifier; i++)
394         {
395             AsRemoveConditionalCompile (FileBuffer, ConditionalTable[i].Identifier);
396         }
397     }
398 
399 #ifdef _OBSOLETE_FUNCTIONS
400     if (MacroTable)
401     {
402         for (i = 0; MacroTable[i].Identifier; i++)
403         {
404             AsRemoveMacro (FileBuffer, MacroTable[i].Identifier);
405         }
406     }
407 #endif
408 
409     if (StructTable)
410     {
411         for (i = 0; StructTable[i].Identifier; i++)
412         {
413             AsInsertPrefix (FileBuffer, StructTable[i].Identifier, StructTable[i].Type);
414         }
415     }
416 
417     if (SpecialMacroTable)
418     {
419         for (i = 0; SpecialMacroTable[i].Identifier; i++)
420         {
421             AsCleanupSpecialMacro (FileBuffer, SpecialMacroTable[i].Identifier);
422         }
423     }
424 
425     /* Process the function table */
426 
427     for (i = 0; i < 32; i++)
428     {
429         /* Decode the function bitmap */
430 
431         switch ((1 << i) & Functions)
432         {
433         case 0:
434 
435             /* This function not configured */
436             break;
437 
438         case CVT_COUNT_TABS:
439 
440             AsCountTabs (FileBuffer, Filename);
441             break;
442 
443         case CVT_COUNT_NON_ANSI_COMMENTS:
444 
445             AsCountNonAnsiComments (FileBuffer, Filename);
446             break;
447 
448         case CVT_CHECK_BRACES:
449 
450             AsCheckForBraces (FileBuffer, Filename);
451             break;
452 
453         case CVT_TRIM_LINES:
454 
455             AsTrimLines (FileBuffer, Filename);
456             break;
457 
458         case CVT_COUNT_LINES:
459 
460             AsCountSourceLines (FileBuffer, Filename);
461             break;
462 
463         case CVT_BRACES_ON_SAME_LINE:
464 
465             AsBracesOnSameLine (FileBuffer);
466             break;
467 
468         case CVT_MIXED_CASE_TO_UNDERSCORES:
469 
470             AsMixedCaseToUnderscores (FileBuffer, Filename);
471             break;
472 
473         case CVT_LOWER_CASE_IDENTIFIERS:
474 
475             AsLowerCaseIdentifiers (FileBuffer);
476             break;
477 
478         case CVT_REMOVE_DEBUG_MACROS:
479 
480             AsRemoveDebugMacros (FileBuffer);
481             break;
482 
483         case CVT_TRIM_WHITESPACE:
484 
485             AsTrimWhitespace (FileBuffer);
486             break;
487 
488         case CVT_REMOVE_EMPTY_BLOCKS:
489 
490             AsRemoveEmptyBlocks (FileBuffer, Filename);
491             break;
492 
493         case CVT_REDUCE_TYPEDEFS:
494 
495             AsReduceTypedefs (FileBuffer, "typedef union");
496             AsReduceTypedefs (FileBuffer, "typedef struct");
497             break;
498 
499         case CVT_SPACES_TO_TABS4:
500 
501             AsTabify4 (FileBuffer);
502             break;
503 
504         case CVT_SPACES_TO_TABS8:
505 
506             AsTabify8 (FileBuffer);
507             break;
508 
509         case CVT_COUNT_SHORTMULTILINE_COMMENTS:
510 
511 #ifdef ACPI_FUTURE_IMPLEMENTATION
512             AsTrimComments (FileBuffer, Filename);
513 #endif
514             break;
515 
516         default:
517 
518             printf ("Unknown conversion subfunction opcode\n");
519             break;
520         }
521     }
522 
523     if (ConversionTable->NewHeader)
524     {
525         AsReplaceHeader (FileBuffer, ConversionTable->NewHeader);
526     }
527 }
528 
529 
530 /******************************************************************************
531  *
532  * FUNCTION:    AsProcessOneFile
533  *
534  * DESCRIPTION: Process one source file. The file is opened, read entirely
535  *              into a buffer, converted, then written to a new file.
536  *
537  ******************************************************************************/
538 
539 ACPI_NATIVE_INT
540 AsProcessOneFile (
541     ACPI_CONVERSION_TABLE   *ConversionTable,
542     char                    *SourcePath,
543     char                    *TargetPath,
544     int                     MaxPathLength,
545     char                    *Filename,
546     ACPI_NATIVE_INT         FileType)
547 {
548     char                    *Pathname;
549     char                    *OutPathname = NULL;
550 
551 
552     /* Allocate a file pathname buffer for both source and target */
553 
554     Pathname = calloc (MaxPathLength + strlen (Filename) + 2, 1);
555     if (!Pathname)
556     {
557         printf ("Could not allocate buffer for file pathnames\n");
558         return (-1);
559     }
560 
561     Gbl_FileType = FileType;
562 
563     /* Generate the source pathname and read the file */
564 
565     if (SourcePath)
566     {
567         strcpy (Pathname, SourcePath);
568         strcat (Pathname, "/");
569     }
570 
571     strcat (Pathname, Filename);
572 
573     if (AsGetFile (Pathname, &Gbl_FileBuffer, &Gbl_FileSize))
574     {
575         return (-1);
576     }
577 
578     Gbl_HeaderSize = 0;
579     if (strstr (Filename, ".asl"))
580     {
581         Gbl_HeaderSize = LINES_IN_ASL_HEADER; /* Lines in default ASL header */
582     }
583     else if (strstr (Gbl_FileBuffer, LEGAL_HEADER_SIGNATURE))
584     {
585         Gbl_HeaderSize = LINES_IN_LEGAL_HEADER; /* Normal C file and H header */
586     }
587     else if (strstr (Gbl_FileBuffer, LINUX_HEADER_SIGNATURE))
588     {
589         Gbl_HeaderSize = LINES_IN_LINUX_HEADER; /* Linuxized C file and H header */
590     }
591 
592     /* Process the file in the buffer */
593 
594     Gbl_MadeChanges = FALSE;
595     if (!Gbl_IgnoreLoneLineFeeds && Gbl_HasLoneLineFeeds)
596     {
597         /*
598          * All lone LFs will be converted to CR/LF
599          * (when file is written, Windows version only)
600          */
601         printf ("Converting lone linefeeds\n");
602         Gbl_MadeChanges = TRUE;
603     }
604 
605     AsConvertFile (ConversionTable, Gbl_FileBuffer, Pathname, FileType);
606 
607     if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT))
608     {
609         if (!(Gbl_Overwrite && !Gbl_MadeChanges))
610         {
611             /* Generate the target pathname and write the file */
612 
613             OutPathname = calloc (MaxPathLength + strlen (Filename) + 2 + strlen (TargetPath), 1);
614             if (!OutPathname)
615             {
616                 printf ("Could not allocate buffer for file pathnames\n");
617                 return (-1);
618             }
619 
620             strcpy (OutPathname, TargetPath);
621             if (SourcePath)
622             {
623                 strcat (OutPathname, "/");
624                 strcat (OutPathname, Filename);
625             }
626 
627             AsPutFile (OutPathname, Gbl_FileBuffer, ConversionTable->Flags);
628         }
629     }
630 
631     free (Gbl_FileBuffer);
632     free (Pathname);
633     if (OutPathname)
634     {
635         free (OutPathname);
636     }
637 
638     return (0);
639 }
640 
641 
642 /******************************************************************************
643  *
644  * FUNCTION:    AsCheckForDirectory
645  *
646  * DESCRIPTION: Check if the current file is a valid directory. If not,
647  *              construct the full pathname for the source and target paths.
648  *              Checks for the dot and dot-dot files (they are ignored)
649  *
650  ******************************************************************************/
651 
652 ACPI_NATIVE_INT
653 AsCheckForDirectory (
654     char                    *SourceDirPath,
655     char                    *TargetDirPath,
656     char                    *Filename,
657     char                    **SourcePath,
658     char                    **TargetPath)
659 {
660     char                    *SrcPath;
661     char                    *TgtPath;
662 
663 
664     if (!(strcmp (Filename, ".")) ||
665         !(strcmp (Filename, "..")))
666     {
667         return (-1);
668     }
669 
670     SrcPath = calloc (strlen (SourceDirPath) + strlen (Filename) + 2, 1);
671     if (!SrcPath)
672     {
673         printf ("Could not allocate buffer for directory source pathname\n");
674         return (-1);
675     }
676 
677     TgtPath = calloc (strlen (TargetDirPath) + strlen (Filename) + 2, 1);
678     if (!TgtPath)
679     {
680         printf ("Could not allocate buffer for directory target pathname\n");
681         free (SrcPath);
682         return (-1);
683     }
684 
685     strcpy (SrcPath, SourceDirPath);
686     strcat (SrcPath, "/");
687     strcat (SrcPath, Filename);
688 
689     strcpy (TgtPath, TargetDirPath);
690     strcat (TgtPath, "/");
691     strcat (TgtPath, Filename);
692 
693     *SourcePath = SrcPath;
694     *TargetPath = TgtPath;
695     return (0);
696 }
697 
698 
699 /******************************************************************************
700  *
701  * FUNCTION:    AsGetFile
702  *
703  * DESCRIPTION: Open a file and read it entirely into a an allocated buffer
704  *
705  ******************************************************************************/
706 
707 int
708 AsGetFile (
709     char                    *Filename,
710     char                    **FileBuffer,
711     UINT32                  *FileSize)
712 {
713     FILE                    *File;
714     UINT32                  Size;
715     char                    *Buffer;
716     size_t                  Actual;
717 
718 
719     /* Binary mode leaves CR/LF pairs */
720 
721     File = fopen (Filename, "rb");
722     if (!File)
723     {
724         printf ("Could not open file %s\n", Filename);
725         return (-1);
726     }
727 
728     /* Need file size to allocate a buffer */
729 
730     Size = CmGetFileSize (File);
731     if (Size == ACPI_UINT32_MAX)
732     {
733         printf ("Could not get file size for %s\n", Filename);
734         goto ErrorExit;
735     }
736 
737     /*
738      * Create a buffer for the entire file
739      * Add plenty extra buffer to accommodate string replacements
740      */
741     Gbl_TotalSize += Size;
742 
743     Buffer = calloc (Size * 2, 1);
744     if (!Buffer)
745     {
746         printf ("Could not allocate buffer of size %u\n", Size * 2);
747         goto ErrorExit;
748     }
749 
750     /* Read the entire file */
751 
752     Actual = fread (Buffer, 1, Size, File);
753     if (Actual != Size)
754     {
755         printf ("Could not read the input file %s (%u bytes)\n",
756             Filename, Size);
757         goto ErrorExit;
758     }
759 
760     Buffer [Size] = 0;         /* Null terminate the buffer */
761     fclose (File);
762 
763     /* Check for unix contamination */
764 
765     Gbl_HasLoneLineFeeds = AsDetectLoneLineFeeds (Filename, Buffer);
766 
767     /*
768      * Convert all CR/LF pairs to LF only. We do this locally so that
769      * this code is portable across operating systems.
770      */
771     AsConvertToLineFeeds (Buffer);
772 
773     *FileBuffer = Buffer;
774     *FileSize = Size;
775     return (0);
776 
777 
778 ErrorExit:
779 
780     fclose (File);
781     return (-1);
782 }
783 
784 
785 /******************************************************************************
786  *
787  * FUNCTION:    AsPutFile
788  *
789  * DESCRIPTION: Create a new output file and write the entire contents of the
790  *              buffer to the new file. Buffer must be a zero terminated string
791  *
792  ******************************************************************************/
793 
794 int
795 AsPutFile (
796     char                    *Pathname,
797     char                    *FileBuffer,
798     UINT32                  SystemFlags)
799 {
800     FILE                    *File;
801     UINT32                  FileSize;
802     size_t                  Actual;
803     int                     Status = 0;
804 
805 
806     /* Create the target file */
807 
808     if (!(SystemFlags & FLG_NO_CARRIAGE_RETURNS))
809     {
810         /* Put back the CR before each LF */
811 
812         AsInsertCarriageReturns (FileBuffer);
813     }
814 
815     File = fopen (Pathname, "w+b");
816     if (!File)
817     {
818         perror ("Could not create destination file");
819         printf ("Could not create destination file \"%s\"\n", Pathname);
820         return (-1);
821     }
822 
823     /* Write the buffer to the file */
824 
825     FileSize = strlen (FileBuffer);
826     Actual = fwrite (FileBuffer, 1, FileSize, File);
827     if (Actual != FileSize)
828     {
829         printf ("Error writing output file \"%s\"\n", Pathname);
830         Status = -1;
831     }
832 
833     fclose (File);
834     return (Status);
835 }
836