diff --git a/src/stubser/cfile_parser.c b/src/stubser/cfile_parser.c index 62c6ed5..c9b380c 100644 --- a/src/stubser/cfile_parser.c +++ b/src/stubser/cfile_parser.c @@ -35,6 +35,8 @@ STATIC bool cfile_parser_initialized = false; STATIC regex_t regXfunction; STATIC regex_t regXprefix; STATIC regex_t regXparameter; +STATIC regex_t regXfuPtrSeparator; +STATIC regex_t regXfunctionPointer; STATIC regex_t regXvariable; STATIC regex_t regXExpressionStart; @@ -71,6 +73,16 @@ int8_t cfile_parser_init() perror("Error regex\n"); return -1; } + if (0 > regcomp(®XfuPtrSeparator, CPARS_REGEX_PARAMETER_FUPTR_SEPA, (REG_EXTENDED))) + { + perror("Error regex\n"); + return -1; + } + if (0 > regcomp(®XfunctionPointer, CPARS_REGEX_PARAMETER_FUPTR, (REG_EXTENDED))) + { + perror("Error regex\n"); + return -1; + } if (0 > regcomp(®Xvariable, CPARS_REGEX_VARIABLE, (REG_EXTENDED | REG_NEWLINE))) { perror("Error regex\n"); @@ -470,6 +482,42 @@ STATIC int8_t removeCcomments(char *aLine) return cBlockRemoval(aLine, CPARS_COMMENT_BLOCK_START, CPARS_COMMENT_BLOCK_END, &cfile_parser_removeCommentHelper, true, true); } +/*! + * @brief Replace ',' within function pointer parameter with '#' + * @attention must be reverted (\ref revertFunctionPointer) before usage + * @param [in,out] *aParameter String of parameter + * @retval uint32_t Amount of ',' replaced + */ +uint32_t prepareFunctionPointer(char *aParameter) +{ + uint32_t matches = 0; + char *worker = aParameter; + regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS]; + while (0 == regexec(®XfuPtrSeparator, worker, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0) && XREGEX_IS_MATCHGROUP(matchGroup, 1)) + { + ++matches; + worker[matchGroup[1].rm_so] = '#'; + } + return matches; +} + +/*! + * @brief Revert '#' within function pointer parameter to ',' + * @param [in,out] *aParameter String of parameter + * @retval uint32_t Amount of '#' replaced + */ +uint32_t revertFunctionPointer(char *aParameter) +{ + uint32_t matches = 0; + char *worker = aParameter; + while ((worker = strstr(worker, "#"))) + { + ++matches; + *worker = ','; + } + return matches; +} + STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction) { char *token = NULL; @@ -480,20 +528,23 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction) { return -1; } - + prepareFunctionPointer(aParameter); token = strtok(aParameter, ","); while (token) { - // TODO special handling for function pointer as argument - if (0 == regexec(®Xparameter, token, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0)) + if (0 == regexec(®XfunctionPointer, token, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0)) { + (void) revertFunctionPointer(token); + tempParameter = cfunction_newParameter(&aFunction->parameter); + tempParameter->type = CPARAMETER_TYPE_FUNCPTR; + if (XREGEX_IS_MATCHGROUP(matchGroup, 1)) { - xmallocStrlcpy(&tempParameter->type, &token[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); - if (NULL != tempParameter->type) + xmallocStrlcpy(&tempParameter->dataType, &token[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); + if (NULL != tempParameter->dataType) { - xStringTrim(tempParameter->type, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); + xStringTrim(tempParameter->dataType, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); } } if (XREGEX_IS_MATCHGROUP(matchGroup, 2)) @@ -504,10 +555,47 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction) xStringTrim(tempParameter->name, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2)); } } + if (XREGEX_IS_MATCHGROUP(matchGroup, 3)) + { + xmallocStrlcpy(&tempParameter->array, &token[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3)); + if (NULL != tempParameter->array) + { + xStringTrim(tempParameter->array, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3)); + } + } + + } + else if (0 == regexec(®Xparameter, token, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0)) + { + tempParameter = cfunction_newParameter(&aFunction->parameter); + tempParameter->type = CPARAMETER_TYPE_REGULAR; + if (XREGEX_IS_MATCHGROUP(matchGroup, 1)) + { + xmallocStrlcpy(&tempParameter->dataType, &token[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); + if (NULL != tempParameter->dataType) + { + xStringTrim(tempParameter->dataType, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1)); + } + } + if (XREGEX_IS_MATCHGROUP(matchGroup, 2)) + { + xmallocStrlcpy(&tempParameter->name, &token[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2)); + if (NULL != tempParameter->name) + { + xStringTrim(tempParameter->name, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2)); + } + } + if (XREGEX_IS_MATCHGROUP(matchGroup, 3)) + { + xmallocStrlcpy(&tempParameter->array, &token[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3)); + if (NULL != tempParameter->array) + { + xStringTrim(tempParameter->array, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2)); + } + } } token = strtok(NULL, ","); } - return 0; } diff --git a/src/stubser/cfile_parser_loc.h b/src/stubser/cfile_parser_loc.h index 1e59280..58890ec 100644 --- a/src/stubser/cfile_parser_loc.h +++ b/src/stubser/cfile_parser_loc.h @@ -31,7 +31,9 @@ #define FUNCTION_BASE CPARS_EXPRESSION_BASE "[[:blank:]]*\\([[:blank:]]*" #define CPARS_REGEX_FUNCTION FUNCTION_BASE "(.*)\\)[[:blank:]\\{\\};]+[[:blank:]]*" #define CPARS_REGEX_VARIABLE CPARS_EXPRESSION_BASE "[[:blank:]]*(\\[*[^;=]*)[[:blank:]]*[;=]" -#define CPARS_REGEX_PARAMETER "[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]+)[[:blank:]]*" +#define CPARS_REGEX_PARAMETER CPARS_EXPRESSION_BASE "[[:blank:]]*(\\[*[^;=]*)" +#define CPARS_REGEX_PARAMETER_FUPTR "^[[:blank:]]*([ _\\*[:alnum:]]* +\\**)\\(([_\\*[:alnum:]]+)\\)(\\([^\\)]*\\))" +#define CPARS_REGEX_PARAMETER_FUPTR_SEPA "\\([^\\,)]*(,)" #define CPARS_REGEX_PREFIX "("CPARS_PREFIX_EXTERN_S"|EXTERN|"CPARS_PREFIX_STATIC_S"|STATIC|volatile|near|far)[[:blank:]]*(.*)" #define CPARS_EXPRESSION_START "^[[:blank:]]*([A-Za-z\\_][\\_\\*[:alnum:]]*)" diff --git a/src/stubser/cfunction.c b/src/stubser/cfunction.c index 4b1ac67..20e4611 100644 --- a/src/stubser/cfunction.c +++ b/src/stubser/cfunction.c @@ -88,7 +88,7 @@ STATIC int8_t cfunction_freeParameter(struct _CFUNCTION_PARAMETER_LIST_T *aParam while (work) { next = work->next; - free(work->type); + free(work->dataType); free(work->name); free(work); work = next; @@ -162,7 +162,7 @@ void cfunction_printList(cfunction_list_t *aList) printf("[ cfu]%d:<%s> (%s) %s [%d] ", work->type, work->prefix, work->dataType, work->name, work->parameter.amount); while (param) { - printf("(%s)%s,", param->type, param->name); + printf("%d(%s)%s%s%s", param->type, param->dataType, param->name, (param->array ? param->array : ""), (param->next ? "," : "")); param = param->next; } printf("\n"); diff --git a/src/stubser/cfunction_if.h b/src/stubser/cfunction_if.h index ec18ef6..e383772 100644 --- a/src/stubser/cfunction_if.h +++ b/src/stubser/cfunction_if.h @@ -25,11 +25,22 @@ typedef enum _CFUNCTION_TYPE_T CFUNCTION_TYPE_LAST_ENUM } cfunction_type_t; +/*! @brief Type of function definition */ +typedef enum _CPARAMETER_TYPE_T +{ + CPARAMETER_TYPE_UNDEF = 0, /*!< @brief undefined */ + CPARAMETER_TYPE_REGULAR = 1, /*!< @brief Regular C function parameter */ + CPARAMETER_TYPE_FUNCPTR = 2, /*!< @brief Function pointer as parameter */ + CPARAMETER_TYPE_LAST_ENUM +} cparameter_type_t; + /*! @brief Parameter list node */ typedef struct _CFUNCTION_PARAMETER_T { - char* type; /*!< @brief data type */ + cparameter_type_t type; /*!< @brief Parameter type */ + char* dataType; /*!< @brief data type */ char* name; /*!< @brief name */ + char* array; /*!< @brief array information (e.g. [10] or [DEF_MAX]) */ struct _CFUNCTION_PARAMETER_T *next; } cfunction_parameter_t; diff --git a/src/stubser/stubser.c b/src/stubser/stubser.c index 785514d..d4e0908 100644 --- a/src/stubser/stubser.c +++ b/src/stubser/stubser.c @@ -126,21 +126,22 @@ STATIC void createVariableSpecificCheck(FILE *aFile, cfile_variable_t *aVariable STATIC void createParameterSpecificCheck(FILE *aFile, cfunction_t *aFunction, cfunction_parameter_t *aParameter, char aParameterIndex) { - if (NULL != strstr(aParameter->type, "*") && NULL != strstr(aParameter->type, "char")) + if (NULL != strstr(aParameter->dataType, "*") && NULL != strstr(aParameter->dataType, "char")) { fprintf(aFile, "\tCU_ASSERT_MEMORY_CHECK(\"%s(%s)\", ", aFunction->name, aParameter->name); fprintf(aFile, STUBINIT_PARAM_PARAMETER_S1", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1, aParameterIndex, aFunction->name, aFunction->name, aParameterIndex); fprintf(aFile, ", strlen("STUBINIT_PARAM_PARAMETER_S1"));"NEWLINES, aParameterIndex); } - else if (NULL != strstr(aParameter->type, "*")) + else if (NULL != strstr(aParameter->dataType, "*") || NULL != aParameter->array) { + // matches also function pointer (array containing function pointer parameter list) fprintf(aFile, "\tCU_ASSERT_PTR_EQUAL("); fprintf(aFile, STUBINIT_PARAM_PARAMETER_S1", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1, aParameterIndex, aFunction->name, aFunction->name, aParameterIndex); fprintf(aFile, ");"NEWLINES); } - else if (isDatatypeStandard(aParameter->type)) + else if (isDatatypeStandard(aParameter->dataType)) { fprintf(aFile, "\tCU_ASSERT_EQUAL("); fprintf(aFile, STUBINIT_PARAM_PARAMETER_S1", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1, aParameterIndex, aFunction->name, @@ -313,17 +314,30 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a fprintf(aFile, "typedef struct _STUBPARAMETER_%s" NEWLINES, aFunction->name); fprintf(aFile, "{" NEWLINES); fprintf(aFile, "\tuint8_t "STUBPARAMETER_CALLTEST_S"; /**< @brief If stub call is a STUB_CALL_PASS or STUB_CALL_FAIL */" NEWLINES); - parameter = aFunction->parameter.head; - parameterIndex = 'a'; - while (parameter) - { - fprintf(aFile, "\t%s "STUBPARAMETER_PARAM_S1"; /*!< @brief %s */" NEWLINES, NCHECK(parameter->type), parameterIndex++, NCHECK(parameter->name)); - parameter = parameter->next; - } if (!isDatatypeVoid(aFunction->dataType)) { fprintf(aFile, "\t%s "STUBPARAMETER_RETURN_S"; /**< @brief return value */" NEWLINES, aFunction->dataType); } + parameter = aFunction->parameter.head; + parameterIndex = 'a'; + while (parameter) + { + if (CPARAMETER_TYPE_FUNCPTR == parameter->type) + { + fprintf(aFile, "\t%s (*"STUBPARAMETER_PARAM_S1")%s; /*!< @brief %s */" NEWLINES, NCHECK(parameter->dataType), parameterIndex++, + NCHECK(parameter->array), NCHECK(parameter->name)); + } + else if (parameter->array) + { + fprintf(aFile, "\t%s *"STUBPARAMETER_PARAM_S1"; /*!< @brief %s */" NEWLINES, NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->name)); + } + else if (CPARAMETER_TYPE_REGULAR == parameter->type) + { + fprintf(aFile, "\t%s "STUBPARAMETER_PARAM_S1"; /*!< @brief %s */" NEWLINES, NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->name)); + } + parameter = parameter->next; + } + fprintf(aFile, "} "STUBPARAMETER_TYPEDEF_S1";" NEWLINES, aFunction->name); NEWLINE(aFile); @@ -348,7 +362,14 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a parameterIndex = 'a'; while (parameter) { - fprintf(aHeader, ", %s "STUBINIT_PARAM_PARAMETER_S1, NCHECK(parameter->type), parameterIndex++); + if (CPARAMETER_TYPE_FUNCPTR == parameter->type) + { + fprintf(aHeader, ", %s (*"STUBINIT_PARAM_PARAMETER_S1")%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array)); + } + else + { + fprintf(aHeader, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array)); + } parameter = parameter->next; } fprintf(aHeader, ");" NEWLINES); @@ -363,7 +384,14 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a parameterIndex = 'a'; while (parameter) { - fprintf(aFile, ", %s "STUBINIT_PARAM_PARAMETER_S1, NCHECK(parameter->type), parameterIndex++); + if (CPARAMETER_TYPE_FUNCPTR == parameter->type) + { + fprintf(aFile, ", %s (*"STUBINIT_PARAM_PARAMETER_S1")%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array)); + } + else + { + fprintf(aFile, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array)); + } parameter = parameter->next; } fprintf(aFile, ")" NEWLINES); @@ -398,7 +426,17 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a parameterIndex = 'a'; while (parameter) { - fprintf(aFile, "%s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->type), parameterIndex++, (NULL != parameter->next ? ", " : "")); + if (CPARAMETER_TYPE_FUNCPTR == parameter->type) + { + fprintf(aFile, "%s (*"STUBINIT_PARAM_PARAMETER_S1")%s%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array), + (NULL != parameter->next ? ", " : "")); + } + else + { + fprintf(aFile, "%s "STUBINIT_PARAM_PARAMETER_S1"%s%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array), + (NULL != parameter->next ? ", " : "")); + } + parameter = parameter->next; } fprintf(aFile, ")" NEWLINES);