From ba8c750b7563d00ffd21e889a77178c7d2dcb1ea Mon Sep 17 00:00:00 2001 From: Martin Winkler Date: Thu, 23 Feb 2017 10:10:12 +0000 Subject: [PATCH] first commit (work in progress) --- .cproject | 112 +++++++++++ .project | 26 +++ .settings/org.eclipse.cdt.core.prefs | 11 ++ src/stubi.c | 271 +++++++++++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 .cproject create mode 100644 .project create mode 100644 .settings/org.eclipse.cdt.core.prefs create mode 100644 src/stubi.c diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..7f2148c --- /dev/null +++ b/.cproject @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..f649d94 --- /dev/null +++ b/.project @@ -0,0 +1,26 @@ + + + stubi + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs new file mode 100644 index 0000000..f925dfa --- /dev/null +++ b/.settings/org.eclipse.cdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978/CYGWIN_HOME/delimiter=; +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978/CYGWIN_HOME/operation=replace +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978/CYGWIN_HOME/value=C\:\\cygwin +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978/append=true +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978/appendContributed=true +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233/CYGWIN_HOME/delimiter=; +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233/CYGWIN_HOME/operation=replace +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233/CYGWIN_HOME/value=C\:\\cygwin +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233/append=true +environment/project/cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233/appendContributed=true diff --git a/src/stubi.c b/src/stubi.c new file mode 100644 index 0000000..69e9c60 --- /dev/null +++ b/src/stubi.c @@ -0,0 +1,271 @@ +/*! + Name : stubi.c + Author : Martin Winkler + Version : + Copyright : + Description : Scan a folder for .c files and generate stubs from function definitions + + @todo complete function dissection + @todo output stub header and function + @attention Using regular expressions to scan c files for function definitions. No 100% + success rate and should be seen as helper. Result must be reviewed manually. + */ + +#include +#include +#include +#include +#include + +#define STUBI_FUNCTION_REGEX "^[ \\t]*([ _\\*[:alnum:]]*) ([_\\*[:alnum:]]*)[ \\t]*\\(([^\\)]*)" +#define STUBI_FUNCTION_MULTI "[ \\t]*(.*)" +#define STUBI_FUNCTION_MULTI_END "[ \\t]*(.*)\\)[ \\t\\{;]*" + +static int one(const struct dirent *unused) +{ + return 1; +} + +static char *gnu_basename(char *path) +{ + char *base = strrchr(path, '/'); + return base ? base + 1 : path; +} + +/*! + * @brief Process a string (e.g. from getline()) if it is a single or multiple line function definition + * @todo closing parenthesis within parameter list will break the detection + * @retval -1 Invalid regula expressions + * @retval -2 Given String not a function + * @retval 0 function evaluated + */ +static int matchFunction(char *aLine) +{ + const size_t maxGroup = 10; + regmatch_t matchGroup[maxGroup]; + const char *pattern = + STUBI_FUNCTION_REGEX; + const char *patternend = + STUBI_FUNCTION_REGEX "\\)"; + regex_t regX; + regex_t regXEnd; + regex_t regXMulti; + regex_t regXMultiEnd; + uint8_t i = 0; + char funPrefix[256] = + { 0 }; + static uint8_t multiParamFlag = 0; + uint8_t multiParamEndFlag = 0; + + if (0 > regcomp(®X, pattern, REG_EXTENDED | REG_NEWLINE)) + { + perror("Error regex\n"); + return -1; + } + + if (0 > regcomp(®XEnd, patternend, REG_EXTENDED | REG_NEWLINE)) + { + perror("Error regexend\n"); + return -1; + } + + if (0 > regcomp(®XMulti, STUBI_FUNCTION_MULTI, REG_EXTENDED | REG_NEWLINE)) + { + perror("Error regXMulti\n"); + return -1; + } + + if (0 > regcomp(®XMultiEnd, STUBI_FUNCTION_MULTI_END, REG_EXTENDED | REG_NEWLINE)) + { + perror("Error regXMultiEnd\n"); + return -1; + } + + if (multiParamFlag) + { + if (0 == regexec(®XMultiEnd, aLine, maxGroup, matchGroup, 0)) + { + // end of multi line function + ++multiParamFlag; + multiParamEndFlag = 1; + } + else + { + // continuation of multi line function + (void) regexec(®XMulti, aLine, maxGroup, matchGroup, 0); + ++multiParamFlag; + } + } + else if (0 == regexec(®XEnd, aLine, maxGroup, matchGroup, 0)) + { + // single line function + multiParamFlag = 0; + } + else if (0 == regexec(®X, aLine, maxGroup, matchGroup, 0)) + { + // start of multi line function + ++multiParamFlag; + printf("[ mls][%d]:", multiParamFlag); + } + else + { + // no fit + return -2; + } + + switch (multiParamFlag) + { + case 0: // single line function definition + case 1: // first line of multi line function definition + { + (void) strlcpy(funPrefix, &aLine[matchGroup[1].rm_so], (size_t) (matchGroup[1].rm_eo - matchGroup[1].rm_so) + 1); + + if ( // + NULL == strstr(funPrefix, "extern") // + && NULL == strstr(funPrefix, "EXTERN") // + && NULL == strstr(funPrefix, "static") // + && NULL == strstr(funPrefix, "STATIC") // + && matchGroup[2].rm_so < matchGroup[2].rm_eo) + { + printf("[ sl ]:%s", funPrefix); + for (i = 2; i < maxGroup && 0 <= matchGroup[i].rm_so; ++i) + { + printf(" (%.3ld - %.3ld): ", matchGroup[i].rm_so, matchGroup[i].rm_eo); + printf("%.*s", (int) (matchGroup[i].rm_eo - matchGroup[i].rm_so), &aLine[matchGroup[i].rm_so]); + } + printf("\n"); + } + // TODO special handling for static functions (as extern in stub header) + else if (NULL != strstr(funPrefix, "static") || NULL != strstr(funPrefix, "STATIC")) + { + printf("[todo] %s %.*s\n", funPrefix, (int) (matchGroup[2].rm_eo - matchGroup[2].rm_so), &aLine[matchGroup[2].rm_so]); + } + // ignore functions declared as extern + else if (NULL != strstr(funPrefix, "extern") || NULL != strstr(funPrefix, "EXTERN")) + { + printf("[ nu ] %s %.*s\n", funPrefix, (int) (matchGroup[2].rm_eo - matchGroup[2].rm_so), &aLine[matchGroup[2].rm_so]); + } + break; + } + default: // further lines + { + if (multiParamEndFlag) + { + printf("[ mle][%d]:", multiParamFlag); + } + else + { + printf("[ ml ][%d]:", multiParamFlag); + } + + if (matchGroup[1].rm_so < matchGroup[1].rm_eo) + { + for (i = 1; i < maxGroup && 0 <= matchGroup[i].rm_so; ++i) + { + printf("(%.3ld-%.3ld):", matchGroup[i].rm_so, matchGroup[i].rm_eo); + printf("%.*s", (int) (matchGroup[i].rm_eo - matchGroup[i].rm_so), &aLine[matchGroup[i].rm_so]); + } + printf("\n"); + } + + if (multiParamEndFlag) + { + multiParamFlag = 0; + multiParamEndFlag = 0; + } + + break; + } + } + + return 0; +} + +/* + * @brief Opens given file for line by line function matching + * @param *path file path + * @retval 0 matching complete + * @retval -1 error opening file + */ +static int scanFile(char *path) +{ + FILE *fdesc; + ssize_t charRead = 0; + size_t lineSize = 0; + char *fileLine = NULL; // will be allocated by getline(); must be freed + + fdesc = fopen(path, "r"); + if (NULL == fdesc) + { + perror("Error open file"); + return -1; + } + + do + { + charRead = getline(&fileLine, &lineSize, fdesc); + if (0 <= charRead) + { + (void) matchFunction(fileLine); + } + } while (0 <= charRead); + + free(fileLine); + (void) fclose(fdesc); + return 0; +} + +/* + * @brief Scan given folder for .c files + * @param argc amount of command line arguments + * @param **argv array of argments separated by spaces + * @retval -1 Directory not found or regex compilation error + * @retval 0 Direcotry scanned successfully + * @details + * see printf for usage + */ +int main(int argc, char **argv) +{ + struct dirent **eps; + int n; + regex_t regX; + char filePath[256] = + { 0 }; + const char *pattern = "^.*\\.[cC]"; + + printf("%s %s\n\n", argv[1], argv[2]); + + if (3 != argc) + { + printf("Usage:\n"); + printf(" %s \n", gnu_basename(argv[0])); + return -1; + } + + if (regcomp(®X, pattern, REG_NEWLINE)) + { + fprintf(stderr, "bad pattern: '%s'\n", pattern); + return -1; + } + + n = scandir(argv[1], &eps, one, alphasort); + if (n >= 0) + { + int cnt; + for (cnt = 0; cnt < n; ++cnt) + { + if (0 == regexec(®X, eps[cnt]->d_name, 0, NULL, 0) // + && DT_REG == eps[cnt]->d_type) + { + sprintf(filePath, "%s/%s", argv[1], eps[cnt]->d_name); + printf("%s (%d)\n", filePath, eps[cnt]->d_type); + scanFile(filePath); + } + } + } + else + perror("Couldn't open the directory"); + + return 0; +} +