Merge remote-tracking branch 'origin/WIP_multiline'
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978" name="Debug" parent="cdt.managedbuild.config.gnu.cygwin.exe.debug">
|
||||
<configuration artifactName="stubser" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978" name="Debug" parent="cdt.managedbuild.config.gnu.cygwin.exe.debug">
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.cygwin.exe.debug.384908978." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.cygwin.exe.debug.1911704982" name="Cygwin GCC" superClass="cdt.managedbuild.toolchain.gnu.cygwin.exe.debug">
|
||||
<targetPlatform id="cdt.managedbuild.target.gnu.platform.cygwin.exe.debug.417099056" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.cygwin.exe.debug"/>
|
||||
@@ -67,7 +67,7 @@
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233" name="Release" parent="cdt.managedbuild.config.gnu.cygwin.exe.release">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233" name="Release" parent="cdt.managedbuild.config.gnu.cygwin.exe.release" postannouncebuildStep="-- Copy release to bin folder --" postbuildStep="cp -f stubser.exe c:\cygwin\bin">
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.cygwin.exe.release.1204024233." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.cygwin.exe.release.213504424" name="Cygwin GCC" superClass="cdt.managedbuild.toolchain.gnu.cygwin.exe.release">
|
||||
<targetPlatform id="cdt.managedbuild.target.gnu.platform.cygwin.exe.release.1771726366" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.cygwin.exe.release"/>
|
||||
|
2
.project
2
.project
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>stubi</name>
|
||||
<name>stubser</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -71,3 +71,9 @@ char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize)
|
||||
return *aDest;
|
||||
}
|
||||
|
||||
void xfree(void **aDest)
|
||||
{
|
||||
free(*aDest);
|
||||
*aDest = NULL;
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef EXT_XMALLOC_H_
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <malloc.h>
|
||||
|
||||
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);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 01.03.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef EXT_XREGEX_H_
|
||||
|
@@ -8,8 +8,9 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 27.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include "xtypes.h"
|
||||
#include "xstring.h"
|
||||
#include "ctype.h"
|
||||
|
||||
@@ -24,6 +25,29 @@ char* gnu_basename(char *path)
|
||||
return base ? base + 1 : path;
|
||||
}
|
||||
|
||||
uint32_t xStrCount(char *aStr, char aC)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
char *temp = NULL;
|
||||
|
||||
if (NULL == aStr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
temp = aStr;
|
||||
|
||||
while (*temp)
|
||||
{
|
||||
if (aC == *temp)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
temp++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Trim leading and trailing whitespaces
|
||||
* @param [in] *str Input string
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 27.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#ifndef XSTRING_H_
|
||||
#define XSTRING_H_
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <string.h>
|
||||
|
||||
char* gnu_basename(char *path);
|
||||
uint32_t xStrCount(char *aStr, char aC);
|
||||
char* strntrimStatic(char *aStr, size_t aMaxLength);
|
||||
void xStringTrim(char *aStr, size_t aMaxLength);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 08.06.2016
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#ifndef XTIME_H_
|
||||
#define XTIME_H_
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 27.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef XTYPES_H_
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 27.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
99
src/stubser/cfile.c
Normal file
99
src/stubser/cfile.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*!
|
||||
* @file cfile.c
|
||||
* @brief
|
||||
* @details
|
||||
* Project: \n
|
||||
* Subsystem: \n
|
||||
* Module: \n
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 08.03.2017
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#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->dataType);
|
||||
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);
|
||||
}
|
||||
|
||||
void cfile_print(cfile_t *aCfile)
|
||||
{
|
||||
cfile_variable_t *work = NULL;
|
||||
|
||||
if (NULL == aCfile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
work = aCfile->variables.head;
|
||||
|
||||
while (work)
|
||||
{
|
||||
printf("[ cva]%d:<%s> (%s) %s %s\n", work->type, work->prefix, work->dataType, work->name, work->array);
|
||||
work = work->next;
|
||||
}
|
||||
|
||||
cfunction_printList(&aCfile->functions);
|
||||
}
|
74
src/stubser/cfile_if.h
Normal file
74
src/stubser/cfile_if.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*!
|
||||
* @file cfile_if.h
|
||||
* @brief
|
||||
* @details
|
||||
* Project: \n
|
||||
* Subsystem: \n
|
||||
* Module: \n
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 08.03.2017
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_CFILE_IF_H_
|
||||
#define STUBSER_CFILE_IF_H_
|
||||
|
||||
#include "cfunction_if.h"
|
||||
|
||||
#define CVARIABLE_CHECK_TYPE(var, type) (type == (var & type))
|
||||
#define CVARIABLE_SET_TYPE(var, type) do{\
|
||||
var &= ~type; \
|
||||
var |= type; \
|
||||
} while(0)
|
||||
|
||||
/*! @brief Type of function definition for bit field usage */
|
||||
typedef enum _CFILE_VARIABLE_TYPE_T
|
||||
{
|
||||
CVARIABLE_TYPE_UNDEF = 0, /*!< @brief undefined */
|
||||
CVARIABLE_TYPE_REGULAR = 0x01, /*!< @brief Regular C variable definition */
|
||||
CVARIABLE_TYPE_STATIC = 0x02, /*!< @brief Static C variable definition */
|
||||
CVARIABLE_TYPE_EXTERN = 0x04, /*!< @brief External C variable definition */
|
||||
CVARIABLE_TYPE_FUPTR = 0x08, /*!< @brief Function pointer as variable */
|
||||
CVARIABLE_TYPE_CONST = 0x10, /*!< @brief Const C variable */
|
||||
CVARIABLE_TYPE_LAST_ENUM
|
||||
} cfile_variable_type_t;
|
||||
|
||||
/*! @brief Parameter list node */
|
||||
typedef struct _CFILE_VARIABLE_T
|
||||
{
|
||||
cfile_variable_type_t type;
|
||||
char* prefix; /*!< @brief variable prefix (e.g. static) */
|
||||
char* dataType; /*!< @brief data type */
|
||||
char* name; /*!< @brief name */
|
||||
char* array; /*!< @brief array information (e.g. [10] or [DEF_MAX]) */
|
||||
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);
|
||||
void cfile_print(cfile_t *aCfile);
|
||||
|
||||
#endif /* STUBSER_CFILE_IF_H_ */
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -17,12 +17,12 @@
|
||||
#include "xtypes.h"
|
||||
#include "xstring.h"
|
||||
#include "xmalloc.h"
|
||||
#include "cfunction_if.h"
|
||||
#include "cfile_if.h"
|
||||
#include "cfile_parser_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
|
||||
{
|
||||
@@ -33,56 +33,33 @@ typedef enum _CFILE_BLOCK_RETURN_T
|
||||
} cfile_block_return_t;
|
||||
|
||||
STATIC bool cfile_parser_initialized = false;
|
||||
STATIC uint8_t cfile_parser_functionLine = 0;
|
||||
STATIC cfunction_t *cfile_parser_function = NULL;
|
||||
STATIC regex_t regX;
|
||||
STATIC regex_t regXsl;
|
||||
STATIC regex_t regXmlStart;
|
||||
STATIC regex_t regXmlPar;
|
||||
STATIC regex_t regXmlEnd;
|
||||
STATIC regex_t regXmlProto;
|
||||
STATIC regex_t regXproto;
|
||||
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;
|
||||
STATIC regex_t regXExpressionEnd;
|
||||
|
||||
// line evaluation related variables
|
||||
STATIC uint32_t cfile_parser_removeCommentHelper = 0;
|
||||
STATIC uint32_t cfile_parser_removeBraceHelper = 0;
|
||||
STATIC char *cfile_parser_parameterStorage = NULL;
|
||||
|
||||
int8_t cfile_parser_init()
|
||||
{
|
||||
if (0 > regcomp(®X, FUNCTION_BASE, (REG_EXTENDED | REG_NEWLINE)))
|
||||
if (0 > regcomp(®XExpressionStart, CPARS_EXPRESSION_START, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®Xsl, FUNCTION_SL, (REG_EXTENDED | REG_NEWLINE)))
|
||||
if (0 > regcomp(®XExpressionEnd, CPARS_EXPRESSION_END, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®XmlStart, FUNCTION_ML_SOF, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®XmlPar, FUNCTION_ML_PAR, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®XmlEnd, FUNCTION_ML_END, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®XmlProto, FUNCTION_ML_PROTO, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
}
|
||||
if (0 > regcomp(®Xproto, FUNCTION_PROTO, (REG_EXTENDED | REG_NEWLINE)))
|
||||
if (0 > regcomp(®Xfunction, CPARS_REGEX_FUNCTION, (REG_EXTENDED | REG_NEWLINE)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return -1;
|
||||
@@ -97,12 +74,27 @@ 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_FUNCTIONPOINTER, (REG_EXTENDED)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#if(0)
|
||||
#if isDebugLevel(1)
|
||||
STATIC void printMatchGroup(char *aString, regmatch_t *aMatchGroup)
|
||||
{
|
||||
char match[1024] =
|
||||
@@ -113,22 +105,44 @@ STATIC void printMatchGroup(char *aString, regmatch_t *aMatchGroup)
|
||||
{
|
||||
if (aMatchGroup[i].rm_so < aMatchGroup[i].rm_eo)
|
||||
{
|
||||
DEBUG_LOG_APPEND(1, "[%02d](%.3ld - %.3ld)[%03d]:", i, aMatchGroup[i].rm_so, aMatchGroup[i].rm_eo, (int) (aMatchGroup[i].rm_eo - aMatchGroup[i].rm_so));
|
||||
DEBUG_LOG_APPEND(1, "[%02d](%.3ld - %.3ld)[%03d]:", i, aMatchGroup[i].rm_so, aMatchGroup[i].rm_eo,
|
||||
(int ) (aMatchGroup[i].rm_eo - aMatchGroup[i].rm_so));
|
||||
strlcpy(match, &aString[aMatchGroup[i].rm_so], (size_t) (aMatchGroup[i].rm_eo - aMatchGroup[i].rm_so + 1));
|
||||
DEBUG_LOG_APPEND(1, "%s", match);
|
||||
DEBUG_LOG_APPEND(1, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define printMatchGroup(aString, aMatchgroup) do { /*nothing*/ } while(0)
|
||||
#endif
|
||||
|
||||
STATIC void checkFunctionType(cfunction_t *aFunction)
|
||||
STATIC void checkFunctionType(cfunction_t *aFunction, char *aExpression)
|
||||
{
|
||||
char *tempChar = NULL;
|
||||
|
||||
if (NULL == aFunction || NULL == aExpression)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
aFunction->type = CFUNCTION_TYPE_REGULAR;
|
||||
|
||||
tempChar = strrchr(aExpression, CPARS_PROTOTYPE_END_C);
|
||||
if (tempChar)
|
||||
{
|
||||
aFunction->type = CFUNCTION_TYPE_PROTO;
|
||||
}
|
||||
|
||||
if (NULL == aFunction->prefix)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((NULL != strstr(aFunction->prefix, "static") || NULL != strstr(aFunction->prefix, "STATIC")) //
|
||||
if (NULL != strstr(aFunction->prefix, CPARS_PREFIX_EXTERN_S))
|
||||
{
|
||||
aFunction->type = CFUNCTION_TYPE_EXTERN;
|
||||
}
|
||||
else if ((NULL != strstr(aFunction->prefix, CPARS_PREFIX_STATIC_S) || NULL != strstr(aFunction->prefix, CPARS_PREFIX_STATIC2_S))
|
||||
&& CFUNCTION_TYPE_PROTO != aFunction->type)
|
||||
{
|
||||
aFunction->type = CFUNCTION_TYPE_STATIC;
|
||||
@@ -136,24 +150,47 @@ STATIC void checkFunctionType(cfunction_t *aFunction)
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Extract function prefix and data type and removing trailing blanks
|
||||
* @param [out] *aFunction Pointer to function structure
|
||||
* @brief Extract C expression prefix and data type and removing trailing blanks
|
||||
* @param [out] *aElement Pointer to C element structure
|
||||
* @param [in] aElementType C element type (CELEMENT_TYPE_VARIABLE, CELEMENT_TYPE_FUNCTION supported)
|
||||
* @param [in] *aString Pointer to a substring containing data type and/or prefix
|
||||
* @param [in] aSize Length of string
|
||||
* @retval 0 processing successful
|
||||
* @retval -1 processing failed
|
||||
*/
|
||||
STATIC int8_t matchFunctionStart(cfunction_t *aFunction, char *aString, size_t aSize)
|
||||
STATIC int8_t matchPrefix(void *aElement, celement_type_t aElementType, char *aString, size_t aSize)
|
||||
{
|
||||
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
||||
char *temp = NULL;
|
||||
char *end = NULL;
|
||||
char **prefix = NULL;
|
||||
char **type = NULL;
|
||||
|
||||
if (NULL == aFunction || NULL == aString || 0 == aSize)
|
||||
if (NULL == aElement || NULL == aString || 0 == aSize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (aElementType)
|
||||
{
|
||||
case CELEMENT_TYPE_VARIABLE:
|
||||
{
|
||||
prefix = &((cfile_variable_t*) aElement)->prefix;
|
||||
type = &((cfile_variable_t*) aElement)->dataType;
|
||||
break;
|
||||
}
|
||||
case CELEMENT_TYPE_FUNCTION:
|
||||
{
|
||||
prefix = &((cfunction_t*) aElement)->prefix;
|
||||
type = &((cfunction_t*) aElement)->dataType;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
temp = (char*) xmalloc(aSize + 1);
|
||||
if (NULL == temp)
|
||||
{
|
||||
@@ -169,21 +206,44 @@ STATIC int8_t matchFunctionStart(cfunction_t *aFunction, char *aString, size_t a
|
||||
}
|
||||
*(end + 1) = '\0';
|
||||
|
||||
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
||||
{
|
||||
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_REGULAR;
|
||||
}
|
||||
|
||||
if (0 == regexec(®Xprefix, temp, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0))
|
||||
{
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
||||
{
|
||||
xmallocStrlcpy(&aFunction->prefix, &temp[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
checkFunctionType(aFunction);
|
||||
xmallocStrlcpy(prefix, &temp[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
||||
{
|
||||
if (*prefix && NULL != strstr(*prefix, CPARS_PREFIX_EXTERN_S))
|
||||
{
|
||||
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_EXTERN;
|
||||
}
|
||||
else if (*prefix && (NULL != strstr(*prefix, CPARS_PREFIX_STATIC_S) || NULL != strstr(*prefix, CPARS_PREFIX_STATIC2_S)))
|
||||
{
|
||||
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_STATIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 2))
|
||||
{
|
||||
xmallocStrlcpy(&aFunction->dataType, &temp[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
xmallocStrlcpy(type, &temp[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xmallocStrlcpy(&aFunction->dataType, temp, strlen(temp));
|
||||
xmallocStrlcpy(type, temp, strlen(temp));
|
||||
}
|
||||
|
||||
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
||||
{
|
||||
if (*type && NULL != strstr(*type, CPARS_ELEMENT_CONST))
|
||||
{
|
||||
CVARIABLE_SET_TYPE(((cfile_variable_t* ) aElement)->type, CVARIABLE_TYPE_CONST);
|
||||
}
|
||||
}
|
||||
|
||||
free(temp);
|
||||
@@ -195,7 +255,7 @@ STATIC int8_t matchFunctionStart(cfunction_t *aFunction, char *aString, size_t a
|
||||
* @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 [out] **aPosition Pointing to found block string (related 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
|
||||
@@ -328,7 +388,7 @@ STATIC int8_t cBlockRemoval(char *aLine, const char *aBlockStart, const char *aB
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[WARN] Nested block start (see file below): %s", aLine);
|
||||
printf(CPARS_WARNING_START"Nested block start \"%s\": %s", aBlockStart, aLine);
|
||||
}
|
||||
blockWorker = (aRemove ? blockMatch + strlen(aBlockStart) : blockMatch);
|
||||
break;
|
||||
@@ -431,6 +491,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;
|
||||
@@ -441,19 +537,24 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
prepareFunctionPointer(aParameter);
|
||||
token = strtok(aParameter, ",");
|
||||
while (token)
|
||||
{
|
||||
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))
|
||||
{
|
||||
// TODO only "1 dimensional" function pointer supported (e.g. void (**func)(void) NOT SUPPORTED)
|
||||
(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))
|
||||
@@ -464,172 +565,229 @@ 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;
|
||||
}
|
||||
|
||||
STATIC int8_t cfile_parser_evaluateExpression(char *aExpression, cfile_t *aCfile)
|
||||
{
|
||||
uint16_t tempInt16 = 0;
|
||||
char *tempChar = NULL;
|
||||
cfile_variable_t *variable = NULL;
|
||||
cfunction_t *function = NULL;
|
||||
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
||||
|
||||
if (NULL == aExpression || NULL == aCfile)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == regexec(®Xfunction, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup,
|
||||
REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
||||
{
|
||||
printMatchGroup(aExpression, matchGroup);
|
||||
function = cfunction_addNewFunction(&aCfile->functions);
|
||||
(void) matchPrefix(function, CELEMENT_TYPE_FUNCTION, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
checkFunctionType(function, aExpression);
|
||||
xmallocStrlcpy(&function->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
||||
{
|
||||
xmallocStrlcat(&tempChar, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
||||
if (NULL != tempChar)
|
||||
{
|
||||
evaluateParameter(tempChar, function);
|
||||
}
|
||||
xfree((void**) &tempChar);
|
||||
}
|
||||
}
|
||||
else if (0 == regexec(®Xvariable, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup,
|
||||
REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
||||
{
|
||||
printMatchGroup(aExpression, matchGroup);
|
||||
variable = cfile_newVariable(&aCfile->variables);
|
||||
if (variable)
|
||||
{
|
||||
(void) matchPrefix(variable, CELEMENT_TYPE_VARIABLE, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
xmallocStrlcpy(&variable->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
|
||||
// group 3 contains array information, if available
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
||||
{
|
||||
xmallocStrlcpy(&tempChar, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
||||
if (NULL != tempChar)
|
||||
{
|
||||
xStringTrim(tempChar, strlen(tempChar));
|
||||
}
|
||||
|
||||
if (2 == strlen(tempChar) - xStrCount(tempChar, ' '))
|
||||
{
|
||||
// array without size definition
|
||||
xmallocStrlcat(&variable->dataType, "*", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
xmallocStrlcpy(&variable->array, tempChar, strlen(tempChar));
|
||||
}
|
||||
xfree((void**) &tempChar);
|
||||
}
|
||||
|
||||
// would contain more variables separated by ','
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 4))
|
||||
{
|
||||
if (NULL != (tempChar = strstr(&aExpression[matchGroup[4].rm_so], ",")))
|
||||
{
|
||||
// remove leading ,
|
||||
tempInt16 = tempChar - &aExpression[matchGroup[4].rm_so];
|
||||
matchGroup[4].rm_so += tempInt16 + 1;
|
||||
tempChar = NULL;
|
||||
|
||||
DEBUG_LOG_APPEND(1, "Variable list: %s\n", &aExpression[matchGroup[4].rm_so]);
|
||||
xmallocStrlcpy(&tempChar, aCfile->variables.head->dataType, strlen(aCfile->variables.head->dataType));
|
||||
xmallocStrlcat(&tempChar, &aExpression[matchGroup[4].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 4) + 1);
|
||||
DEBUG_LOG_APPEND(1, "Result: %s\n", tempChar);
|
||||
|
||||
cfile_parser_evaluateExpression(tempChar, aCfile);
|
||||
}
|
||||
}
|
||||
xfree((void**) &tempChar);
|
||||
}
|
||||
}
|
||||
else if (0 == regexec(®XfunctionPointer, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0) //
|
||||
&& XREGEX_IS_MATCHGROUP(matchGroup, 1) //
|
||||
&& XREGEX_IS_MATCHGROUP(matchGroup, 2) //
|
||||
&& XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
||||
{
|
||||
// TODO only "1 dimensional" function pointer supported (e.g. void (**func)(void) NOT SUPPORTED)
|
||||
printMatchGroup(aExpression, matchGroup);
|
||||
variable = cfile_newVariable(&aCfile->variables);
|
||||
if (variable)
|
||||
{
|
||||
(void) matchPrefix(variable, CELEMENT_TYPE_VARIABLE, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
CVARIABLE_SET_TYPE(variable->type, CVARIABLE_TYPE_FUPTR);
|
||||
xmallocStrlcpy(&variable->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
// contains array information if available "[10]"
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
||||
{
|
||||
xmallocStrlcpy(&variable->array, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 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
|
||||
* @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 cfile_parser_evaluateLine(uint32_t aNumber, char *aLine, cfile_t *aCfile)
|
||||
{
|
||||
const size_t maxGroup = CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS;
|
||||
regmatch_t matchGroup[maxGroup];
|
||||
bool functionEnd = false;
|
||||
cfunction_type_t tempFunctionType = CFUNCTION_TYPE_UNDEF;
|
||||
char *position = aLine;
|
||||
uint32_t warnings = 0;
|
||||
static char *match = NULL;
|
||||
static uint8_t depth = 0;
|
||||
char *tempMatch = NULL;
|
||||
char *tempChar = NULL;
|
||||
int8_t ret = 0;
|
||||
|
||||
if (0 != removeCcomments(aLine))
|
||||
regex_t *matchStart = ®XExpressionStart;
|
||||
regex_t *matchEnd = ®XExpressionEnd;
|
||||
|
||||
ret = removeCcomments(aLine);
|
||||
if (-1 == ret)
|
||||
{
|
||||
return NULL;
|
||||
++warnings;
|
||||
}
|
||||
if (0 != cBlockRemoval(aLine, "{", "}", &cfile_parser_removeBraceHelper, false, false))
|
||||
else if (0 != ret)
|
||||
{
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
ret = cBlockRemoval(aLine, "{", "}", &cfile_parser_removeBraceHelper, false, false);
|
||||
if (-1 == ret)
|
||||
{
|
||||
++warnings;
|
||||
}
|
||||
else if (0 != ret)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
DEBUG_LOG_APPEND(2, "[ Li %04u] %s\n", aNumber, aLine);
|
||||
tempChar = strrchr(aLine, '\n');
|
||||
if (tempChar)
|
||||
{
|
||||
*tempChar = '\0';
|
||||
}
|
||||
tempChar = strrchr(aLine, '\r');
|
||||
if (tempChar)
|
||||
{
|
||||
*tempChar = '\0';
|
||||
}
|
||||
|
||||
if (cfile_parser_functionLine)
|
||||
while (position)
|
||||
{
|
||||
if (0 == regexec(®XmlEnd, aLine, maxGroup, matchGroup, REG_NOTEOL))
|
||||
if (NULL != (tempMatch = strstr(position, "#include")))
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_REGULAR;
|
||||
DEBUG_LOG_APPEND(1, "[ mle]");
|
||||
functionEnd = true;
|
||||
// TODO save include information
|
||||
DEBUG_LOG_APPEND(1, "[ Re %04u][%zu] %s\n", aNumber, strlen(tempMatch), tempMatch);
|
||||
position = NULL;
|
||||
continue;
|
||||
}
|
||||
else if (0 == regexec(®XmlProto, aLine, maxGroup, matchGroup, REG_NOTEOL))
|
||||
warnings += regExWorker(&match, &position, matchStart, matchEnd, &depth, false);
|
||||
if (match && 0 == depth)
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_PROTO;
|
||||
DEBUG_LOG_APPEND(1, "[ mlp]");
|
||||
functionEnd = true;
|
||||
DEBUG_LOG_APPEND(1, "[ Re %04u][%zu] %s\n", aNumber, strlen(match), match);
|
||||
// Evaluate C expression
|
||||
(void) cfile_parser_evaluateExpression(match, aCfile);
|
||||
xfree((void**) &match);
|
||||
}
|
||||
else if (0 == regexec(®XmlPar, aLine, maxGroup, matchGroup, REG_NOTEOL))
|
||||
{
|
||||
DEBUG_LOG_APPEND(1, "[ ml+]");
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG_APPEND(1, "[ na ]");
|
||||
tempFunctionType = CFUNCTION_TYPE_UNDEF;
|
||||
functionEnd = true;
|
||||
return warnings;
|
||||
}
|
||||
|
||||
++cfile_parser_functionLine;
|
||||
}
|
||||
else if (0 == regexec(®Xsl, aLine, maxGroup, matchGroup, REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_REGULAR;
|
||||
DEBUG_LOG_APPEND(1, "[ sl ]");
|
||||
}
|
||||
else if (0 == regexec(®XmlStart, aLine, maxGroup, matchGroup, REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_REGULAR;
|
||||
DEBUG_LOG_APPEND(1, "[ mls]");
|
||||
++cfile_parser_functionLine;
|
||||
}
|
||||
else if (0 == regexec(®Xproto, aLine, maxGroup, matchGroup, REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_PROTO;
|
||||
DEBUG_LOG_APPEND(1, "[prot]");
|
||||
}
|
||||
else if (0 == regexec(®X, aLine, maxGroup, matchGroup, REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
||||
{
|
||||
tempFunctionType = CFUNCTION_TYPE_UNDEF;
|
||||
DEBUG_LOG_APPEND(1, "[ fuX]");
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#if (0)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
char match[1024] =
|
||||
{ 0};
|
||||
|
||||
for (i = 0; i < maxGroup && 0 <= matchGroup[i].rm_so; ++i)
|
||||
{
|
||||
if (matchGroup[i].rm_so < matchGroup[i].rm_eo)
|
||||
{
|
||||
if (0 < i)
|
||||
DEBUG_LOG_APPEND(1, " ");
|
||||
DEBUG_LOG_APPEND(1, "[%02d](%.3ld - %.3ld)[%03d]: ", i, matchGroup[i].rm_so, matchGroup[i].rm_eo, (int) (matchGroup[i].rm_eo - matchGroup[i].rm_so));
|
||||
strlcpy(match, &aLine[matchGroup[i].rm_so], (size_t) (matchGroup[i].rm_eo - matchGroup[i].rm_so + 1));
|
||||
DEBUG_LOG_APPEND(1, "%s", match);
|
||||
DEBUG_LOG_APPEND(1, "\n");
|
||||
}
|
||||
}
|
||||
if (functionEnd)
|
||||
{
|
||||
cfile_parser_functionLine = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
switch (cfile_parser_functionLine)
|
||||
{
|
||||
case 0: // single line function definition
|
||||
case 1: // first line of multi line function definition
|
||||
{
|
||||
// TODO multiple functions in one line
|
||||
cfile_parser_function = cfunction_newFunction();
|
||||
cfile_parser_function->type = tempFunctionType;
|
||||
matchFunctionStart(cfile_parser_function, &aLine[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
xmallocStrlcpy(&cfile_parser_function->name, &aLine[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
||||
{
|
||||
xmallocStrlcat(&cfile_parser_parameterStorage, &aLine[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // further lines
|
||||
{
|
||||
if (XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
||||
{
|
||||
xmallocStrlcat(&cfile_parser_parameterStorage, &aLine[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
||||
}
|
||||
if (functionEnd)
|
||||
{
|
||||
if (CFUNCTION_TYPE_UNDEF == tempFunctionType)
|
||||
{
|
||||
cfunction_freeFunction(&cfile_parser_function);
|
||||
}
|
||||
else
|
||||
{
|
||||
cfile_parser_function->type = tempFunctionType;
|
||||
checkFunctionType(cfile_parser_function);
|
||||
}
|
||||
cfile_parser_functionLine = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return evaluated function
|
||||
if (0 == cfile_parser_functionLine)
|
||||
{
|
||||
evaluateParameter(cfile_parser_parameterStorage, cfile_parser_function);
|
||||
free(cfile_parser_parameterStorage);
|
||||
cfile_parser_parameterStorage = NULL;
|
||||
cfunction_t *funTemp = cfile_parser_function;
|
||||
cfile_parser_function = NULL;
|
||||
return funTemp;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int8_t cfile_parser(char *aPath, cfunction_list_t *aList)
|
||||
uint32_t cfile_parser(char *aPath, cfile_t *aCfile)
|
||||
{
|
||||
FILE *fdesc;
|
||||
ssize_t charRead = 0;
|
||||
size_t lineSize = 0;
|
||||
uint32_t lineNumber = 0;
|
||||
char *fileLine = NULL; // will be allocated by getline(); must be freed
|
||||
uint32_t warningCounter = 0;
|
||||
|
||||
if (false == cfile_parser_initialized)
|
||||
{
|
||||
@@ -648,12 +806,8 @@ 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)
|
||||
{
|
||||
(void) cfunction_addFunction(aList, function);
|
||||
}
|
||||
lineNumber++;
|
||||
warningCounter += cfile_parser_evaluateLine(lineNumber, fileLine, aCfile);
|
||||
}
|
||||
} while (0 <= charRead);
|
||||
|
||||
@@ -663,21 +817,16 @@ int8_t cfile_parser(char *aPath, cfunction_list_t *aList)
|
||||
// error detection for block removal
|
||||
if (0 != cfile_parser_removeCommentHelper || 0 != cfile_parser_removeBraceHelper)
|
||||
{
|
||||
DEBUG_LOG_APPEND(1, "Helper (%d/%d) %s %s\n", cfile_parser_removeCommentHelper, cfile_parser_removeBraceHelper, gnu_basename(aPath),
|
||||
cfile_parser_parameterStorage);
|
||||
DEBUG_LOG_APPEND(1, "Helper (%d/%d) %s\n", cfile_parser_removeCommentHelper, cfile_parser_removeBraceHelper, gnu_basename(aPath));
|
||||
cfile_parser_removeCommentHelper = 0;
|
||||
cfile_parser_removeBraceHelper = 0;
|
||||
return -2;
|
||||
++warningCounter;
|
||||
}
|
||||
|
||||
// error detection for function parameter detection
|
||||
if (NULL != cfile_parser_parameterStorage)
|
||||
{
|
||||
DEBUG_LOG_APPEND(1, "Function parameter not free: %s\n", cfile_parser_parameterStorage);
|
||||
free(cfile_parser_parameterStorage);
|
||||
cfile_parser_parameterStorage = NULL;
|
||||
return -3;
|
||||
}
|
||||
// if (warningCounter)
|
||||
// {
|
||||
// ret = -4;
|
||||
// }
|
||||
|
||||
return 0;
|
||||
return warningCounter;
|
||||
}
|
||||
|
@@ -8,12 +8,14 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_CFILE_PARSER_IF_H_
|
||||
#define STUBSER_CFILE_PARSER_IF_H_
|
||||
|
||||
int8_t cfile_parser(char *aPath, cfunction_list_t *aList);
|
||||
#define CPARS_ELEMENT_CONST "const"
|
||||
|
||||
uint32_t cfile_parser(char *aPath, cfile_t *aList);
|
||||
|
||||
#endif /* STUBSER_CFILE_PARSER_IF_H_ */
|
||||
|
@@ -8,29 +8,49 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#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 "/*"
|
||||
#define CPARS_COMMENT_BLOCK_END "*/"
|
||||
|
||||
#define FUNCTION_BASE "^[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]*)[[:blank:]]*\\([[:blank:]]*([^\r\\)]*)"
|
||||
#define FUNCTION_SL FUNCTION_BASE "\\)[^;]*$"
|
||||
#define FUNCTION_ML_SOF FUNCTION_BASE "[\r]*$"
|
||||
#define FUNCTION_ML_PAR "^[[:blank:]]*([^\r]*)"
|
||||
#define FUNCTION_ML_END FUNCTION_ML_PAR "\\)[^;]*$"
|
||||
#define FUNCTION_ML_PROTO FUNCTION_ML_PAR "\\).*[[:blank:]]*;"
|
||||
#define FUNCTION_PROTO FUNCTION_BASE "\\).*[[:blank:]]*;"
|
||||
#define CPARS_PROTOTYPE_END_C ';'
|
||||
#define CPARS_PREFIX_STATIC_S "static"
|
||||
#define CPARS_PREFIX_STATIC2_S "STATIC"
|
||||
#define CPARS_PREFIX_EXTERN_S "extern"
|
||||
|
||||
#define CPARS_REGEX_PARAMETER "[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]*)[[:blank:]]*"
|
||||
#define CPARS_EXPRESSION_BASE "^[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]+)"
|
||||
#define CPARS_REGEX_FUNCTIONPOINTER "^[[:blank:]]*([ _\\*[:alnum:]]* +\\**)\\(([_\\*[:alnum:]]+)\\)(\\([^\\)]*\\))"
|
||||
|
||||
#define CPARS_REGEX_PREFIX "(extern|EXTERN|static|STATIC|volatile|near|far)[[:blank:]]+([^\\*]*\\**)"
|
||||
#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 CPARS_EXPRESSION_BASE "[[:blank:]]*(\\[*[^;=]*)"
|
||||
#define CPARS_REGEX_PARAMETER_FUPTR_SEPA "\\([^\\,)]*(,)" // function pointer parameter separation
|
||||
#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:]]*)"
|
||||
#define CPARS_EXPRESSION_END "[[:blank:]]*([\\};]+)"
|
||||
|
||||
#define CPARS_WARNING_START " W-> "
|
||||
|
||||
#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_ */
|
||||
|
152
src/stubser/cfile_parser_worker.c
Normal file
152
src/stubser/cfile_parser_worker.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*!
|
||||
* @file cfile_parser_worker.c
|
||||
* @brief
|
||||
* @details
|
||||
* Project: \n
|
||||
* Subsystem: \n
|
||||
* Module: \n
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 09.03.2017
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#include "xtypes.h"
|
||||
#include "xregex.h"
|
||||
#include "xmalloc.h"
|
||||
#include "debug.h"
|
||||
#include "cfile_parser_loc.h"
|
||||
#include "cfile_parser_worker_loc.h"
|
||||
|
||||
/*!
|
||||
* @brief String block detection using regular expressions
|
||||
* @attention Recursive function (calls itself to find block end on same line)
|
||||
* @param [out] **aOutput Matched group content across multiple calls (will be allocated as needed)
|
||||
* @param [in,out] **aInput Char pointer to search string (will be moved to position after match)
|
||||
* @param [in] *aStart Regular expression defining block start
|
||||
* @param [in] *aEnd Regular expression defining block end
|
||||
* @param [out] *aBlockDepth Current depth of parsing
|
||||
* @param [in] aMultiLevel false - starts within block are ignored
|
||||
* @return Matched string and various information about the parsing
|
||||
* @retval uint32_t amount of warnings during parser run
|
||||
*
|
||||
* @details
|
||||
* - Parsing done when (match && 0 == aBlockDepth)
|
||||
* - Orphan end markers are ignored and skipped.
|
||||
*/
|
||||
uint32_t regExWorker(char **aOutput, char **aInput, const regex_t *aStart, const regex_t *aEnd, uint8_t *aBlockDepth, bool aMultiLevel)
|
||||
{
|
||||
uint32_t warningCounter = 0;
|
||||
regmatch_t matchStart[2];
|
||||
regmatch_t matchEnd[2];
|
||||
regmatch_t *match = NULL;
|
||||
char *begin = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (!**aInput || NULL == *aInput)
|
||||
{
|
||||
if (*aBlockDepth)
|
||||
{
|
||||
xmallocStrlcat(aOutput, " ", 2);
|
||||
}
|
||||
*aInput = NULL;
|
||||
goto regExWorker_end;
|
||||
}
|
||||
|
||||
// start
|
||||
if (0 == regexec(aStart, *aInput, 2, matchStart, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchStart, 1))
|
||||
{
|
||||
match = matchStart;
|
||||
}
|
||||
|
||||
// end < start
|
||||
if (0 == regexec(aEnd, *aInput, 2, matchEnd, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchEnd, 1))
|
||||
{
|
||||
if (match && match->rm_so > matchEnd[1].rm_so)
|
||||
{
|
||||
match = matchEnd;
|
||||
}
|
||||
else if (!match)
|
||||
{
|
||||
match = matchEnd;
|
||||
}
|
||||
}
|
||||
|
||||
if (*aBlockDepth)
|
||||
{
|
||||
begin = *aInput;
|
||||
size = strlen(*aInput);
|
||||
if (!match)
|
||||
{
|
||||
// complete line within block
|
||||
*aInput += strlen(*aInput);
|
||||
goto regExWorker_end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
begin = NULL;
|
||||
// no findings
|
||||
if (!match)
|
||||
{
|
||||
// skip remaining character within line without match
|
||||
*aInput += strlen(*aInput);
|
||||
goto regExWorker_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == matchStart)
|
||||
{
|
||||
if ((*aBlockDepth && aMultiLevel) || 0 == *aBlockDepth)
|
||||
{
|
||||
DEBUG_LOG_APPEND(2, "[ CEs]");
|
||||
++*aBlockDepth;
|
||||
size = XREGEX_SIZEOF_MATCHGROUP(match, 1);
|
||||
//begin = *aInput + match[1].rm_eo; // don't include start marker in result
|
||||
begin = *aInput + match[1].rm_so; // include start marker in result
|
||||
*aInput += match[1].rm_eo;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore starts within block
|
||||
size = match->rm_eo;
|
||||
*aInput += match->rm_eo;
|
||||
}
|
||||
goto regExWorker_end;
|
||||
}
|
||||
|
||||
if (match == matchEnd)
|
||||
{
|
||||
DEBUG_LOG_APPEND(2, "[ CEe]");
|
||||
//size = match[1].rm_so; // don't include end marker in result
|
||||
size = match[1].rm_eo; // include end marker in result
|
||||
*aInput += match[1].rm_eo;
|
||||
if (0 < *aBlockDepth)
|
||||
{
|
||||
--*aBlockDepth;
|
||||
}
|
||||
// TODO orphan end markers
|
||||
// must be evaluated depending on expression
|
||||
// e.g. array[]={}; -> must have } and ;
|
||||
// function{} -> must not have ;
|
||||
// else
|
||||
// {
|
||||
// // orphan end marker
|
||||
// ++warningCounter;
|
||||
// }
|
||||
goto regExWorker_end;
|
||||
}
|
||||
|
||||
regExWorker_end:
|
||||
|
||||
if (begin)
|
||||
{
|
||||
xmallocStrlcat(aOutput, begin, size);
|
||||
if (*aBlockDepth)
|
||||
{
|
||||
warningCounter += regExWorker(aOutput, aInput, aStart, aEnd, aBlockDepth, aMultiLevel);
|
||||
}
|
||||
}
|
||||
|
||||
return warningCounter;
|
||||
}
|
19
src/stubser/cfile_parser_worker_loc.h
Normal file
19
src/stubser/cfile_parser_worker_loc.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* @file cfile_parser_worker_loc.h
|
||||
* @brief
|
||||
* @details
|
||||
* Project: \n
|
||||
* Subsystem: \n
|
||||
* Module: \n
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 09.03.2017
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_CFILE_PARSER_WORKER_LOC_H_
|
||||
#define STUBSER_CFILE_PARSER_WORKER_LOC_H_
|
||||
|
||||
uint32_t regExWorker(char **aOutput, char **aInput, const regex_t *aStart, const regex_t *aEnd, uint8_t *aBlockDepth, bool aMultiLevel);
|
||||
|
||||
#endif /* STUBSER_CFILE_PARSER_WORKER_LOC_H_ */
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -16,39 +16,35 @@
|
||||
#include "xmalloc.h"
|
||||
#include "cfunction_if.h"
|
||||
|
||||
cfunction_t* cfunction_newFunction()
|
||||
cfunction_t* cfunction_addNewFunction(cfunction_list_t *aList)
|
||||
{
|
||||
cfunction_t *new = NULL;
|
||||
|
||||
if (NULL == aList)
|
||||
{
|
||||
perror("Null pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = (cfunction_t*) xmalloc(sizeof(cfunction_t));
|
||||
memset(new, 0, sizeof(cfunction_t));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
int8_t cfunction_addFunction(cfunction_list_t *aList, cfunction_t *aNew)
|
||||
{
|
||||
if (NULL == aList || NULL == aNew)
|
||||
{
|
||||
perror("Null pointer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == aList->head)
|
||||
{
|
||||
aList->head = aNew;
|
||||
aList->current = aNew;
|
||||
aList->amount = 0;
|
||||
aList->head = new;
|
||||
aList->current = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
aList->current->next = aNew;
|
||||
aList->current = aNew;
|
||||
aList->current->next = new;
|
||||
aList->current = new;
|
||||
}
|
||||
++aList->amount;
|
||||
return new;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cfunction_parameter_t* cfunction_newParameter(struct _CFUNCTION_PARAMETER_LIST_T *aList)
|
||||
cfunction_parameter_t* cfunction_newParameter(cfunction_parameterList_t *aList)
|
||||
{
|
||||
cfunction_parameter_t *new = NULL;
|
||||
|
||||
@@ -63,6 +59,7 @@ cfunction_parameter_t* cfunction_newParameter(struct _CFUNCTION_PARAMETER_LIST_T
|
||||
|
||||
if (NULL == aList->head)
|
||||
{
|
||||
aList->amount = 0;
|
||||
aList->head = new;
|
||||
aList->current = new;
|
||||
}
|
||||
@@ -91,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,14 +159,14 @@ void cfunction_printList(cfunction_list_t *aList)
|
||||
while (work)
|
||||
{
|
||||
param = work->parameter.head;
|
||||
printf("[ cfu]%d:%s %s %s [%d] ", work->type, work->prefix, work->dataType, work->name, work->parameter.amount);
|
||||
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");
|
||||
work = work->next;
|
||||
|
||||
}
|
||||
printf(" %d Functions\n", aList->amount);
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 28.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_CFUNCTION_IF_H_
|
||||
@@ -18,20 +18,40 @@
|
||||
typedef enum _CFUNCTION_TYPE_T
|
||||
{
|
||||
CFUNCTION_TYPE_UNDEF = 0, /*!< @brief undefined */
|
||||
CFUNCTION_TYPE_REGULAR = 1, /*!< @brief Regular c function definition */
|
||||
CFUNCTION_TYPE_STATIC = 2, /*!< @brief Static c function definition */
|
||||
CFUNCTION_TYPE_PROTO = 3, /*!< @brief Prototype c function definition */
|
||||
CFUNCTION_TYPE_REGULAR = 1, /*!< @brief Regular C function definition */
|
||||
CFUNCTION_TYPE_STATIC = 2, /*!< @brief Static C function definition */
|
||||
CFUNCTION_TYPE_PROTO = 3, /*!< @brief Prototype C function definition */
|
||||
CFUNCTION_TYPE_EXTERN = 4, /*!< @brief External C function definition */
|
||||
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;
|
||||
|
||||
/*! @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,29 +59,25 @@ 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;
|
||||
|
||||
/*! @brief Dynamic function list */
|
||||
typedef struct _CFUNCTION_LIST_T
|
||||
{
|
||||
uint16_t amount;
|
||||
cfunction_t *head;
|
||||
cfunction_t *current;
|
||||
} cfunction_list_t;
|
||||
|
||||
#define CFUNCTION_LIST_DEFAULT {\
|
||||
.amount = 0, \
|
||||
.head = NULL, \
|
||||
.current = NULL }
|
||||
|
||||
cfunction_t* cfunction_newFunction();
|
||||
int8_t cfunction_addFunction(cfunction_list_t *aList, cfunction_t *aNew);
|
||||
cfunction_parameter_t* cfunction_newParameter(struct _CFUNCTION_PARAMETER_LIST_T *aList);
|
||||
cfunction_t* cfunction_addNewFunction(cfunction_list_t *aList);
|
||||
cfunction_parameter_t* cfunction_newParameter(cfunction_parameterList_t *aList);
|
||||
int8_t cfunction_freeFunction(cfunction_t **aFunction);
|
||||
int8_t cfunction_freeList(cfunction_list_t *aList);
|
||||
void cfunction_printList(cfunction_list_t *aList);
|
||||
|
@@ -10,16 +10,18 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 06.03.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
#include <regex.h>
|
||||
#include <sys/stat.h>
|
||||
#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"
|
||||
@@ -37,17 +39,394 @@ STATIC bool isDatatypeVoid(char *aType)
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool isDatatypeStandard(char *aDataType)
|
||||
{
|
||||
regex_t regXvariable;
|
||||
|
||||
if (0 > regcomp(®Xvariable, STUB_REGEX_STD_DATATYPE, (REG_EXTENDED)))
|
||||
{
|
||||
perror("Error regex\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == regexec(®Xvariable, aDataType, 0, NULL, 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC void addPrintfFormat(FILE *aFile, const char* aType)
|
||||
{
|
||||
if (NULL != strstr(aType, "double"))
|
||||
{
|
||||
fprintf(aFile, ("\"%%e\""));
|
||||
}
|
||||
else if (NULL != strstr(aType, "int32_t"))
|
||||
{
|
||||
fprintf(aFile, ("\"%%d\""));
|
||||
}
|
||||
else if (NULL != strstr(aType, "32") || NULL != strstr(aType, "long"))
|
||||
{
|
||||
fprintf(aFile, ("\"%%ld\""));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, ("\"%%d\""));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void createVariableSpecificInit(const char* aVariableTemplate, FILE *aFile, cfile_variable_t *aVariable)
|
||||
{
|
||||
char *tempChar = NULL;
|
||||
|
||||
if (NULL != strstr(aVariable->dataType, CPARS_ELEMENT_CONST))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL != strstr(aVariable->dataType, "*") || aVariable->array)
|
||||
{
|
||||
if (CVARIABLE_CHECK_TYPE(aVariable->type, CVARIABLE_TYPE_FUPTR))
|
||||
{
|
||||
// removing all "*" for function pointer initialization
|
||||
tempChar = strrchr(aVariable->name, '*');
|
||||
if (NULL != tempChar)
|
||||
{
|
||||
++tempChar; // skip last '*'
|
||||
}
|
||||
else
|
||||
{
|
||||
tempChar = aVariable->name;
|
||||
}
|
||||
fprintf(aFile, "\t");
|
||||
fprintf(aFile, aVariableTemplate, tempChar);
|
||||
fprintf(aFile, " = NULL;" NEWLINES);
|
||||
}
|
||||
else if (aVariable->array)
|
||||
{
|
||||
fprintf(aFile, "\t(void) memset(");
|
||||
fprintf(aFile, aVariableTemplate, aVariable->name);
|
||||
fprintf(aFile, ", "STUBDEFAULT_VALUE_VARIABLE_S", sizeof(%s)); /* %s */" NEWLINES, aVariable->name, aVariable->dataType);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\t");
|
||||
fprintf(aFile, aVariableTemplate, aVariable->name);
|
||||
fprintf(aFile, " = NULL;" NEWLINES);
|
||||
}
|
||||
|
||||
}
|
||||
else if (isDatatypeStandard(aVariable->dataType))
|
||||
{
|
||||
fprintf(aFile, "\t");
|
||||
fprintf(aFile, aVariableTemplate, aVariable->name);
|
||||
fprintf(aFile, " = "STUBDEFAULT_VALUE_VARIABLE_S";" NEWLINES);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\t(void) memset(&");
|
||||
fprintf(aFile, aVariableTemplate, aVariable->name);
|
||||
fprintf(aFile, ", "STUBDEFAULT_VALUE_VARIABLE_S", sizeof(%s)); /* %s */" NEWLINES, aVariable->name, aVariable->dataType);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void createVariableSpecificCheck(FILE *aFile, cfile_variable_t *aVariable)
|
||||
{
|
||||
char *tempChar = NULL;
|
||||
|
||||
if (NULL != strstr(aVariable->dataType, "const"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL != strstr(aVariable->dataType, "*") || aVariable->array)
|
||||
{
|
||||
if (CVARIABLE_CHECK_TYPE(aVariable->type, CVARIABLE_TYPE_FUPTR))
|
||||
{
|
||||
// removing all "*" for function pointer ASSERTs
|
||||
tempChar = strrchr(aVariable->name, '*');
|
||||
if (NULL != tempChar)
|
||||
{
|
||||
++tempChar; // skip last '*'
|
||||
}
|
||||
else
|
||||
{
|
||||
tempChar = aVariable->name;
|
||||
}
|
||||
fprintf(aFile, "\tCU_ASSERT_PTR_EQUAL(%s, "STUBVARIABLE_EXPECTED_S1");"NEWLINES, tempChar, tempChar);
|
||||
}
|
||||
else if (aVariable->array && !CVARIABLE_CHECK_TYPE(aVariable->type, CVARIABLE_TYPE_FUPTR))
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_MEMORY_CHECK(\"%s\", %s, "STUBVARIABLE_EXPECTED_S1", sizeof(%s));"NEWLINES, aVariable->name, aVariable->name,
|
||||
aVariable->name, aVariable->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_PTR_EQUAL(%s, "STUBVARIABLE_EXPECTED_S1");"NEWLINES, aVariable->name, aVariable->name);
|
||||
}
|
||||
|
||||
}
|
||||
else if (isDatatypeStandard(aVariable->dataType))
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_EQUAL_OUTPUT(%s, "STUBVARIABLE_EXPECTED_S1", ", aVariable->name, aVariable->name);
|
||||
addPrintfFormat(aFile, aVariable->dataType);
|
||||
fprintf(aFile, ");" NEWLINES);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_MEMORY_CHECK(\"%s\", &%s, &"STUBVARIABLE_EXPECTED_S1", sizeof(%s));"NEWLINES, aVariable->name, aVariable->name,
|
||||
aVariable->name, aVariable->name);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void createParameterSpecificCheck(FILE *aFile, cfunction_t *aFunction, cfunction_parameter_t *aParameter, char aParameterIndex)
|
||||
{
|
||||
if (CPARAMETER_TYPE_FUNCPTR == aParameter->type)
|
||||
{
|
||||
// function pointer
|
||||
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);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_POINTER_S";" NEWLINES, aFunction->name,
|
||||
aFunction->name, aParameterIndex, aParameter->dataType);
|
||||
}
|
||||
else if (NULL != strstr(aParameter->dataType, "*") && NULL != strstr(aParameter->dataType, "char"))
|
||||
{
|
||||
// char array with string comparison
|
||||
fprintf(aFile, "\tif (" //
|
||||
STUBPARAMETER_POINTERHANDLING_ADDRESS_S " == " STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_POINTERHANDLING_S//
|
||||
")" NEWLINES "\t{" NEWLINES, aFunction->name, aFunction->name);
|
||||
// only assert if result should not be ignored (_size parameter)
|
||||
fprintf(aFile, "\t\tif ("STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size)" NEWLINES, aFunction->name, aFunction->name,
|
||||
aParameterIndex);
|
||||
fprintf(aFile, "\t\t\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);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
// injection only for non constant and non NULL parameter
|
||||
if (NULL == strstr(aParameter->dataType, "const"))
|
||||
{
|
||||
fprintf(aFile, "\telse if (NULL != " STUBINIT_PARAM_PARAMETER_S1 ")" NEWLINES "\t{" NEWLINES, aParameterIndex);
|
||||
fprintf(aFile, "\t\tmemcpy(" STUBINIT_PARAM_PARAMETER_S1 ", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1", " //
|
||||
STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size",//
|
||||
aParameterIndex, aFunction->name, aFunction->name, aParameterIndex, aFunction->name, aFunction->name, aParameterIndex);
|
||||
fprintf(aFile, ");" NEWLINES);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
}
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_POINTER_S";" NEWLINES, aFunction->name,
|
||||
aFunction->name, aParameterIndex, aParameter->dataType);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size = "STUBDEFAULT_VALUE_POINTERSIZE_S";" NEWLINES,
|
||||
aFunction->name, aFunction->name, aParameterIndex);
|
||||
}
|
||||
else if (NULL != strstr(aParameter->dataType, "*") || NULL != aParameter->array)
|
||||
{
|
||||
// pointer
|
||||
fprintf(aFile, "\tif (" //
|
||||
STUBPARAMETER_POINTERHANDLING_ADDRESS_S " == " STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_POINTERHANDLING_S//
|
||||
")" NEWLINES "\t{" NEWLINES, aFunction->name, aFunction->name);
|
||||
// only assert if result should not be ignored (_size parameter)
|
||||
fprintf(aFile, "\t\tif ("STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size)" NEWLINES, aFunction->name, aFunction->name,
|
||||
aParameterIndex);
|
||||
fprintf(aFile, "\t\t\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);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
// injection only for non constant and non NULL parameter
|
||||
if (NULL == strstr(aParameter->dataType, "const"))
|
||||
{
|
||||
fprintf(aFile, "\telse if (NULL != " STUBINIT_PARAM_PARAMETER_S1 ")" NEWLINES "\t{" NEWLINES, aParameterIndex);
|
||||
fprintf(aFile, "\t\tmemcpy(" STUBINIT_PARAM_PARAMETER_S1 ", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1", " //
|
||||
STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size",//
|
||||
aParameterIndex, aFunction->name, aFunction->name, aParameterIndex, aFunction->name, aFunction->name, aParameterIndex);
|
||||
fprintf(aFile, ");" NEWLINES);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
}
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_POINTER_S";" NEWLINES, aFunction->name,
|
||||
aFunction->name, aParameterIndex, aParameter->dataType);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1"_size = "STUBDEFAULT_VALUE_POINTERSIZE_S";" NEWLINES,
|
||||
aFunction->name, aFunction->name, aParameterIndex);
|
||||
}
|
||||
else if (isDatatypeStandard(aParameter->dataType))
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_EQUAL_OUTPUT(");
|
||||
fprintf(aFile, STUBINIT_PARAM_PARAMETER_S1", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1", ", aParameterIndex, aFunction->name,
|
||||
aFunction->name, aParameterIndex);
|
||||
addPrintfFormat(aFile, aParameter->dataType);
|
||||
fprintf(aFile, ");"NEWLINES);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_VARIABLE_S";" NEWLINES, aFunction->name,
|
||||
aFunction->name, aParameterIndex, aParameter->dataType);
|
||||
}
|
||||
else
|
||||
{
|
||||
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, ", sizeof("STUBINIT_PARAM_PARAMETER_S1"));"NEWLINES, aParameterIndex);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_VARIABLE_S";" NEWLINES, aFunction->name,
|
||||
aFunction->name, aParameterIndex, aParameter->dataType);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int8_t createStubExpected(char *aNoSuffix, FILE *aFile, FILE *aHeader, cfile_variableList_t *aList)
|
||||
{
|
||||
cfile_variable_t *work = NULL;
|
||||
if (NULL == aFile || NULL == aHeader || NULL == aList)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
work = aList->head;
|
||||
while (work)
|
||||
{
|
||||
if (!CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_REGULAR) || NULL != strstr(work->dataType, "const"))
|
||||
{
|
||||
work = work->next;
|
||||
continue;
|
||||
}
|
||||
if (CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_FUPTR))
|
||||
{
|
||||
fprintf(aFile, "%s ("STUBVARIABLE_EXPECTED_S1")%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
fprintf(aHeader, "extern %s ("STUBVARIABLE_EXPECTED_S1")%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "%s "STUBVARIABLE_EXPECTED_S1"%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
fprintf(aHeader, "extern %s "STUBVARIABLE_EXPECTED_S1"%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
}
|
||||
work = work->next;
|
||||
}
|
||||
|
||||
fprintf(aHeader, "void "STUBFUNCTION_INITEXPECTED_S1"();"NEWLINES NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "void "STUBFUNCTION_INITEXPECTED_S1"()"NEWLINES"{"NEWLINES, aNoSuffix);
|
||||
|
||||
work = aList->head;
|
||||
while (work)
|
||||
{
|
||||
if (!CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_REGULAR))
|
||||
{
|
||||
work = work->next;
|
||||
continue;
|
||||
}
|
||||
createVariableSpecificInit(STUBVARIABLE_EXPECTED_S1, aFile, work);
|
||||
work = work->next;
|
||||
}
|
||||
fprintf(aFile, "\t"STUBFUNCTION_USER_INITEXPECTED_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "}"NEWLINES NEWLINES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int8_t createStubGlobals(char *aNoSuffix, FILE *aFile, FILE *aHeader, cfile_variableList_t *aList)
|
||||
{
|
||||
cfile_variable_t *work = NULL;
|
||||
if (NULL == aFile || NULL == aHeader || NULL == aList)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
work = aList->head;
|
||||
while (work)
|
||||
{
|
||||
if (!CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_REGULAR))
|
||||
{
|
||||
work = work->next;
|
||||
continue;
|
||||
}
|
||||
if (CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_FUPTR))
|
||||
{
|
||||
fprintf(aFile, "%s (%s)%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
fprintf(aHeader, "extern %s (%s)%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "%s %s%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
fprintf(aHeader, "extern %s %s%s;"NEWLINES, work->dataType, work->name, (work->array ? work->array : ""));
|
||||
}
|
||||
|
||||
work = work->next;
|
||||
}
|
||||
|
||||
fprintf(aFile, "void "STUBFUNCTION_INITGLOBALS_S1"()"NEWLINES"{"NEWLINES, aNoSuffix);
|
||||
|
||||
work = aList->head;
|
||||
while (work)
|
||||
{
|
||||
if (!CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_REGULAR))
|
||||
{
|
||||
work = work->next;
|
||||
continue;
|
||||
}
|
||||
createVariableSpecificInit("%s", aFile, work);
|
||||
work = work->next;
|
||||
}
|
||||
fprintf(aFile, "\t"STUBFUNCTION_USER_INITGLOBALS_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "}"NEWLINES);
|
||||
fprintf(aHeader, "void "STUBFUNCTION_INITGLOBALS_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aHeader, "void "STUBFUNCTION_INIT_S1"();"NEWLINES NEWLINES, aNoSuffix);
|
||||
|
||||
fprintf(aFile, NEWLINES"void "STUBFUNCTION_INIT_S1"()"NEWLINES"{"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "\t"STUBFUNCTION_INITEXPECTED_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "\t"STUBFUNCTION_INITGLOBALS_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "}"NEWLINES NEWLINES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int8_t createStubCheck(char *aNoSuffix, FILE *aFile, FILE *aHeader, cfile_variableList_t *aList)
|
||||
{
|
||||
cfile_variable_t *work = NULL;
|
||||
if (NULL == aFile || NULL == aHeader || NULL == aList)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(aHeader, "void "STUBFUNCTION_CHECK_S1"();"NEWLINES NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "void "STUBFUNCTION_CHECK_S1"()"NEWLINES"{"NEWLINES, aNoSuffix);
|
||||
|
||||
work = aList->head;
|
||||
while (work)
|
||||
{
|
||||
if (!CVARIABLE_CHECK_TYPE(work->type, CVARIABLE_TYPE_REGULAR))
|
||||
{
|
||||
work = work->next;
|
||||
continue;
|
||||
}
|
||||
createVariableSpecificCheck(aFile, work);
|
||||
work = work->next;
|
||||
}
|
||||
fprintf(aFile, "\t"STUBFUNCTION_USER_CHECK_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(aFile, "}"NEWLINES NEWLINES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *aFunction)
|
||||
{
|
||||
cfunction_parameter_t *parameter = NULL;
|
||||
char parameterIndex = 'a';
|
||||
bool pointerAvailable = false;
|
||||
|
||||
parameter = aFunction->parameter.head;
|
||||
while (parameter)
|
||||
{
|
||||
if (NULL != strstr(parameter->dataType, "*") || parameter->array)
|
||||
{
|
||||
pointerAvailable = true;
|
||||
break;
|
||||
}
|
||||
parameter = parameter->next;
|
||||
}
|
||||
|
||||
if (NULL == aFile || NULL == aHeader || NULL == aFunction)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (CFUNCTION_TYPE_REGULAR != aFunction->type && CFUNCTION_TYPE_STATIC != aFunction->type)
|
||||
if (CFUNCTION_TYPE_REGULAR != aFunction->type)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -63,34 +442,127 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a
|
||||
fprintf(aFile, "// Expected parameter and return value structures" NEWLINES);
|
||||
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);
|
||||
fprintf(aFile, "\tuint8_t "STUBPARAMETER_CALLTEST_S"; /*!< @brief Stub call is a STUB_CALL_PASS or STUB_CALL_FAIL */" NEWLINES);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile, "\t%s "STUBPARAMETER_POINTERHANDLING_S"; /*!< @brief pointer handling */" NEWLINES, STUBPARAMETER_POINTERHANDLING_ENUM_S);
|
||||
}
|
||||
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)
|
||||
{
|
||||
fprintf(aFile, "\t%s "STUBPARAMETER_PARAM_S1"; /*!< @brief %s */" NEWLINES, NCHECK(parameter->type), parameterIndex++, NCHECK(parameter->name));
|
||||
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));
|
||||
fprintf(aFile, "\tuint32_t "STUBPARAMETER_PARAM_S1"_size; /*!< @brief \"%s\" size to copy in case of parameter injection */" NEWLINES,
|
||||
parameterIndex++, NCHECK(parameter->name));
|
||||
}
|
||||
else if (NULL != strstr(parameter->dataType, "*"))
|
||||
{
|
||||
fprintf(aFile, "\t%s "STUBPARAMETER_PARAM_S1"; /*!< @brief \"%s\" */" NEWLINES, NCHECK(parameter->dataType), parameterIndex, NCHECK(parameter->name));
|
||||
fprintf(aFile, "\tuint32_t "STUBPARAMETER_PARAM_S1"_size; /*!< @brief \"%s\" size to copy in case of parameter injection */" NEWLINES,
|
||||
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;
|
||||
}
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
fprintf(aFile, "\t%s "STUBPARAMETER_RETURN_S"; /**< @brief return value */" NEWLINES, aFunction->dataType);
|
||||
}
|
||||
|
||||
fprintf(aFile, "} "STUBPARAMETER_TYPEDEF_S1";" NEWLINES, aFunction->name);
|
||||
NEWLINE(aFile);
|
||||
|
||||
// Instance counter
|
||||
fprintf(aFile, "// Instance counter for stub functions" NEWLINES);
|
||||
fprintf(aFile, "uint8_t "STUBINSTANCE_S1" = 0;" NEWLINES, aFunction->name);
|
||||
fprintf(aFile, STUBINSTANCE_DATATYPE_S" "STUBINSTANCE_S1" = 0;" NEWLINES, aFunction->name);
|
||||
NEWLINE(aFile);
|
||||
|
||||
// expected parameter
|
||||
fprintf(aFile, "// Expected parameter and return value arrays for in-stub tests" NEWLINES);
|
||||
fprintf(aFile, STUBPARAMETER_TYPEDEF_S1 " " STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_AMOUNT_S1"];" NEWLINES, aFunction->name, aFunction->name,
|
||||
aFunction->name);
|
||||
fprintf(aFile, STUBPARAMETER_TYPEDEF_S1 " " STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_AMOUNT_S1"]", aFunction->name, aFunction->name, aFunction->name);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile, " = {" NEWLINES);
|
||||
// pointer address check by default
|
||||
|
||||
parameter = aFunction->parameter.head;
|
||||
parameterIndex = 'a';
|
||||
while (parameter)
|
||||
{
|
||||
// initialize _size parameter to 1 (default to check addresses)
|
||||
if (CPARAMETER_TYPE_FUNCPTR != parameter->type && (parameter->array || NULL != strstr(parameter->dataType, "*")))
|
||||
{
|
||||
fprintf(aFile, "\t[0 ... %u]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_POINTER_S"," NEWLINES, STUB_INSTANCES_AMOUNT - 1, parameterIndex,
|
||||
parameter->dataType);
|
||||
fprintf(aFile, "\t[0 ... %u]."STUBPARAMETER_PARAM_S1"_size = 1," NEWLINES, STUB_INSTANCES_AMOUNT - 1, parameterIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\t[0 ... %u]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_VARIABLE_S"," NEWLINES, STUB_INSTANCES_AMOUNT - 1, parameterIndex,
|
||||
parameter->dataType);
|
||||
}
|
||||
|
||||
++parameterIndex;
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aFile, "};" NEWLINES);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, ";" NEWLINES);
|
||||
}
|
||||
NEWLINE(aFile);
|
||||
|
||||
// stub function init header; function comment
|
||||
fprintf(aHeader, "/*! @brief Stub initialization of init_%s" NEWLINES, aFunction->name);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aHeader,
|
||||
" * @attention In case of address comparison, ..._size parameter = 0 ignores result (@ref " STUBINIT_PARAM_POINTERHANDLING_S ")." NEWLINES);
|
||||
}
|
||||
fprintf(aHeader, " * @param " STUBINIT_PARAM_INSTANCE_S " Which stub call to initialize" NEWLINES);
|
||||
fprintf(aHeader, " * @param " STUBINIT_PARAM_CALLTEST_S " Is stub call allowed (STUB_CALL_FAIL, STUB_CALL_PASS)" NEWLINES);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aHeader,
|
||||
" * @param " STUBINIT_PARAM_POINTERHANDLING_S " How to handle pointer to data (STUB_PARAMETER_POINTER_HANDLING_ADDRESS, STUB_PARAMETER_POINTER_HANDLING_INJECT" NEWLINES);
|
||||
}
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
fprintf(aHeader, " * @param " STUBINIT_PARAM_RETURN_S " Return value to inject" NEWLINES);
|
||||
}
|
||||
parameter = aFunction->parameter.head;
|
||||
parameterIndex = 'a';
|
||||
while (parameter)
|
||||
{
|
||||
if (NULL != strstr(parameter->dataType, "*") || parameter->array)
|
||||
{
|
||||
fprintf(aHeader,
|
||||
" * @param " STUBINIT_PARAM_PARAMETER_S1 "_size 0 to ignore pointer for address comparison and injection (e.g. test subject references to internal variables)" NEWLINES,
|
||||
parameterIndex);
|
||||
}
|
||||
parameterIndex++;
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aHeader, " */" NEWLINES);
|
||||
|
||||
// stub function init header
|
||||
fprintf(aHeader, "void init_%s(uint8_t "STUBINIT_PARAM_INSTANCE_S", uint8_t "STUBINIT_PARAM_CALLTEST_S, aFunction->name);
|
||||
fprintf(aHeader, "void init_%s("STUBINSTANCE_DATATYPE_S " " STUBINIT_PARAM_INSTANCE_S", uint8_t "STUBINIT_PARAM_CALLTEST_S, aFunction->name);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aHeader, ", %s "STUBINIT_PARAM_POINTERHANDLING_S, STUBPARAMETER_POINTERHANDLING_ENUM_S);
|
||||
}
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
fprintf(aHeader, ", %s "STUBINIT_PARAM_RETURN_S, aFunction->dataType);
|
||||
@@ -99,13 +571,29 @@ 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 if (NULL != strstr(parameter->dataType, "*") || parameter->array)
|
||||
{
|
||||
fprintf(aHeader, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex, NCHECK(parameter->array));
|
||||
fprintf(aHeader, ", uint32_t "STUBINIT_PARAM_PARAMETER_S1"_size", parameterIndex++);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aHeader, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array));
|
||||
}
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aHeader, ");" NEWLINES);
|
||||
|
||||
// stub function init
|
||||
fprintf(aFile, "void init_%s(uint8_t "STUBINIT_PARAM_INSTANCE_S", uint8_t "STUBINIT_PARAM_CALLTEST_S, aFunction->name);
|
||||
fprintf(aFile, "void init_%s("STUBINSTANCE_DATATYPE_S " " STUBINIT_PARAM_INSTANCE_S", uint8_t "STUBINIT_PARAM_CALLTEST_S, aFunction->name);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile, ", %s "STUBINIT_PARAM_POINTERHANDLING_S, STUBPARAMETER_POINTERHANDLING_ENUM_S);
|
||||
}
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
fprintf(aFile, ", %s "STUBINIT_PARAM_RETURN_S, aFunction->dataType);
|
||||
@@ -114,7 +602,19 @@ 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 if (NULL != strstr(parameter->dataType, "*") || parameter->array)
|
||||
{
|
||||
fprintf(aFile, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex, NCHECK(parameter->array));
|
||||
fprintf(aFile, ", uint32_t "STUBINIT_PARAM_PARAMETER_S1"_size", parameterIndex++);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, ", %s "STUBINIT_PARAM_PARAMETER_S1"%s", NCHECK(parameter->dataType), parameterIndex++, NCHECK(parameter->array));
|
||||
}
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aFile, ")" NEWLINES);
|
||||
@@ -123,21 +623,72 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a
|
||||
fprintf(aFile, "\t{" NEWLINES);
|
||||
fprintf(aFile, "\t\tCU_FAIL_FATAL(\"init_%s() - "STUBINIT_PARAM_INSTANCE_S" out of bounce\");" NEWLINES, aFunction->name);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
// setting parameter
|
||||
fprintf(aFile, "\t"STUBINSTANCE_S1" = 0;" NEWLINES, aFunction->name);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_CALLTEST_S" = "STUBINIT_PARAM_CALLTEST_S";" NEWLINES,
|
||||
aFunction->name);
|
||||
|
||||
// if STUB_CALL_PASS is requested init with parameter
|
||||
fprintf(aFile, "\tif ( STUB_CALL_PASS == " STUBINIT_PARAM_CALLTEST_S ")" NEWLINES "\t{" NEWLINES);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile,
|
||||
"\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_POINTERHANDLING_S" = "STUBINIT_PARAM_POINTERHANDLING_S";" NEWLINES,
|
||||
aFunction->name);
|
||||
}
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_RETURN_S" = "STUBINIT_PARAM_RETURN_S";" NEWLINES,
|
||||
fprintf(aFile, "\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_RETURN_S" = "STUBINIT_PARAM_RETURN_S";" NEWLINES,
|
||||
aFunction->name);
|
||||
}
|
||||
parameter = aFunction->parameter.head;
|
||||
parameterIndex = 'a';
|
||||
while (parameter)
|
||||
{
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1" = "STUBINIT_PARAM_PARAMETER_S1";" NEWLINES,
|
||||
fprintf(aFile, "\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1" = "STUBINIT_PARAM_PARAMETER_S1";" NEWLINES,
|
||||
aFunction->name, parameterIndex, parameterIndex);
|
||||
if ((NULL != strstr(parameter->dataType, "*") || parameter->array) && CPARAMETER_TYPE_FUNCPTR != parameter->type)
|
||||
{
|
||||
fprintf(aFile,
|
||||
"\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1"_size = "STUBINIT_PARAM_PARAMETER_S1"_size;" NEWLINES,
|
||||
aFunction->name, parameterIndex, parameterIndex);
|
||||
}
|
||||
++parameterIndex;
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
// if STUB_CALL_FAIL is requested init with default parameter
|
||||
fprintf(aFile, "\telse" NEWLINES "\t{" NEWLINES);
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile,
|
||||
"\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_POINTERHANDLING_S" = "STUBPARAMETER_POINTERHANDLING_ADDRESS_S";" NEWLINES,
|
||||
aFunction->name);
|
||||
}
|
||||
parameter = aFunction->parameter.head;
|
||||
parameterIndex = 'a';
|
||||
while (parameter)
|
||||
{
|
||||
// initialize _size parameter to 1 (default to check addresses)
|
||||
if (CPARAMETER_TYPE_FUNCPTR != parameter->type && (parameter->array || NULL != strstr(parameter->dataType, "*")))
|
||||
{
|
||||
fprintf(aFile, "\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_POINTER_S";" NEWLINES,
|
||||
aFunction->name, parameterIndex, parameter->dataType);
|
||||
fprintf(aFile,
|
||||
"\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1"_size = "STUBDEFAULT_VALUE_POINTERSIZE_S";" NEWLINES,
|
||||
aFunction->name, parameterIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\t\t"STUBPARAMETER_STRUCT_S1"["STUBINIT_PARAM_INSTANCE_S"]."STUBPARAMETER_PARAM_S1" = (%s) "STUBDEFAULT_VALUE_VARIABLE_S";" NEWLINES,
|
||||
aFunction->name, parameterIndex, parameter->dataType);
|
||||
}
|
||||
|
||||
++parameterIndex;
|
||||
parameter = parameter->next;
|
||||
}
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
|
||||
fprintf(aFile, "}" NEWLINES);
|
||||
NEWLINE(aFile);
|
||||
|
||||
@@ -147,7 +698,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);
|
||||
@@ -157,26 +718,27 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a
|
||||
fprintf(aFile, "\t\tCU_FAIL(\"Inadvertent %s() call.\");"NEWLINES"\t\tbreak;"NEWLINES, aFunction->name);
|
||||
fprintf(aFile, "\tcase STUB_CALL_PASS:" NEWLINES);
|
||||
fprintf(aFile, "\t\tCU_PASS(\"%s() called.\");"NEWLINES"\t\tbreak;"NEWLINES, aFunction->name);
|
||||
fprintf(aFile, "\tdefault:"NEWLINES"\t\tbreak;"NEWLINES);
|
||||
fprintf(aFile, "\tdefault:"NEWLINES);
|
||||
fprintf(aFile,
|
||||
"\t\tCU_FAIL_OUTPUT_LESS(\"Invalid STUB_CALL test value: \","STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_CALLTEST_S", \"%%u\");"NEWLINES,
|
||||
aFunction->name, aFunction->name);
|
||||
fprintf(aFile, "\t\tbreak;"NEWLINES);
|
||||
fprintf(aFile, "\t}" NEWLINES);
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_CALLTEST_S" = STUB_CALL_FAIL;" NEWLINES, aFunction->name, aFunction->name);
|
||||
|
||||
parameter = aFunction->parameter.head;
|
||||
parameterIndex = 'a';
|
||||
while (parameter)
|
||||
{
|
||||
if (NULL != strstr(parameter->type, "*"))
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_PTR_EQUAL(");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(aFile, "\tCU_ASSERT_EQUAL(");
|
||||
}
|
||||
fprintf(aFile, STUBINIT_PARAM_PARAMETER_S1", "STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_PARAM_S1");" NEWLINES, parameterIndex,
|
||||
aFunction->name, aFunction->name, parameterIndex);
|
||||
createParameterSpecificCheck(aFile, aFunction, parameter, parameterIndex);
|
||||
++parameterIndex;
|
||||
parameter = parameter->next;
|
||||
}
|
||||
if (pointerAvailable)
|
||||
{
|
||||
fprintf(aFile, "\t"STUBPARAMETER_STRUCT_S1"["STUBINSTANCE_S1"]."STUBPARAMETER_POINTERHANDLING_S" = " STUBPARAMETER_POINTERHANDLING_ADDRESS_S ";" NEWLINES,
|
||||
aFunction->name, aFunction->name);
|
||||
}
|
||||
|
||||
if (!isDatatypeVoid(aFunction->dataType))
|
||||
{
|
||||
@@ -194,7 +756,86 @@ 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)
|
||||
/*!
|
||||
* @brief Check if file exists using stat
|
||||
* @param [in] *filename Path to file
|
||||
* @retval 0 file does not exist
|
||||
* @retval 1 file exists
|
||||
*/
|
||||
int file_exist(const char *filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat(filename, &buffer) == 0);
|
||||
}
|
||||
|
||||
STATIC void createUserHeader(char *aOutput, char *aNoSuffix)
|
||||
{
|
||||
FILE *fileDesc = NULL;
|
||||
char *cHeaderName = NULL;
|
||||
char *cFileName = NULL;
|
||||
xmallocStrlcpy(&cHeaderName, aOutput, strlen(aOutput));
|
||||
xmallocStrlcat(&cHeaderName, "_user.h", 8);
|
||||
xmallocStrlcpy(&cFileName, aOutput, strlen(aOutput));
|
||||
xmallocStrlcat(&cFileName, "_user.c", 8);
|
||||
|
||||
if (!file_exist(cHeaderName))
|
||||
{
|
||||
// user header doesn't exist
|
||||
fileDesc = fopen(cHeaderName, "w");
|
||||
if (NULL != fileDesc)
|
||||
{
|
||||
|
||||
fprintf(fileDesc, "/*! @file %s"NEWLINES, gnu_basename(cHeaderName));
|
||||
fprintf(fileDesc, " * @details"NEWLINES" * This is a user defined stub header.\\n"NEWLINES);
|
||||
fprintf(fileDesc, " * Define subject header needed for compilation of stub (e.g. typedefs, structures, ...).\\n"NEWLINES);
|
||||
fprintf(fileDesc, " * - generated by stubser -"NEWLINES" */" NEWLINES NEWLINES);
|
||||
|
||||
fprintf(fileDesc, "#ifndef _STUB_%s_USER_H"NEWLINES, aNoSuffix);
|
||||
fprintf(fileDesc, "#define _STUB_%s_USER_H"NEWLINES, aNoSuffix);
|
||||
|
||||
fprintf(fileDesc, NEWLINES"// predefined stub user functions"NEWLINES);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_INITEXPECTED_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_INITGLOBALS_S1"();"NEWLINES, aNoSuffix);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_CHECK_S1"();"NEWLINES, aNoSuffix);
|
||||
|
||||
fprintf(fileDesc, NEWLINES"#endif // _STUB_%s_USER_H"NEWLINES, aNoSuffix);
|
||||
|
||||
fclose(fileDesc);
|
||||
fileDesc = NULL;
|
||||
}
|
||||
}
|
||||
free(cHeaderName);
|
||||
|
||||
if (!file_exist(cFileName))
|
||||
{
|
||||
// user code doesn't exist
|
||||
fileDesc = fopen(cFileName, "w");
|
||||
if (NULL != fileDesc)
|
||||
{
|
||||
|
||||
fprintf(fileDesc, "/*! @file %s"NEWLINES, gnu_basename(cFileName));
|
||||
fprintf(fileDesc, " * @details"NEWLINES" * This is a user defined stub.\\n"NEWLINES);
|
||||
fprintf(fileDesc, " * Define additional elements which need to be tested, or helper functions.\\n"NEWLINES);
|
||||
fprintf(fileDesc, " * - generated by stubser -"NEWLINES" */" NEWLINES NEWLINES);
|
||||
|
||||
fprintf(fileDesc, "#include <CUnit/CUnit.h>"NEWLINES);
|
||||
fprintf(fileDesc, "#include \"xasserts.h\""NEWLINES);
|
||||
fprintf(fileDesc, "#include \"xtypes.h\""NEWLINES);
|
||||
fprintf(fileDesc, "#include \"stub.h\""NEWLINES);
|
||||
fprintf(fileDesc, "#include \"stub_%s_user.h\""NEWLINES, aNoSuffix);
|
||||
|
||||
fprintf(fileDesc, "// predefined stub user functions"NEWLINES);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_INITEXPECTED_S1"()"NEWLINES"{"NEWLINES"\t"NEWLINES"}"NEWLINES NEWLINES, aNoSuffix);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_INITGLOBALS_S1"()"NEWLINES"{"NEWLINES"\t"NEWLINES"}"NEWLINES NEWLINES, aNoSuffix);
|
||||
fprintf(fileDesc, "void "STUBFUNCTION_USER_CHECK_S1"()"NEWLINES"{"NEWLINES"\t"NEWLINES"}"NEWLINES NEWLINES, aNoSuffix);
|
||||
|
||||
fclose(fileDesc);
|
||||
}
|
||||
}
|
||||
free(cFileName);
|
||||
}
|
||||
|
||||
STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfile_t *aCfile)
|
||||
{
|
||||
FILE *cfile;
|
||||
FILE *cheader;
|
||||
@@ -202,7 +843,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;
|
||||
}
|
||||
@@ -231,22 +872,30 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(cfile, "/* @file %s"NEWLINES, gnu_basename(cFileName));
|
||||
createUserHeader(aOutput, aNoSuffix);
|
||||
|
||||
fprintf(cfile, "/*! @file %s"NEWLINES, gnu_basename(cFileName));
|
||||
fprintf(cfile, " * @details"NEWLINES" * This is a stub for CUnit.\\n"NEWLINES);
|
||||
fprintf(cfile, " * - generated by stubser -"NEWLINES" */" NEWLINES NEWLINES);
|
||||
fprintf(cfile, "#include <CUnit/CUnit.h>"NEWLINES);
|
||||
fprintf(cfile, "#include \"xasserts.h\""NEWLINES);
|
||||
fprintf(cfile, "#include \"xtypes.h\""NEWLINES);
|
||||
fprintf(cfile, "#include \"stub.h\""NEWLINES);
|
||||
fprintf(cfile, "#include \"stub_%s_user.h\""NEWLINES, aNoSuffix);
|
||||
fprintf(cfile, "#include \"%s\""NEWLINES NEWLINES, gnu_basename(cHeaderName));
|
||||
|
||||
fprintf(cheader, "/* @file %s"NEWLINES, gnu_basename(cHeaderName));
|
||||
fprintf(cheader, "/*! @file %s"NEWLINES, gnu_basename(cHeaderName));
|
||||
fprintf(cheader, " * @details"NEWLINES" * This is a stub header.\\n"NEWLINES);
|
||||
fprintf(cheader, " * - generated by stubser -"NEWLINES" */" NEWLINES NEWLINES);
|
||||
|
||||
fprintf(cheader, "#ifndef _STUB_%s_H"NEWLINES, aNoSuffix);
|
||||
fprintf(cheader, "#define _STUB_%s_H"NEWLINES NEWLINES, aNoSuffix);
|
||||
|
||||
function = aFunctionList->head;
|
||||
createStubExpected(aNoSuffix, cfile, cheader, &aCfile->variables);
|
||||
createStubGlobals(aNoSuffix, cfile, cheader, &aCfile->variables);
|
||||
createStubCheck(aNoSuffix, cfile, cheader, &aCfile->variables);
|
||||
|
||||
function = aCfile->functions.head;
|
||||
while (function)
|
||||
{
|
||||
(void) createStubFunctionBlock(cfile, cheader, function);
|
||||
@@ -271,38 +920,37 @@ 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;
|
||||
uint32_t warnings = 0;
|
||||
char fileName[PATH_MAX] =
|
||||
{ '\0' };
|
||||
|
||||
ret = cfile_parser(path, &functionList);
|
||||
#if isDebugLevel(1)
|
||||
printf(STUB_CONSOLE_PARSE_RUN_S1, path);
|
||||
#else
|
||||
printf(STUB_CONSOLE_PARSE_RUN_S1, gnu_basename(path));
|
||||
#endif
|
||||
warnings = cfile_parser(path, &cFile);
|
||||
DEBUG_LOG_APPEND(1, "\n");
|
||||
if (0 != ret)
|
||||
if (0 != warnings)
|
||||
{
|
||||
#if isDebugLevel(1)
|
||||
printf(STUB_CONSOLE_PARSE_ERROR_S2, path, ret);
|
||||
printf(STUB_CONSOLE_PARSE_ERROR_S2, path, warnings);
|
||||
#else
|
||||
printf(STUB_CONSOLE_PARSE_ERROR_S2, gnu_basename(path), ret);
|
||||
printf(STUB_CONSOLE_PARSE_ERROR_S2, gnu_basename(path), warnings);
|
||||
#endif
|
||||
if (-2 == ret)
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" Block removal error (likely nested comments).\n");
|
||||
}
|
||||
else if (-3 == ret)
|
||||
{
|
||||
printf(" Function parameter detection error\n");
|
||||
}
|
||||
ret = -1;
|
||||
goto end_stubser_createStub;
|
||||
}
|
||||
#if isDebugLevel(1)
|
||||
printf(STUB_CONSOLE_PARSE_OK_S1, path);
|
||||
#else
|
||||
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);
|
||||
@@ -311,9 +959,13 @@ int stubser_createStub(char *path, char* aNoSuffix, char *aOutput)
|
||||
}
|
||||
printf(STUB_CONSOLE_CREATE_OK_S1, fileName);
|
||||
|
||||
#if isDebugLevel(1)
|
||||
cfile_print(&cFile);
|
||||
#endif
|
||||
|
||||
end_stubser_createStub: // function end target
|
||||
|
||||
cfunction_freeList(&functionList);
|
||||
cfile_free(&cFile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 27.02.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_STUBSER_IF_H_
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Code: GNU-C\n
|
||||
*
|
||||
* @date 04.03.2017
|
||||
* @author SESA354004
|
||||
* @author Martin Winkler
|
||||
*/
|
||||
|
||||
#ifndef STUBSER_STUBSER_LOC_H_
|
||||
@@ -31,17 +31,44 @@
|
||||
#define STUBPARAMETER_STRUCT_S1 "stubparameter_%s" // stubparameter_modulfunction_1
|
||||
#define STUBPARAMETER_PARAM_S1 "parameter_%c" // "stubparameter_modulfunction_1".parameter_a
|
||||
#define STUBPARAMETER_CALLTEST_S "stubCallTest"
|
||||
#define STUBPARAMETER_POINTERHANDLING_S "stubPointerHandling"
|
||||
#define STUBPARAMETER_POINTERHANDLING_ENUM_S "stub_parameter_pointer_handling_t"
|
||||
#define STUBPARAMETER_POINTERHANDLING_ADDRESS_S "STUB_PARAMETER_POINTER_HANDLING_ADDRESS"
|
||||
#define STUBPARAMETER_POINTERHANDLING_INJECT_S "STUB_PARAMETER_POINTER_HANDLING_INJECT"
|
||||
#define STUBPARAMETER_RETURN_S "returnValue" // "stubparameter_modulfunction_1".returnValue
|
||||
#define STUBINSTANCE_S1 "stubInstance_%s" // stubInstance_modulfunction_1
|
||||
#define STUBINSTANCE_DATATYPE_S "uint8_t"
|
||||
#define STUBINIT_PARAM_INSTANCE_S "aInstance"
|
||||
#define STUBINIT_PARAM_CALLTEST_S "aStubCallTest"
|
||||
#define STUBINIT_PARAM_PARAMETER_S1 "aParameter_%c" // aParameter_a
|
||||
#define STUBINIT_PARAM_RETURN_S "aReturnValue"
|
||||
#define STUBINIT_PARAM_POINTERHANDLING_S "aPointerHandling"
|
||||
|
||||
#define STUBDEFAULT_VALUE_FUNCTIONPOINTER_S "0xAA"
|
||||
#define STUBDEFAULT_VALUE_POINTER_S "0xAA"
|
||||
#define STUBDEFAULT_VALUE_POINTERSIZE_S "1"
|
||||
#define STUBDEFAULT_VALUE_VARIABLE_S "0xAA"
|
||||
|
||||
#define STUBFUNCTION_USER_INITEXPECTED_S1 "stub_%s_user_initExpected" // stub_testfunction_initExpected
|
||||
#define STUBFUNCTION_USER_INITGLOBALS_S1 "stub_%s_user_initGlobals" // stub_testfunction_initGlobals
|
||||
#define STUBFUNCTION_USER_CHECK_S1 "stub_%s_user_checkGlobals" // stub_testfunction_checkGlobals
|
||||
|
||||
#define STUBFUNCTION_INITEXPECTED_S1 "stub_%s_initExpected" // stub_testfunction_initExpected
|
||||
#define STUBFUNCTION_INITGLOBALS_S1 "stub_%s_initGlobals" // stub_testfunction_initGlobals
|
||||
#define STUBFUNCTION_CHECK_S1 "stub_%s_checkGlobals" // stub_testfunction_checkGlobals
|
||||
#define STUBFUNCTION_INIT_S1 "stub_%s_init" // stub_testfunction_init
|
||||
#define STUBVARIABLE_EXPECTED_S1 "%s_expected" // variable_expected
|
||||
|
||||
#define STUB_CONSOLE_GOBACK "\033[2K\r"
|
||||
#define STUB_CONSOLE_RUN "[ ]"
|
||||
#define STUB_CONSOLE_OK "[ OK ]"
|
||||
#define STUB_CONSOLE_WARN "[WARN]"
|
||||
#define STUB_CONSOLE_FAIL "[FAIL]"
|
||||
#define STUB_CONSOLE_PARSE_ERROR_S2 STUB_CONSOLE_FAIL " %s parsing failed (%d)\n"
|
||||
#define STUB_CONSOLE_PARSE_OK_S1 STUB_CONSOLE_OK " %s parsing..."
|
||||
#define STUB_CONSOLE_CREATE_ERROR_S2 "fail\n"STUB_CONSOLE_FAIL " %s creation failed (%d)\n"
|
||||
#define STUB_CONSOLE_CREATE_OK_S1 "ok > %s\n"
|
||||
#define STUB_CONSOLE_PARSE_ERROR_S2 "\n" STUB_CONSOLE_WARN " %s parsing with %d warnings (check output manually)"
|
||||
#define STUB_CONSOLE_PARSE_RUN_S1 STUB_CONSOLE_RUN " %s parsing..."
|
||||
#define STUB_CONSOLE_PARSE_OK_S1 STUB_CONSOLE_GOBACK STUB_CONSOLE_OK " %s parsing..."
|
||||
#define STUB_CONSOLE_CREATE_ERROR_S2 "...stub creation failed\n"STUB_CONSOLE_FAIL " %s creation failed (%d)\n"
|
||||
#define STUB_CONSOLE_CREATE_OK_S1 "...stub created > %s\n"
|
||||
|
||||
#define STUB_REGEX_STD_DATATYPE "(^|[^_[:alnum:]])([ui]+nt[0-9]{1,2}_t|char|uchar|word[12346]{2}|int[12346]{0,2}|byte)([^_[:alnum:]]|$)"
|
||||
#endif /* STUBSER_STUBSER_LOC_H_ */
|
||||
|
Reference in New Issue
Block a user