int strcasecmp(const char *s1, const char *s2);
#define strcmpi(a,b) strcasecmp(a,b)

typedef struct IniString
{
    /* private */
    char *buffer;
} IniString;

#define IniString_init(i) ((i)->buffer = NULL)

IniString *IniString_append(IniString *this, char ch);

#define IniString_c_str(i) ((i)->buffer ? (i)->buffer : "")

#define IniString_destroy(i) free((i)->buffer)

void IniString_copy(IniString *dst, const IniString *src);

bool IniString_is_null(const IniString *);


typedef struct IniStringList
{
    /* private */
    IniString *list;
    int count;
} IniStringList;

#define IniStringList_init(l) ((l)->list = NULL, (l)->count = 0)

void IniStringList_destroy(IniStringList *);

void IniStringList_Erase(IniStringList *);

#define IniStringList_length(l) ((l)->count)

typedef struct IniRecord
{
  /* public */
  char flags;
  IniString key;
  IniStringList values;
  struct IniRecord *next;
} IniRecord;

typedef struct IniSection
{
    /* private */
    IniRecord *lastrecord;
    /* public */
    IniString section;
    struct IniSection *next;
    IniRecord *record;
} IniSection;

bool IniSection_ReadIniFile(IniSection *this, const char *Filename, const char *Section, long offset);

void IniSection_init(IniSection *this);
void IniSection_destroy(IniSection *this);

bool IniSection_WriteIniFile(IniSection *this, const char *filename);

IniStringList *IniSection_getkey(IniSection *this, const char *Section, const char *Key, const char *DefValue, bool AutoAdd);

IniRecord *IniSection_setrecord(IniSection *this, const char *Section, const char *Key, const char *Value);

IniRecord *IniSection_findfirst(const IniSection *this, const char *Section, const char *Key);
