inih (INI Not Invented Here) هو محلل بسيط لملفات .INI مكتوب بلغة C. وهو عبارة عن صفحتين فقط من التعليمات البرمجية، وقد تم تصميمه ليكون صغيرًا وبسيطًا ، لذا فهو جيد للأنظمة المدمجة. كما أنه متوافق بشكل أو بآخر مع نمط Python ConfigParser لملفات .INI، بما في ذلك بناء الجملة متعدد الأسطر بنمط RFC 822 name: value
.
لاستخدامه، ما عليك سوى إعطاء ini_parse()
ملف INI، وسيقوم باستدعاء رد اتصال لكل زوج name=value
الذي تم تحليله، مما يمنحك سلاسل للقسم والاسم والقيمة. يتم ذلك بهذه الطريقة ("نمط SAX") لأنه يعمل بشكل جيد على الأنظمة المدمجة ذات الذاكرة المنخفضة، ولكن أيضًا لأنه يعمل على تنفيذ KISS.
يمكنك أيضًا استدعاء ini_parse_file()
للتحليل مباشرة من كائن FILE*
، أو ini_parse_string()
لتحليل البيانات من سلسلة، أو ini_parse_stream()
للتحليل باستخدام وظيفة قارئ مخصصة على نمط fgets للإدخال/الإخراج المخصص.
قم بتنزيل إصدار أو تصفح المصدر أو اقرأ عن كيفية استخدام 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
على NULL.malloc
بدلاً من ذلك، حدد -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++ البسيطة هذه بشكل جيد، ولكنها ليست مكتملة تمامًا. لا أخطط للعمل أكثر على واجهة برمجة تطبيقات C++ في الوقت الحالي، لذلك إذا كنت تريد المزيد من القوة (على سبيل المثال وظائف GetSections()
و GetFields()
)، راجع هذه التشعبات:
بعض الاختلافات بين وحدة المكتبة القياسية inih وPython ConfigParser:
_wfopen()
لفتح ملف ثم ini_parse_file()
لتحليله؛ inih لا يتضمن معالجة wchar_t
أو Unicode. meson.build
غير مطلوب لاستخدام inih أو تجميعه، والغرض الرئيسي منه هو التوزيعات.-Ddefault_library=static
.-Ddistro_install=false
، لن يتم تثبيت الرؤوس وملفات pkg-config.-Dwith_INIReader=false
يمكنك تعطيل إنشاء مكتبة C++.distro_install
على true
.inih
و INIReader
.inih_dep
و INIReader_dep
. قد ترغب في تعيين default_library=static
و distro_install=false
للمشروع الفرعي. يتم توفير غلاف رسمي على WrapDB.version : '<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.