1 /******************************************************************************
2  *
3  * Module Name: asfile - Main module for the acpi source processor utility
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 
263             LineCount++;
264         }
265         i++;
266     }
267 
268     if (LfCount)
269     {
270         if (LineCount == LfCount)
271         {
272             if (!Gbl_IgnoreLoneLineFeeds)
273             {
274                 printf ("%s: ****File has UNIX format**** (LF only, not CR/LF) %u lines\n",
275                     Filename, LfCount);
276             }
277         }
278         else
279         {
280             printf ("%s: %u lone linefeeds in file\n", Filename, LfCount);
281         }
282 
283         return (TRUE);
284     }
285 
286     return (FALSE);
287 }
288 
289 
290 /******************************************************************************
291  *
292  * FUNCTION:    AsConvertFile
293  *
294  * DESCRIPTION: Perform the requested transforms on the file buffer (as
295  *              determined by the ConversionTable and the FileType).
296  *
297  ******************************************************************************/
298 
299 void
300 AsConvertFile (
301     ACPI_CONVERSION_TABLE   *ConversionTable,
302     char                    *FileBuffer,
303     char                    *Filename,
304     ACPI_NATIVE_INT         FileType)
305 {
306     UINT32                  i;
307     UINT32                  Functions;
308     ACPI_STRING_TABLE       *StringTable;
309     ACPI_IDENTIFIER_TABLE   *ConditionalTable;
310     ACPI_IDENTIFIER_TABLE   *LineTable;
311     ACPI_TYPED_IDENTIFIER_TABLE *StructTable;
312     ACPI_IDENTIFIER_TABLE   *SpecialMacroTable;
313 
314 
315     switch (FileType)
316     {
317     case FILE_TYPE_SOURCE:
318 
319         Functions           = ConversionTable->SourceFunctions;
320         StringTable         = ConversionTable->SourceStringTable;
321         LineTable           = ConversionTable->SourceLineTable;
322         ConditionalTable    = ConversionTable->SourceConditionalTable;
323         StructTable         = ConversionTable->SourceStructTable;
324         SpecialMacroTable   = ConversionTable->SourceSpecialMacroTable;
325        break;
326 
327     case FILE_TYPE_HEADER:
328 
329         Functions           = ConversionTable->HeaderFunctions;
330         StringTable         = ConversionTable->HeaderStringTable;
331         LineTable           = ConversionTable->HeaderLineTable;
332         ConditionalTable    = ConversionTable->HeaderConditionalTable;
333         StructTable         = ConversionTable->HeaderStructTable;
334         SpecialMacroTable   = ConversionTable->HeaderSpecialMacroTable;
335         break;
336 
337     case FILE_TYPE_PATCH:
338 
339         Functions           = ConversionTable->PatchFunctions;
340         StringTable         = ConversionTable->PatchStringTable;
341         LineTable           = ConversionTable->PatchLineTable;
342         ConditionalTable    = ConversionTable->PatchConditionalTable;
343         StructTable         = ConversionTable->PatchStructTable;
344         SpecialMacroTable   = ConversionTable->PatchSpecialMacroTable;
345         break;
346 
347     default:
348 
349         printf ("Unknown file type, cannot process\n");
350         return;
351     }
352 
353 
354     Gbl_StructDefs = strstr (FileBuffer, "/* acpisrc:StructDefs");
355     Gbl_Files++;
356     VERBOSE_PRINT (("Processing %u bytes\n",
357         (unsigned int) strlen (FileBuffer)));
358 
359     if (Gbl_Cleanup)
360     {
361         AsRemoveExtraLines (FileBuffer, Filename);
362         AsRemoveSpacesAfterPeriod (FileBuffer, Filename);
363     }
364 
365     if (ConversionTable->LowerCaseTable)
366     {
367         for (i = 0; ConversionTable->LowerCaseTable[i].Identifier; i++)
368         {
369             AsLowerCaseString (ConversionTable->LowerCaseTable[i].Identifier,
370                 FileBuffer);
371         }
372     }
373 
374     /* Process all the string replacements */
375 
376     if (StringTable)
377     {
378         for (i = 0; StringTable[i].Target; i++)
379         {
380             AsReplaceString (StringTable[i].Target, StringTable[i].Replacement,
381                 StringTable[i].Type, FileBuffer);
382         }
383     }
384 
385     if (LineTable)
386     {
387         for (i = 0; LineTable[i].Identifier; i++)
388         {
389             AsRemoveLine (FileBuffer, LineTable[i].Identifier);
390         }
391     }
392 
393     if (ConditionalTable)
394     {
395         for (i = 0; ConditionalTable[i].Identifier; i++)
396         {
397             AsRemoveConditionalCompile (FileBuffer, ConditionalTable[i].Identifier);
398         }
399     }
400 
401 #ifdef _OBSOLETE_FUNCTIONS
402     if (MacroTable)
403     {
404         for (i = 0; MacroTable[i].Identifier; i++)
405         {
406             AsRemoveMacro (FileBuffer, MacroTable[i].Identifier);
407         }
408     }
409 #endif
410 
411     if (StructTable)
412     {
413         for (i = 0; StructTable[i].Identifier; i++)
414         {
415             AsInsertPrefix (FileBuffer, StructTable[i].Identifier,
416                 StructTable[i].Type);
417         }
418     }
419 
420     if (SpecialMacroTable)
421     {
422         for (i = 0; SpecialMacroTable[i].Identifier; i++)
423         {
424             AsCleanupSpecialMacro (FileBuffer, SpecialMacroTable[i].Identifier);
425         }
426     }
427 
428     /* Process the function table */
429 
430     for (i = 0; i < 32; i++)
431     {
432         /* Decode the function bitmap */
433 
434         switch ((1 << i) & Functions)
435         {
436         case 0:
437 
438             /* This function not configured */
439             break;
440 
441         case CVT_COUNT_TABS:
442 
443             AsCountTabs (FileBuffer, Filename);
444             break;
445 
446         case CVT_COUNT_NON_ANSI_COMMENTS:
447 
448             AsCountNonAnsiComments (FileBuffer, Filename);
449             break;
450 
451         case CVT_CHECK_BRACES:
452 
453             AsCheckForBraces (FileBuffer, Filename);
454             break;
455 
456         case CVT_TRIM_LINES:
457 
458             AsTrimLines (FileBuffer, Filename);
459             break;
460 
461         case CVT_COUNT_LINES:
462 
463             AsCountSourceLines (FileBuffer, Filename);
464             break;
465 
466         case CVT_BRACES_ON_SAME_LINE:
467 
468             AsBracesOnSameLine (FileBuffer);
469             break;
470 
471         case CVT_MIXED_CASE_TO_UNDERSCORES:
472 
473             AsMixedCaseToUnderscores (FileBuffer, Filename);
474             break;
475 
476         case CVT_LOWER_CASE_IDENTIFIERS:
477 
478             AsLowerCaseIdentifiers (FileBuffer);
479             break;
480 
481         case CVT_REMOVE_DEBUG_MACROS:
482 
483             AsRemoveDebugMacros (FileBuffer);
484             break;
485 
486         case CVT_TRIM_WHITESPACE:
487 
488             AsTrimWhitespace (FileBuffer);
489             break;
490 
491         case CVT_REMOVE_EMPTY_BLOCKS:
492 
493             AsRemoveEmptyBlocks (FileBuffer, Filename);
494             break;
495 
496         case CVT_REDUCE_TYPEDEFS:
497 
498             AsReduceTypedefs (FileBuffer, "typedef union");
499             AsReduceTypedefs (FileBuffer, "typedef struct");
500             break;
501 
502         case CVT_SPACES_TO_TABS4:
503 
504             AsTabify4 (FileBuffer);
505             break;
506 
507         case CVT_SPACES_TO_TABS8:
508 
509             AsTabify8 (FileBuffer);
510             break;
511 
512         case CVT_COUNT_SHORTMULTILINE_COMMENTS:
513 
514 #ifdef ACPI_FUTURE_IMPLEMENTATION
515             AsTrimComments (FileBuffer, Filename);
516 #endif
517             break;
518 
519         default:
520 
521             printf ("Unknown conversion subfunction opcode\n");
522             break;
523         }
524     }
525 
526     if (ConversionTable->NewHeader)
527     {
528         AsReplaceHeader (FileBuffer, ConversionTable->NewHeader);
529     }
530 }
531 
532 
533 /******************************************************************************
534  *
535  * FUNCTION:    AsProcessOneFile
536  *
537  * DESCRIPTION: Process one source file. The file is opened, read entirely
538  *              into a buffer, converted, then written to a new file.
539  *
540  ******************************************************************************/
541 
542 ACPI_NATIVE_INT
543 AsProcessOneFile (
544     ACPI_CONVERSION_TABLE   *ConversionTable,
545     char                    *SourcePath,
546     char                    *TargetPath,
547     int                     MaxPathLength,
548     char                    *Filename,
549     ACPI_NATIVE_INT         FileType)
550 {
551     char                    *Pathname;
552     char                    *OutPathname;
553     int                     Status = 0;
554 
555 
556     /* Allocate a file pathname buffer for both source and target */
557 
558     Pathname = calloc (MaxPathLength + strlen (Filename) + 2, 1);
559     if (!Pathname)
560     {
561         printf ("Could not allocate buffer for file pathnames\n");
562         return (-1);
563     }
564 
565     Gbl_FileType = FileType;
566 
567     /* Generate the source pathname and read the file */
568 
569     if (SourcePath)
570     {
571         strcpy (Pathname, SourcePath);
572         strcat (Pathname, "/");
573     }
574 
575     strcat (Pathname, Filename);
576 
577     if (AsGetFile (Pathname, &Gbl_FileBuffer, &Gbl_FileSize))
578     {
579         Status = -1;
580         goto Exit1;
581     }
582 
583     Gbl_HeaderSize = 0;
584     if (strstr (Filename, ".asl"))
585     {
586         Gbl_HeaderSize = LINES_IN_ASL_HEADER; /* Lines in default ASL header */
587     }
588     else if (strstr (Gbl_FileBuffer, LEGAL_HEADER_SIGNATURE))
589     {
590         Gbl_HeaderSize = LINES_IN_LEGAL_HEADER; /* Normal C file and H header */
591     }
592     else if (strstr (Gbl_FileBuffer, LINUX_HEADER_SIGNATURE))
593     {
594         Gbl_HeaderSize = LINES_IN_LINUX_HEADER; /* Linuxized C file and H header */
595     }
596 
597     /* Process the file in the buffer */
598 
599     Gbl_MadeChanges = FALSE;
600     if (!Gbl_IgnoreLoneLineFeeds && Gbl_HasLoneLineFeeds)
601     {
602         /*
603          * All lone LFs will be converted to CR/LF
604          * (when file is written, Windows version only)
605          */
606         printf ("Converting lone linefeeds\n");
607         Gbl_MadeChanges = TRUE;
608     }
609 
610     AsConvertFile (ConversionTable, Gbl_FileBuffer, Pathname, FileType);
611 
612     if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT))
613     {
614         if (!(Gbl_Overwrite && !Gbl_MadeChanges))
615         {
616             /* Generate the target pathname and write the file */
617 
618             OutPathname = calloc (MaxPathLength +
619                 strlen (Filename) + 2 + strlen (TargetPath), 1);
620             if (!OutPathname)
621             {
622                 printf ("Could not allocate buffer for file pathnames\n");
623                 Status = -1;
624                 goto Exit2;
625             }
626 
627             strcpy (OutPathname, TargetPath);
628             if (SourcePath)
629             {
630                 strcat (OutPathname, "/");
631                 strcat (OutPathname, Filename);
632             }
633 
634             AsPutFile (OutPathname, Gbl_FileBuffer, ConversionTable->Flags);
635             free (OutPathname);
636         }
637     }
638 
639 Exit2:
640     free (Gbl_FileBuffer);
641 
642 Exit1:
643     free (Pathname);
644     return (Status);
645 }
646 
647 
648 /******************************************************************************
649  *
650  * FUNCTION:    AsCheckForDirectory
651  *
652  * DESCRIPTION: Check if the current file is a valid directory. If not,
653  *              construct the full pathname for the source and target paths.
654  *              Checks for the dot and dot-dot files (they are ignored)
655  *
656  ******************************************************************************/
657 
658 ACPI_NATIVE_INT
659 AsCheckForDirectory (
660     char                    *SourceDirPath,
661     char                    *TargetDirPath,
662     char                    *Filename,
663     char                    **SourcePath,
664     char                    **TargetPath)
665 {
666     char                    *SrcPath;
667     char                    *TgtPath;
668 
669 
670     if (!(strcmp (Filename, ".")) ||
671         !(strcmp (Filename, "..")))
672     {
673         return (-1);
674     }
675 
676     SrcPath = calloc (strlen (SourceDirPath) + strlen (Filename) + 2, 1);
677     if (!SrcPath)
678     {
679         printf ("Could not allocate buffer for directory source pathname\n");
680         return (-1);
681     }
682 
683     TgtPath = calloc (strlen (TargetDirPath) + strlen (Filename) + 2, 1);
684     if (!TgtPath)
685     {
686         printf ("Could not allocate buffer for directory target pathname\n");
687         free (SrcPath);
688         return (-1);
689     }
690 
691     strcpy (SrcPath, SourceDirPath);
692     strcat (SrcPath, "/");
693     strcat (SrcPath, Filename);
694 
695     strcpy (TgtPath, TargetDirPath);
696     strcat (TgtPath, "/");
697     strcat (TgtPath, Filename);
698 
699     *SourcePath = SrcPath;
700     *TargetPath = TgtPath;
701     return (0);
702 }
703 
704 
705 /******************************************************************************
706  *
707  * FUNCTION:    AsGetFile
708  *
709  * DESCRIPTION: Open a file and read it entirely into a an allocated buffer
710  *
711  ******************************************************************************/
712 
713 int
714 AsGetFile (
715     char                    *Filename,
716     char                    **FileBuffer,
717     UINT32                  *FileSize)
718 {
719     FILE                    *File;
720     UINT32                  Size;
721     char                    *Buffer;
722     size_t                  Actual;
723 
724 
725     /* Binary mode leaves CR/LF pairs */
726 
727     File = fopen (Filename, "rb");
728     if (!File)
729     {
730         printf ("Could not open file %s\n", Filename);
731         return (-1);
732     }
733 
734     /* Need file size to allocate a buffer */
735 
736     Size = CmGetFileSize (File);
737     if (Size == ACPI_UINT32_MAX)
738     {
739         printf ("Could not get file size for %s\n", Filename);
740         goto ErrorExit;
741     }
742 
743     /*
744      * Create a buffer for the entire file
745      * Add plenty extra buffer to accommodate string replacements
746      */
747     Gbl_TotalSize += Size;
748 
749     Buffer = calloc (Size * 2, 1);
750     if (!Buffer)
751     {
752         printf ("Could not allocate buffer of size %u\n", Size * 2);
753         goto ErrorExit;
754     }
755 
756     /* Read the entire file */
757 
758     Actual = fread (Buffer, 1, Size, File);
759     if (Actual != Size)
760     {
761         printf ("Could not read the input file %s (%u bytes)\n",
762             Filename, Size);
763         goto ErrorFree;
764     }
765 
766     Buffer [Size] = 0;         /* Null terminate the buffer */
767     fclose (File);
768 
769     /* Check for unix contamination */
770 
771     Gbl_HasLoneLineFeeds = AsDetectLoneLineFeeds (Filename, Buffer);
772 
773     /*
774      * Convert all CR/LF pairs to LF only. We do this locally so that
775      * this code is portable across operating systems.
776      */
777     AsConvertToLineFeeds (Buffer);
778 
779     *FileBuffer = Buffer;
780     *FileSize = Size;
781     return (0);
782 
783 ErrorFree:
784     free (Buffer);
785 
786 ErrorExit:
787 
788     fclose (File);
789     return (-1);
790 }
791 
792 
793 /******************************************************************************
794  *
795  * FUNCTION:    AsPutFile
796  *
797  * DESCRIPTION: Create a new output file and write the entire contents of the
798  *              buffer to the new file. Buffer must be a zero terminated string
799  *
800  ******************************************************************************/
801 
802 int
803 AsPutFile (
804     char                    *Pathname,
805     char                    *FileBuffer,
806     UINT32                  SystemFlags)
807 {
808     FILE                    *File;
809     UINT32                  FileSize;
810     size_t                  Actual;
811     int                     Status = 0;
812 
813 
814     /* Create the target file */
815 
816     if (!(SystemFlags & FLG_NO_CARRIAGE_RETURNS))
817     {
818         /* Put back the CR before each LF */
819 
820         AsInsertCarriageReturns (FileBuffer);
821     }
822 
823     File = fopen (Pathname, "w+b");
824     if (!File)
825     {
826         perror ("Could not create destination file");
827         printf ("Could not create destination file \"%s\"\n", Pathname);
828         return (-1);
829     }
830 
831     /* Write the buffer to the file */
832 
833     FileSize = strlen (FileBuffer);
834     Actual = fwrite (FileBuffer, 1, FileSize, File);
835     if (Actual != FileSize)
836     {
837         printf ("Error writing output file \"%s\"\n", Pathname);
838         Status = -1;
839     }
840 
841     fclose (File);
842     return (Status);
843 }
844