%{
/*---------------------------------*- C -*-----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see .
Application
wmkdep
Description
A fast dependency list generator that emulates the behaviour and the
output of cpp -M. However, the output contains no duplicates and
is approx. 40% faster than cpp.
The algorithm uses flex to scan the directories specified with '-Idir'
options for include files and searches the files found. Each file is
entered into a hash table so that files are scanned only once. The
resulting file paths are added to the dependencies file after replacing
strings specified with the '-R string replacement' options.
Usage
wmkdep [ -R string replacement ... -R string replacement ] \
[ -Idir ... -Idir ]
\*---------------------------------------------------------------------------*/
#define HASH_TABLE_SIZE 500
#define REPLACEMENTS_SIZE 10
#define INITIAL_MAX_N_FILES 1000
#include
#include
#include
#include
#include
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* char* entry in hash table */
struct HashEntry
{
char* name;
struct HashEntry* next;
};
/* String search/replace pair */
struct searchReplace
{
char* search;
size_t searchLen;
char* replace;
size_t replaceLen;
};
int nDirectories = 0;
char** directories;
char* sourceFile = NULL;
char* sourcePath = NULL;
char* depFilePath = NULL;
char* depFileName = NULL;
int nReplacements = 0;
struct searchReplace replacements[REPLACEMENTS_SIZE];
/* Set of files already visited */
struct HashEntry* visitedFiles[HASH_TABLE_SIZE];
/* List of dependency files */
int nFiles = 0;
int currentFile = 0;
int maxNfiles = INITIAL_MAX_N_FILES;
char** files;
/* Current path of the dependency file */
const char* currentPath = NULL;
void nextFile(const char* fileName);
int lookUp(struct HashEntry** hashTable, const char* p);
void addFile(char* filePath);
void openFile(const char* filePath);
char* strRep(char* str, struct searchReplace* sr);
char* substitutePath(char* filePath);
void printFile(FILE* file, const char* filePath);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#undef yywrap /* Sometimes a macro by default */
%}
%x CMNT CFNAME
%%
"//".*\n ; /* Remove c++ style line comments */
"/*" BEGIN(CMNT); /* Start removing c style comment */
.|\n ;
"*/" BEGIN(INITIAL); /* End removing c style comment */
^[ \t]*#[ \t]*include[ \t]+\" BEGIN(CFNAME); /* c-file name */
[^"\n ]* { BEGIN(INITIAL); nextFile(yytext); } /*"*/
.|\t|\n ;
%%
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main(int argc, char* argv[])
{
if (argc == 1)
{
fprintf(stderr, "input file not supplied\n");
exit(1);
}
sourceFile = strdup(argv[argc-2]);
depFilePath = strdup(argv[argc-1]);
char* basePos = strrchr(sourceFile, '/');
if (basePos == NULL)
{
sourcePath = strdup(".");
}
else
{
sourcePath = (char*)calloc(basePos - sourceFile + 1, sizeof(char*));
strncpy(sourcePath, sourceFile, basePos - sourceFile);
}
if (basePos == NULL)
{
basePos = sourceFile;
}
else
{
basePos++;
}
char* dotPos = strrchr(sourceFile, '.');
if (dotPos == NULL || dotPos < basePos)
{
fprintf
(
stderr,
"cannot find extension in source file name %s\n",
sourceFile
);
exit(1);
}
/* Build list of string replacements */
int i;
for (i = 1; i < argc - 1; i++)
{
if (strncmp(argv[i], "-R", 2) == 0)
{
replacements[nReplacements].search = strdup(argv[++i]);
replacements[nReplacements].searchLen =
strlen(replacements[nReplacements].search);
replacements[nReplacements].replace = strdup(argv[++i]);
replacements[nReplacements].replaceLen =
strlen(replacements[nReplacements].replace);
nReplacements++;
}
}
/* Count number of -I directories */
nDirectories = 1;
for (i = 1; i < argc - 1; i++)
{
if (strncmp(argv[i], "-I", 2) == 0)
{
if (strlen(argv[i]) > 2)
{
nDirectories++;
}
}
}
directories = (char**)malloc(sizeof(char*)*nDirectories);
// Insert the source directory as the first directory searched
directories[0] = strdup(sourcePath);
/* Build list of -I directories */
nDirectories = 1;
for (i = 1; i < argc - 1; i++)
{
if (strncmp(argv[i], "-I", 2) == 0)
{
if (strlen(argv[i]) > 2)
{
directories[nDirectories++] = strdup(argv[i] + 2);
}
}
}
depFileName = substitutePath(strdup(depFilePath));
/* Initialise storage for the list of the dependencies */
files = (char**)malloc(sizeof(char*)*maxNfiles);
openFile(sourceFile);
yylex();
/* Write dependencies file */
FILE* depFile;
if (!(depFile = fopen(depFilePath, "w")))
{
fprintf
(
stderr,
"could not open dependencies file %s "
"for source file %s due to %s\n",
depFilePath, sourceFile, strerror(errno)
);
exit(1);
}
fprintf(depFile, "%s: \\\n", depFileName);
printFile(depFile, sourceFile);
for (i = 0; i < nFiles; i++)
{
files[i] = substitutePath(files[i]);
printFile(depFile, files[i]);
}
fputs("\n", depFile);
/* Write the dummy rules for the dependencies */
for (i = 0; i < nFiles; i++)
{
fprintf(depFile, "%s :\n", files[i]);
}
fputs("\n", depFile);
/* Clean-up storage */
for (i = 0; i < nDirectories; i++)
{
free(directories[i]);
}
free(directories);
free(sourceFile);
free(depFilePath);
free(depFileName);
for (i = 0; i < nFiles; i++)
{
free(files[i]);
}
free(files);
return 0;
}
/* Add a directory name to the file name */
char* addDirectoryName(const char* dirName, const char* fileName)
{
char* filePath = (char*)malloc(strlen(dirName) + strlen(fileName) + 2);
strcpy(filePath, dirName);
if (dirName[strlen(dirName)-1] != '/')
{
strcat(filePath, "/");
}
strcat(filePath, fileName);
return filePath;
}
/* Find path to next file and add it to the list */
void nextFile(const char* fileName)
{
if (lookUp(visitedFiles, fileName))
{
return; /* Already existed (did not insert) */
}
if (access(fileName, R_OK ) != -1)
{
addFile(strdup(fileName));
currentPath = NULL;
}
else
{
int i;
for (i = 0; i < nDirectories; i++)
{
char* filePath = addDirectoryName(directories[i], fileName);
if (access(filePath, R_OK ) != -1)
{
addFile(filePath);
currentPath = directories[i];
return;
}
free(filePath);
}
if (nDirectories == 0)
{
fprintf
(
stderr,
"could not open file %s for source file %s\n",
fileName, sourceFile
);
}
else
{
fprintf
(
stderr,
"could not open file %s for source file %s due to %s\n",
fileName, sourceFile, strerror(errno)
);
}
/* Only report error on the first occurrence */
lookUp(visitedFiles, fileName);
}
}
/* Lookup name in hash table.
If found - return 1
If not found - insert in table and return 0
*/
int lookUp(struct HashEntry** hashTable, const char* p)
{
int ii = 0;
struct HashEntry* n;
struct HashEntry* nn;
/* Hash */
const char* pp = p;
while (*pp) ii = ii<<1 ^ *pp++;
if (ii < 0) ii = -ii;
ii %= HASH_TABLE_SIZE;
/* Search */
for (n = hashTable[ii]; n; n = n->next)
{
if (strcmp(p, n->name) == 0)
{
/* Entry found so return true */
return 1;
}
}
/* Insert */
nn = (struct HashEntry*)malloc(sizeof(struct HashEntry));
nn->name = strdup(p);
nn->next = hashTable[ii];
hashTable[ii] = nn;
/* Entry not found, and therefore added. return false */
return 0;
}
/* Add file to list */
void addFile(char* filePath)
{
if (nFiles == maxNfiles - 1)
{
maxNfiles *= 2;
files = (char**)realloc(files, sizeof(char*)*maxNfiles);
}
files[nFiles++] = filePath;
}
/* Open file and set yyin */
void openFile(const char* filePath)
{
if (!(yyin = fopen(filePath, "r")))
{
fprintf
(
stderr,
"could not open file %s for source file %s due to %s\n",
filePath, sourceFile, strerror(errno)
);
}
}
/* String search/replace */
char* strRep(char* str, struct searchReplace* sr)
{
char* searchStart = strstr(str, sr->search);
if (searchStart != NULL)
{
if (sr->replaceLen > sr->searchLen)
{
const size_t start = str - searchStart;
str = realloc
(
str,
strlen(str) + sr->replaceLen - sr->searchLen + 1
);
searchStart = str + start;
}
const size_t tailLen = strlen(searchStart + sr->searchLen);
memmove
(
searchStart + sr->replaceLen,
searchStart + sr->searchLen,
tailLen + 1
);
memcpy(searchStart, sr->replace, sr->replaceLen);
}
return str;
}
/* Substitute path components with command-line replacements */
char* substitutePath(char* filePath)
{
if (nReplacements)
{
int i;
for (i = 0; i < nReplacements; i++)
{
filePath = strRep(filePath, &replacements[i]);
}
}
return filePath;
}
/* Print file path to the dependencies file */
void printFile(FILE* file, const char* filePath)
{
fprintf(file, "%s \\\n", filePath);
}
/* The lexer calls yywrap to handle EOF conditions */
int yywrap()
{
/* Close the current file which has just reached EOF */
fclose(yyin);
if (currentFile == nFiles) /* There are no more files in the list */
{
/* Return 1 to inform lex finish now that all files have been read */
return 1;
}
else
{
/* Open the next file on the list */
openFile(files[currentFile++]);
/* Return to the normal state for the next file */
BEGIN(INITIAL);
/* Return 0 to inform lex to continue reading */
return 0;
}
}
/*****************************************************************************/