Last active
September 28, 2023 22:38
-
-
Save ssleert/c80c42dae753ad492778f0d818c54f41 to your computer and use it in GitHub Desktop.
Super simple stack-only ini parser for embedded systems in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ini.h" | |
#include <assert.h> | |
#include <string.h> | |
// return pointer to truncated string | |
static inline char* StrTruncate(char s[]) { | |
if (s[0] == '\0') { | |
return s; | |
} | |
char* Str = s; | |
for (; | |
*Str == ' '; | |
++Str | |
); | |
char* StrEnd = Str + strlen(Str) - 1; | |
for (; | |
*StrEnd == ' ' && StrEnd > Str; | |
--StrEnd | |
); | |
StrEnd[1] = '\0'; | |
return Str; | |
} | |
int32_t IniLoad(FILE* Stream, IniCallBack* Func) { | |
assert(Stream != NULL && "file stream is NULL"); | |
assert(Func != NULL && "callback func is NULL"); | |
char Section[__INI_H_BUFSIZE + 1]; size_t SectionIdx = 0; | |
char Key[__INI_H_BUFSIZE + 1]; size_t KeyIdx = 0; | |
char Value[__INI_H_BUFSIZE + 1]; size_t ValueIdx = 0; | |
INI_LEXEME Lexeme = INI_LEXEME_Key; | |
INI_LEXEME PrevLexeme = Lexeme; | |
size_t CallBackCount = 0; | |
while (!feof(Stream)) { | |
char ch = fgetc(Stream); | |
switch (ch) { | |
case '#': case ';': | |
PrevLexeme = Lexeme; | |
Lexeme = INI_LEXEME_Comment; | |
continue; | |
case '[': | |
Lexeme = INI_LEXEME_Section; | |
SectionIdx = 0; | |
*Section = '\0'; | |
continue; | |
case ']': | |
Lexeme = INI_LEXEME_Key; | |
Section[SectionIdx] = '\0'; | |
continue; | |
case '=': | |
if (Lexeme == INI_LEXEME_Value) { | |
goto ValueHandle; | |
} | |
Lexeme = INI_LEXEME_Value; | |
Key[KeyIdx] = '\0'; | |
KeyIdx = 0; | |
continue; | |
case '\n': | |
Value[ValueIdx] = '\0'; | |
if (Lexeme == INI_LEXEME_Value | |
|| (Lexeme == INI_LEXEME_Comment | |
&& PrevLexeme == INI_LEXEME_Value) | |
) { | |
size_t CallBackResult = Func( | |
StrTruncate(Section), | |
StrTruncate(Key), | |
StrTruncate(Value) | |
); | |
if (CallBackResult != 0) { | |
return CallBackResult; | |
} | |
CallBackCount++; | |
} | |
Lexeme = INI_LEXEME_Key; | |
KeyIdx = 0; | |
ValueIdx = 0; | |
continue; | |
default: | |
ValueHandle: | |
switch (Lexeme) { | |
case INI_LEXEME_Section: | |
if (SectionIdx == __INI_H_BUFSIZE) { | |
continue; | |
} | |
Section[SectionIdx] = ch; | |
SectionIdx++; | |
continue; | |
case INI_LEXEME_Key: | |
if (KeyIdx == __INI_H_BUFSIZE) { | |
continue; | |
} | |
Key[KeyIdx] = ch; | |
KeyIdx++; | |
continue; | |
case INI_LEXEME_Value: | |
if (ValueIdx == __INI_H_BUFSIZE) { | |
continue; | |
} | |
Value[ValueIdx] = ch; | |
ValueIdx++; | |
continue; | |
default: continue; | |
} | |
} | |
} | |
// ini file is incorrect | |
if (CallBackCount < 1) { | |
return 1; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Super simple stack-only ini parser | |
// for embedded systems in C | |
// 2023 Simon Ryabinkov <smnrbkv@proton.me> | |
#ifndef __INI_H__ | |
#define __INI_H__ | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#define __INI_H_BUFSIZE 4096 | |
// func that was called on all values in .ini file | |
typedef int32_t (IniCallBack)( | |
const char Section[], | |
const char Key[], | |
const char Val[] | |
); | |
typedef enum { | |
INI_LEXEME_Section = 1, | |
INI_LEXEME_Key, | |
INI_LEXEME_Value, | |
INI_LEXEME_Comment | |
} INI_LEXEME; | |
#define INI_LEXEME_LEN 4 | |
static inline bool IniCheckValue( | |
const char Section[], const char Key[], | |
const char NeededSection[], const char NeededKey[] | |
) { | |
return ( | |
strcmp(Section, NeededSection) == 0 && | |
strcmp(Key, NeededKey) == 0 | |
); | |
} | |
// Stream - opened file stream | |
// Func - return non-zero to stop, error is passed back through function | |
// return - 0 on success | |
int32_t IniLoad(FILE* Stream, IniCallBack* Func); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment