minIni - a minimal INI file parser

2020-08-11 14:47:29

minIni-最小的INI檔案解析器

 

minIni是一個程式設計師的庫,用於在嵌入式系統中讀取和寫入「 INI」檔案。minIni佔用很少的資源,具有確定的記憶體佔用空間,並且可以針對各種檔案I / O庫進行設定。minIni提供了用於從INI檔案中讀取,寫入和刪除金鑰的功能,全部功能都用830行C 語言的(註釋)原始碼(1.2版)(該程式碼也用C ++編譯,並帶有包裝器類)。

minIni的主要用途是在執行RTOS(甚至沒有任何操作系統)的嵌入式系統上使用。minIni要求這樣的系統提供一種儲存和檔案I / O系統,但是不需要此檔案I / O系統與標準C / C ++庫相容-實際上,標準庫也經常與之相容。嵌入式系統的龐大資源需求。

如果您想瞭解有關minIni的更多資訊,請參見原始碼存檔中的手冊。

下載和許可

minIni庫是根據Apache許可證2.0版分發的 ,外加一個例外條款,以明確允許將該庫靜態鏈接到商業應用程式。

INI檔案語法

INI檔案具有簡單的語法,在純文字檔案中具有名稱/值對。名稱必須唯一(每節),並且值必須在一行中。INI檔案通常分爲幾部分-在minIni中,這是可選的。節是方括號之間的名稱,[Network]例如下面 下麪的範例中的「 」。

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

在API和本文件中,設定的「名稱」表示爲設定的 。鍵和值之間用等號(「 =」)分隔。minIni支援使用冒號(「 :」)替代鍵/值定界符的等號。

值或鍵名周圍的前導空格被刪除。如果需要在值中包含前導和/或尾隨空格,請將值放在雙引號之間。該ini_gets()函數(來自minIni庫,請參見minIni手冊)從返回值中去除雙引號。ini_puts()如果要寫入的值包含尾隨空格(或特殊字元),則函數 將雙引號引起來。

minIni會忽略定界符「 =」或「 :」 周圍的空格,但不會忽略節名稱中括號之間的空格。換句話說,最好不要在節名稱[的左括號「 ]」 後面或右括號「 」 之前放置空格。

INI中的註釋必須以分號(「;」)或井號(「#」)開頭,並一直到行尾。註釋可以是一行,也可以是鍵/值對(「#」字元和尾隨註釋是minIni的擴充套件名)。

INI檔案讀取範例

有兩種方法可以從INI檔案中讀取設定。一種方法是呼叫一個函數,例如GetProfileString()針對所需的每個部分和鍵。如果有一個大的INI檔案,這特別方便,但是您隨時都需要從該檔案中進行一些設定,尤其是在程式執行時INI檔案也可以更改的情況下。這是Microsoft Windows API使用的方法。

但是,當您需要連續從INI檔案中檢索很多設定時,尤其是如果INI檔案未快取在記憶體中(在minIni中不是),上述過程效率很低。從INI檔案中獲取設定的另一種方法是呼叫「解析」函數,然後讓該函數使用部分和鍵名以及相關數據來呼叫應用程式。XML解析庫通常使用這種方法。參見例如 Expat庫

minIni支援兩種方法。要讀取單個設定,請使用功能 ini_gets()。對於回撥方法,實現一個回撥並呼叫 ini_browse()。有關詳細資訊,請參見minIni手冊。

使minIni適應檔案系統

必須藉助所謂的「膠水檔案」爲平臺設定minIni庫。此粘合檔案包含宏(可能還有函數),這些宏將minIni庫使用的檔案讀寫功能對映到操作系統提供的功能。膠合檔案必須稱爲「 minGlue.h」。

首先,minIni發行版附帶以下範例粘合檔案:

多工

minIni庫沒有任何全域性變數,並且不使用任何動態分配的記憶體。但是,該庫不應被認爲是「執行緒安全的」或可重入的,因爲它隱式使用了一種特殊的共用資源:檔案系統。

從INI檔案讀取多個任務不會造成問題。但是,當一個任務正在寫入INI檔案時,沒有其他任務可以存取該INI檔案-既不讀取也不寫入。在實現中,序列化INI檔案的所有存取可能會更容易。

在多工環境中保護資源免受併發存取的第一個建議是避免在任務之間共用資源。如果僅單個任務使用資源,則不需要號志保護,也不會發生優先順序倒置或死鎖問題。此建議也適用於minIni庫。如果可能,將單個任務設爲INI檔案的「所有者」,併爲其他任務建立用戶端/伺服器體系結構以查詢和調整設定。

如果必須在任務之間共用INI檔案(並且至少有一個任務寫入了INI檔案),則需要圍繞minIni庫的函數編寫包裝程式,這些函數在互斥量或二進制號志上阻塞。
 

test.ini

[First]
String=noot # trailing commment
Val=1

[Second]
Val = 2
#comment=3
String = mies
/* Simple test program
 *
 *  gcc -o test test.c minIni.c
 */
#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";
const char inifile2[] = "testplain.ini";

int Callback(const char *section, const char *key, const char *value, const 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("", "string", "dummy", str, sizearray(str), inifile2);
  assert(n==4 && strcmp(str,"noot")==0);
  n = ini_gets(NULL, "string", "dummy", str, sizearray(str), inifile2);
  assert(n==4 && strcmp(str,"noot")==0);
  /* ----- */
  printf("1. String reading tests passed\n");

  /* 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(NULL, "val", -1, inifile2);
  assert(n==1);
  /* ----- */
  printf("2. Value reading tests passed\n");

  /* 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("second", "alt", "correct", inifile);
  assert(n==1);
  n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);
  assert(n==7 && strcmp(str,"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(NULL, "alt", "correct", inifile2);
  assert(n==1);
  n = ini_gets(NULL, "alt", "dummy", str, sizearray(str), inifile2);
  assert(n==7 && strcmp(str,"correct")==0);
  /* ----- */
  printf("3. String writing tests passed\n");

  /* section/key enumeration */
  printf("4. Section/key enumertion, file contents 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 */

  /* browsing through the file */
  printf("5. browse through all settings, file contents 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);
  /* ----- */
  n = ini_puts(NULL, "alt", NULL, inifile2);
  assert(n==1);
  printf("6. String deletion tests passed\n");

  return 0;
}