From 444b9fb07800c1e34a85ed954924f4daf8acf4e0 Mon Sep 17 00:00:00 2001 From: Martin Winkler Date: Fri, 3 Mar 2017 11:08:07 +0000 Subject: [PATCH] - still WIP for parsing of parameter - new blockdetection and -removal functions (used for comments and function bodies) --- src/stubser/cfile_parser.c | 273 +++++++++++++++++++++++++++++++------ 1 file changed, 230 insertions(+), 43 deletions(-) diff --git a/src/stubser/cfile_parser.c b/src/stubser/cfile_parser.c index 8c3af2d..7b58863 100644 --- a/src/stubser/cfile_parser.c +++ b/src/stubser/cfile_parser.c @@ -22,8 +22,16 @@ #define CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS 10 +/*! @brief Block detection return values */ +typedef enum _CFILE_BLOCK_RETURN_T +{ + CFILE_BLOCK_DETECT_ERROR = -1, /*!< @brief description */ + CFILE_BLOCK_DETECT_NONE = 0, /*!< @brief description */ + CFILE_BLOCK_DETECT_START = 1, /*!< @brief description */ + CFILE_BLOCK_DETECT_END = 2, /*!< @brief description */ +} cfile_block_return_t; + STATIC bool cfile_parser_initialized = false; -STATIC bool blockComment = false; STATIC uint8_t cfile_parser_functionLine = 0; STATIC cfunction_t *cfile_parser_function = NULL; STATIC regex_t regX; @@ -82,10 +90,11 @@ int8_t cfile_parser_init() return 0; } +#if(0) STATIC void printMatchGroup(char *aString, regmatch_t *aMatchGroup) { char match[1024] = - { 0 }; + { 0}; uint8_t i = 0; for (i = 0; i < CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS && 0 <= aMatchGroup[i].rm_so; ++i) @@ -99,6 +108,7 @@ STATIC void printMatchGroup(char *aString, regmatch_t *aMatchGroup) } } } +#endif STATIC void checkFunctionType(cfunction_t *aFunction) { @@ -168,24 +178,226 @@ STATIC int8_t matchFunctionStart(cfunction_t *aFunction, char *aString, size_t a return 0; } +/*! + * @brief Find first given "start" or "end" string and return position + * @param [in] *aBlockStart Terminated string defining the start of a block + * @param [in] *aBlockEnd Terminated string defining the end of a block + * @param [in] *aLine Terminated line (e.g. read from a file getline()) + * @param [out] **aPosition Pointing to found block string (realted to \ref aRemove) / NULL for CFILE_BLOCK_DETECT_NONE or CFILE_BLOCK_DETECT_ERROR + * @param [in] aRemove false - remove only content of block; true - also remove block strings + * @return cfile_block_return_t + * @retval CFILE_BLOCK_DETECT_START Start found + * @retval CFILE_BLOCK_DETECT_END End found + * @retval CFILE_BLOCK_DETECT_NONE No start or end found + * @retval CFILE_BLOCK_DETECT_ERROR Null pointer detected + */ +STATIC cfile_block_return_t cBlockDetection(const char *aBlockStart, const char *aBlockEnd, char *aLine, char **aPosition, bool aRemove) +{ + char *blockStart = NULL; + char *blockEnd = NULL; + cfile_block_return_t ret = CFILE_BLOCK_DETECT_NONE; + + if ( NULL == aBlockStart || NULL == aBlockEnd || NULL == aLine || NULL == aPosition) + { + perror("Null pointer"); + return CFILE_BLOCK_DETECT_ERROR; + } + + blockStart = strstr(aLine, aBlockStart); + blockEnd = strstr(aLine, aBlockEnd); + + if (NULL == blockStart && NULL == blockEnd) + { + // no block element + ret = CFILE_BLOCK_DETECT_NONE; + } + else if (NULL == blockStart) + { + // last line of block + ret = CFILE_BLOCK_DETECT_END; + } + else if (NULL == blockEnd) + { + // first line of block + + ret = CFILE_BLOCK_DETECT_START; + } + else if (blockStart < blockEnd) + { + // inline block + ret = CFILE_BLOCK_DETECT_START; + } + else + { + // last line of multi line block with further blocks in line + ret = CFILE_BLOCK_DETECT_END; + } + + switch (ret) + { + case CFILE_BLOCK_DETECT_START: + { + *aPosition = (aRemove ? blockStart : blockStart + strlen(aBlockStart)); + break; + } + case CFILE_BLOCK_DETECT_END: + { + *aPosition = (aRemove ? blockEnd + strlen(aBlockEnd) : blockEnd); + break; + } + case CFILE_BLOCK_DETECT_NONE: + { + *aPosition = NULL; + break; + } + default: + { + ret = CFILE_BLOCK_DETECT_ERROR; + *aPosition = NULL; + break; + } + } + + return ret; +} + +/*! + * @brief Remove blocks defined by "start" and "end" + * @attention May be called multiple time (for a whole file). *aHelper must not be changed within the process. + * @param [in] *aLine Terminated line (e.g. read from a file getline()) + * @param [in] *aBlockStart Terminated string defining the start of a block + * @param [in] *aBlockEnd Terminated string defining the end of a block + * @param [in,out] *aHelper Storage for block traversal + * @param [in] aRemove false - remove only content of block; true - also remove block strings + * @retval 0 Blocks removed or none found + * @retval 1 Line only within block + * @retval -1 Invalid block ending ("end" without corresponding "start") + * @retval -2 Null pointer detected + */ +STATIC int8_t cBlockRemoval(char *aLine, const char *aBlockStart, const char *aBlockEnd, uint32_t *aHelper, bool aRemove) +{ + const uint8_t depth = 1; // preparation to support which depth should be removed for nested block + bool blockLine = false; + int8_t ret = -1; + bool whileRun = true; + char *blockWorker = NULL; + char *blockMatch = NULL; + char *blockStart = NULL; + cfile_block_return_t blockDetected = CFILE_BLOCK_DETECT_NONE; + + if (NULL == aLine || NULL == aBlockStart || NULL == aBlockEnd || NULL == aHelper) + { + perror("Null pointer"); + return -2; + } + + blockWorker = aLine; + if (depth <= *aHelper) + { + blockStart = aLine; + blockLine = true; + } + + while (whileRun && CFILE_BLOCK_DETECT_NONE <= (blockDetected = cBlockDetection(aBlockStart, aBlockEnd, blockWorker, &blockMatch, aRemove))) + { + switch (blockDetected) + { + case CFILE_BLOCK_DETECT_START: + { + ++*aHelper; + if (NULL == blockStart && depth <= *aHelper) + { + blockStart = blockMatch; + } + blockWorker = (aRemove ? blockMatch + strlen(aBlockStart) : blockMatch); + break; + } + case CFILE_BLOCK_DETECT_END: + { + if (NULL != blockStart) + { + // inline comment + if (depth < *aHelper) + { + // remove block elements within depth + n + blockMatch += (aRemove ? 0 : strlen(aBlockEnd)); + } + strlcpy(blockStart, blockMatch, strlen(blockMatch) + 1); + blockMatch = NULL; + if (depth >= *aHelper) + { + // block removed when last end is hit + blockWorker = (aRemove ? blockStart : blockStart + strlen(aBlockEnd)); + blockStart = NULL; + } + else + { + blockWorker = blockStart; + } + } + + if (depth == *aHelper) + { + blockLine = false; + } + if (0 < *aHelper) + { + --*aHelper; + } + else + { + // error closing brace without beginning + whileRun = false; + ret = -1; + } + break; + } + case CFILE_BLOCK_DETECT_NONE: + { + if (NULL != blockStart && depth <= *aHelper) + { + // lines within a block + strlcpy(blockStart, CPARS_LINE_ENDING, strlen(CPARS_LINE_ENDING) + 1); + } + whileRun = false; + if (blockLine) + { + ret = 1; + } + else + { + ret = 0; + } + break; + } + default: + { + perror("Fatal unknown case"); + whileRun = false; + ret = -1; + break; + } + } + } + + return ret; +} + /*! * @brief Remove comments from given line * @param [in] *aLine terminated string - * @param [out] param1 paramdescription1 - * @retval 0 comments removed - * @retval 1 line within block comment (no c evaluation needed) - * @retval -1 NULL pointer detected + * @return see \ref cBlockRemoval() + * @retval -2 NULL pointer detected */ -int8_t removeComments(char *aLine) +STATIC int8_t removeCcomments(char *aLine) { - bool emptyLine = false; + static uint32_t helper = 0; char *comment = NULL; - char *commentEnd = NULL; if (NULL == aLine) { perror("Null pointer"); - return -1; + return -2; } // remove basic inline comments @@ -196,54 +408,30 @@ int8_t removeComments(char *aLine) comment = NULL; } - // remove block comments (also across multiple lines) - if (blockComment) - { - emptyLine = true; - comment = aLine; - } - else - { - comment = strstr(aLine, CPARS_COMMENT_BLOCK_START); - } - while (comment) - { - commentEnd = strstr(comment, CPARS_COMMENT_BLOCK_END); - if (NULL != commentEnd) - { - // copy character without block comment ending (strlen(CPARS_COMMENT_BLOCK_END)) - strlcpy(comment, commentEnd + strlen(CPARS_COMMENT_BLOCK_END), strlen(commentEnd + strlen(CPARS_COMMENT_BLOCK_END)) + 1); - comment = strstr(aLine, "/*"); - blockComment = false; - emptyLine = false; - } - else - { - strlcpy(comment, CPARS_LINE_ENDING, strlen(CPARS_LINE_ENDING) + 1); - blockComment = true; - comment = NULL; - } - } - - return (int8_t) emptyLine; + return cBlockRemoval(aLine, CPARS_COMMENT_BLOCK_START, CPARS_COMMENT_BLOCK_END, &helper, true); } /*! * @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 -1 Invalid regular expressions * @retval -2 Given String not a function * @retval 0 function evaluated */ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) { + static uint32_t braceHelper = 0; const size_t maxGroup = CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS; regmatch_t matchGroup[maxGroup]; bool functionEnd = false; cfunction_type_t tempFunctionType = CFUNCTION_TYPE_UNDEF; cfunction_parameter_t *tempParameter = NULL; - if (0 != removeComments(aLine)) + if (0 != removeCcomments(aLine)) + { + return NULL; + } + if (0 != cBlockRemoval(aLine, "{", "}", &braceHelper, false)) { return NULL; } @@ -349,7 +537,6 @@ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) } if (functionEnd) { - // TODO clean function if (CFUNCTION_TYPE_UNDEF == tempFunctionType) { cfunction_freeFunction(&cfile_parser_function);