Files
config-parser/config.c
jonathan santis a05c9ce786 update doc
2025-05-21 09:46:06 +02:00

311 lines
10 KiB
C

#include"config.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
/**
@brief Here we check if the given string contains a section
for example [SECTIONName] here delimiterLeft is [ and delimiterRight is ]
if a section is found, the section name will be written to sectionName
@brief Input:
@param char **str: the string to check
@param char delimiterLeft: the left delimiter to check for
@param char delimiterRight: the right delimiter to check for
@brief Output:
@param char **sectionName: if found the section Name of the section
@brief Return:
@param int status_code: one of the following values:
*/
int checkSection(char *str,char delimiterLeft,char delimiterRight,char **sectionName)
{
char section[MAX_LEN_SECTIONNAME];
int i = 0; //most outer loop -> character of string
if(str == NULL)
{
return ERROR_STR;
}
int len = strlen(str);
int state = ST_INIT;
int leftDelimiterPos=0;
int rightDelimiterPos=0;
char *sectionName2 = NULL;
while(state != ST_FINISH)
{
switch(state)
{
case ST_INIT:
for(i=0;i<=len;i++) //find first (left) delimiter
{
if(str[i] == delimiterLeft)
{
state = ST_FOUND_LEFT_DELIMITER;
leftDelimiterPos = i;
break;
}
}
if(state != ST_FOUND_LEFT_DELIMITER)
{
return ST_ERROR_NOT_FOUND_LEFT_DELIMITER;
}
break;
case ST_FOUND_LEFT_DELIMITER:
for(i=0;i<=len;i++) //find second (right) delimiter
{
if(str[i] == delimiterRight)
{
state = ST_FOUND_RIGHT_DELIMITER;
rightDelimiterPos = i;
break;
}
}
if(state != ST_FOUND_RIGHT_DELIMITER)
{
return ST_ERROR_NOT_FOUND_RIGHT_DELIMITER;
}
break;
case ST_FOUND_RIGHT_DELIMITER:
int ret=0;
if((ret=getStrAtPos(str,leftDelimiterPos,rightDelimiterPos,sectionName,MAX_LEN_SECTIONNAME)) == NO_ERROR)
{
state = ST_FINISH;
}else{
return ret;
}
case ST_FINISH:
return FOUND_SECTION;
}
}
return NO_SECTION;
}
/**
@brief Here we get / cut from fromPos to toPos and write it to an address
@brief Input:
@param char *str: the string to cut
@param int fromPos: from which position we want to copy, the pos is included and zero indexed
@param int toPos: to which position we want to copy, the pos is included and zero indexed
@brief Output:
@param char **name: here we will write the section name to
@brief Input:
@param int sizeName: the size of the user allocated buffer at **name
*/
int getStrAtPos(char *str,int fromPos,int toPos,char **name,int sizeName)
{
if(*name == NULL)
{
int error = errno;
printf("Pointer NULL:%d\n",error);
return error;
}
int i=fromPos; //character iterator, which starts from specified pos
int j=0; //the character iterator for the target string
int diffLen=toPos-fromPos;
char *ptr_name=*name;
if(diffLen > MAX_LEN_SECTIONNAME || diffLen>sizeName)
{
return ERROR_MAX_LEN;
}
for(i=fromPos,j=0;i<=toPos;i++,j++)
{
ptr_name[j] = str[i];
}
ptr_name[j+1]='\0';
return NO_ERROR;
}
/**
Here we get a "pair" of data, parsed from *str, witch consists of a keyname and a keyvalue.
These are written to the pointers at char **name and char **value.
These pair can be in the form of: \n
ex1: \n
NAME=VALUE \n
____^_____^ \n
____|_____Here we have no delimiter this means rightDelimiterPos must be NULL \n
____This is the left delimiter \n
ex2: \n
name(value) \n
____^_____^ \n
____|_____This is the rightDelimiterPos and must be ')' \n
____This is leftDelimiterPos which must be '(' \n
@brief Input:
@param char *str: the line in the form of a string where a key value pair is stored
@param char leftDelimiterPos: the left delimiter for example '='
@param char rightDelimiterPos: the right delimiter can be NULL in most cases, if NULL we assume that there is only one delimiter, which is in this case the leftDelimiterPos
@brief Output:
@param char **name: The address where we store the name of the Key
@param char **value: The address where we store the key value
@param int sizeName: for size checking against memory allocated at **name
@param int sizeValue: for size checking against memory allocated at **value
@brief Return:
@return will return NO_ERROR (0) if successfull.
If not it will return the error of the subroutine
*/
int getNameValuePair(char *str,char leftDelimiterPos,char rightDelimiterPos,char **name,char **value,int sizeName,int sizeValue)
{
if(*name == NULL || *value == NULL)
{
int error = errno;
printf("Pointer NULL:%d\n",error);
return error;
}
int state=ST_INIT;
char *ptr_name=*name;
char *ptr_value=*value;
int ret=0;
char *ptrDelimiter=NULL;
int posDelimiter=0;
int posEnd=0;
ptrDelimiter=strchr(str,leftDelimiterPos);
if(ptrDelimiter==NULL)
{
return ERROR_DELIMITER_NOT_FOUND;
}
posDelimiter = (ptrDelimiter - str);
printf("LenUntilDelimiter: %d\n",posDelimiter);
if((ret=getStrAtPos(str,0,posDelimiter-1,&ptr_name,sizeName)) == NO_ERROR)
{
printf("ptr_name:%s\n",ptr_name);
}else {
printf("Error at getStrAtPos:%d\n",ret);
return ret;
}
if(rightDelimiterPos == 0)
{
posEnd = strlen(str);
}else{
posEnd = rightDelimiterPos;
}
if((ret=getStrAtPos(str,posDelimiter+1,posEnd,&ptr_value,sizeValue)) == NO_ERROR)
{
printf("ptr_name:%s\n",ptr_value);
}else {
return ret;
}
return NO_ERROR;
}
/**
Given a null terminated buffer of content(ex. from a file) an parse it with a default syntax of:
Sections -> [SECTIONNAME]
name / value -> name=value
Input:
char *originalBuffer: the buffer which holds the string for parsing.
struct configEntry **entry: a user allocated buffer to which we write the parsed config data.
int configSizeCount: the user allocated size of **entry.
Output:
int *returnedCount: to this variable the function writes the count of struct, which will be required to store all alavaible data.
Note:
The funtion returns the maximum allowed data structures, determined by configSizeCount. All data which exceeds will be dropped.
To get the whole data we run the funtion a second time with the realloced configSizeCount in the size of [returnedCount] structures.
*/
int parseConfig(char *originalBuffer,struct configEntry **entry,int configSizeCount,int *returnedCount)
{
int state=ST_INIT;
int ret=0;
int i=0;
*returnedCount=0;
char *sectionName=NULL;
struct configEntry *ptr_entry = *entry;
char *keyName=NULL;
char *keyValue=NULL;
char *buffer=NULL;
buffer = malloc(strlen(originalBuffer)+1);
if(buffer == NULL)
{
int error = errno;
printf("ERROR MALLOC:%d",error);
return ERR_PARSECONFIG_UNKNOWN;
}
memset(buffer,0,strlen(originalBuffer)+1);
strcpy(buffer,originalBuffer);
//this step is necessary, because the strok function modifys the originalBuffer
//so we make a copy of it
strcpy(buffer,originalBuffer);
printf("buffer:%s\n--",buffer);
sectionName = malloc(MAX_LEN_SECTIONNAME);
memset(sectionName,0,MAX_LEN_SECTIONNAME);
//read buffer line by line
char *token;
token = strtok(buffer,"\n");
while(token != NULL && state != ST_FINISH)
{
switch(state)
{
case ST_INIT:
if((ret=checkSection(token,'[',']',&sectionName))==FOUND_SECTION)
{
state = ST_FOUND_SECTION;
printf("FOUND_SECTION:%s\n",sectionName);
}
break;
case ST_FOUND_SECTION:
keyName = malloc(MAX_LEN_SECTIONNAME);
keyValue = malloc(MAX_LEN_SECTIONNAME);
if(keyName == NULL || keyValue == NULL)
{
int error = errno;
printf("MALLOC:%d\n",error);
return error;
}
memset(keyName,0,MAX_LEN_SECTIONNAME);
memset(keyValue,0,MAX_LEN_SECTIONNAME);
ret=getNameValuePair(token,'=',0,&keyName,&keyValue,MAX_LEN_SECTIONNAME,MAX_LEN_SECTIONNAME);
if(ret==NO_ERROR)
{
printf("configSizeCount: %d, i:%d\n",configSizeCount,i);
if(i<configSizeCount)
{
ptr_entry[i].sectionName = strdup(sectionName);
ptr_entry[i].keyValue= strdup(keyValue);
ptr_entry[i].keyName = strdup(keyName);
}
i++;
*returnedCount = i;
state = ST_FOUND_SECTION;
}
else {
state = ST_SKIP_READ;
}
free(keyName);
free(keyValue);
break;
}
if(state != ST_SKIP_READ)
{
token = strtok(NULL,"\n");
}
else {
state = ST_INIT;
}
}
printf("token: %s\n",token);
printf("buffer:%s\n--",buffer);
free(sectionName);
free(buffer);
printf("finish exitting parsing\nSTATE:%d\n",state);
return NO_ERROR;
}