/******************************************************************************
*
* Module Name: asfile - Main module for the acpi source processor utility
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2019, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#include "acpisrc.h"
/* Local prototypes */
void
AsDoWildcard (
ACPI_CONVERSION_TABLE *ConversionTable,
char *SourcePath,
char *TargetPath,
int MaxPathLength,
int FileType,
char *WildcardSpec);
BOOLEAN
AsDetectLoneLineFeeds (
char *Filename,
char *Buffer);
static BOOLEAN
AsCheckForNonPrintableChars (
char *FileBuffer,
UINT32 FileSize);
static ACPI_INLINE int
AsMaxInt (int a, int b)
{
return (a > b ? a : b);
}
/******************************************************************************
*
* FUNCTION: AsDoWildcard
*
* DESCRIPTION: Process files via wildcards
*
******************************************************************************/
void
AsDoWildcard (
ACPI_CONVERSION_TABLE *ConversionTable,
char *SourcePath,
char *TargetPath,
int MaxPathLength,
int FileType,
char *WildcardSpec)
{
void *DirInfo;
char *Filename;
char *SourceDirPath;
char *TargetDirPath;
char RequestedFileType;
if (FileType == FILE_TYPE_DIRECTORY)
{
RequestedFileType = REQUEST_DIR_ONLY;
}
else
{
RequestedFileType = REQUEST_FILE_ONLY;
}
VERBOSE_PRINT (("Checking for %s source files in directory \"%s\"\n",
WildcardSpec, SourcePath));
/* Open the directory for wildcard search */
DirInfo = AcpiOsOpenDirectory (SourcePath, WildcardSpec, RequestedFileType);
if (DirInfo)
{
/*
* Get all of the files that match both the
* wildcard and the requested file type
*/
while ((Filename = AcpiOsGetNextFilename (DirInfo)))
{
/* Looking for directory files, must check file type */
switch (RequestedFileType)
{
case REQUEST_DIR_ONLY:
/* If we actually have a dir, process the subtree */
if (!AsCheckForDirectory (SourcePath, TargetPath, Filename,
&SourceDirPath, &TargetDirPath))
{
VERBOSE_PRINT (("Subdirectory: %s\n", Filename));
AsProcessTree (ConversionTable, SourceDirPath, TargetDirPath);
free (SourceDirPath);
free (TargetDirPath);
}
break;
case REQUEST_FILE_ONLY:
/* Otherwise, this is a file, not a directory */
VERBOSE_PRINT (("File: %s\n", Filename));
AsProcessOneFile (ConversionTable, SourcePath, TargetPath,
MaxPathLength, Filename, FileType);
break;
default:
break;
}
}
/* Cleanup */
AcpiOsCloseDirectory (DirInfo);
}
}
/******************************************************************************
*
* FUNCTION: AsProcessTree
*
* DESCRIPTION: Process the directory tree. Files with the extension ".C" and
* ".H" are processed as the tree is traversed.
*
******************************************************************************/
ACPI_NATIVE_INT
AsProcessTree (
ACPI_CONVERSION_TABLE *ConversionTable,
char *SourcePath,
char *TargetPath)
{
int MaxPathLength;
MaxPathLength = AsMaxInt (strlen (SourcePath), strlen (TargetPath));
if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT))
{
if (ConversionTable->Flags & FLG_LOWERCASE_DIRNAMES)
{
AcpiUtStrlwr (TargetPath);
}
VERBOSE_PRINT (("Creating Directory \"%s\"\n", TargetPath));
if (mkdir (TargetPath))
{
if (errno != EEXIST)
{
printf ("Could not create target directory\n");
return (-1);
}
}
}
/* Do the C source files */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_SOURCE, "*.c");
/* Do the C header files */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_HEADER, "*.h");
/* Do the Lex file(s) */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_SOURCE, "*.l");
/* Do the yacc file(s) */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_SOURCE, "*.y");
/* Do any ASL files */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_HEADER, "*.asl");
/* Do any subdirectories */
AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength,
FILE_TYPE_DIRECTORY, "*");
return (0);
}
/******************************************************************************
*
* FUNCTION: AsDetectLoneLineFeeds
*
* DESCRIPTION: Find LF without CR.
*
******************************************************************************/
BOOLEAN
AsDetectLoneLineFeeds (
char *Filename,
char *Buffer)
{
UINT32 i = 1;
UINT32 LfCount = 0;
UINT32 LineCount = 0;
if (!Buffer[0])
{
return (FALSE);
}
while (Buffer[i])
{
if (Buffer[i] == 0x0A)
{
if (Buffer[i-1] != 0x0D)
{
LfCount++;
}
LineCount++;
}
i++;
}
if (LfCount)
{
if (LineCount == LfCount)
{
if (!Gbl_IgnoreLoneLineFeeds)
{
printf ("%s: ****File has UNIX format**** (LF only, not CR/LF) %u lines\n",
Filename, LfCount);
}
}
else
{
printf ("%s: %u lone linefeeds in file\n", Filename, LfCount);
}
return (TRUE);
}
return (FALSE);
}
/******************************************************************************
*
* FUNCTION: AsConvertFile
*
* DESCRIPTION: Perform the requested transforms on the file buffer (as
* determined by the ConversionTable and the FileType).
*
******************************************************************************/
void
AsConvertFile (
ACPI_CONVERSION_TABLE *ConversionTable,
char *FileBuffer,
char *Filename,
ACPI_NATIVE_INT FileType)
{
UINT32 i;
UINT32 Functions;
ACPI_STRING_TABLE *StringTable;
ACPI_IDENTIFIER_TABLE *ConditionalTable;
ACPI_IDENTIFIER_TABLE *LineTable;
ACPI_TYPED_IDENTIFIER_TABLE *StructTable;
ACPI_IDENTIFIER_TABLE *SpecialMacroTable;
char *SpdxHeader=NULL;
switch (FileType)
{
case FILE_TYPE_SOURCE:
Functions = ConversionTable->SourceFunctions;
StringTable = ConversionTable->SourceStringTable;
LineTable = ConversionTable->SourceLineTable;
ConditionalTable = ConversionTable->SourceConditionalTable;
StructTable = ConversionTable->SourceStructTable;
SpecialMacroTable = ConversionTable->SourceSpecialMacroTable;
SpdxHeader = ConversionTable->SourceSpdxHeader;
break;
case FILE_TYPE_HEADER:
Functions = ConversionTable->HeaderFunctions;
StringTable = ConversionTable->HeaderStringTable;
LineTable = ConversionTable->HeaderLineTable;
ConditionalTable = ConversionTable->HeaderConditionalTable;
StructTable = ConversionTable->HeaderStructTable;
SpecialMacroTable = ConversionTable->HeaderSpecialMacroTable;
SpdxHeader = ConversionTable->HeaderSpdxHeader;
break;
case FILE_TYPE_PATCH:
Functions = ConversionTable->PatchFunctions;
StringTable = ConversionTable->PatchStringTable;
LineTable = ConversionTable->PatchLineTable;
ConditionalTable = ConversionTable->PatchConditionalTable;
StructTable = ConversionTable->PatchStructTable;
SpecialMacroTable = ConversionTable->PatchSpecialMacroTable;
break;
default:
printf ("Unknown file type, cannot process\n");
return;
}
Gbl_StructDefs = strstr (FileBuffer, "/* acpisrc:StructDefs");
Gbl_Files++;
VERBOSE_PRINT (("Processing %u bytes\n",
(unsigned int) strlen (FileBuffer)));
if (Gbl_Cleanup)
{
AsRemoveExtraLines (FileBuffer, Filename);
AsRemoveSpacesAfterPeriod (FileBuffer, Filename);
}
if (ConversionTable->LowerCaseTable)
{
for (i = 0; ConversionTable->LowerCaseTable[i].Identifier; i++)
{
AsLowerCaseString (ConversionTable->LowerCaseTable[i].Identifier,
FileBuffer);
}
}
/* Process all the string replacements */
if (StringTable)
{
for (i = 0; StringTable[i].Target; i++)
{
AsReplaceString (StringTable[i].Target, StringTable[i].Replacement,
StringTable[i].Type, FileBuffer);
}
}
if (LineTable)
{
for (i = 0; LineTable[i].Identifier; i++)
{
AsRemoveLine (FileBuffer, LineTable[i].Identifier);
}
}
if (ConditionalTable)
{
for (i = 0; ConditionalTable[i].Identifier; i++)
{
AsRemoveConditionalCompile (FileBuffer, ConditionalTable[i].Identifier);
}
}
#ifdef _OBSOLETE_FUNCTIONS
if (MacroTable)
{
for (i = 0; MacroTable[i].Identifier; i++)
{
AsRemoveMacro (FileBuffer, MacroTable[i].Identifier);
}
}
#endif
if (StructTable)
{
for (i = 0; StructTable[i].Identifier; i++)
{
AsInsertPrefix (FileBuffer, StructTable[i].Identifier,
StructTable[i].Type);
}
}
if (SpecialMacroTable)
{
for (i = 0; SpecialMacroTable[i].Identifier; i++)
{
AsCleanupSpecialMacro (FileBuffer, SpecialMacroTable[i].Identifier);
}
}
/* Process the function table */
for (i = 0; i < 32; i++)
{
/* Decode the function bitmap */
switch ((1 << i) & Functions)
{
case 0:
/* This function not configured */
break;
case CVT_COUNT_TABS:
AsCountTabs (FileBuffer, Filename);
break;
case CVT_COUNT_NON_ANSI_COMMENTS:
AsCountNonAnsiComments (FileBuffer, Filename);
break;
case CVT_CHECK_BRACES:
AsCheckForBraces (FileBuffer, Filename);
break;
case CVT_TRIM_LINES:
AsTrimLines (FileBuffer, Filename);
break;
case CVT_COUNT_LINES:
AsCountSourceLines (FileBuffer, Filename);
break;
case CVT_BRACES_ON_SAME_LINE:
AsBracesOnSameLine (FileBuffer);
break;
case CVT_MIXED_CASE_TO_UNDERSCORES:
AsMixedCaseToUnderscores (FileBuffer, Filename);
break;
case CVT_LOWER_CASE_IDENTIFIERS:
AsLowerCaseIdentifiers (FileBuffer);
break;
case CVT_REMOVE_DEBUG_MACROS:
AsRemoveDebugMacros (FileBuffer);
break;
case CVT_TRIM_WHITESPACE:
AsTrimWhitespace (FileBuffer);
break;
case CVT_REMOVE_EMPTY_BLOCKS:
AsRemoveEmptyBlocks (FileBuffer, Filename);
break;
case CVT_REDUCE_TYPEDEFS:
AsReduceTypedefs (FileBuffer, "typedef union");
AsReduceTypedefs (FileBuffer, "typedef struct");
break;
case CVT_SPACES_TO_TABS4:
AsTabify4 (FileBuffer);
break;
case CVT_SPACES_TO_TABS8:
AsTabify8 (FileBuffer);
break;
case CVT_COUNT_SHORTMULTILINE_COMMENTS:
#ifdef ACPI_FUTURE_IMPLEMENTATION
AsTrimComments (FileBuffer, Filename);
#endif
break;
default:
printf ("Unknown conversion subfunction opcode\n");
break;
}
}
if (ConversionTable->NewHeader)
{
AsReplaceHeader (FileBuffer, ConversionTable->NewHeader);
}
if (SpdxHeader)
{
AsDoSpdxHeader (FileBuffer, SpdxHeader);
}
}
/*******************************************************************************
*
* FUNCTION: AsCheckForNonPrintableChars
*
* PARAMETERS: FileBuffer - Buffer with contents of entire file
* FileSize - Size of the file and buffer
*
* RETURN: TRUE if there are no non-printable characters
*
* DESCRIPTION: Scan a file for any non-printable ASCII bytes.
*
******************************************************************************/
static BOOLEAN
AsCheckForNonPrintableChars (
char *FileBuffer,
UINT32 FileSize)
{
BOOLEAN Found = TRUE;
UINT8 Byte;
UINT32 i;
/* Scan entire file for any non-printable characters */
for (i = 0; i < FileSize; i++)
{
Byte = FileBuffer[i];
if (!isprint (Byte) && !isspace (Byte))
{
printf ( "Non-printable character (0x%2.2X) "
"at file offset: %8u (0x%X)\n", Byte, i, i);
Found = FALSE;
}
}
return (Found);
}
/******************************************************************************
*
* FUNCTION: AsProcessOneFile
*
* DESCRIPTION: Process one source file. The file is opened, read entirely
* into a buffer, converted, then written to a new file.
*
******************************************************************************/
ACPI_NATIVE_INT
AsProcessOneFile (
ACPI_CONVERSION_TABLE *ConversionTable,
char *SourcePath,
char *TargetPath,
int MaxPathLength,
char *Filename,
ACPI_NATIVE_INT FileType)
{
char *Pathname;
char *OutPathname;
int Status = 0;
/* Allocate a file pathname buffer for both source and target */
Pathname = calloc (MaxPathLength + strlen (Filename) + 2, 1);
if (!Pathname)
{
printf ("Could not allocate buffer for file pathnames\n");
return (-1);
}
Gbl_FileType = FileType;
/* Generate the source pathname and read the file */
if (SourcePath)
{
strcpy (Pathname, SourcePath);
strcat (Pathname, "/");
}
strcat (Pathname, Filename);
if (AsGetFile (Pathname, &Gbl_FileBuffer, &Gbl_FileSize))
{
Status = -1;
goto Exit1;
}
/* Exit now if simply checking the file for printable ascii chars */
if (Gbl_CheckAscii)
{
Status = 0;
goto Exit2;
}
Gbl_HeaderSize = 0;
if (strstr (Filename, ".asl"))
{
Gbl_HeaderSize = LINES_IN_ASL_HEADER; /* Lines in default ASL header */
}
else if (strstr (Gbl_FileBuffer, LEGAL_HEADER_SIGNATURE))
{
Gbl_HeaderSize = LINES_IN_LEGAL_HEADER; /* Normal C file and H header */
}
else if (strstr (Gbl_FileBuffer, LINUX_HEADER_SIGNATURE))
{
Gbl_HeaderSize = LINES_IN_LINUX_HEADER; /* Linuxized C file and H header */
}
/* Process the file in the buffer */
Gbl_MadeChanges = FALSE;
if (!Gbl_IgnoreLoneLineFeeds && Gbl_HasLoneLineFeeds)
{
/*
* All lone LFs will be converted to CR/LF
* (when file is written, Windows version only)
*/
printf ("Converting lone linefeeds\n");
Gbl_MadeChanges = TRUE;
}
AsConvertFile (ConversionTable, Gbl_FileBuffer, Pathname, FileType);
if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT))
{
if (!(Gbl_Overwrite && !Gbl_MadeChanges))
{
/* Generate the target pathname and write the file */
OutPathname = calloc (MaxPathLength +
strlen (Filename) + 2 + strlen (TargetPath), 1);
if (!OutPathname)
{
printf ("Could not allocate buffer for file pathnames\n");
Status = -1;
goto Exit2;
}
strcpy (OutPathname, TargetPath);
if (SourcePath)
{
strcat (OutPathname, "/");
strcat (OutPathname, Filename);
}
AsPutFile (OutPathname, Gbl_FileBuffer, ConversionTable->Flags);
free (OutPathname);
}
}
Exit2:
free (Gbl_FileBuffer);
Exit1:
free (Pathname);
return (Status);
}
/******************************************************************************
*
* FUNCTION: AsCheckForDirectory
*
* DESCRIPTION: Check if the current file is a valid directory. If not,
* construct the full pathname for the source and target paths.
* Checks for the dot and dot-dot files (they are ignored)
*
******************************************************************************/
ACPI_NATIVE_INT
AsCheckForDirectory (
char *SourceDirPath,
char *TargetDirPath,
char *Filename,
char **SourcePath,
char **TargetPath)
{
char *SrcPath;
char *TgtPath;
if (!(strcmp (Filename, ".")) ||
!(strcmp (Filename, "..")))
{
return (-1);
}
SrcPath = calloc (strlen (SourceDirPath) + strlen (Filename) + 2, 1);
if (!SrcPath)
{
printf ("Could not allocate buffer for directory source pathname\n");
return (-1);
}
TgtPath = calloc (strlen (TargetDirPath) + strlen (Filename) + 2, 1);
if (!TgtPath)
{
printf ("Could not allocate buffer for directory target pathname\n");
free (SrcPath);
return (-1);
}
strcpy (SrcPath, SourceDirPath);
strcat (SrcPath, "/");
strcat (SrcPath, Filename);
strcpy (TgtPath, TargetDirPath);
strcat (TgtPath, "/");
strcat (TgtPath, Filename);
*SourcePath = SrcPath;
*TargetPath = TgtPath;
return (0);
}
/******************************************************************************
*
* FUNCTION: AsGetFile
*
* DESCRIPTION: Open a file and read it entirely into a an allocated buffer
*
******************************************************************************/
int
AsGetFile (
char *Filename,
char **FileBuffer,
UINT32 *FileSize)
{
FILE *File;
UINT32 Size;
char *Buffer;
size_t Actual;
/* Binary mode leaves CR/LF pairs */
File = fopen (Filename, "rb");
if (!File)
{
printf ("Could not open file %s\n", Filename);
return (-1);
}
/* Need file size to allocate a buffer */
Size = CmGetFileSize (File);
if (Size == ACPI_UINT32_MAX)
{
printf ("Could not get file size for %s\n", Filename);
goto ErrorExit;
}
/*
* Create a buffer for the entire file
* Add plenty extra buffer to accommodate string replacements
*/
Gbl_TotalSize += Size;
Buffer = calloc (Size * 2, 1);
if (!Buffer)
{
printf ("Could not allocate buffer of size %u\n", Size * 2);
goto ErrorExit;
}
/* Read the entire file */
Actual = fread (Buffer, 1, Size, File);
if (Actual != Size)
{
printf ("Could not read the input file %s (%u bytes)\n",
Filename, Size);
goto ErrorFree;
}
Buffer [Size] = 0; /* Null terminate the buffer */
fclose (File);
/* This option checks the entire file for non-printable chars */
if (Gbl_CheckAscii)
{
if (AsCheckForNonPrintableChars (Buffer, Size))
{
printf ("File contains only printable ASCII characters\n");
}
free (Buffer);
return (0);
}
/* Check for unix contamination */
Gbl_HasLoneLineFeeds = AsDetectLoneLineFeeds (Filename, Buffer);
/*
* Convert all CR/LF pairs to LF only. We do this locally so that
* this code is portable across operating systems.
*/
AsConvertToLineFeeds (Buffer);
*FileBuffer = Buffer;
*FileSize = Size;
return (0);
ErrorFree:
free (Buffer);
ErrorExit:
fclose (File);
return (-1);
}
/******************************************************************************
*
* FUNCTION: AsPutFile
*
* DESCRIPTION: Create a new output file and write the entire contents of the
* buffer to the new file. Buffer must be a zero terminated string
*
******************************************************************************/
int
AsPutFile (
char *Pathname,
char *FileBuffer,
UINT32 SystemFlags)
{
FILE *File;
UINT32 FileSize;
size_t Actual;
int Status = 0;
/* Create the target file */
if (!(SystemFlags & FLG_NO_CARRIAGE_RETURNS))
{
/* Put back the CR before each LF */
AsInsertCarriageReturns (FileBuffer);
}
File = fopen (Pathname, "w+b");
if (!File)
{
perror ("Could not create destination file");
printf ("Could not create destination file \"%s\"\n", Pathname);
return (-1);
}
/* Write the buffer to the file */
FileSize = strlen (FileBuffer);
Actual = fwrite (FileBuffer, 1, FileSize, File);
if (Actual != FileSize)
{
printf ("Error writing output file \"%s\"\n", Pathname);
Status = -1;
}
fclose (File);
return (Status);
}