153 lines
4.0 KiB
C
153 lines
4.0 KiB
C
/*!
|
|
* @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;
|
|
}
|