diff --git a/src/ext/xmalloc.c b/src/ext/xmalloc.c index ea215dc..6ef87b1 100644 --- a/src/ext/xmalloc.c +++ b/src/ext/xmalloc.c @@ -71,3 +71,9 @@ char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize) return *aDest; } +void xfree(void **aDest) +{ + free(*aDest); + *aDest = NULL; +} + diff --git a/src/ext/xmalloc.h b/src/ext/xmalloc.h index fe5e5c9..7a6653a 100644 --- a/src/ext/xmalloc.h +++ b/src/ext/xmalloc.h @@ -17,6 +17,7 @@ #include void *xmalloc(size_t size); +void xfree(void**); char* xmallocStrlcpy(char **aDest, char *aSource, size_t aSize); char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize); diff --git a/src/stubser/cfile.c b/src/stubser/cfile.c new file mode 100644 index 0000000..e58dfab --- /dev/null +++ b/src/stubser/cfile.c @@ -0,0 +1,79 @@ +/*! + * @file cfile.c + * @brief + * @details + * Project: \n + * Subsystem: \n + * Module: \n + * Code: GNU-C\n + * + * @date 08.03.2017 + * @author SESA354004 + */ +#include +#include +#include "xtypes.h" +#include "xmalloc.h" +#include "cfile_if.h" + +cfile_variable_t* cfile_newVariable(cfile_variableList_t *aList) +{ + cfile_variable_t *new = NULL; + + if (NULL == aList) + { + perror("Null pointer"); + return NULL; + } + + new = (cfile_variable_t*) xmalloc(sizeof(cfile_variable_t)); + memset(new, 0, sizeof(cfile_variable_t)); + + if (NULL == aList->head) + { + aList->head = new; + aList->current = new; + } + else + { + aList->current->next = new; + aList->current = new; + } + ++aList->amount; + return new; +} + +int8_t cfile_freeVariables(cfile_variableList_t *aVariable) +{ + cfile_variable_t *work = NULL; + cfile_variable_t *next = NULL; + + if (NULL == aVariable) + { + perror("Null pointer"); + return -1; + } + + work = aVariable->head; + + while (work) + { + next = work->next; + free(work->type); + free(work->name); + free(work); + work = next; + } + + aVariable->amount = 0; + aVariable->head = NULL; + aVariable->current = NULL; + + return 0; +} + +void cfile_free(cfile_t *aCfile) +{ + cfile_freeVariables(&aCfile->variables); + cfunction_freeList(&aCfile->functions); +} diff --git a/src/stubser/cfile_if.h b/src/stubser/cfile_if.h new file mode 100644 index 0000000..fff067d --- /dev/null +++ b/src/stubser/cfile_if.h @@ -0,0 +1,53 @@ +/*! + * @file cfile_if.h + * @brief + * @details + * Project: \n + * Subsystem: \n + * Module: \n + * Code: GNU-C\n + * + * @date 08.03.2017 + * @author SESA354004 + */ + +#ifndef STUBSER_CFILE_IF_H_ +#define STUBSER_CFILE_IF_H_ + +#include "cfunction_if.h" + +/*! @brief Parameter list node */ +typedef struct _CFILE_VARIABLE_T +{ + char* prefix; /*!< @brief variable prefix (e.g. static) */ + char* type; /*!< @brief data type */ + char* name; /*!< @brief name */ + struct _CFILE_VARIABLE_T *next; +} cfile_variable_t; + +/*! @brief parameter array */ +typedef struct _CFILE_VARIABLE_LIST_T +{ + uint8_t amount; + cfile_variable_t *head; + cfile_variable_t *current; +} cfile_variableList_t; + +/*! @brief brief_description */ +typedef struct _CFILE_T +{ + cfile_variableList_t variables; /*! @brief C variables */ + cfunction_list_t functions; /*!< @brief C functions */ +} cfile_t; + +#define CFILE_T_DEFAULT {\ + .variables.amount = 0, \ + .variables.head = NULL, \ + .variables.current = NULL, \ + .functions = CFUNCTION_LIST_DEFAULT } + +cfile_variable_t* cfile_newVariable(cfile_variableList_t *aList); +int8_t cfile_freeVariables(cfile_variableList_t *aVariable); +void cfile_free(cfile_t *aCfile); + +#endif /* STUBSER_CFILE_IF_H_ */ diff --git a/src/stubser/cfile_parser.c b/src/stubser/cfile_parser.c index 2a3dbf0..7923294 100644 --- a/src/stubser/cfile_parser.c +++ b/src/stubser/cfile_parser.c @@ -17,12 +17,11 @@ #include "xtypes.h" #include "xstring.h" #include "xmalloc.h" -#include "cfunction_if.h" +#include "cfile_if.h" #include "cfile_parser_loc.h" +#include "cfile_parser_worker_loc.h" #include "debug.h" -#define CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS 10 - /*! @brief Block detection return values */ typedef enum _CFILE_BLOCK_RETURN_T { @@ -44,6 +43,11 @@ STATIC regex_t regXmlProto; STATIC regex_t regXproto; STATIC regex_t regXprefix; STATIC regex_t regXparameter; +STATIC regex_t regXvariable; + +STATIC regex_t regXExpressionStart; +STATIC regex_t regXExpressionAssign; +STATIC regex_t regXExpressionEnd; // line evaluation related variables STATIC uint32_t cfile_parser_removeCommentHelper = 0; @@ -52,6 +56,21 @@ STATIC char *cfile_parser_parameterStorage = NULL; int8_t cfile_parser_init() { + if (0 > regcomp(®XExpressionStart, CPARS_EXPRESSION_START, (REG_EXTENDED | REG_NEWLINE))) + { + perror("Error regex\n"); + return -1; + } + if (0 > regcomp(®XExpressionAssign, CPARS_EXPRESSION_EXPEND, (REG_EXTENDED | REG_NEWLINE))) + { + perror("Error regex\n"); + return -1; + } + if (0 > regcomp(®XExpressionEnd, CPARS_EXPRESSION_END, (REG_EXTENDED | REG_NEWLINE))) + { + perror("Error regex\n"); + return -1; + } if (0 > regcomp(®X, FUNCTION_BASE, (REG_EXTENDED | REG_NEWLINE))) { perror("Error regex\n"); @@ -97,6 +116,11 @@ int8_t cfile_parser_init() perror("Error regex\n"); return -1; } + if (0 > regcomp(®Xvariable, CPARS_REGEX_VARIABLE, (REG_EXTENDED | REG_NEWLINE))) + { + perror("Error regex\n"); + return -1; + } cfile_parser_initialized = true; return 0; @@ -471,6 +495,7 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction) return 0; } +#if(0) /*! * @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 @@ -478,7 +503,7 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction) * @retval -2 Given String not a function * @retval 0 function evaluated */ -STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) +STATIC cfunction_t* cfile_parser_evaluateLine1(char *aLine) { const size_t maxGroup = CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS; regmatch_t matchGroup[maxGroup]; @@ -573,7 +598,7 @@ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) switch (cfile_parser_functionLine) { case 0: // single line function definition - case 1: // first line of multi line function definition + case 1:// first line of multi line function definition { // TODO multiple functions in one line cfile_parser_function = cfunction_newFunction(); @@ -623,12 +648,63 @@ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) return NULL; } +#endif -int8_t cfile_parser(char *aPath, cfunction_list_t *aList) +STATIC bool workerActive = false; +const stringWorker cWorker[2] = +{ cfile_expWorker, // Parse for variables + NULL }; +STATIC char *match = NULL; +STATIC int8_t cfile_parser_evaluateLine(uint32_t aNumber, char *aLine, cfile_t *aCfile) +{ + stringWorker *worker = (stringWorker*) cWorker; + char *position = aLine; + char *result = NULL; + size_t cSize = 0; + + regex_t *matchStart = ®XExpressionStart; + regex_t *matchEnd = ®XExpressionEnd; + + DEBUG_LOG_APPEND(1, "[ Li %04u] %s\n", aNumber, aLine); + // start with variable worker + + while (position && NULL != *worker) + { + result = (*worker)(&position, matchStart, matchEnd, &workerActive, &cSize); + if (NULL == result) + { + if (false == workerActive) + { + xfree((void**) &match); + ++worker; + } + continue; + } + xmallocStrlcat(&match, result, cSize); + + if (false == workerActive) + { + DEBUG_LOG_APPEND(1, "Works %zu %s\n", cSize, match); + // TODO evaluate expression according to worker + xfree((void**) &match); + worker = (stringWorker*) cWorker; + } + else + { + // force space between findings + xmallocStrlcat(&match, " ", 2); + } + } + return 0; +} + +int8_t cfile_parser(char *aPath, cfile_t *aCfile) { FILE *fdesc; ssize_t charRead = 0; size_t lineSize = 0; + uint32_t lineNumber = 1; + char *cTemp = NULL; char *fileLine = NULL; // will be allocated by getline(); must be freed if (false == cfile_parser_initialized) @@ -648,12 +724,25 @@ int8_t cfile_parser(char *aPath, cfunction_list_t *aList) charRead = getline(&fileLine, &lineSize, fdesc); if (0 <= charRead) { - cfunction_t *function = NULL; - function = cfile_parser_evaluateLine(fileLine); - if (NULL != function) + if (0 != removeCcomments(fileLine)) { - (void) cfunction_addFunction(aList, function); + continue; } + if (0 != cBlockRemoval(fileLine, "{", "}", &cfile_parser_removeBraceHelper, false, false)) + { + continue; + } + cTemp = strrchr(fileLine, '\n'); + if (cTemp) + { + *cTemp = '\0'; + } + cTemp = strrchr(fileLine, '\r'); + if (cTemp) + { + *cTemp = '\0'; + } + (void) cfile_parser_evaluateLine(lineNumber++, fileLine, aCfile); } } while (0 <= charRead); diff --git a/src/stubser/cfile_parser_if.h b/src/stubser/cfile_parser_if.h index 0d93cf9..4dcfb18 100644 --- a/src/stubser/cfile_parser_if.h +++ b/src/stubser/cfile_parser_if.h @@ -14,6 +14,6 @@ #ifndef STUBSER_CFILE_PARSER_IF_H_ #define STUBSER_CFILE_PARSER_IF_H_ -int8_t cfile_parser(char *aPath, cfunction_list_t *aList); +int8_t cfile_parser(char *aPath, cfile_t *aList); #endif /* STUBSER_CFILE_PARSER_IF_H_ */ diff --git a/src/stubser/cfile_parser_loc.h b/src/stubser/cfile_parser_loc.h index 8620025..393142b 100644 --- a/src/stubser/cfile_parser_loc.h +++ b/src/stubser/cfile_parser_loc.h @@ -14,6 +14,8 @@ #ifndef STUBSER_CFILE_PARSER_LOC_H_ #define STUBSER_CFILE_PARSER_LOC_H_ +#define CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS 10 + #define CPARS_LINE_ENDING "\r\n" #define CPARS_COMMENT_INLINE "//" #define CPARS_COMMENT_BLOCK_START "/*" @@ -27,10 +29,25 @@ #define FUNCTION_ML_PROTO FUNCTION_ML_PAR "\\).*[[:blank:]]*;" #define FUNCTION_PROTO FUNCTION_BASE "\\).*[[:blank:]]*;" +#define CPARS_REGEX_VARIABLE "^[[:blank:]]*([ _\\*[:alnum:]]*)[[:blank:]]*[;=]" #define CPARS_REGEX_PARAMETER "[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]*)[[:blank:]]*" - #define CPARS_REGEX_PREFIX "(extern|EXTERN|static|STATIC|volatile|near|far)[[:blank:]]+([^\\*]*\\**)" +#define CPARS_EXPRESSION_START "^[[:blank:]]*([A-Za-z][\\_\\*[:alnum:]]*)" +#define CPARS_EXPRESSION_EXPEND "[[:blank:]]*([=\{])[[:blank:]]*" +#define CPARS_EXPRESSION_END "[[:blank:]]*([\\};]+)" + #define CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup) (XREGEX_IS_MATCHGROUP(matchGroup, 1) && XREGEX_IS_MATCHGROUP(matchGroup, 2)) +/*! @brief Type of function definition */ +typedef enum _CELEMENT_TYPE_T +{ + CELEMENT_TYPE_UNDEF = 0, /*!< @brief undefined */ + CELEMENT_TYPE_INCLUDE = 1, /*!< @brief C #include */ + CELEMENT_TYPE_DEFINE = 2, /*!< @brief C #define */ + CELEMENT_TYPE_VARIABLE = 3, /*!< @brief Prototype C variable definition */ + CELEMENT_TYPE_FUNCTION = 4, /*!< @brief Prototype C function definition */ + CELEMENT_TYPE_LAST_ENUM +} celement_type_t; + #endif /* STUBSER_CFILE_PARSER_LOC_H_ */ diff --git a/src/stubser/cfile_parser_worker.c b/src/stubser/cfile_parser_worker.c new file mode 100644 index 0000000..0e7d4a4 --- /dev/null +++ b/src/stubser/cfile_parser_worker.c @@ -0,0 +1,69 @@ +/*! + * @file cfile_parser_worker.c + * @brief + * @details + * Project: \n + * Subsystem: \n + * Module: \n + * Code: GNU-C\n + * + * @date 09.03.2017 + * @author SESA354004 + */ + +#include "xtypes.h" +#include "xregex.h" +#include "debug.h" +#include "cfile_parser_loc.h" +#include "cfile_parser_worker_loc.h" + +char* cfile_expWorker(char **aInput, const regex_t *aStart, const regex_t *aEnd, bool *aActive, size_t *aSize) +{ + regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS]; + char *begin; + + if (!**aInput) + { + *aInput = NULL; + return NULL; + } + if (!*aActive) + { + *aSize = 0; + begin = NULL; + } + else + { + begin = *aInput; + } + + if (*aActive) + { + if (aEnd != NULL && 0 == regexec(aEnd, *aInput, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1)) + { + DEBUG_LOG_APPEND(1, "[ CEe]"); + *aActive = false; + *aSize += matchGroup[1].rm_so; // don't include end marker in result + *aInput += matchGroup[1].rm_eo; + return begin; + } + else + { + DEBUG_LOG_APPEND(1, "[ CE+]"); + *aSize += strlen(*aInput); + *aInput += strlen(*aInput); + return begin; + } + } + else if (0 == regexec(aStart, *aInput, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1)) + { + DEBUG_LOG_APPEND(1, "[ CEs]"); + *aActive = true; + *aSize += XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1); + begin = *aInput + matchGroup[1].rm_so; + *aInput += matchGroup[1].rm_eo; + cfile_expWorker(aInput, aStart, aEnd, aActive, aSize); + } + + return begin; +} diff --git a/src/stubser/cfile_parser_worker_loc.h b/src/stubser/cfile_parser_worker_loc.h new file mode 100644 index 0000000..5a7d1b4 --- /dev/null +++ b/src/stubser/cfile_parser_worker_loc.h @@ -0,0 +1,21 @@ +/*! + * @file cfile_parser_worker_loc.h + * @brief + * @details + * Project: \n + * Subsystem: \n + * Module: \n + * Code: GNU-C\n + * + * @date 09.03.2017 + * @author SESA354004 + */ + +#ifndef STUBSER_CFILE_PARSER_WORKER_LOC_H_ +#define STUBSER_CFILE_PARSER_WORKER_LOC_H_ + +typedef char* (*stringWorker)(char**, const regex_t *, const regex_t *, bool*, size_t*); + +char* cfile_expWorker(char **aInput, const regex_t *aStart, const regex_t *aEnd, bool *aActive, size_t *aSize); + +#endif /* STUBSER_CFILE_PARSER_WORKER_LOC_H_ */ diff --git a/src/stubser/cfunction_if.h b/src/stubser/cfunction_if.h index 2a23859..0981656 100644 --- a/src/stubser/cfunction_if.h +++ b/src/stubser/cfunction_if.h @@ -32,6 +32,14 @@ typedef struct _CFUNCTION_PARAMETER_T struct _CFUNCTION_PARAMETER_T *next; } cfunction_parameter_t; +/*! @brief parameter array */ +typedef struct _CFUNCTION_PARAMETER_LIST_T +{ + uint8_t amount; + cfunction_parameter_t *head; + cfunction_parameter_t *current; +} cfunction_parameterList_t; + /*! @brief brief_description */ typedef struct _CFUNCTION_T { @@ -39,12 +47,7 @@ typedef struct _CFUNCTION_T char *prefix; /*!< @brief prefix like static or extern */ char *dataType; /*!< @brief return type */ char *name; /*!< @brief name */ - struct _CFUNCTION_PARAMETER_LIST_T - { - uint8_t amount; - cfunction_parameter_t *head; - cfunction_parameter_t *current; - } parameter;/*!< @brief parameter array */ + cfunction_parameterList_t parameter;/*!< @brief parameter array */ struct _CFUNCTION_T *next; } cfunction_t; diff --git a/src/stubser/stubser.c b/src/stubser/stubser.c index 9a22fe8..887bd4c 100644 --- a/src/stubser/stubser.c +++ b/src/stubser/stubser.c @@ -19,7 +19,7 @@ #include "xtypes.h" #include "xstring.h" #include "xmalloc.h" -#include "cfunction_if.h" +#include "cfile_if.h" #include "cfile_parser_if.h" #include "stubser_if.h" #include "stubser_loc.h" @@ -194,7 +194,7 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a return 0; } -STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunctionList) +STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfile_t *aCfile) { FILE *cfile; FILE *cheader; @@ -202,7 +202,7 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc char *cHeaderName = NULL; cfunction_t *function = NULL; - if (NULL == aOutput || NULL == aFunctionList) + if (NULL == aOutput || NULL == aCfile) { return -1; } @@ -246,7 +246,7 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc fprintf(cheader, "#ifndef _STUB_%s_H"NEWLINES, aNoSuffix); fprintf(cheader, "#define _STUB_%s_H"NEWLINES NEWLINES, aNoSuffix); - function = aFunctionList->head; + function = aCfile->functions.head; while (function) { (void) createStubFunctionBlock(cfile, cheader, function); @@ -271,12 +271,12 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc int stubser_createStub(char *path, char* aNoSuffix, char *aOutput) { int8_t ret = -1; - cfunction_list_t functionList = - CFUNCTION_LIST_DEFAULT; + cfile_t cFile = + CFILE_T_DEFAULT; char fileName[PATH_MAX] = { '\0' }; - ret = cfile_parser(path, &functionList); + ret = cfile_parser(path, &cFile); DEBUG_LOG_APPEND(1, "\n"); if (0 != ret) { @@ -302,7 +302,7 @@ int stubser_createStub(char *path, char* aNoSuffix, char *aOutput) printf(STUB_CONSOLE_PARSE_OK_S1, gnu_basename(path)); #endif sprintf(fileName, "%s/stub_%s", aOutput, aNoSuffix); - ret = createStub(fileName, aNoSuffix, &functionList); + ret = createStub(fileName, aNoSuffix, &cFile); if (0 != ret) { printf(STUB_CONSOLE_CREATE_ERROR_S2, gnu_basename(path), ret); @@ -313,7 +313,7 @@ int stubser_createStub(char *path, char* aNoSuffix, char *aOutput) end_stubser_createStub: // function end target - cfunction_freeList(&functionList); + cfile_free(&cFile); return ret; }