ini.h 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. /*
  2. ------------------------------------------------------------------------------
  3. Licensing information can be found at the end of the file.
  4. ------------------------------------------------------------------------------
  5. ini.h - v1.2 - Simple ini-file reader for C/C++.
  6. Do this:
  7. #define INI_IMPLEMENTATION
  8. before you include this file in *one* C/C++ file to create the implementation.
  9. */
  10. #ifndef ini_h
  11. #define ini_h
  12. #define INI_GLOBAL_SECTION ( 0 )
  13. #define INI_NOT_FOUND ( -1 )
  14. typedef struct ini_t ini_t;
  15. ini_t* ini_create( void* memctx );
  16. ini_t* ini_load( char const* data, unsigned int len, void* memctx );
  17. int ini_save( ini_t const* ini, char* data, int size );
  18. void ini_destroy( ini_t* ini );
  19. int ini_section_count( ini_t const* ini );
  20. char const* ini_section_name( ini_t const* ini, int section );
  21. int ini_property_count( ini_t const* ini, int section );
  22. char const* ini_property_name( ini_t const* ini, int section, int property );
  23. char const* ini_property_value( ini_t const* ini, int section, int property );
  24. int ini_find_section( ini_t const* ini, char const* name, int name_length );
  25. int ini_find_property( ini_t const* ini, int section, char const* name, int name_length );
  26. int ini_section_add( ini_t* ini, char const* name, int length );
  27. void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length );
  28. void ini_section_remove( ini_t* ini, int section );
  29. void ini_property_remove( ini_t* ini, int section, int property );
  30. void ini_section_name_set( ini_t* ini, int section, char const* name, int length );
  31. void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length );
  32. void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length );
  33. #endif /* ini_h */
  34. /**
  35. ini.h
  36. =====
  37. Simple ini-file reader for C/C++.
  38. Examples
  39. --------
  40. #### Loading an ini file and retrieving values
  41. #define INI_IMPLEMENTATION
  42. #include "ini.h"
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. int main()
  46. {
  47. FILE* fp = fopen( "test.ini", "r" );
  48. fseek( fp, 0, SEEK_END );
  49. int size = ftell( fp );
  50. fseek( fp, 0, SEEK_SET );
  51. char* data = (char*) malloc( size + 1 );
  52. fread( data, 1, size, fp );
  53. data[ size ] = '\0';
  54. fclose( fp );
  55. ini_t* ini = ini_load( data, NULL );
  56. free( data );
  57. int second_index = ini_find_property( ini, INI_GLOBAL_SECTION, "SecondSetting", 0 );
  58. char const* second = ini_property_value( ini, INI_GLOBAL_SECTION, second_index );
  59. printf( "%s=%s\n", "SecondSetting", second );
  60. int section = ini_find_section( ini, "MySection", 0 );
  61. int third_index = ini_find_property( ini, section, "ThirdSetting", 0 );
  62. char const* third = ini_property_value( ini, section, third_index );
  63. printf( "%s=%s\n", "ThirdSetting", third );
  64. ini_destroy( ini );
  65. return 0;
  66. }
  67. -----------------------------------------------------------------------------------------------
  68. #### Creating a new ini file
  69. #define INI_IMPLEMENTATION
  70. #include "ini.h"
  71. #include <stdio.h>
  72. #include <stdlib.h>
  73. int main()
  74. {
  75. ini_t* ini = ini_create( NULL );
  76. ini_property_add( ini, INI_GLOBAL_SECTION, "FirstSetting", 0, "Test", 0 );
  77. ini_property_add( ini, INI_GLOBAL_SECTION, "SecondSetting", 0, "2", 0 );
  78. int section = ini_section_add( ini, "MySection", 0 );
  79. ini_property_add( ini, section, "ThirdSetting", 0, "Three", 0 );
  80. int size = ini_save( ini, NULL, 0 ); // Find the size needed
  81. char* data = (char*) malloc( size );
  82. size = ini_save( ini, data, size ); // Actually save the file
  83. ini_destroy( ini );
  84. FILE* fp = fopen( "test.ini", "w" );
  85. fwrite( data, 1, size - 1, fp );
  86. fclose( fp );
  87. free( data );
  88. return 0;
  89. }
  90. API Documentation
  91. -----------------
  92. ini.h is a small library for reading classic .ini files. It is a single-header library, and does not need any .lib files
  93. or other binaries, or any build scripts. To use it, you just include ini.h to get the API declarations. To get the
  94. definitions, you must include ini.h from *one* single C or C++ file, and #define the symbol `INI_IMPLEMENTATION` before
  95. you do.
  96. ### Customization
  97. There are a few different things in ini.h which are configurable by #defines. The customizations only affect the
  98. implementation, so will only need to be defined in the file where you have the #define INI_IMPLEMENTATION.
  99. Note that if all customizations are utilized, ini.h will include no external files whatsoever, which might be useful
  100. if you need full control over what code is being built.
  101. #### Custom memory allocators
  102. To store the internal data structures, ini.h needs to do dynamic allocation by calling `malloc`. Programs might want to
  103. keep track of allocations done, or use custom defined pools to allocate memory from. ini.h allows for specifying custom
  104. memory allocation functions for `malloc` and `free`.
  105. This is done with the following code:
  106. #define INI_IMPLEMENTATION
  107. #define INI_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) )
  108. #define INI_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) )
  109. #include "ini.h"
  110. where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter
  111. is an optional parameter of type `void*`. When `ini_create` or `ini_load` is called, you can pass in a `memctx`
  112. parameter, which can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every
  113. `INI_MALLOC`/`INI_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your tracking
  114. data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the
  115. right type, and access the tracking data.
  116. If no custom allocator is defined, ini.h will default to `malloc` and `free` from the C runtime library.
  117. #### Custom C runtime function
  118. The library makes use of three additional functions from the C runtime library, and for full flexibility, it allows you
  119. to substitute them for your own. Here's an example:
  120. #define INI_IMPLEMENTATION
  121. #define INI_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) )
  122. #define INI_STRLEN( s ) ( my_strlen_func( s ) )
  123. #define INI_STRNICMP( s1, s2, cnt ) ( my_strnicmp_func( s1, s2, cnt ) )
  124. #include "ini.h"
  125. If no custom function is defined, ini.h will default to the C runtime library equivalent.
  126. ini_create
  127. ----------
  128. ini_t* ini_create( void* memctx )
  129. Instantiates a new, empty ini structure, which can be manipulated with other API calls, to fill it with data. To save it
  130. out to an ini-file string, use `ini_save`. When no longer needed, it can be destroyed by calling `ini_destroy`.
  131. `memctx` is a pointer to user defined data which will be passed through to the custom INI_MALLOC/INI_FREE calls. It can
  132. be NULL if no user defined data is needed.
  133. ini_load
  134. --------
  135. ini_t* ini_load( char const* data, void* memctx )
  136. Parse the zero-terminated string `data` containing an ini-file, and create a new ini_t instance containing the data.
  137. The instance can be manipulated with other API calls to enumerate sections/properties and retrieve values. When no
  138. longer needed, it can be destroyed by calling `ini_destroy`. `memctx` is a pointer to user defined data which will be
  139. passed through to the custom INI_MALLOC/INI_FREE calls. It can be NULL if no user defined data is needed.
  140. ini_save
  141. --------
  142. int ini_save( ini_t const* ini, char* data, int size )
  143. Saves an ini structure as a zero-terminated ini-file string, into the specified buffer. Returns the number of bytes
  144. written, including the zero terminator. If `data` is NULL, nothing is written, but `ini_save` still returns the number
  145. of bytes it would have written. If the size of `data`, as specified in the `size` parameter, is smaller than that
  146. required, only part of the ini-file string will be written. `ini_save` still returns the number of bytes it would have
  147. written had the buffer been large enough.
  148. ini_destroy
  149. -----------
  150. void ini_destroy( ini_t* ini )
  151. Destroy an `ini_t` instance created by calling `ini_load` or `ini_create`, releasing the memory allocated by it. No
  152. further API calls are valid on an `ini_t` instance after calling `ini_destroy` on it.
  153. ini_section_count
  154. -----------------
  155. int ini_section_count( ini_t const* ini )
  156. Returns the number of sections in an ini file. There's at least one section in an ini file (the global section), but
  157. there can be many more, each specified in the file by the section name wrapped in square brackets [ ].
  158. ini_section_name
  159. ----------------
  160. char const* ini_section_name( ini_t const* ini, int section )
  161. Returns the name of the section with the specified index. `section` must be non-negative and less than the value
  162. returned by `ini_section_count`, or `ini_section_name` will return NULL. The defined constant `INI_GLOBAL_SECTION` can
  163. be used to indicate the global section.
  164. ini_property_count
  165. ------------------
  166. int ini_property_count( ini_t const* ini, int section )
  167. Returns the number of properties belonging to the section with the specified index. `section` must be non-negative and
  168. less than the value returned by `ini_section_count`, or `ini_section_name` will return 0. The defined constant
  169. `INI_GLOBAL_SECTION` can be used to indicate the global section. Properties are declared in the ini-file on he format
  170. `name=value`.
  171. ini_property_name
  172. -----------------
  173. char const* ini_property_name( ini_t const* ini, int section, int property )
  174. Returns the name of the property with the specified index `property` in the section with the specified index `section`.
  175. `section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be
  176. non-negative and less than the value returned by `ini_property_count`, or `ini_property_name` will return NULL. The
  177. defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section.
  178. ini_property_value
  179. ------------------
  180. char const* ini_property_value( ini_t const* ini, int section, int property )
  181. Returns the value of the property with the specified index `property` in the section with the specified index `section`.
  182. `section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be
  183. non-negative and less than the value returned by `ini_property_count`, or `ini_property_value` will return NULL. The
  184. defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section.
  185. ini_find_section
  186. ----------------
  187. int ini_find_section( ini_t const* ini, char const* name, int name_length )
  188. Finds the section with the specified name, and returns its index. `name_length` specifies the number of characters in
  189. `name`, which does not have to be zero-terminated. If `name_length` is zero, the length is determined automatically, but
  190. in this case `name` has to be zero-terminated. If no section with the specified name could be found, the value
  191. `INI_NOT_FOUND` is returned.
  192. ini_find_property
  193. -----------------
  194. int ini_find_property( ini_t const* ini, int section, char const* name, int name_length )
  195. Finds the property with the specified name, within the section with the specified index, and returns the index of the
  196. property. `name_length` specifies the number of characters in `name`, which does not have to be zero-terminated. If
  197. `name_length` is zero, the length is determined automatically, but in this case `name` has to be zero-terminated. If no
  198. property with the specified name could be found within the specified section, the value `INI_NOT_FOUND` is returned.
  199. `section` must be non-negative and less than the value returned by `ini_section_count`, or `ini_find_property` will
  200. return `INI_NOT_FOUND`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section.
  201. ini_section_add
  202. ---------------
  203. int ini_section_add( ini_t* ini, char const* name, int length )
  204. Adds a section with the specified name, and returns the index it was added at. There is no check done to see if a
  205. section with the specified name already exists - multiple sections of the same name are allowed. `length` specifies the
  206. number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length is determined
  207. automatically, but in this case `name` has to be zero-terminated.
  208. ini_property_add
  209. ----------------
  210. void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length )
  211. Adds a property with the specified name and value to the specified section, and returns the index it was added at. There
  212. is no check done to see if a property with the specified name already exists - multiple properties of the same name are
  213. allowed. `name_length` and `value_length` specifies the number of characters in `name` and `value`, which does not have
  214. to be zero-terminated. If `name_length` or `value_length` is zero, the length is determined automatically, but in this
  215. case `name`/`value` has to be zero-terminated. `section` must be non-negative and less than the value returned by
  216. `ini_section_count`, or the property will not be added. The defined constant `INI_GLOBAL_SECTION` can be used to
  217. indicate the global section.
  218. ini_section_remove
  219. ------------------
  220. void ini_section_remove( ini_t* ini, int section )
  221. Removes the section with the specified index, and all properties within it. `section` must be non-negative and less than
  222. the value returned by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global
  223. section. Note that removing a section will shuffle section indices, so that section indices you may have stored will no
  224. longer indicate the same section as it did before the remove. Use the find functions to update your indices.
  225. ini_property_remove
  226. -------------------
  227. void ini_property_remove( ini_t* ini, int section, int property )
  228. Removes the property with the specified index from the specified section. `section` must be non-negative and less than
  229. the value returned by `ini_section_count`, and `property` must be non-negative and less than the value returned by
  230. `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. Note that
  231. removing a property will shuffle property indices within the specified section, so that property indices you may have
  232. stored will no longer indicate the same property as it did before the remove. Use the find functions to update your
  233. indices.
  234. ini_section_name_set
  235. --------------------
  236. void ini_section_name_set( ini_t* ini, int section, char const* name, int length )
  237. Change the name of the section with the specified index. `section` must be non-negative and less than the value returned
  238. by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. `length`
  239. specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length
  240. is determined automatically, but in this case `name` has to be zero-terminated.
  241. ini_property_name_set
  242. ---------------------
  243. void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length )
  244. Change the name of the property with the specified index in the specified section. `section` must be non-negative and
  245. less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value
  246. returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section.
  247. `length` specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero,
  248. the length is determined automatically, but in this case `name` has to be zero-terminated.
  249. ini_property_value_set
  250. ----------------------
  251. void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length )
  252. Change the value of the property with the specified index in the specified section. `section` must be non-negative and
  253. less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value
  254. returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section.
  255. `length` specifies the number of characters in `value`, which does not have to be zero-terminated. If `length` is zero,
  256. the length is determined automatically, but in this case `value` has to be zero-terminated.
  257. */
  258. /*
  259. ----------------------
  260. IMPLEMENTATION
  261. ----------------------
  262. */
  263. #ifdef INI_IMPLEMENTATION
  264. #undef INI_IMPLEMENTATION
  265. #define INITIAL_CAPACITY ( 256 )
  266. #undef _CRT_NONSTDC_NO_DEPRECATE
  267. #define _CRT_NONSTDC_NO_DEPRECATE
  268. #undef _CRT_SECURE_NO_WARNINGS
  269. #define _CRT_SECURE_NO_WARNINGS
  270. #include <stddef.h>
  271. #ifndef INI_MALLOC
  272. #include <stdlib.h>
  273. #define INI_MALLOC( ctx, size ) ( malloc( size ) )
  274. #define INI_FREE( ctx, ptr ) ( free( ptr ) )
  275. #endif
  276. #ifndef INI_MEMCPY
  277. #include <string.h>
  278. #define INI_MEMCPY( dst, src, cnt ) ( memcpy( dst, src, cnt ) )
  279. #endif
  280. #ifndef INI_STRLEN
  281. #include <string.h>
  282. #define INI_STRLEN( s ) ( strlen( s ) )
  283. #endif
  284. #ifndef INI_STRNICMP
  285. #ifdef _WIN32
  286. #include <string.h>
  287. #define INI_STRNICMP( s1, s2, cnt ) ( strnicmp( s1, s2, cnt ) )
  288. #else
  289. #include <string.h>
  290. #define INI_STRNICMP( s1, s2, cnt ) ( strncasecmp( s1, s2, cnt ) )
  291. #endif
  292. #endif
  293. struct ini_internal_section_t
  294. {
  295. char name[ 32 ];
  296. char* name_large;
  297. };
  298. struct ini_internal_property_t
  299. {
  300. int section;
  301. char name[ 32 ];
  302. char* name_large;
  303. char value[ 64 ];
  304. char* value_large;
  305. };
  306. struct ini_t
  307. {
  308. struct ini_internal_section_t* sections;
  309. int section_capacity;
  310. int section_count;
  311. struct ini_internal_property_t* properties;
  312. int property_capacity;
  313. int property_count;
  314. void* memctx;
  315. };
  316. static int ini_internal_property_index( ini_t const* ini, int section, int property )
  317. {
  318. int i;
  319. int p;
  320. if( ini && section >= 0 && section < ini->section_count )
  321. {
  322. p = 0;
  323. for( i = 0; i < ini->property_count; ++i )
  324. {
  325. if( ini->properties[ i ].section == section )
  326. {
  327. if( p == property ) return i;
  328. ++p;
  329. }
  330. }
  331. }
  332. return INI_NOT_FOUND;
  333. }
  334. ini_t* ini_create( void* memctx )
  335. {
  336. ini_t* ini;
  337. ini = (ini_t*) INI_MALLOC( memctx, sizeof( ini_t ) );
  338. ini->memctx = memctx;
  339. ini->sections = (struct ini_internal_section_t*) INI_MALLOC( ini->memctx, INITIAL_CAPACITY * sizeof( ini->sections[ 0 ] ) );
  340. ini->section_capacity = INITIAL_CAPACITY;
  341. ini->section_count = 1; /* global section */
  342. ini->sections[ 0 ].name[ 0 ] = '\0';
  343. ini->sections[ 0 ].name_large = 0;
  344. ini->properties = (struct ini_internal_property_t*) INI_MALLOC( ini->memctx, INITIAL_CAPACITY * sizeof( ini->properties[ 0 ] ) );
  345. ini->property_capacity = INITIAL_CAPACITY;
  346. ini->property_count = 0;
  347. return ini;
  348. }
  349. ini_t* ini_load( char const* data, unsigned int len, void* memctx )
  350. {
  351. ini_t* ini;
  352. char const* ptr;
  353. int s;
  354. char const* start;
  355. char const* start2;
  356. int l;
  357. char const* end;
  358. ini = ini_create( memctx );
  359. ptr = data;
  360. end = ptr + len;
  361. if( ptr )
  362. {
  363. s = 0;
  364. while( ptr < end && *ptr )
  365. {
  366. /* trim leading whitespace */
  367. while( ptr < end && *ptr && *ptr <=' ' )
  368. ++ptr;
  369. /* done? */
  370. if( ptr == end || !*ptr ) break;
  371. /* comment */
  372. else if( *ptr == ';' )
  373. {
  374. while( ptr < end && *ptr && *ptr !='\n' )
  375. ++ptr;
  376. }
  377. /* section */
  378. else if( *ptr == '[' )
  379. {
  380. ++ptr;
  381. start = ptr;
  382. while( ptr < end && *ptr && *ptr !=']' && *ptr != '\n' )
  383. ++ptr;
  384. if( *ptr == ']' )
  385. {
  386. s = ini_section_add( ini, start, (int)( ptr - start) );
  387. ++ptr;
  388. }
  389. }
  390. /* property */
  391. else
  392. {
  393. start = ptr;
  394. while( ptr < end && *ptr && *ptr !='=' && *ptr != '\n' )
  395. ++ptr;
  396. if( *ptr == '=' )
  397. {
  398. l = (int)( ptr - start);
  399. ++ptr;
  400. while( ptr < end && *ptr && *ptr <= ' ' && *ptr != '\n' )
  401. ptr++;
  402. start2 = ptr;
  403. while( ptr < end && *ptr && *ptr != '\n' )
  404. ++ptr;
  405. while( ptr >= start2 && *(--ptr) <= ' ' )
  406. (void)ptr;
  407. ptr++;
  408. if( ptr == start2 )
  409. ini_property_add( ini, s, start, l, "", 1 );
  410. else
  411. ini_property_add( ini, s, start, l, start2, (int)( ptr - start2 ) );
  412. }
  413. }
  414. }
  415. }
  416. return ini;
  417. }
  418. int ini_save( ini_t const* ini, char* data, int size )
  419. {
  420. int s;
  421. int p;
  422. int i;
  423. int l;
  424. char* n;
  425. int pos;
  426. if( ini )
  427. {
  428. pos = 0;
  429. for( s = 0; s < ini->section_count; ++s )
  430. {
  431. n = ini->sections[ s ].name_large ? ini->sections[ s ].name_large : ini->sections[ s ].name;
  432. l = (int) INI_STRLEN( n );
  433. if( l > 0 )
  434. {
  435. if( data && pos < size ) data[ pos ] = '[';
  436. ++pos;
  437. for( i = 0; i < l; ++i )
  438. {
  439. if( data && pos < size ) data[ pos ] = n[ i ];
  440. ++pos;
  441. }
  442. if( data && pos < size ) data[ pos ] = ']';
  443. ++pos;
  444. if( data && pos < size ) data[ pos ] = '\n';
  445. ++pos;
  446. }
  447. for( p = 0; p < ini->property_count; ++p )
  448. {
  449. if( ini->properties[ p ].section == s )
  450. {
  451. n = ini->properties[ p ].name_large ? ini->properties[ p ].name_large : ini->properties[ p ].name;
  452. l = (int) INI_STRLEN( n );
  453. for( i = 0; i < l; ++i )
  454. {
  455. if( data && pos < size ) data[ pos ] = n[ i ];
  456. ++pos;
  457. }
  458. if( data && pos < size ) data[ pos ] = '=';
  459. ++pos;
  460. n = ini->properties[ p ].value_large ? ini->properties[ p ].value_large : ini->properties[ p ].value;
  461. l = (int) INI_STRLEN( n );
  462. for( i = 0; i < l; ++i )
  463. {
  464. if( data && pos < size ) data[ pos ] = n[ i ];
  465. ++pos;
  466. }
  467. if( data && pos < size ) data[ pos ] = '\n';
  468. ++pos;
  469. }
  470. }
  471. if( pos > 0 )
  472. {
  473. if( data && pos < size ) data[ pos ] = '\n';
  474. ++pos;
  475. }
  476. }
  477. if( data && pos < size ) data[ pos ] = '\0';
  478. ++pos;
  479. return pos;
  480. }
  481. return 0;
  482. }
  483. void ini_destroy( ini_t* ini )
  484. {
  485. int i;
  486. if( ini )
  487. {
  488. for( i = 0; i < ini->property_count; ++i )
  489. {
  490. if( ini->properties[ i ].value_large ) INI_FREE( ini->memctx, ini->properties[ i ].value_large );
  491. if( ini->properties[ i ].name_large ) INI_FREE( ini->memctx, ini->properties[ i ].name_large );
  492. }
  493. for( i = 0; i < ini->section_count; ++i )
  494. if( ini->sections[ i ].name_large ) INI_FREE( ini->memctx, ini->sections[ i ].name_large );
  495. INI_FREE( ini->memctx, ini->properties );
  496. INI_FREE( ini->memctx, ini->sections );
  497. INI_FREE( ini->memctx, ini );
  498. }
  499. }
  500. int ini_section_count( ini_t const* ini )
  501. {
  502. if( ini ) return ini->section_count;
  503. return 0;
  504. }
  505. char const* ini_section_name( ini_t const* ini, int section )
  506. {
  507. if( ini && section >= 0 && section < ini->section_count )
  508. return ini->sections[ section ].name_large ? ini->sections[ section ].name_large : ini->sections[ section ].name;
  509. return NULL;
  510. }
  511. int ini_property_count( ini_t const* ini, int section )
  512. {
  513. int i;
  514. int count;
  515. if( ini )
  516. {
  517. count = 0;
  518. for( i = 0; i < ini->property_count; ++i )
  519. {
  520. if( ini->properties[ i ].section == section ) ++count;
  521. }
  522. return count;
  523. }
  524. return 0;
  525. }
  526. char const* ini_property_name( ini_t const* ini, int section, int property )
  527. {
  528. int p;
  529. if( ini && section >= 0 && section < ini->section_count )
  530. {
  531. p = ini_internal_property_index( ini, section, property );
  532. if( p != INI_NOT_FOUND )
  533. return ini->properties[ p ].name_large ? ini->properties[ p ].name_large : ini->properties[ p ].name;
  534. }
  535. return NULL;
  536. }
  537. char const* ini_property_value( ini_t const* ini, int section, int property )
  538. {
  539. int p;
  540. if( ini && section >= 0 && section < ini->section_count )
  541. {
  542. p = ini_internal_property_index( ini, section, property );
  543. if( p != INI_NOT_FOUND )
  544. return ini->properties[ p ].value_large ? ini->properties[ p ].value_large : ini->properties[ p ].value;
  545. }
  546. return NULL;
  547. }
  548. int ini_find_section( ini_t const* ini, char const* name, int name_length )
  549. {
  550. int i;
  551. if( ini && name )
  552. {
  553. if( name_length <= 0 ) name_length = (int) INI_STRLEN( name );
  554. for( i = 0; i < ini->section_count; ++i )
  555. {
  556. char const* const other =
  557. ini->sections[ i ].name_large ? ini->sections[ i ].name_large : ini->sections[ i ].name;
  558. if( INI_STRLEN( other ) == name_length && INI_STRNICMP( name, other, (size_t)name_length ) == 0 )
  559. return i;
  560. }
  561. }
  562. return INI_NOT_FOUND;
  563. }
  564. int ini_find_property( ini_t const* ini, int section, char const* name, int name_length )
  565. {
  566. int i;
  567. int c;
  568. if( ini && name && section >= 0 && section < ini->section_count)
  569. {
  570. if( name_length <= 0 ) name_length = (int) INI_STRLEN( name );
  571. c = 0;
  572. for( i = 0; i < ini->property_count; ++i )
  573. {
  574. if( ini->properties[ i ].section == section )
  575. {
  576. char const* const other =
  577. ini->properties[ i ].name_large ? ini->properties[ i ].name_large : ini->properties[ i ].name;
  578. if( INI_STRLEN( other ) == name_length && INI_STRNICMP( name, other, (size_t) name_length ) == 0 )
  579. return c;
  580. ++c;
  581. }
  582. }
  583. }
  584. return INI_NOT_FOUND;
  585. }
  586. int ini_section_add( ini_t* ini, char const* name, int length )
  587. {
  588. struct ini_internal_section_t* new_sections;
  589. if( ini && name )
  590. {
  591. if( length <= 0 ) length = (int) INI_STRLEN( name );
  592. if( ini->section_count >= ini->section_capacity )
  593. {
  594. ini->section_capacity *= 2;
  595. new_sections = (struct ini_internal_section_t*) INI_MALLOC( ini->memctx,
  596. ini->section_capacity * sizeof( ini->sections[ 0 ] ) );
  597. INI_MEMCPY( new_sections, ini->sections, ini->section_count * sizeof( ini->sections[ 0 ] ) );
  598. INI_FREE( ini->memctx, ini->sections );
  599. ini->sections = new_sections;
  600. }
  601. ini->sections[ ini->section_count ].name_large = 0;
  602. if( (size_t) length + 1 >= sizeof( ini->sections[ 0 ].name ) )
  603. {
  604. ini->sections[ ini->section_count ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 );
  605. INI_MEMCPY( ini->sections[ ini->section_count ].name_large, name, (size_t) length );
  606. ini->sections[ ini->section_count ].name_large[ length ] = '\0';
  607. }
  608. else
  609. {
  610. INI_MEMCPY( ini->sections[ ini->section_count ].name, name, (size_t) length );
  611. ini->sections[ ini->section_count ].name[ length ] = '\0';
  612. }
  613. return ini->section_count++;
  614. }
  615. return INI_NOT_FOUND;
  616. }
  617. void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length )
  618. {
  619. struct ini_internal_property_t* new_properties;
  620. if( ini && name && section >= 0 && section < ini->section_count )
  621. {
  622. if( name_length <= 0 ) name_length = (int) INI_STRLEN( name );
  623. if( value_length <= 0 ) value_length = (int) INI_STRLEN( value );
  624. if( ini->property_count >= ini->property_capacity )
  625. {
  626. ini->property_capacity *= 2;
  627. new_properties = (struct ini_internal_property_t*) INI_MALLOC( ini->memctx,
  628. ini->property_capacity * sizeof( ini->properties[ 0 ] ) );
  629. INI_MEMCPY( new_properties, ini->properties, ini->property_count * sizeof( ini->properties[ 0 ] ) );
  630. INI_FREE( ini->memctx, ini->properties );
  631. ini->properties = new_properties;
  632. }
  633. ini->properties[ ini->property_count ].section = section;
  634. ini->properties[ ini->property_count ].name_large = 0;
  635. ini->properties[ ini->property_count ].value_large = 0;
  636. if( (size_t) name_length + 1 >= sizeof( ini->properties[ 0 ].name ) )
  637. {
  638. ini->properties[ ini->property_count ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) name_length + 1 );
  639. INI_MEMCPY( ini->properties[ ini->property_count ].name_large, name, (size_t) name_length );
  640. ini->properties[ ini->property_count ].name_large[ name_length ] = '\0';
  641. }
  642. else
  643. {
  644. INI_MEMCPY( ini->properties[ ini->property_count ].name, name, (size_t) name_length );
  645. ini->properties[ ini->property_count ].name[ name_length ] = '\0';
  646. }
  647. if( (size_t) value_length + 1 >= sizeof( ini->properties[ 0 ].value ) )
  648. {
  649. ini->properties[ ini->property_count ].value_large = (char*) INI_MALLOC( ini->memctx, (size_t) value_length + 1 );
  650. INI_MEMCPY( ini->properties[ ini->property_count ].value_large, value, (size_t) value_length );
  651. ini->properties[ ini->property_count ].value_large[ value_length ] = '\0';
  652. }
  653. else
  654. {
  655. INI_MEMCPY( ini->properties[ ini->property_count ].value, value, (size_t) value_length );
  656. ini->properties[ ini->property_count ].value[ value_length ] = '\0';
  657. }
  658. ++ini->property_count;
  659. }
  660. }
  661. void ini_section_remove( ini_t* ini, int section )
  662. {
  663. int p;
  664. if( ini && section >= 0 && section < ini->section_count )
  665. {
  666. if( ini->sections[ section ].name_large ) INI_FREE( ini->memctx, ini->sections[ section ].name_large );
  667. for( p = ini->property_count - 1; p >= 0; --p )
  668. {
  669. if( ini->properties[ p ].section == section )
  670. {
  671. if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large );
  672. if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large );
  673. ini->properties[ p ] = ini->properties[ --ini->property_count ];
  674. }
  675. }
  676. ini->sections[ section ] = ini->sections[ --ini->section_count ];
  677. for( p = 0; p < ini->property_count; ++p )
  678. {
  679. if( ini->properties[ p ].section == ini->section_count )
  680. ini->properties[ p ].section = section;
  681. }
  682. }
  683. }
  684. void ini_property_remove( ini_t* ini, int section, int property )
  685. {
  686. int p;
  687. if( ini && section >= 0 && section < ini->section_count )
  688. {
  689. p = ini_internal_property_index( ini, section, property );
  690. if( p != INI_NOT_FOUND )
  691. {
  692. if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large );
  693. if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large );
  694. ini->properties[ p ] = ini->properties[ --ini->property_count ];
  695. return;
  696. }
  697. }
  698. }
  699. void ini_section_name_set( ini_t* ini, int section, char const* name, int length )
  700. {
  701. if( ini && name && section >= 0 && section < ini->section_count )
  702. {
  703. if( length <= 0 ) length = (int) INI_STRLEN( name );
  704. if( ini->sections[ section ].name_large ) INI_FREE( ini->memctx, ini->sections[ section ].name_large );
  705. ini->sections[ section ].name_large = 0;
  706. if( (size_t) length + 1 >= sizeof( ini->sections[ 0 ].name ) )
  707. {
  708. ini->sections[ section ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 );
  709. INI_MEMCPY( ini->sections[ section ].name_large, name, (size_t) length );
  710. ini->sections[ section ].name_large[ length ] = '\0';
  711. }
  712. else
  713. {
  714. INI_MEMCPY( ini->sections[ section ].name, name, (size_t) length );
  715. ini->sections[ section ].name[ length ] = '\0';
  716. }
  717. }
  718. }
  719. void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length )
  720. {
  721. int p;
  722. if( ini && name && section >= 0 && section < ini->section_count )
  723. {
  724. if( length <= 0 ) length = (int) INI_STRLEN( name );
  725. p = ini_internal_property_index( ini, section, property );
  726. if( p != INI_NOT_FOUND )
  727. {
  728. if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large );
  729. ini->properties[ ini->property_count ].name_large = 0;
  730. if( (size_t) length + 1 >= sizeof( ini->properties[ 0 ].name ) )
  731. {
  732. ini->properties[ p ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 );
  733. INI_MEMCPY( ini->properties[ p ].name_large, name, (size_t) length );
  734. ini->properties[ p ].name_large[ length ] = '\0';
  735. }
  736. else
  737. {
  738. INI_MEMCPY( ini->properties[ p ].name, name, (size_t) length );
  739. ini->properties[ p ].name[ length ] = '\0';
  740. }
  741. }
  742. }
  743. }
  744. void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length )
  745. {
  746. int p;
  747. if( ini && value && section >= 0 && section < ini->section_count )
  748. {
  749. if( length <= 0 ) length = (int) INI_STRLEN( value );
  750. p = ini_internal_property_index( ini, section, property );
  751. if( p != INI_NOT_FOUND )
  752. {
  753. if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large );
  754. ini->properties[ ini->property_count ].value_large = 0;
  755. if( (size_t) length + 1 >= sizeof( ini->properties[ 0 ].value ) )
  756. {
  757. ini->properties[ p ].value_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 );
  758. INI_MEMCPY( ini->properties[ p ].value_large, value, (size_t) length );
  759. ini->properties[ p ].value_large[ length ] = '\0';
  760. }
  761. else
  762. {
  763. INI_MEMCPY( ini->properties[ p ].value, value, (size_t) length );
  764. ini->properties[ p ].value[ length ] = '\0';
  765. }
  766. }
  767. }
  768. }
  769. #endif /* INI_IMPLEMENTATION */
  770. /*
  771. contributors:
  772. Randy Gaul (copy-paste bug in ini_property_value_set)
  773. Branimir Karadzic (INI_STRNICMP bugfix)
  774. revision history:
  775. 1.2 using strnicmp for correct length compares, fixed copy-paste bug in ini_property_value_set
  776. 1.1 customization, added documentation, cleanup
  777. 1.0 first publicly released version
  778. */
  779. /*
  780. ------------------------------------------------------------------------------
  781. This software is available under 2 licenses - you may choose the one you like.
  782. ------------------------------------------------------------------------------
  783. ALTERNATIVE A - MIT License
  784. Copyright (c) 2015 Mattias Gustavsson
  785. Permission is hereby granted, free of charge, to any person obtaining a copy of
  786. this software and associated documentation files (the "Software"), to deal in
  787. the Software without restriction, including without limitation the rights to
  788. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  789. of the Software, and to permit persons to whom the Software is furnished to do
  790. so, subject to the following conditions:
  791. The above copyright notice and this permission notice shall be included in all
  792. copies or substantial portions of the Software.
  793. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  794. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  795. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  796. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  797. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  798. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  799. SOFTWARE.
  800. ------------------------------------------------------------------------------
  801. ALTERNATIVE B - Public Domain (www.unlicense.org)
  802. This is free and unencumbered software released into the public domain.
  803. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
  804. software, either in source code form or as a compiled binary, for any purpose,
  805. commercial or non-commercial, and by any means.
  806. In jurisdictions that recognize copyright laws, the author or authors of this
  807. software dedicate any and all copyright interest in the software to the public
  808. domain. We make this dedication for the benefit of the public at large and to
  809. the detriment of our heirs and successors. We intend this dedication to be an
  810. overt act of relinquishment in perpetuity of all present and future rights to
  811. this software under copyright law.
  812. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  813. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  814. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  815. AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  816. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  817. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  818. ------------------------------------------------------------------------------
  819. */