- refactored to modular structure

This commit is contained in:
2017-02-27 07:28:38 +00:00
parent ba8c750b75
commit 05dd972ec7
9 changed files with 478 additions and 271 deletions

75
src/ext/xstring.c Normal file
View File

@@ -0,0 +1,75 @@
/*!
* @file xstring.c
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 27.02.2017
* @author SESA354004
*/
#include "xstring.h"
#include "ctype.h"
char* gnu_basename(char *path)
{
char *base = strrchr(path, '/');
return base ? base + 1 : path;
}
/*!
* @brief Trim leading and trailing whitespaces
* @param [in] *str Input string
* @retval char* pointer to the trimmed substring
*
* @details
* This function returns a pointer to a substring of the original string.
* If the given string was allocated dynamically, the caller must not overwrite
* that pointer with the returned value, since the original pointer must be
* deallocated using the same allocator with which it was allocated. The return
* value must NOT be deallocated using free() etc.
*/
char* strntrimStatic(char *aStr, size_t aMaxLength)
{
char *end;
// Trim leading space
while (isspace((unsigned char)*aStr) && 0 < aMaxLength)
{
if (--aMaxLength > 0)
{
++aStr;
}
}
// All spaces at termination or end of max length
if (*aStr == '\0' || 0 == aMaxLength)
{
return aStr;
}
// Trim trailing space
if (strlen(aStr) >= aMaxLength)
{
end = aStr + aMaxLength - 1;
}
else
{
end = aStr + strlen(aStr) - 1;
}
while (end > aStr && isspace((unsigned char)*end))
{
end--;
}
// Write new null terminator (if length is enough)
if (end < (aStr + aMaxLength - 1))
{
*(end + 1) = '\0';
}
return aStr;
}

21
src/ext/xstring.h Normal file
View File

@@ -0,0 +1,21 @@
/*!
* @file xstring.h
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 27.02.2017
* @author SESA354004
*/
#ifndef XSTRING_H_
#define XSTRING_H_
#include <string.h>
char* gnu_basename(char *path);
char* strntrimStatic(char *aStr, size_t aMaxLength);
#endif /* XSTRING_H_ */

32
src/ext/xtime.h Normal file
View File

@@ -0,0 +1,32 @@
/*!
* @file xtime.h
* @brief Provides additional definitions for working with delays
*
* Project: \n
* Subsystem: \n
* Module: mst\n
* Code: GNU-C\n
*
* @date 08.06.2016
* @author SESA354004
*/
#ifndef XTIME_H_
#define XTIME_H_
#include <time.h>
/*! @brief Convert milliseconds to nanoseconds */
#define XTIME_MSTONS(milliseconds) (milliseconds * 1000000L)
/*! @brief Convert microseconds to nanoseconds */
#define XTIME_USTONS(microseconds) (microseconds * 1000L)
/*! @brief Convert nanoseconds to milliseconds*/
#define XTIME_NSTOMS(nanoseconds) (nanoseconds / 1000000L)
/*! @brief Convert nanoseconds to microseconds*/
#define XTIME_NSTOUS(nanoseconds) (nanoseconds / 1000L)
/*! @brief Only microseconds up to 1000000 are supported */
#define XTIME_TIMESPEC_US(seconds, microseconds) (const struct timespec[]){{seconds, XTIME_USTONS(microseconds)}}
/*! @brief Only milliseconds up to 1000 are supported */
#define XTIME_TIMESPEC_MS(seconds, milliseconds) (const struct timespec[]){{seconds, XTIME_MSTONS(milliseconds)}}
#endif /* XTIME_H_ */

41
src/ext/xtypes.h Normal file
View File

@@ -0,0 +1,41 @@
/*!
* @file xtypes.h
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 27.02.2017
* @author SESA354004
*/
#ifndef XTYPES_H_
#define XTYPES_H_
#include <stddef.h> // definition of NULL
#include <stdint.h> // fixed width types
#include <stdbool.h> // definition of bool
#define STRINGIZE_2(s) #s
/*!
* @brief Stringify the content of a definition
* @details
* Usage example:
* @code
#define VERSION_MAJOR 4
#define VERSION_MINOR 47
#define VERSION_STRING "v" STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR)
@endcode
*/
#define STRINGIZE(s) STRINGIZE_2(s)
#if defined(UNIT_TEST) || defined(_DEBUG)
#define STATIC
#else
#define STATIC static
#endif
#endif /* XTYPES_H_ */

78
src/main.c Normal file
View File

@@ -0,0 +1,78 @@
/*!
* @file main.c
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 27.02.2017
* @author SESA354004
*/
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <regex.h>
#include "xtypes.h"
#include "xstring.h"
#include "stubser/stubser_if.h"
static int one(const struct dirent *unused)
{
return 1;
}
/*
* @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 <Source Dir> <Target Dir>\n", gnu_basename(argv[0]));
return -1;
}
if (regcomp(&regX, 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(&regX, 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;
}

View File

@@ -1,271 +0,0 @@
/*!
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 <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <regex.h>
#include <string.h>
#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(&regX, pattern, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regex\n");
return -1;
}
if (0 > regcomp(&regXEnd, patternend, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regexend\n");
return -1;
}
if (0 > regcomp(&regXMulti, STUBI_FUNCTION_MULTI, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regXMulti\n");
return -1;
}
if (0 > regcomp(&regXMultiEnd, STUBI_FUNCTION_MULTI_END, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regXMultiEnd\n");
return -1;
}
if (multiParamFlag)
{
if (0 == regexec(&regXMultiEnd, aLine, maxGroup, matchGroup, 0))
{
// end of multi line function
++multiParamFlag;
multiParamEndFlag = 1;
}
else
{
// continuation of multi line function
(void) regexec(&regXMulti, aLine, maxGroup, matchGroup, 0);
++multiParamFlag;
}
}
else if (0 == regexec(&regXEnd, aLine, maxGroup, matchGroup, 0))
{
// single line function
multiParamFlag = 0;
}
else if (0 == regexec(&regX, 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 <Source Dir> <Target Dir>\n", gnu_basename(argv[0]));
return -1;
}
if (regcomp(&regX, 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(&regX, 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;
}

207
src/stubser/stubser.c Normal file
View File

@@ -0,0 +1,207 @@
/*!
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 <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <regex.h>
#include "xtypes.h"
#include "xstring.h"
#define STUBI_FUNCTION_REGEX "^[ \\t]*([ _\\*[:alnum:]]*) ([_\\*[:alnum:]]*)[ \\t]*\\(([^\\)]*)"
#define STUBI_FUNCTION_MULTI "[ \\t]*(.*)"
#define STUBI_FUNCTION_MULTI_END "[ \\t]*(.*)\\)[ \\t\\{;]*"
/*!
* @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(&regX, pattern, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regex\n");
return -1;
}
if (0 > regcomp(&regXEnd, patternend, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regexend\n");
return -1;
}
if (0 > regcomp(&regXMulti, STUBI_FUNCTION_MULTI, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regXMulti\n");
return -1;
}
if (0 > regcomp(&regXMultiEnd, STUBI_FUNCTION_MULTI_END, REG_EXTENDED | REG_NEWLINE))
{
perror("Error regXMultiEnd\n");
return -1;
}
if (multiParamFlag)
{
if (0 == regexec(&regXMultiEnd, aLine, maxGroup, matchGroup, 0))
{
// end of multi line function
++multiParamFlag;
multiParamEndFlag = 1;
}
else
{
// continuation of multi line function
(void) regexec(&regXMulti, aLine, maxGroup, matchGroup, 0);
++multiParamFlag;
}
}
else if (0 == regexec(&regXEnd, aLine, maxGroup, matchGroup, 0))
{
// single line function
multiParamFlag = 0;
}
else if (0 == regexec(&regX, 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
*/
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;
}

19
src/stubser/stubser_if.h Normal file
View File

@@ -0,0 +1,19 @@
/*!
* @file stubser_if.h
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 27.02.2017
* @author SESA354004
*/
#ifndef STUBSER_STUBSER_IF_H_
#define STUBSER_STUBSER_IF_H_
int scanFile(char *path);
#endif /* STUBSER_STUBSER_IF_H_ */