嵌入式系统(embedded systems)-配置文件解析-开源库minIni

这篇具有很好参考价值的文章主要介绍了嵌入式系统(embedded systems)-配置文件解析-开源库minIni。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

minIni开源库的介绍

minIni是一个用于在嵌入式系统中读写“INI”文件的程序库。minIni占用很少的资源,具有确定的内存占用,并且可以为各种类型的文件I/O库配置。
gitee 链接:link
https://gitee.com/resetlove/minIni
github 链接:link
https://github.com/compuphase/minIni.git
minlni是一个可移植和可配置的库,用于读取和写入“。ini”文件。在大约950行注释的源代码中,minlni确实是一个“迷你”INI文件解析器,特别是考虑到它的特性。该库不需要标准C/ c++库中的文件I/O函数,而是允许你配置通过宏来配置文件I/O接口。
Minlni使用有限的堆栈空间,根本不使用动态内存。还支持标准INI文件的一些小变化,特别是minIni支持缺少节(sections)的INI文件。
minIni是一个库,用于读取和写入与“INI”文件兼容的格式的简单配置文件。minIni库的特点是代码占用空间小,它只需要很少的资源(例如RAM)。因此,它适合在(小型)嵌入式系统中使用。
可以使用冒号分隔键和值,冒号相当于等号。即"Name:Value"和"Name=Value"具有相同的含义。
允许尾随注释(即在一行的键/值对后面)。散列字符(“#”)是分号开始注释的另一种选择。
当写入包含注释字符(“;”或“#”)的值时,该值将自动放在双引号之间;读取值时,这些双引号会被移除。当双引号本身出现在设置中时,这些字符将被转义。
具体来说,minIni不缓存它从它们的INI文件中读取的任何键/值对。它也不会在调用之间保持INI文件打开;minIni在每次读或写操作后关闭文件。
当写入INI文件时,minIni创建一个临时文件,它将原始文件复制(修改)到该文件中。如果成功,它会删除原始文件并将临时文件重命名回来。如果必须更改多个设置,则每个设置重复此循环。
没有固有的文件锁定机制来防止多个应用程序(或线程或任务)访问相同的INI文件。如果INI文件在多个程序/线程/任务之间共享,请参阅多任务小节以获得提示和选项。
INI文件示例

[Network]
hostname = My Computer
address = dhcp
dns = 192.168.1.1

其中

“ DNS = 192.168.1.1 ”等价于 “ dns = 192.168.1.1 ”

代码:

// minGlue.h
/* map required file I/O types and functions to the standard C library */

#include <stdio.h>

#define INI_FILETYPE                    FILE*
#define ini_openread(filename,file)     ((*(file) = fopen((filename),"rb")) != NULL)
#define ini_openwrite(filename,file)    ((*(file) = fopen((filename),"wb")) != NULL)
#define ini_openrewrite(filename,file)  ((*(file) = fopen((filename),"r+b")) != NULL)
#define ini_close(file)                 (fclose(*(file)) == 0)
#define ini_read(buffer,size,file)      (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file)          (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest)         (rename((source), (dest)) == 0)
#define ini_remove(filename)            (remove(filename) == 0)
#define INI_FILEPOS                     long int
#define ini_tell(file,pos)              (*(pos) = ftell(*(file)))
#define ini_seek(file,pos)              (fseek(*(file), *(pos), SEEK_SET) == 0)
/* for floating-point support, define additional types and functions */
#define INI_REAL                        float
#define ini_ftoa(string,value)          sprintf((string),"%f",(value))
#define ini_atof(string)                (INI_REAL)strtod((string),NULL)
//minIni.h
#ifndef MININI_H
#define MININI_H
#include "minGlue.h"

#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
  #include <tchar.h>
  #define mTCHAR TCHAR
#else
  /* force TCHAR to be "char", but only for minIni */
  #define mTCHAR char
#endif

#if !defined INI_BUFFERSIZE
  #define INI_BUFFERSIZE  512
#endif

#if defined __cplusplus
  extern "C" {
#endif

int   ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
long  ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
int   ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int   ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int   ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int   ini_hassection(const mTCHAR *Section, const mTCHAR *Filename);
int   ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename);
#if defined INI_REAL
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
#endif

#if !defined INI_READONLY
int   ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
int   ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
#if defined INI_REAL
int   ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
#endif
#endif /* INI_READONLY */

#if !defined INI_NOBROWSE
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData);
int  ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename);
#endif /* INI_NOBROWSE */
#if defined __cplusplus
  }
#endif
#if defined __cplusplus
#if defined __WXWINDOWS__
	#include "wxMinIni.h"
#else
  #include <string>
  /* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */
  class minIni
  {
  public:
    minIni(const std::string& filename) : iniFilename(filename)
      { }
    bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const
      { return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; }
    long getl(const std::string& Section, const std::string& Key, long DefValue=0) const
      { return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
    int geti(const std::string& Section, const std::string& Key, int DefValue=0) const
      { return static_cast<int>(this->getl(Section, Key, long(DefValue))); }
    std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const
      {
        char buffer[INI_BUFFERSIZE];

        ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str());

        return buffer;

      }



    std::string getsection(int idx) const

      {

        char buffer[INI_BUFFERSIZE];

        ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());

        return buffer;

      }



    std::string getkey(const std::string& Section, int idx) const

      {

        char buffer[INI_BUFFERSIZE];

        ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());

        return buffer;

      }



    bool hassection(const std::string& Section) const

      { return ini_hassection(Section.c_str(), iniFilename.c_str()) != 0; }



    bool haskey(const std::string& Section, const std::string& Key) const

      { return ini_haskey(Section.c_str(), Key.c_str(), iniFilename.c_str()) != 0; }



#if defined INI_REAL

    INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const

      { return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }

#endif



#if ! defined INI_READONLY

    bool put(const std::string& Section, const std::string& Key, long Value)

      { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }



    bool put(const std::string& Section, const std::string& Key, int Value)

      { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }



    bool put(const std::string& Section, const std::string& Key, bool Value)

      { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }



    bool put(const std::string& Section, const std::string& Key, const std::string& Value)

      { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; }



    bool put(const std::string& Section, const std::string& Key, const char* Value)

      { return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }



#if defined INI_REAL

    bool put(const std::string& Section, const std::string& Key, INI_REAL Value)

      { return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }

#endif



    bool del(const std::string& Section, const std::string& Key)

      { return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; }



    bool del(const std::string& Section)

      { return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; }

#endif



#if !defined INI_NOBROWSE

    bool browse(INI_CALLBACK Callback, void *UserData) const

      { return ini_browse(Callback, UserData, iniFilename.c_str()) != 0; }

#endif



  private:

    std::string iniFilename;

  };
#endif /* __WXWINDOWS__ */
#endif /* __cplusplus */
#endif /* MININI_H */
//minIni.c
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY

# if !defined UNICODE   /* for Windows */

#   define UNICODE

# endif

# if !defined _UNICODE  /* for C library */

#   define _UNICODE

# endif

#endif



#define MININI_IMPLEMENTATION

#include "minIni.h"

#if defined NDEBUG

  #define assert(e)

#else

  #include <assert.h>

#endif



#if !defined __T || defined INI_ANSIONLY

  #include <ctype.h>

  #include <string.h>

  #include <stdlib.h>

  #define TCHAR     char

  #define __T(s)    s

  #define _tcscat   strcat

  #define _tcschr   strchr

  #define _tcscmp   strcmp

  #define _tcscpy   strcpy

  #define _tcsicmp  stricmp

  #define _tcslen   strlen

  #define _tcsncmp  strncmp

  #define _tcsnicmp strnicmp

  #define _tcsrchr  strrchr

  #define _tcstol   strtol

  #define _tcstod   strtod

  #define _totupper toupper

  #define _stprintf sprintf

  #define _tfgets   fgets

  #define _tfputs   fputs

  #define _tfopen   fopen

  #define _tremove  remove

  #define _trename  rename

#endif



#if defined __linux || defined __linux__

  #define __LINUX__

#elif defined FREEBSD && !defined __FreeBSD__

  #define __FreeBSD__

#elif defined(_MSC_VER)

  #pragma warning(disable: 4996)	/* for Microsoft Visual C/C++ */

#endif

#if !defined strnicmp && !defined PORTABLE_STRNICMP

  #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ || defined __NetBSD__ || defined __DragonFly__ || defined __GNUC__

    #define strnicmp  strncasecmp

  #endif

#endif

#if !defined _totupper

  #define _totupper toupper

#endif



#if !defined INI_LINETERM

  #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ || defined __NetBSD__ || defined __DragonFly__

    #define INI_LINETERM    __T("\n")

  #else

    #define INI_LINETERM    __T("\r\n")

  #endif

#endif

#if !defined INI_FILETYPE

  #error Missing definition for INI_FILETYPE.

#endif



#if !defined sizearray

  #define sizearray(a)    (sizeof(a) / sizeof((a)[0]))

#endif



enum quote_option {

  QUOTE_NONE,

  QUOTE_ENQUOTE,

  QUOTE_DEQUOTE,

};



#if defined PORTABLE_STRNICMP

int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n)

{

  while (n-- != 0 && (*s1 || *s2)) {

    register int c1, c2;

    c1 = *s1++;

    if ('a' <= c1 && c1 <= 'z')

      c1 += ('A' - 'a');

    c2 = *s2++;

    if ('a' <= c2 && c2 <= 'z')

      c2 += ('A' - 'a');

    if (c1 != c2)

      return c1 - c2;

  }

  return 0;

}

#endif /* PORTABLE_STRNICMP */



static TCHAR *skipleading(const TCHAR *str)

{

  assert(str != NULL);

  while ('\0' < *str && *str <= ' ')

    str++;

  return (TCHAR *)str;

}



static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base)

{

  assert(str != NULL);

  assert(base != NULL);

  while (str > base && '\0' < *(str-1) && *(str-1) <= ' ')

    str--;

  return (TCHAR *)str;

}



static TCHAR *striptrailing(TCHAR *str)

{

  TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str);

  assert(ptr != NULL);

  *ptr = '\0';

  return str;

}



static TCHAR *ini_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option)

{

  size_t d, s;



  assert(maxlen>0);

  assert(source != NULL && dest != NULL);

  assert((dest < source || (dest == source && option != QUOTE_ENQUOTE)) || dest > source + strlen(source));

  if (option == QUOTE_ENQUOTE && maxlen < 3)

    option = QUOTE_NONE;  /* cannot store two quotes and a terminating zero in less than 3 characters */



  switch (option) {

  case QUOTE_NONE:

    for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++)

      dest[d] = source[d];

    assert(d < maxlen);

    dest[d] = '\0';

    break;

  case QUOTE_ENQUOTE:

    d = 0;

    dest[d++] = '"';

    for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) {

      if (source[s] == '"') {

        if (d >= maxlen - 3)

          break;  /* no space to store the escape character plus the one that follows it */

        dest[d++] = '\\';

      }

      dest[d] = source[s];

    }

    dest[d++] = '"';

    dest[d] = '\0';

    break;

  case QUOTE_DEQUOTE:

    for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) {

      if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"')

        s++;

      dest[d] = source[s];

    }

    dest[d] = '\0';

    break;

  default:

    assert(0);

  }



  return dest;

}



static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes)

{

  int isstring;

  TCHAR *ep;



  assert(string != NULL);

  assert(quotes != NULL);



  /* Remove a trailing comment */

  isstring = 0;

  for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) {

    if (*ep == '"') {

      if (*(ep + 1) == '"')

        ep++;                 /* skip "" (both quotes) */

      else

        isstring = !isstring; /* single quote, toggle isstring */

    } else if (*ep == '\\' && *(ep + 1) == '"') {

      ep++;                   /* skip \" (both quotes */

    }

  }

  assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#'));

  *ep = '\0';                 /* terminate at a comment */

  striptrailing(string);

  /* Remove double quotes surrounding a value */

  *quotes = QUOTE_NONE;

  if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') {

    string++;

    *--ep = '\0';

    *quotes = QUOTE_DEQUOTE;  /* this is a string, so remove escaped characters */

  }

  return string;

}



static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key,

                        int idxSection, int idxKey, TCHAR *Buffer, int BufferSize,

                        INI_FILEPOS *mark)

{

  TCHAR *sp, *ep;

  int len, idx;

  enum quote_option quotes;

  TCHAR LocalBuffer[INI_BUFFERSIZE];



  assert(fp != NULL);

  /* Move through file 1 line at a time until a section is matched or EOF. If

   * parameter Section is NULL, only look at keys above the first section. If

   * idxSection is positive, copy the relevant section name.

   */

  len = (Section != NULL) ? (int)_tcslen(Section) : 0;

  if (len > 0 || idxSection >= 0) {

    assert(idxSection >= 0 || Section != NULL);

    idx = -1;

    do {

      do {

        if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp))

          return 0;

        sp = skipleading(LocalBuffer);

        ep = _tcsrchr(sp, ']');

      } while (*sp != '[' || ep == NULL);

      /* When arrived here, a section was found; now optionally skip leading and

       * trailing whitespace.

       */

      assert(sp != NULL && *sp == '[');

      sp = skipleading(sp + 1);

      assert(ep != NULL && *ep == ']');

      ep = skiptrailing(ep, sp);

    } while ((((int)(ep-sp) != len || Section == NULL || _tcsnicmp(sp, Section, len) != 0) && ++idx != idxSection));

    if (idxSection >= 0) {

      if (idx == idxSection) {

        assert(ep != NULL);

        *ep = '\0'; /* the end of the section name was found earlier */

        ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE);

        return 1;

      }

      return 0; /* no more section found */

    }

  }



  /* Now that the section has been found, find the entry.

   * Stop searching upon leaving the section's area.

   */

  assert(Key != NULL || idxKey >= 0);

  len = (Key != NULL) ? (int)_tcslen(Key) : 0;

  idx = -1;

  do {

    if (mark != NULL)

      ini_tell(fp, mark);   /* optionally keep the mark to the start of the line */

    if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[')

      return 0;

    sp = skipleading(LocalBuffer);

    ep = _tcschr(sp, '=');  /* Parse out the equal sign */

    if (ep == NULL)

      ep = _tcschr(sp, ':');

  } while (*sp == ';' || *sp == '#' || ep == NULL

           || ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey));

  if (idxKey >= 0) {

    if (idx == idxKey) {

      assert(ep != NULL);

      assert(*ep == '=' || *ep == ':');

      *ep = '\0';

      striptrailing(sp);

      ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE);

      return 1;

    }

    return 0;   /* no more key found (in this section) */

  }



  /* Copy up to BufferSize chars to buffer */

  assert(ep != NULL);

  assert(*ep == '=' || *ep == ':');

  sp = skipleading(ep + 1);

  sp = cleanstring(sp, &quotes);  /* Remove a trailing comment */

  ini_strncpy(Buffer, sp, BufferSize, quotes);

  return 1;

}



/** ini_gets()

 * \param Section     the name of the section to search for

 * \param Key         the name of the entry to find the value of

 * \param DefValue    default string in the event of a failed read

 * \param Buffer      a pointer to the buffer to copy into

 * \param BufferSize  the maximum number of characters to copy

 * \param Filename    the name and full path of the .ini file to read from

 *

 * \return            the number of characters copied into the supplied buffer

 */

int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue,

             TCHAR *Buffer, int BufferSize, const TCHAR *Filename)

{

  INI_FILETYPE fp;

  int ok = 0;



  if (Buffer == NULL || BufferSize <= 0 || Key == NULL)

    return 0;

  if (ini_openread(Filename, &fp)) {

    ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL);

    (void)ini_close(&fp);

  }

  if (!ok)

    ini_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE);

  return (int)_tcslen(Buffer);

}



/** ini_getl()

 * \param Section     the name of the section to search for

 * \param Key         the name of the entry to find the value of

 * \param DefValue    the default value in the event of a failed read

 * \param Filename    the name of the .ini file to read from

 *

 * \return            the value located at Key

 */

long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename)

{

  TCHAR LocalBuffer[64];

  int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);

  return (len == 0) ? DefValue

                    : ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16)

                                                                           : _tcstol(LocalBuffer, NULL, 10));

}



#if defined INI_REAL

/** ini_getf()

 * \param Section     the name of the section to search for

 * \param Key         the name of the entry to find the value of

 * \param DefValue    the default value in the event of a failed read

 * \param Filename    the name of the .ini file to read from

 *

 * \return            the value located at Key

 */

INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename)

{

  TCHAR LocalBuffer[64];

  int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);

  return (len == 0) ? DefValue : ini_atof(LocalBuffer);

}

#endif



/** ini_getbool()

 * \param Section     the name of the section to search for

 * \param Key         the name of the entry to find the value of

 * \param DefValue    default value in the event of a failed read; it should

 *                    zero (0) or one (1).

 * \param Filename    the name and full path of the .ini file to read from

 *

 * A true boolean is found if one of the following is matched:

 * - A string starting with 'y' or 'Y'

 * - A string starting with 't' or 'T'

 * - A string starting with '1'

 *

 * A false boolean is found if one of the following is matched:

 * - A string starting with 'n' or 'N'

 * - A string starting with 'f' or 'F'

 * - A string starting with '0'

 *

 * \return            the true/false flag as interpreted at Key

 */

int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename)

{

  TCHAR LocalBuffer[2] = __T("");

  int ret;



  ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);

  LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]);

  if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T')

    ret = 1;

  else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F')

    ret = 0;

  else

    ret = DefValue;



  return(ret);

}



/** ini_getsection()

 * \param idx         the zero-based sequence number of the section to return

 * \param Buffer      a pointer to the buffer to copy into

 * \param BufferSize  the maximum number of characters to copy

 * \param Filename    the name and full path of the .ini file to read from

 *

 * \return            the number of characters copied into the supplied buffer

 */

int  ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)

{

  INI_FILETYPE fp;

  int ok = 0;



  if (Buffer == NULL || BufferSize <= 0 || idx < 0)

    return 0;

  if (ini_openread(Filename, &fp)) {

    ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL);

    (void)ini_close(&fp);

  }

  if (!ok)

    *Buffer = '\0';

  return (int)_tcslen(Buffer);

}



/** ini_getkey()

 * \param Section     the name of the section to browse through, or NULL to

 *                    browse through the keys outside any section

 * \param idx         the zero-based sequence number of the key to return

 * \param Buffer      a pointer to the buffer to copy into

 * \param BufferSize  the maximum number of characters to copy

 * \param Filename    the name and full path of the .ini file to read from

 *

 * \return            the number of characters copied into the supplied buffer

 */

int  ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)

{

  INI_FILETYPE fp;

  int ok = 0;



  if (Buffer == NULL || BufferSize <= 0 || idx < 0)

    return 0;

  if (ini_openread(Filename, &fp)) {

    ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL);

    (void)ini_close(&fp);

  }

  if (!ok)

    *Buffer = '\0';

  return (int)_tcslen(Buffer);

}



/** ini_hassection()

 * \param Section     the name of the section to search for

 * \param Filename    the name of the .ini file to read from

 *

 * \return            1 if the section is found, 0 if not found

 */

int ini_hassection(const mTCHAR *Section, const mTCHAR *Filename)

{

  TCHAR LocalBuffer[32];  /* dummy buffer */

  INI_FILETYPE fp;

  int ok = 0;



  if (ini_openread(Filename, &fp)) {

    ok = getkeystring(&fp, Section, NULL, -1, 0, LocalBuffer, sizearray(LocalBuffer), NULL);

    (void)ini_close(&fp);

  }

  return ok;

}



/** ini_haskey()

 * \param Section     the name of the section to search for

 * \param Key         the name of the entry to find the value of

 * \param Filename    the name of the .ini file to read from

 *

 * \return            1 if the key is found, 0 if not found

 */

int ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename)

{

  TCHAR LocalBuffer[32];  /* dummy buffer */

  INI_FILETYPE fp;

  int ok = 0;



  if (ini_openread(Filename, &fp)) {

    ok = getkeystring(&fp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), NULL);

    (void)ini_close(&fp);

  }

  return ok;

}





#if !defined INI_NOBROWSE

/** ini_browse()

 * \param Callback    a pointer to a function that will be called for every

 *                    setting in the INI file.

 * \param UserData    arbitrary data, which the function passes on the

 *                    \c Callback function

 * \param Filename    the name and full path of the .ini file to read from

 *

 * \return            1 on success, 0 on failure (INI file not found)

 *

 * \note              The \c Callback function must return 1 to continue

 *                    browsing through the INI file, or 0 to stop. Even when the

 *                    callback stops the browsing, this function will return 1

 *                    (for success).

 */

int ini_browse(INI_CALLBACK Callback, void *UserData, const TCHAR *Filename)

{

  TCHAR LocalBuffer[INI_BUFFERSIZE];

  int lenSec, lenKey;

  enum quote_option quotes;

  INI_FILETYPE fp;



  if (Callback == NULL)

    return 0;

  if (!ini_openread(Filename, &fp))

    return 0;



  LocalBuffer[0] = '\0';   /* copy an empty section in the buffer */

  lenSec = (int)_tcslen(LocalBuffer) + 1;

  for ( ;; ) {

    TCHAR *sp, *ep;

    if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp))

      break;

    sp = skipleading(LocalBuffer + lenSec);

    /* ignore empty strings and comments */

    if (*sp == '\0' || *sp == ';' || *sp == '#')

      continue;

    /* see whether we reached a new section */

    ep = _tcsrchr(sp, ']');

    if (*sp == '[' && ep != NULL) {

      sp = skipleading(sp + 1);

      ep = skiptrailing(ep, sp);

      *ep = '\0';

      ini_strncpy(LocalBuffer, sp, INI_BUFFERSIZE, QUOTE_NONE);

      lenSec = (int)_tcslen(LocalBuffer) + 1;

      continue;

    }

    /* not a new section, test for a key/value pair */

    ep = _tcschr(sp, '=');    /* test for the equal sign or colon */

    if (ep == NULL)

      ep = _tcschr(sp, ':');

    if (ep == NULL)

      continue;               /* invalid line, ignore */

    *ep++ = '\0';             /* split the key from the value */

    striptrailing(sp);

    ini_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE);

    lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1;

    /* clean up the value */

    sp = skipleading(ep);

    sp = cleanstring(sp, &quotes);  /* Remove a trailing comment */

    ini_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes);

    /* call the callback */

    if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData))

      break;

  }



  (void)ini_close(&fp);

  return 1;

}

#endif /* INI_NOBROWSE */



#if ! defined INI_READONLY

static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength)

{

  TCHAR *p;



  ini_strncpy(dest, source, maxlength, QUOTE_NONE);

  p = _tcschr(dest, '\0');

  assert(p != NULL);

  *(p - 1) = '~';

}



static enum quote_option check_enquote(const TCHAR *Value)

{

  const TCHAR *p;



  /* run through the value, if it has trailing spaces, or '"', ';' or '#'

   * characters, enquote it

   */

  assert(Value != NULL);

  for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++)

    /* nothing */;

  return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE;

}



static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp)

{

  if (Section != NULL && _tcslen(Section) > 0) {

    TCHAR *p;

    LocalBuffer[0] = '[';

    ini_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE);  /* -1 for '[', -1 for ']', -2 for '\r\n' */

    p = _tcschr(LocalBuffer, '\0');

    assert(p != NULL);

    *p++ = ']';

    _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */

    if (fp != NULL)

      (void)ini_write(LocalBuffer, fp);

  }

}



static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp)

{

  TCHAR *p;

  enum quote_option option = check_enquote(Value);

  ini_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE);  /* -1 for '=', -2 for '\r\n' */

  p = _tcschr(LocalBuffer, '\0');

  assert(p != NULL);

  *p++ = '=';

  ini_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */

  p = _tcschr(LocalBuffer, '\0');

  assert(p != NULL);

  _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */

  if (fp != NULL)

    (void)ini_write(LocalBuffer, fp);

}



static int cache_accum(const TCHAR *string, int *size, int max)

{

  int len = (int)_tcslen(string);

  if (*size + len >= max)

    return 0;

  *size += len;

  return 1;

}



static int cache_flush(TCHAR *buffer, int *size,

                      INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark)

{

  int terminator_len = (int)_tcslen(INI_LINETERM);

  int pos = 0, pos_prev = -1;



  (void)ini_seek(rfp, mark);

  assert(buffer != NULL);

  buffer[0] = '\0';

  assert(size != NULL);

  assert(*size <= INI_BUFFERSIZE);

  while (pos < *size && pos != pos_prev) {

    pos_prev = pos;     /* to guard against zero bytes in the INI file */

    (void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp);

    while (pos < *size && buffer[pos] != '\0')

      pos++;            /* cannot use _tcslen() because buffer may not be zero-terminated */

  }

  if (buffer[0] != '\0') {

    assert(pos > 0 && pos <= INI_BUFFERSIZE);

    if (pos == INI_BUFFERSIZE)

      pos--;

    buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */

    (void)ini_write(buffer, wfp);

  }

  ini_tell(rfp, mark);  /* update mark */

  *size = 0;

  /* return whether the buffer ended with a line termination */

  return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0);

}



static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer)

{

  (void)ini_close(rfp);

  (void)ini_close(wfp);

  (void)ini_tempname(buffer, filename, INI_BUFFERSIZE);

  #if defined ini_remove || defined INI_REMOVE

    (void)ini_remove(filename);

  #endif

  (void)ini_rename(buffer, filename);

  return 1;

}



/** ini_puts()

 * \param Section     the name of the section to write the string in

 * \param Key         the name of the entry to write, or NULL to erase all keys in the section

 * \param Value       a pointer to the buffer the string, or NULL to erase the key

 * \param Filename    the name and full path of the .ini file to write to

 *

 * \return            1 if successful, otherwise 0

 */

int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename)

{

  INI_FILETYPE rfp;

  INI_FILETYPE wfp;

  INI_FILEPOS mark;

  INI_FILEPOS head, tail;

  TCHAR *sp, *ep;

  TCHAR LocalBuffer[INI_BUFFERSIZE];

  int len, match, flag, cachelen;



  assert(Filename != NULL);

  if (!ini_openread(Filename, &rfp)) {

    /* If the .ini file doesn't exist, make a new file */

    if (Key != NULL && Value != NULL) {

      if (!ini_openwrite(Filename, &wfp))

        return 0;

      writesection(LocalBuffer, Section, &wfp);

      writekey(LocalBuffer, Key, Value, &wfp);

      (void)ini_close(&wfp);

    }

    return 1;

  }



  /* If parameters Key and Value are valid (so this is not an "erase" request)

   * and the setting already exists, there are two short-cuts to avoid rewriting

   * the INI file.

   */

  if (Key != NULL && Value != NULL) {

    match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head);

    if (match) {

      /* if the current setting is identical to the one to write, there is

       * nothing to do.

       */

      if (_tcscmp(LocalBuffer,Value) == 0) {

        (void)ini_close(&rfp);

        return 1;

      }

      /* if the new setting has the same length as the current setting, and the

       * glue file permits file read/write access, we can modify in place.

       */

      #if defined ini_openrewrite || defined INI_OPENREWRITE

        /* we already have the start of the (raw) line, get the end too */

        ini_tell(&rfp, &tail);

        /* create new buffer (without writing it to file) */

        writekey(LocalBuffer, Key, Value, NULL);

        if (_tcslen(LocalBuffer) == (size_t)(tail - head)) {

          /* length matches, close the file & re-open for read/write, then

           * write at the correct position

           */

          (void)ini_close(&rfp);

          if (!ini_openrewrite(Filename, &wfp))

            return 0;

          (void)ini_seek(&wfp, &head);

          (void)ini_write(LocalBuffer, &wfp);

          (void)ini_close(&wfp);

          return 1;

        }

      #endif

    }

    /* key not found, or different value & length -> proceed */

  } else if (Key != NULL && Value == NULL) {

    /* Conversely, for a request to delete a setting; if that setting isn't

       present, just return */

    match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), NULL);

    if (!match) {

      (void)ini_close(&rfp);

      return 1;

    }

    /* key found -> proceed to delete it */

  }



  /* Get a temporary file name to copy to. Use the existing name, but with

   * the last character set to a '~'.

   */

  (void)ini_close(&rfp);

  ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE);

  if (!ini_openwrite(LocalBuffer, &wfp))

    return 0;

  /* In the case of (advisory) file locks, ini_openwrite() may have been blocked

   * on the open, and after the block is lifted, the original file may have been

   * renamed, which is why the original file was closed and is now reopened */

  if (!ini_openread(Filename, &rfp)) {

    /* If the .ini file doesn't exist any more, make a new file */

    assert(Key != NULL && Value != NULL);

    writesection(LocalBuffer, Section, &wfp);

    writekey(LocalBuffer, Key, Value, &wfp);

    (void)ini_close(&wfp);

    return 1;

  }



  (void)ini_tell(&rfp, &mark);

  cachelen = 0;



  /* Move through the file one line at a time until a section is

   * matched or until EOF. Copy to temp file as it is read.

   */

  len = (Section != NULL) ? (int)_tcslen(Section) : 0;

  if (len > 0) {

    do {

      if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {

        /* Failed to find section, so add one to the end */

        flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

        if (Key!=NULL && Value!=NULL) {

          if (!flag)

            (void)ini_write(INI_LINETERM, &wfp);  /* force a new line behind the last line of the INI file */

          writesection(LocalBuffer, Section, &wfp);

          writekey(LocalBuffer, Key, Value, &wfp);

        }

        return close_rename(&rfp, &wfp, Filename, LocalBuffer);  /* clean up and rename */

      }

      /* Check whether this line is a section */

      sp = skipleading(LocalBuffer);

      ep = _tcsrchr(sp, ']');

      match = (*sp == '[' && ep != NULL);

      if (match) {

        /* A section was found, skip leading and trailing whitespace */

        assert(sp != NULL && *sp == '[');

        sp = skipleading(sp + 1);

        assert(ep != NULL && *ep == ']');

        ep = skiptrailing(ep, sp);

        match = ((int)(ep-sp) == len && _tcsnicmp(sp, Section, len) == 0);

      }

      /* Copy the line from source to dest, but not if this is the section that

       * we are looking for and this section must be removed

       */

      if (!match || Key != NULL) {

        if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {

          cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

          (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);

          cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);

        }

      }

    } while (!match);

  }

  cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

  /* when deleting a section, the section head that was just found has not been

   * copied to the output file, but because this line was not "accumulated" in

   * the cache, the position in the input file was reset to the point just

   * before the section; this must now be skipped (again)

   */

  if (Key == NULL) {

    (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);

    (void)ini_tell(&rfp, &mark);

  }



  /* Now that the section has been found, find the entry. Stop searching

   * upon leaving the section's area. Copy the file as it is read

   * and create an entry if one is not found.

   */

  len = (Key != NULL) ? (int)_tcslen(Key) : 0;

  for( ;; ) {

    if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {

      /* EOF without an entry so make one */

      flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

      if (Key!=NULL && Value!=NULL) {

        if (!flag)

          (void)ini_write(INI_LINETERM, &wfp);  /* force a new line behind the last line of the INI file */

        writekey(LocalBuffer, Key, Value, &wfp);

      }

      return close_rename(&rfp, &wfp, Filename, LocalBuffer);  /* clean up and rename */

    }

    sp = skipleading(LocalBuffer);

    ep = _tcschr(sp, '='); /* Parse out the equal sign */

    if (ep == NULL)

      ep = _tcschr(sp, ':');

    match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0);

    if ((Key != NULL && match) || *sp == '[')

      break;  /* found the key, or found a new section */

    /* copy other keys in the section */

    if (Key == NULL) {

      (void)ini_tell(&rfp, &mark);  /* we are deleting the entire section, so update the read position */

    } else {

      if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {

        cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

        (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);

        cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);

      }

    }

  }

  /* the key was found, or we just dropped on the next section (meaning that it

   * wasn't found); in both cases we need to write the key, but in the latter

   * case, we also need to write the line starting the new section after writing

   * the key

   */

  flag = (*sp == '[');

  cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

  if (Key != NULL && Value != NULL)

    writekey(LocalBuffer, Key, Value, &wfp);

  /* cache_flush() reset the "read pointer" to the start of the line with the

   * previous key or the new section; read it again (because writekey() destroyed

   * the buffer)

   */

  (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);

  if (flag) {

    /* the new section heading needs to be copied to the output file */

    cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);

  } else {

    /* forget the old key line */

    (void)ini_tell(&rfp, &mark);

  }

  /* Copy the rest of the INI file */

  while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {

    if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {

      cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

      (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);

      cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);

    }

  }

  cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);

  return close_rename(&rfp, &wfp, Filename, LocalBuffer);  /* clean up and rename */

}



/* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */

#define ABS(v)  ((v) < 0 ? -(v) : (v))



static void strreverse(TCHAR *str)

{

  int i, j;

  for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) {

    TCHAR t = str[i];

    str[i] = str[j];

    str[j] = t;

  }

}



static void long2str(long value, TCHAR *str)

{

  int i = 0;

  long sign = value;



  /* generate digits in reverse order */

  do {

    int n = (int)(value % 10);          /* get next lowest digit */

    str[i++] = (TCHAR)(ABS(n) + '0');   /* handle case of negative digit */

  } while (value /= 10);                /* delete the lowest digit */

  if (sign < 0)

    str[i++] = '-';

  str[i] = '\0';



  strreverse(str);

}



/** ini_putl()

 * \param Section     the name of the section to write the value in

 * \param Key         the name of the entry to write

 * \param Value       the value to write

 * \param Filename    the name and full path of the .ini file to write to

 *

 * \return            1 if successful, otherwise 0

 */

int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename)

{

  TCHAR LocalBuffer[32];

  long2str(Value, LocalBuffer);

  return ini_puts(Section, Key, LocalBuffer, Filename);

}



#if defined INI_REAL

/** ini_putf()

 * \param Section     the name of the section to write the value in

 * \param Key         the name of the entry to write

 * \param Value       the value to write

 * \param Filename    the name and full path of the .ini file to write to

 *

 * \return            1 if successful, otherwise 0

 */

int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename)

{

  TCHAR LocalBuffer[64];

  ini_ftoa(LocalBuffer, Value);

  return ini_puts(Section, Key, LocalBuffer, Filename);

}

#endif /* INI_REAL */

#endif /* !INI_READONLY */

主要API

读取参数
嵌入式系统(embedded systems)-配置文件解析-开源库minIni,开源
写入参数
嵌入式系统(embedded systems)-配置文件解析-开源库minIni,开源

默认初始配置文件

//test.ini
[First]

String=noot # trailing commment

Val=1



[Second]

Val = 2

#comment=3

String = mies

name=haha

age:18

测试代码

#include <assert.h>

#include <stdio.h>

#include <string.h>

#include "minIni.h"



#define sizearray(a)  (sizeof(a) / sizeof((a)[0]))



const char inifile[] = "test.ini";



int Callback(const char *section, const char *key, const char *value, void *userdata)

{

  (void)userdata; /* this parameter is not used in this example */

  printf("    [%s]\t%s=%s\n", section, key, value);

  return 1;

}



int main(void)

{

  char str[100];

  long n;

  int s, k;

  char section[50];



  /* string reading */

  n = ini_gets("first", "string", "dummy", str, sizearray(str), inifile);

  assert(n==4 && strcmp(str,"noot")==0);

  n = ini_gets("second", "string", "dummy", str, sizearray(str), inifile);

  assert(n==4 && strcmp(str,"mies")==0);

  n = ini_gets("first", "undefined", "dummy", str, sizearray(str), inifile);

  assert(n==5 && strcmp(str,"dummy")==0);



    n = ini_gets("second", "name", "dummy", str, sizearray(str), inifile);

  assert(n==4 && strcmp(str,"haha")==0);

  /* ----- */



  /* value reading */

  n = ini_getl("first", "val", -1, inifile);

  assert(n==1);

  n = ini_getl("second", "val", -1, inifile);

  assert(n==2);

  n = ini_getl("first", "undefined", -1, inifile);

  assert(n==-1);



    n = ini_getl("second", "age", -1, inifile);

  assert(n==18);



  /* string writing */

  n = ini_puts("first", "alt", "flagged as \"correct\"", inifile);

  assert(n==1);

  n = ini_gets("first", "alt", "dummy", str, sizearray(str), inifile);

  assert(n==20 && strcmp(str,"flagged as \"correct\"")==0);

  

  /* ----- */

  n = ini_puts("third", "test", "correct", inifile);

  assert(n==1);

  n = ini_gets("third", "test", "dummy", str, sizearray(str), inifile);

  assert(n==7 && strcmp(str,"correct")==0);

  /* ----- */

  n = ini_puts("second", "alt", "overwrite", inifile);

  assert(n==1);

  n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);

  assert(n==9 && strcmp(str,"overwrite")==0);

  /* ----- */

  n = ini_puts("second", "alt", "123456789", inifile);

  assert(n==1);

  n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);

  assert(n==9 && strcmp(str,"123456789")==0);

  /* ----- */

    /* ----- */

  n = ini_putl("second", "age", 20, inifile);

  assert(n==1);

  n = ini_getl("second", "age", -1, inifile);

  assert(n==20);

  /* ----- */





  /* section/key enumeration */

  printf("4. Section/key enumeration, file structure follows\n");

  for (s = 0; ini_getsection(s, section, sizearray(section), inifile) > 0; s++) {

    printf("    [%s]\n", section);

    for (k = 0; ini_getkey(section, k, str, sizearray(str), inifile) > 0; k++) {

      printf("\t%s\n", str);

    } /* for */

  } /* for */



  /* section/key presence check */

  assert(ini_hassection("first", inifile));

  assert(!ini_hassection("fourth", inifile));

  assert(ini_haskey("first", "val", inifile));

  assert(!ini_haskey("first", "test", inifile));

  printf("5. checking presence of sections and keys passed\n");



  /* browsing through the file */

  printf("6. browse through all settings, file field list follows\n");

  ini_browse(Callback, NULL, inifile);





  /* string deletion */

  n = ini_puts("first", "alt", NULL, inifile);

  assert(n==1);

  n = ini_puts("second", "alt", NULL, inifile);

  assert(n==1);

//   n = ini_puts("third", NULL, NULL, inifile);

//   assert(n==1);

  /* ----- */



  return 0;

}

测试结果

嵌入式系统(embedded systems)-配置文件解析-开源库minIni,开源

运行后的配置文件

[First]

String=noot # trailing commment

Val=1



[Second]

Val = 2

#comment=3

String = mies

name=haha

age=20

[third]

test=correct


欢迎关注公众号:嵌入式学习与实践文章来源地址https://www.toymoban.com/news/detail-767835.html

到了这里,关于嵌入式系统(embedded systems)-配置文件解析-开源库minIni的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Git基础教程:配置.gitignore文件以忽略指定的文件和文件夹(嵌入式)

    Git基础教程:配置.gitignore文件以忽略指定的文件和文件夹(嵌入式) 在进行Git版本控制时,经常需要忽略某些文件或文件夹,以避免将它们包含在版本控制中。这在嵌入式系统开发中尤其重要,因为项目中可能包含大量生成的文件、临时文件和编译输出等,这些文件不应该

    2024年02月08日
    浏览(41)
  • 嵌入式Linux系统OpenWRT路由的基本配置

    OpenWRT是一个嵌入式Linux系统,想要了解嵌入式Linux系统的朋友有福了,今天小编要给大家介绍下OpenWRT路由的基本配置,一起来学习下吧。 chnroutes 路由表 这个路由表集中了所有分配到中国大陆的 IP 段,根据 http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest 每天自动更新,可使得

    2024年02月07日
    浏览(47)
  • 已解决org.springframework.boot.context.embedded.EmbeddedServletContainerException嵌入式Servlet容器异常的正确解决方法

    已解决org.springframework.boot.context.embedded.EmbeddedServletContainerException嵌入式Servlet容器异常的正确解决方法,亲测有效!!! 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 总结 Spring Boot应用程序通过自动配置和简化部署流程,使得开发现代Java Web应用变得更加快捷。

    2024年03月14日
    浏览(39)
  • 修改嵌入式 ARM Linux 内核映像中的文件系统

    zImage 是编译内核后在 arch/arm/boot 目录下生成的一个已经压缩过的内核映像。通常我们不会使用编译生成的原始内核映像 vmlinux ,因其体积很大。因此, zImage 是我们最常见的内核二进制,可以直接嵌入到固件,也可以直接使用 qemu 进行调试。当然,在 32 位嵌入式领域还能见到

    2024年02月10日
    浏览(67)
  • 《嵌入式系统开发实践》实践一 Linux 文件I/O操作

    一、 实验目的 掌握函数stat中文件属性的应用; 掌握系统函数system、opendir等的使用; 掌握struct dirent的结构体变量的使用方法; 掌握文件属性的判断; 掌握系统函数open、read、write、close的使用方法。 掌握设备操作的系统函数使用方法。 二、 实验任务与要求 测试文件S_IRU

    2023年04月14日
    浏览(34)
  • 【ChatGPT】从零开始构建基于ChatGPT的嵌入式(Embedding) 本地(Local) 智能客服问答机器人模型

      目录 方案流程 1. Embeddings 介绍 术语:微调 vs 嵌入

    2024年02月10日
    浏览(42)
  • 在嵌入式Linux中使用C++读取 /proc/meminfo 文件来获取系统内存大小

    在嵌入式Linux中,可以使用C++编程语言通过读取  /proc/meminfo  文件来获取系统内存大小。以下是一个示例代码片段: 上述代码打开  /proc/meminfo  文件并逐行读取其中的内容。当找到以 \\\"MemTotal:\\\" 开头的行时,提取出内存大小信息并去除空格和单位(KB),然后将其转换为无符

    2024年02月10日
    浏览(32)
  • 嵌入式系统>嵌入式硬件知识

    AI芯片的特点包括 :新型计算范式AI芯片的关键特征: 1、新型的计算范式 AI 计算既不脱离传统计算,也具有新的计算特质,如处理的内容往往是非结构化数据(视频、图片等)。处理的过程通常需要很大的计算量,基本的计算主要是线性代数运算,而控制流程则相对简单。

    2024年02月08日
    浏览(41)
  • 嵌入式操作系统(嵌入式学习)

    嵌入式操作系统是一种专门设计和优化用于嵌入式系统的操作系统。它是在资源受限的嵌入式设备上运行的操作系统,如微控制器、嵌入式处理器和系统芯片等。 嵌入式操作系统的主要目标是提供对硬件资源的有效管理和对应用程序的调度,以实现系统的可靠性、实时性和效

    2024年02月10日
    浏览(42)
  • 软考-嵌入式系统设计师:[嵌入式系统基础:笔记(一)]

    大家不要只收藏不关注呀,哪怕只是点个赞也可以呀!🤣 粉丝私信发邮箱,免费发你PDF!!! 因为准备备考中级嵌入式设计师证书,所以买了一些资料回来准备复习,本书为倪奕文老师编制的书,如果大家有时间和精力还是很建议大家去买一本的,这本书反而是能够让小白很快

    2023年04月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包