inih (INI Not Invented Here) เป็นตัวแยกวิเคราะห์ไฟล์ .INI ธรรมดาที่เขียนด้วยภาษาซี มีโค้ดเพียงไม่กี่หน้า และได้รับการออกแบบให้มี ขนาดเล็กและเรียบง่าย ดังนั้นจึงเหมาะสำหรับระบบฝังตัว นอกจากนี้ยังเข้ากันได้กับรูปแบบ ConfigParser ของไฟล์ .INI ของ Python ไม่มากก็น้อย รวมถึงไวยากรณ์หลายบรรทัดสไตล์ RFC 822 และรายการ name: value
หากต้องการใช้งาน เพียงให้ไฟล์ INI แก่ ini_parse()
จากนั้นมันจะโทรกลับสำหรับทุกคู่ name=value
ที่แยกวิเคราะห์ โดยให้สตริงสำหรับส่วน ชื่อ และค่า ที่ทำในลักษณะนี้ ("รูปแบบ SAX") เนื่องจากทำงานได้ดีบนระบบฝังตัวที่มีหน่วยความจำต่ำ แต่ยังเป็นเพราะทำให้มีการใช้งาน KISS อีกด้วย
คุณยังสามารถเรียก ini_parse_file()
เพื่อแยกวิเคราะห์โดยตรงจากออบเจ็กต์ FILE*
, ini_parse_string()
เพื่อแยกวิเคราะห์ข้อมูลจากสตริง หรือ ini_parse_stream()
เพื่อแยกวิเคราะห์โดยใช้ฟังก์ชันตัวอ่านสไตล์ fgets แบบกำหนดเองสำหรับ I/O แบบกำหนดเอง
ดาวน์โหลดรุ่น ค้นหาแหล่งที่มา หรืออ่านเกี่ยวกับวิธีใช้ inih ในรูปแบบ DRY ด้วย X-Macros
คุณสามารถควบคุมแง่มุมต่างๆ ของ inih ได้โดยใช้ตัวประมวลผลล่วงหน้ากำหนด:
-DINI_ALLOW_MULTILINE=0
-DINI_ALLOW_BOM=0
;
อักขระ. หากต้องการปิดใช้งาน ให้เพิ่ม -DINI_ALLOW_INLINE_COMMENTS=0
คุณยังสามารถระบุอักขระที่จะเริ่มต้นความคิดเห็นแบบอินไลน์โดยใช้ INI_INLINE_COMMENT_PREFIXES
;
และ #
เพื่อเริ่มความคิดเห็นที่ต้นบรรทัด คุณสามารถแทนที่สิ่งนี้ได้โดยเปลี่ยน INI_START_COMMENT_PREFIXES
=
หรือ :
ในบรรทัด) เป็นข้อผิดพลาด หากต้องการอนุญาตชื่อที่ไม่มีค่า ให้เพิ่ม -DINI_ALLOW_NO_VALUE=1
และ inih จะเรียกใช้ฟังก์ชันตัวจัดการของคุณโดยตั้งค่าเป็น NULL-DINI_STOP_ON_FIRST_ERROR=1
ini_handler
จะไม่ได้รับหมายเลขบรรทัดเป็นพารามิเตอร์ หากคุณต้องการสิ่งนั้น ให้เพิ่ม -DINI_HANDLER_LINENO=1
name=value
หากต้องการตรวจหาส่วนใหม่ (เช่น ไฟล์ INI มีหลายส่วนที่มีชื่อเดียวกัน) ให้เพิ่ม -DINI_CALL_HANDLER_ON_NEW_SECTION=1
จากนั้นฟังก์ชันตัวจัดการของคุณจะถูกเรียกทุกครั้งที่พบส่วนใหม่ โดยตั้ง section
เป็นชื่อส่วนใหม่ แต่ตั้ง name
และ value
เป็น NULLmalloc
แทน ให้ระบุ -DINI_USE_STACK=0
-DINI_MAX_LINE=1000
โปรดทราบว่า INI_MAX_LINE
จะต้องมากกว่าบรรทัดที่ยาวที่สุด 3 (เนื่องจาก r
, n
และ NUL)INI_INITIAL_ALLOC
ระบุขนาด malloc เริ่มต้นเมื่อใช้ฮีป มีค่าเริ่มต้นอยู่ที่ 200 ไบต์-DINI_USE_STACK=0
) inih จะจัดสรรบัฟเฟอร์ขนาดคงที่จำนวน INI_INITIAL_ALLOC
ไบต์ หากต้องการอนุญาตให้ขยายเป็น INI_MAX_LINE
ไบต์ หรือเพิ่มขึ้นเป็นสองเท่าหากจำเป็น ให้ตั้งค่า -DINI_ALLOW_REALLOC=1
malloc
, free
และ realloc
ของไลบรารีมาตรฐานจะถูกใช้ หากต้องการใช้ตัวจัดสรรที่กำหนดเอง ให้ระบุ -DINI_CUSTOM_ALLOCATOR=1
(และ -DINI_USE_STACK=0
) คุณต้องกำหนดและลิงก์ฟังก์ชันชื่อ ini_malloc
, ini_free
และ (หากตั้งค่า INI_ALLOW_REALLOC
) ini_realloc
ซึ่งต้องมีลายเซ็นเดียวกันกับฟังก์ชันการจัดสรรหน่วยความจำ stdlib.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../ini.h"
typedef struct
{
int version ;
const char * name ;
const char * email ;
} configuration ;
static int handler ( void * user , const char * section , const char * name ,
const char * value )
{
configuration * pconfig = ( configuration * ) user ;
#define MATCH ( s , n ) strcmp(section, s) == 0 && strcmp(name, n) == 0
if ( MATCH ( "protocol" , "version" )) {
pconfig -> version = atoi ( value );
} else if ( MATCH ( "user" , "name" )) {
pconfig -> name = strdup ( value );
} else if ( MATCH ( "user" , "email" )) {
pconfig -> email = strdup ( value );
} else {
return 0 ; /* unknown section/name, error */
}
return 1 ;
}
int main ( int argc , char * argv [])
{
configuration config ;
if ( ini_parse ( "test.ini" , handler , & config ) < 0 ) {
printf ( "Can't load 'test.ini'n" );
return 1 ;
}
printf ( "Config loaded from 'test.ini': version=%d, name=%s, email=%sn" ,
config . version , config . name , config . email );
return 0 ;
}
หากคุณใช้ C++ และ STL ก็ยังมีคลาส INIReader ที่ใช้งานง่ายซึ่งเก็บค่าไว้ใน map
และให้คุณ Get()
ค่าเหล่านั้น:
# include < iostream >
# include " INIReader.h "
int main ()
{
INIReader reader ( " ../examples/test.ini " );
if (reader. ParseError () < 0 ) {
std::cout << " Can't load 'test.ini' n " ;
return 1 ;
}
std::cout << " Config loaded from 'test.ini': version= "
<< reader. GetInteger ( " protocol " , " version " , - 1 ) << " , name= "
<< reader. Get ( " user " , " name " , " UNKNOWN " ) << " , email= "
<< reader. Get ( " user " , " email " , " UNKNOWN " ) << " , pi= "
<< reader. GetReal ( " user " , " pi " , - 1 ) << " , active= "
<< reader. GetBoolean ( " user " , " active " , true ) << " n " ;
return 0 ;
}
C ++ API แบบง่ายนี้ทำงานได้ดี แต่ก็ไม่ได้เต็มประสิทธิภาพมากนัก ฉันไม่ได้วางแผนที่จะทำงานกับ C++ API มากขึ้นในขณะนี้ ดังนั้นหากคุณต้องการประสิทธิภาพเพิ่มขึ้นอีกเล็กน้อย (เช่น ฟังก์ชัน GetSections()
และ GetFields()
) โปรดดูทางแยกเหล่านี้:
ความแตกต่างบางประการระหว่างโมดูลไลบรารีมาตรฐาน ConfigParser ของ inih และ Python:
_wfopen()
เพื่อเปิดไฟล์ จากนั้นจึง ini_parse_file()
เพื่อแยกวิเคราะห์ inih ไม่รวมการจัดการ wchar_t
หรือ Unicode meson.build
ไม่จำเป็นต้องใช้หรือคอมไพล์ inih จุดประสงค์หลักคือเพื่อการแจกแจง-Ddefault_library=static
static libraries ถูกสร้างขึ้น-Ddistro_install=false
ไลบรารี่ ส่วนหัวและไฟล์ pkg-config จะไม่ถูกติดตั้ง-Dwith_INIReader=false
คุณสามารถปิดการใช้งานการสร้างไลบรารี C++ ได้distro_install
ถูกตั้งค่าเป็น true
inih
และ INIReader
inih_dep
และ INIReader_dep
ได้ คุณอาจต้องการตั้งค่า default_library=static
และ distro_install=false
สำหรับโปรเจ็กต์ย่อย Wrap อย่างเป็นทางการมีให้ใน WrapDBversion : '<version_as_int>',
หลังแท็ก license
ในฟังก์ชัน project()
และ version : meson.project_version(),
หลังแท็ก soversion
ในฟังก์ชัน library()
ทั้งสอง inih
สามารถใช้งานได้ง่ายในโปรเจ็กต์ tipi.build เพียงเพิ่มรายการต่อไปนี้ใน .tipi/deps
ของคุณ (แทนที่ r56
ด้วยแท็กเวอร์ชันล่าสุด):
{
"benhoyt/inih" : { "@" : " r56 " }
}
เส้นทางรวมที่จำเป็นในโครงการของคุณคือ:
#include <ini.h>
คุณสามารถสร้างและติดตั้ง inih โดยใช้ตัวจัดการการพึ่งพา vcpkg:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih
พอร์ต inih ใน vcpkg ได้รับการปรับปรุงให้ทันสมัยอยู่เสมอโดยสมาชิกทีม Microsoft และผู้สนับสนุนชุมชน หากเวอร์ชันล้าสมัย โปรดสร้างปัญหาหรือดึงคำขอบนที่เก็บ vcpkg