1 /****************************************************************************** 2 * 3 * Module Name: asfile - Main module for the acpi source processor utility 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 46 /* Local prototypes */ 47 48 void 49 AsDoWildcard ( 50 ACPI_CONVERSION_TABLE *ConversionTable, 51 char *SourcePath, 52 char *TargetPath, 53 int MaxPathLength, 54 int FileType, 55 char *WildcardSpec); 56 57 BOOLEAN 58 AsDetectLoneLineFeeds ( 59 char *Filename, 60 char *Buffer); 61 62 static ACPI_INLINE int 63 AsMaxInt (int a, int b) 64 { 65 return (a > b ? a : b); 66 } 67 68 69 /****************************************************************************** 70 * 71 * FUNCTION: AsDoWildcard 72 * 73 * DESCRIPTION: Process files via wildcards 74 * 75 ******************************************************************************/ 76 77 void 78 AsDoWildcard ( 79 ACPI_CONVERSION_TABLE *ConversionTable, 80 char *SourcePath, 81 char *TargetPath, 82 int MaxPathLength, 83 int FileType, 84 char *WildcardSpec) 85 { 86 void *DirInfo; 87 char *Filename; 88 char *SourceDirPath; 89 char *TargetDirPath; 90 char RequestedFileType; 91 92 93 if (FileType == FILE_TYPE_DIRECTORY) 94 { 95 RequestedFileType = REQUEST_DIR_ONLY; 96 } 97 else 98 { 99 RequestedFileType = REQUEST_FILE_ONLY; 100 } 101 102 VERBOSE_PRINT (("Checking for %s source files in directory \"%s\"\n", 103 WildcardSpec, SourcePath)); 104 105 /* Open the directory for wildcard search */ 106 107 DirInfo = AcpiOsOpenDirectory (SourcePath, WildcardSpec, RequestedFileType); 108 if (DirInfo) 109 { 110 /* 111 * Get all of the files that match both the 112 * wildcard and the requested file type 113 */ 114 while ((Filename = AcpiOsGetNextFilename (DirInfo))) 115 { 116 /* Looking for directory files, must check file type */ 117 118 switch (RequestedFileType) 119 { 120 case REQUEST_DIR_ONLY: 121 122 /* If we actually have a dir, process the subtree */ 123 124 if (!AsCheckForDirectory (SourcePath, TargetPath, Filename, 125 &SourceDirPath, &TargetDirPath)) 126 { 127 VERBOSE_PRINT (("Subdirectory: %s\n", Filename)); 128 129 AsProcessTree (ConversionTable, SourceDirPath, TargetDirPath); 130 free (SourceDirPath); 131 free (TargetDirPath); 132 } 133 break; 134 135 case REQUEST_FILE_ONLY: 136 137 /* Otherwise, this is a file, not a directory */ 138 139 VERBOSE_PRINT (("File: %s\n", Filename)); 140 141 AsProcessOneFile (ConversionTable, SourcePath, TargetPath, 142 MaxPathLength, Filename, FileType); 143 break; 144 145 default: 146 147 break; 148 } 149 } 150 151 /* Cleanup */ 152 153 AcpiOsCloseDirectory (DirInfo); 154 } 155 } 156 157 158 /****************************************************************************** 159 * 160 * FUNCTION: AsProcessTree 161 * 162 * DESCRIPTION: Process the directory tree. Files with the extension ".C" and 163 * ".H" are processed as the tree is traversed. 164 * 165 ******************************************************************************/ 166 167 ACPI_NATIVE_INT 168 AsProcessTree ( 169 ACPI_CONVERSION_TABLE *ConversionTable, 170 char *SourcePath, 171 char *TargetPath) 172 { 173 int MaxPathLength; 174 175 176 MaxPathLength = AsMaxInt (strlen (SourcePath), strlen (TargetPath)); 177 178 if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT)) 179 { 180 if (ConversionTable->Flags & FLG_LOWERCASE_DIRNAMES) 181 { 182 AsStrlwr (TargetPath); 183 } 184 185 VERBOSE_PRINT (("Creating Directory \"%s\"\n", TargetPath)); 186 if (mkdir (TargetPath)) 187 { 188 if (errno != EEXIST) 189 { 190 printf ("Could not create target directory\n"); 191 return (-1); 192 } 193 } 194 } 195 196 /* Do the C source files */ 197 198 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 199 FILE_TYPE_SOURCE, "*.c"); 200 201 /* Do the C header files */ 202 203 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 204 FILE_TYPE_HEADER, "*.h"); 205 206 /* Do the Lex file(s) */ 207 208 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 209 FILE_TYPE_SOURCE, "*.l"); 210 211 /* Do the yacc file(s) */ 212 213 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 214 FILE_TYPE_SOURCE, "*.y"); 215 216 /* Do any ASL files */ 217 218 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 219 FILE_TYPE_HEADER, "*.asl"); 220 221 /* Do any subdirectories */ 222 223 AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, 224 FILE_TYPE_DIRECTORY, "*"); 225 226 return (0); 227 } 228 229 230 /****************************************************************************** 231 * 232 * FUNCTION: AsDetectLoneLineFeeds 233 * 234 * DESCRIPTION: Find LF without CR. 235 * 236 ******************************************************************************/ 237 238 BOOLEAN 239 AsDetectLoneLineFeeds ( 240 char *Filename, 241 char *Buffer) 242 { 243 UINT32 i = 1; 244 UINT32 LfCount = 0; 245 UINT32 LineCount = 0; 246 247 248 if (!Buffer[0]) 249 { 250 return (FALSE); 251 } 252 253 while (Buffer[i]) 254 { 255 if (Buffer[i] == 0x0A) 256 { 257 if (Buffer[i-1] != 0x0D) 258 { 259 LfCount++; 260 } 261 LineCount++; 262 } 263 i++; 264 } 265 266 if (LfCount) 267 { 268 if (LineCount == LfCount) 269 { 270 if (!Gbl_IgnoreLoneLineFeeds) 271 { 272 printf ("%s: ****File has UNIX format**** (LF only, not CR/LF) %u lines\n", 273 Filename, LfCount); 274 } 275 } 276 else 277 { 278 printf ("%s: %u lone linefeeds in file\n", Filename, LfCount); 279 } 280 return (TRUE); 281 } 282 283 return (FALSE); 284 } 285 286 287 /****************************************************************************** 288 * 289 * FUNCTION: AsConvertFile 290 * 291 * DESCRIPTION: Perform the requested transforms on the file buffer (as 292 * determined by the ConversionTable and the FileType). 293 * 294 ******************************************************************************/ 295 296 void 297 AsConvertFile ( 298 ACPI_CONVERSION_TABLE *ConversionTable, 299 char *FileBuffer, 300 char *Filename, 301 ACPI_NATIVE_INT FileType) 302 { 303 UINT32 i; 304 UINT32 Functions; 305 ACPI_STRING_TABLE *StringTable; 306 ACPI_IDENTIFIER_TABLE *ConditionalTable; 307 ACPI_IDENTIFIER_TABLE *LineTable; 308 ACPI_IDENTIFIER_TABLE *MacroTable; 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 MacroTable = ConversionTable->SourceMacroTable; 322 StructTable = ConversionTable->SourceStructTable; 323 SpecialMacroTable = ConversionTable->SourceSpecialMacroTable; 324 break; 325 326 case FILE_TYPE_HEADER: 327 328 Functions = ConversionTable->HeaderFunctions; 329 StringTable = ConversionTable->HeaderStringTable; 330 LineTable = ConversionTable->HeaderLineTable; 331 ConditionalTable = ConversionTable->HeaderConditionalTable; 332 MacroTable = ConversionTable->HeaderMacroTable; 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 MacroTable = ConversionTable->PatchMacroTable; 344 StructTable = ConversionTable->PatchStructTable; 345 SpecialMacroTable = ConversionTable->PatchSpecialMacroTable; 346 break; 347 348 default: 349 350 printf ("Unknown file type, cannot process\n"); 351 return; 352 } 353 354 355 Gbl_StructDefs = strstr (FileBuffer, "/* acpisrc:StructDefs"); 356 Gbl_Files++; 357 VERBOSE_PRINT (("Processing %u bytes\n", 358 (unsigned int) strlen (FileBuffer))); 359 360 if (Gbl_Cleanup) 361 { 362 AsRemoveExtraLines (FileBuffer, Filename); 363 AsRemoveSpacesAfterPeriod (FileBuffer, Filename); 364 } 365 366 if (ConversionTable->LowerCaseTable) 367 { 368 for (i = 0; ConversionTable->LowerCaseTable[i].Identifier; i++) 369 { 370 AsLowerCaseString (ConversionTable->LowerCaseTable[i].Identifier, 371 FileBuffer); 372 } 373 } 374 375 /* Process all the string replacements */ 376 377 if (StringTable) 378 { 379 for (i = 0; StringTable[i].Target; i++) 380 { 381 AsReplaceString (StringTable[i].Target, StringTable[i].Replacement, 382 StringTable[i].Type, FileBuffer); 383 } 384 } 385 386 if (LineTable) 387 { 388 for (i = 0; LineTable[i].Identifier; i++) 389 { 390 AsRemoveLine (FileBuffer, LineTable[i].Identifier); 391 } 392 } 393 394 if (ConditionalTable) 395 { 396 for (i = 0; ConditionalTable[i].Identifier; i++) 397 { 398 AsRemoveConditionalCompile (FileBuffer, ConditionalTable[i].Identifier); 399 } 400 } 401 402 if (MacroTable) 403 { 404 for (i = 0; MacroTable[i].Identifier; i++) 405 { 406 AsRemoveMacro (FileBuffer, MacroTable[i].Identifier); 407 } 408 } 409 410 if (StructTable) 411 { 412 for (i = 0; StructTable[i].Identifier; i++) 413 { 414 AsInsertPrefix (FileBuffer, StructTable[i].Identifier, StructTable[i].Type); 415 } 416 } 417 418 if (SpecialMacroTable) 419 { 420 for (i = 0; SpecialMacroTable[i].Identifier; i++) 421 { 422 AsCleanupSpecialMacro (FileBuffer, SpecialMacroTable[i].Identifier); 423 } 424 } 425 426 /* Process the function table */ 427 428 for (i = 0; i < 32; i++) 429 { 430 /* Decode the function bitmap */ 431 432 switch ((1 << i) & Functions) 433 { 434 case 0: 435 436 /* This function not configured */ 437 break; 438 439 case CVT_COUNT_TABS: 440 441 AsCountTabs (FileBuffer, Filename); 442 break; 443 444 case CVT_COUNT_NON_ANSI_COMMENTS: 445 446 AsCountNonAnsiComments (FileBuffer, Filename); 447 break; 448 449 case CVT_CHECK_BRACES: 450 451 AsCheckForBraces (FileBuffer, Filename); 452 break; 453 454 case CVT_TRIM_LINES: 455 456 AsTrimLines (FileBuffer, Filename); 457 break; 458 459 case CVT_COUNT_LINES: 460 461 AsCountSourceLines (FileBuffer, Filename); 462 break; 463 464 case CVT_BRACES_ON_SAME_LINE: 465 466 AsBracesOnSameLine (FileBuffer); 467 break; 468 469 case CVT_MIXED_CASE_TO_UNDERSCORES: 470 471 AsMixedCaseToUnderscores (FileBuffer, Filename); 472 break; 473 474 case CVT_LOWER_CASE_IDENTIFIERS: 475 476 AsLowerCaseIdentifiers (FileBuffer); 477 break; 478 479 case CVT_REMOVE_DEBUG_MACROS: 480 481 AsRemoveDebugMacros (FileBuffer); 482 break; 483 484 case CVT_TRIM_WHITESPACE: 485 486 AsTrimWhitespace (FileBuffer); 487 break; 488 489 case CVT_REMOVE_EMPTY_BLOCKS: 490 491 AsRemoveEmptyBlocks (FileBuffer, Filename); 492 break; 493 494 case CVT_REDUCE_TYPEDEFS: 495 496 AsReduceTypedefs (FileBuffer, "typedef union"); 497 AsReduceTypedefs (FileBuffer, "typedef struct"); 498 break; 499 500 case CVT_SPACES_TO_TABS4: 501 502 AsTabify4 (FileBuffer); 503 break; 504 505 case CVT_SPACES_TO_TABS8: 506 507 AsTabify8 (FileBuffer); 508 break; 509 510 case CVT_COUNT_SHORTMULTILINE_COMMENTS: 511 512 #ifdef ACPI_FUTURE_IMPLEMENTATION 513 AsTrimComments (FileBuffer, Filename); 514 #endif 515 break; 516 517 default: 518 519 printf ("Unknown conversion subfunction opcode\n"); 520 break; 521 } 522 } 523 524 if (ConversionTable->NewHeader) 525 { 526 AsReplaceHeader (FileBuffer, ConversionTable->NewHeader); 527 } 528 } 529 530 531 /****************************************************************************** 532 * 533 * FUNCTION: AsProcessOneFile 534 * 535 * DESCRIPTION: Process one source file. The file is opened, read entirely 536 * into a buffer, converted, then written to a new file. 537 * 538 ******************************************************************************/ 539 540 ACPI_NATIVE_INT 541 AsProcessOneFile ( 542 ACPI_CONVERSION_TABLE *ConversionTable, 543 char *SourcePath, 544 char *TargetPath, 545 int MaxPathLength, 546 char *Filename, 547 ACPI_NATIVE_INT FileType) 548 { 549 char *Pathname; 550 char *OutPathname = NULL; 551 552 553 /* Allocate a file pathname buffer for both source and target */ 554 555 Pathname = calloc (MaxPathLength + strlen (Filename) + 2, 1); 556 if (!Pathname) 557 { 558 printf ("Could not allocate buffer for file pathnames\n"); 559 return (-1); 560 } 561 562 Gbl_FileType = FileType; 563 564 /* Generate the source pathname and read the file */ 565 566 if (SourcePath) 567 { 568 strcpy (Pathname, SourcePath); 569 strcat (Pathname, "/"); 570 } 571 572 strcat (Pathname, Filename); 573 574 if (AsGetFile (Pathname, &Gbl_FileBuffer, &Gbl_FileSize)) 575 { 576 return (-1); 577 } 578 579 Gbl_HeaderSize = 0; 580 if (strstr (Filename, ".asl")) 581 { 582 Gbl_HeaderSize = LINES_IN_ASL_HEADER; /* Lines in default ASL header */ 583 } 584 else if (strstr (Gbl_FileBuffer, LEGAL_HEADER_SIGNATURE)) 585 { 586 Gbl_HeaderSize = LINES_IN_LEGAL_HEADER; /* Normal C file and H header */ 587 } 588 else if (strstr (Gbl_FileBuffer, LINUX_HEADER_SIGNATURE)) 589 { 590 Gbl_HeaderSize = LINES_IN_LINUX_HEADER; /* Linuxized C file and H header */ 591 } 592 593 /* Process the file in the buffer */ 594 595 Gbl_MadeChanges = FALSE; 596 if (!Gbl_IgnoreLoneLineFeeds && Gbl_HasLoneLineFeeds) 597 { 598 /* 599 * All lone LFs will be converted to CR/LF 600 * (when file is written, Windows version only) 601 */ 602 printf ("Converting lone linefeeds\n"); 603 Gbl_MadeChanges = TRUE; 604 } 605 606 AsConvertFile (ConversionTable, Gbl_FileBuffer, Pathname, FileType); 607 608 if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT)) 609 { 610 if (!(Gbl_Overwrite && !Gbl_MadeChanges)) 611 { 612 /* Generate the target pathname and write the file */ 613 614 OutPathname = calloc (MaxPathLength + strlen (Filename) + 2 + strlen (TargetPath), 1); 615 if (!OutPathname) 616 { 617 printf ("Could not allocate buffer for file pathnames\n"); 618 return (-1); 619 } 620 621 strcpy (OutPathname, TargetPath); 622 if (SourcePath) 623 { 624 strcat (OutPathname, "/"); 625 strcat (OutPathname, Filename); 626 } 627 628 AsPutFile (OutPathname, Gbl_FileBuffer, ConversionTable->Flags); 629 } 630 } 631 632 free (Gbl_FileBuffer); 633 free (Pathname); 634 if (OutPathname) 635 { 636 free (OutPathname); 637 } 638 639 return (0); 640 } 641 642 643 /****************************************************************************** 644 * 645 * FUNCTION: AsCheckForDirectory 646 * 647 * DESCRIPTION: Check if the current file is a valid directory. If not, 648 * construct the full pathname for the source and target paths. 649 * Checks for the dot and dot-dot files (they are ignored) 650 * 651 ******************************************************************************/ 652 653 ACPI_NATIVE_INT 654 AsCheckForDirectory ( 655 char *SourceDirPath, 656 char *TargetDirPath, 657 char *Filename, 658 char **SourcePath, 659 char **TargetPath) 660 { 661 char *SrcPath; 662 char *TgtPath; 663 664 665 if (!(strcmp (Filename, ".")) || 666 !(strcmp (Filename, ".."))) 667 { 668 return (-1); 669 } 670 671 SrcPath = calloc (strlen (SourceDirPath) + strlen (Filename) + 2, 1); 672 if (!SrcPath) 673 { 674 printf ("Could not allocate buffer for directory source pathname\n"); 675 return (-1); 676 } 677 678 TgtPath = calloc (strlen (TargetDirPath) + strlen (Filename) + 2, 1); 679 if (!TgtPath) 680 { 681 printf ("Could not allocate buffer for directory target pathname\n"); 682 free (SrcPath); 683 return (-1); 684 } 685 686 strcpy (SrcPath, SourceDirPath); 687 strcat (SrcPath, "/"); 688 strcat (SrcPath, Filename); 689 690 strcpy (TgtPath, TargetDirPath); 691 strcat (TgtPath, "/"); 692 strcat (TgtPath, Filename); 693 694 *SourcePath = SrcPath; 695 *TargetPath = TgtPath; 696 return (0); 697 } 698 699 700 /****************************************************************************** 701 * 702 * FUNCTION: AsGetFile 703 * 704 * DESCRIPTION: Open a file and read it entirely into a an allocated buffer 705 * 706 ******************************************************************************/ 707 708 int 709 AsGetFile ( 710 char *Filename, 711 char **FileBuffer, 712 UINT32 *FileSize) 713 { 714 FILE *File; 715 UINT32 Size; 716 char *Buffer; 717 int Seek1; 718 int Seek2; 719 size_t Actual; 720 721 722 /* Binary mode leaves CR/LF pairs */ 723 724 File = fopen (Filename, "rb"); 725 if (!File) 726 { 727 printf ("Could not open file %s\n", Filename); 728 return (-1); 729 } 730 731 /* Need file size to allocate a buffer */ 732 733 Seek1 = fseek (File, 0L, SEEK_END); 734 Size = ftell (File); 735 Seek2 = fseek (File, 0L, SEEK_SET); 736 737 if (Seek1 || Seek2 || (Size == -1)) 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 ErrorExit; 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 784 ErrorExit: 785 786 fclose (File); 787 return (-1); 788 } 789 790 791 /****************************************************************************** 792 * 793 * FUNCTION: AsPutFile 794 * 795 * DESCRIPTION: Create a new output file and write the entire contents of the 796 * buffer to the new file. Buffer must be a zero terminated string 797 * 798 ******************************************************************************/ 799 800 int 801 AsPutFile ( 802 char *Pathname, 803 char *FileBuffer, 804 UINT32 SystemFlags) 805 { 806 FILE *File; 807 UINT32 FileSize; 808 size_t Actual; 809 int Status = 0; 810 811 812 /* Create the target file */ 813 814 if (!(SystemFlags & FLG_NO_CARRIAGE_RETURNS)) 815 { 816 /* Put back the CR before each LF */ 817 818 AsInsertCarriageReturns (FileBuffer); 819 } 820 821 File = fopen (Pathname, "w+b"); 822 if (!File) 823 { 824 perror ("Could not create destination file"); 825 printf ("Could not create destination file \"%s\"\n", Pathname); 826 return (-1); 827 } 828 829 /* Write the buffer to the file */ 830 831 FileSize = strlen (FileBuffer); 832 Actual = fwrite (FileBuffer, 1, FileSize, File); 833 if (Actual != FileSize) 834 { 835 printf ("Error writing output file \"%s\"\n", Pathname); 836 Status = -1; 837 } 838 839 fclose (File); 840 return (Status); 841 }