CAPS Universe documentation  1.0.4
All you need to know to be successful
Data Structures | Functions

INI file content management. More...

Data Structures

struct  caps_inif_table
 Manage a table of INI entries. More...
 

Functions

void caps_libinif_init (void)
 
void caps_inif_table_init (struct caps_inif_table *dst)
 
void caps_inif_table_cleanup (struct caps_inif_table *dst)
 
int caps_inif_file_read (struct caps_inif_table *dst, const char *level, const char *file_name)
 
struct caps_inif_lockcaps_inif_locked_file_read (struct caps_inif_table *dst, const char *level, const char *file_name)
 
int caps_inif_locked_file_write (const struct caps_inif_table *dst, struct caps_inif_lock *li)
 
void caps_inif_locked_file_close (struct caps_inif_lock *li)
 
int caps_inif_dir_read (struct caps_inif_table *dst, const char *level, const char *dir)
 
int caps_inif_dir_merge (struct caps_inif_table *dst, const char *level, const char *dir)
 
int caps_inif_file_merge (struct caps_inif_table *dst, const char *level, const char *ini_file)
 
const char * caps_inif_option_get (const struct caps_inif_table *dst, const char *level, const char *section, const char *key)
 
int caps_inif_option_add (struct caps_inif_table *dst, const char *level, const char *section, const char *key, const char *val)
 
struct caps_inif_cursorcaps_inif_cursor_create (void)
 
void caps_inif_cursor_destroy (struct caps_inif_cursor *cursor)
 
const char * caps_inif_next_key_get (const struct caps_inif_table *dst, struct caps_inif_cursor *cursor)
 
const char * caps_inif_next_section_get (const struct caps_inif_table *dst, struct caps_inif_cursor *cursor)
 
const char * caps_inif_next_level_get (const struct caps_inif_table *dst, struct caps_inif_cursor *cursor)
 
size_t caps_inif_option_count_get (const struct caps_inif_table *dst)
 
void caps_inif_option_list_print (const struct caps_inif_table *dst)
 

Detailed Description

The config files use the INI style with sections ("[section]") and key/value pairs ("bla=blub").

When an INI file gets read in, three names are used to get something like a namespace. This is intended to handle the information from more then one INI file in one key/value table. Using the functions caps_inif_file_read() and caps_inif_dir_read() read-in the INI file information and create special keys to distinguish and access the values later on. Each key has three components in the string format:

Single INI

Example:

Lets assume the INI file is called program.ini and its content and read-in was called without a level setting:

[base]
    key1=value1;
[extension]
    key2=value2;

With this information the key/value table gets filled with:

key value
program/base/key1 value1
program/extension/key2 value2

These values can be accessed later on with:

var1 = caps_inif_option_get(dst, "program", "base", "key1");
var2 = caps_inif_option_get(dst, "program", "extension", "key2");
const char * caps_inif_option_get(const struct caps_inif_table *dst, const char *level, const char *section, const char *key)
Definition: libcapsinif.c:656
Note
Currently a few restrictions do exist:
  • a text line in the INI file can be up to INI_MAX_LINE characters (including the trailing newline)
  • a section name can be up to MAX_SECTION characters
  • a key name can be up to MAX_NAME characters

Cascaded INI

INI files can be cascaded and this feature is used to read in various INI files if a CAPS universe component starts up. This enables a user to change settings in a generic way (for all components) or unique for one component dependent which INI file the user modifies.

Example:

The first read-in INI file is called base.ini:

[base]
    key1=value1;
[extension]
    key2=value2;

The second read-in INI file is called application.ini:

[base]
    key1=value3;
[extension]
    key3=value4;

With this information the key/value table gets filled with:

key value
base/base/key1 value1
base/extension/key2 value2
application/base/key1 value3
application/extension/key3 value4

These values can be accessed later on with:

var1 = caps_inif_option_get(dst, "base", "base", "key1");
var2 = caps_inif_option_get(dst, "base", "extension", "key2");
var3 = caps_inif_option_get(dst, "application", "extension", "key1");
var4 = caps_inif_option_get(dst, "application", "extension", "key3");

But merging INI files into one table makes more sense, if the same keys overwrite each other. In the example above both INI files define base/key1, but with different values.

If you imagine base.ini settings are shared by all applications, and application.ini is for one application only, then this application can read-in the key1's value differently:

var1 = caps_inif_option_get(dst, NULL, "base", "key1");

In this case the application gets value3 from the application.ini. If application.ini wouldn't overwrite base/key1, the application gets value1 from the base.ini instead.
At the end this means: If you modify base/key1 in the base.ini you may change a behaviour of all applications. If you change base/key1 in application.ini, you change a behaviour of one application only.

Sorted INI

Sometimes it is required to manage various INI files (due to different or external sources) in one directory. In these cases it might be important to control the order of the INI files when they get read-in, to ensure a key/value of a later INI file overwrites a key/value of a previous INI file.

Note
The mechanism described here is different from reading-in various directories described in Cascaded INI. Because it works for one directory only.

The regular read-in order is based on some alphabetical order of the INI file names or their creation order in the directory. libcapsinif uses the scandir()-API and a version order sorting. Thus, you can control the read-in order via their names. For example if you name your INI files in one directory this way:

The 1-this.ini INI file is read-in first, the 2-that.ini INI file second. And thus way settings in the 2-that.ini INI file can overwrite settings in the 1-this.ini INI file. Due to the version order sorting, this works for 1-this.ini and 10-that.ini INI file names as well. E.g. 1-this.ini INI file is read-in first, 10-that.ini INI file second.

INI file as a database

Instead of querying single keys from a key/value table, you can walk through it as well. This is where cursors come into play. With cursors you can jump from level to level, section to section or key to key in the table.

Example:

[printer_ZDIsns]
type = usb
vid = 0x4f9
pid = 0x27
serial = M5JXX5421
descr-ini = caps-brother-HL2030-driver.ini
param-dir = printer_ZDIsns
[printer_qJkTfj]
type = usb
vid = 0x4e8
pid = 0x3292
serial = 8678QBAHS2234960M.
descr-ini = caps-samsung-ml-1640-driver.ini
param-dir = printer_qJkTfj

The example shows the CAPS device database of already known printers. Each device has its own section, each section contains at most the same keys to describe a printer device. Only the key-names are known, the section names are generated at run-time, so you don't know them in advance.
Whenever a printer is attached to the system, the Printer Driver Launcher walks through this table and jumps from section to section to check if this device is already known or if it is a new one.

For this it uses:

while ((next_section = caps_inif_next_section_get(ini_tab, cursor)) != NULL)
value = caps_inif_option_get(ini_tab, NULL, next_section, "some key");
// read more keys and check
const char * caps_inif_next_section_get(const struct caps_inif_table *dst, struct caps_inif_cursor *cursor)
Definition: libcapsinif.c:779
struct caps_inif_cursor * caps_inif_cursor_create(void)
Definition: libcapsinif.c:716
void caps_inif_cursor_destroy(struct caps_inif_cursor *cursor)
Definition: libcapsinif.c:727

Function Documentation

◆ caps_libinif_init()

void caps_libinif_init ( void  )

Initialize the library prior use

Note
Does not return in case of memory failure

◆ caps_inif_table_init()

void caps_inif_table_init ( struct caps_inif_table dst)

Initialize a table to store INI information

Parameters
[in,out]dstPointer to key/value table

◆ caps_inif_table_cleanup()

void caps_inif_table_cleanup ( struct caps_inif_table dst)

Free all resources in the table

Parameters
[in,out]dstPointer to key/value table

◆ caps_inif_file_read()

int caps_inif_file_read ( struct caps_inif_table dst,
const char *  level,
const char *  file_name 
)

Read an INI file content into a yet empty table

Parameters
[in,out]dstPointer to INI table
[in]levelName of the level these entries correspond to (can be NULL)
[in]file_nameFull path and name of INI file to be read
Return values
0on success
-EACCESAccess to ini_file is not allowed
-ENOENTNo such file or directory
-EINVALINI file file_name contains an error

In case level is NULL, the file_name's basename is used instead (e.g. example for a file example.ini).

Note
-EINVAL can mean some kind of a syntax error in the INI file file_name or the section/key read from the INI file already exists at level in dst
Does not return in case of memory failure

◆ caps_inif_locked_file_read()

struct caps_inif_lock * caps_inif_locked_file_read ( struct caps_inif_table dst,
const char *  level,
const char *  file_name 
)

Lock an INI file, read its content into a table and keep the INI file open and locked until caps_inif_locked_file_close() is called

Parameters
[in,out]dstPointer to INI table
[in]levelName of the level these entries correspond to (can be NULL)
[in]file_nameFull path and name of INI file to be read
Return values
pointerPointer to transparent lock info
NULLIn case of failure

Intendend for some atomic read-update-write actions in the INI file. Used to update the Printer Device Database in an atomic manner for example.

Note
This function does not return in case of memory failure.
Keep the locked period as short as possible, since other processes might wait for it.
This call blocks until the file can be locked.
Postcondition
Call caps_inif_locked_file_close() or caps_inif_locked_file_write() when done to free the lock.

◆ caps_inif_locked_file_write()

int caps_inif_locked_file_write ( const struct caps_inif_table dst,
struct caps_inif_lock li 
)

Write back the table content into an opened and locked INI file and unlock and close the INI file

Parameters
[in]dstPointer to INI table
[in]liPointer to transparent info caps_inif_locked_file_read() call
Return values
0On success
negativeerrno

This function ensures, the new content is bound to the same inode than before. Used to update the Printer Device Database in an atomic manner for example.

Precondition
The file must be opened via caps_inif_locked_file_read().

◆ caps_inif_locked_file_close()

void caps_inif_locked_file_close ( struct caps_inif_lock li)

Close and unlock a read INI file

Parameters
[in]liPointer to transparent info caps_inif_locked_file_read() call

This function unlocks and closes an open INI file created by caps_inif_locked_file_read() and frees the data structure in li.

Precondition
The file was opened via caps_inif_locked_file_read().

◆ caps_inif_dir_read()

int caps_inif_dir_read ( struct caps_inif_table dst,
const char *  level,
const char *  dir 
)

Read in all ini files within the given directory into one single table

Parameters
[in,out]dstThe INI table to store the result to
[in]levelName of the level these entries correspond to (can be NULL)
[in]dirDirectory where to load the INI files from
Return values
0On success
-ENOENTThe path in dir doesn't exist
-ENOTDIRThe path in dir isn't a directory
-EACCESAccess to dir or it's file(s) is not allowed
-EINVALOne of the INI file(s) in dir contain an error

This function expects all INI files contain different content and there is no overlapping. If there is overlapping, use caps_inif_dir_merge() instead.

Note
It uses caps_inif_option_add() and its restrictions internally.

In case the level is NULL, the name of the INI files (without its trailing .ini) is used for the content of each individual INI file instead.

Note
Does not return in case of memory failure

◆ caps_inif_dir_merge()

int caps_inif_dir_merge ( struct caps_inif_table dst,
const char *  level,
const char *  dir 
)

Merge in all INI files within the given directory into one single table

Parameters
[in,out]dstThe INI table to store the result to
[in]levelName of the level these entries correspond to (can be NULL)
[in]dirDirectory where to load the INI files from
Return values
0On success
-ENOENTThe path in dir doesn't exist
-ENOTDIRThe path in dir isn't a directory
-EACCESAccess to dir or it's file(s) is not allowed
-EINVALOne of the INI file(s) in dir contain an error

This function expects the INI files can contain overlapping content and in this case, settings get replaced in the final dst (and the INI file read-in order is important as well).

Note
It replaces the content of an already existing entry in dst or uses caps_inif_option_add() to add it to dst

In case the level is NULL, the name of the INI files (without its trailing .ini) is used for the content of each individual INI file instead.

Note
Does not return in case of memory failure

◆ caps_inif_file_merge()

int caps_inif_file_merge ( struct caps_inif_table dst,
const char *  level,
const char *  ini_file 
)

Merge an INI file content into an existing table

Parameters
[in,out]dstThe INI table to store the result to
[in]levelName of the level these entries correspond to
[in]ini_fileName of the INI file to merge (FQP)
Return values
0On success
-EACCESAccess to ini_file is not allowed
-ENOENTNo such file or directory
-EINVALINI file file_name contains an error

This will replace existing entries at the same level or add new entries into dst.

Note
Does not return in case of memory failure

◆ caps_inif_option_get()

const char * caps_inif_option_get ( const struct caps_inif_table dst,
const char *  level,
const char *  section,
const char *  key 
)

Get the value for a specified level/section/key

Parameters
[in]dstThe INI table to search in
[in]levelFirst part of the key triple (can be NULL)
[in]sectionSecond part of the key triple (can be NULL)
[in]keyThird part of the key triple
Return values
stringPointer to the key's value
NULLIf the key does not exist

The returned value is predictable only, if all three (e.g. level, section and key) components are given. Else:

  • if level is NULL, the first match of section and key is returned.
  • if section is NULL, the first match of level and key is returned.
  • if level and section is NULL, the first match of key is returned.

Which means, if level and section are only partially given, the returned value might surprise you. But it depends on the structure of the data as well. For example for data with one level only, you can omit the level parameter without any problem.

Note
Boolean keys return a valid pointer to an empty string (e.g. the first character is '\0').

◆ caps_inif_option_add()

int caps_inif_option_add ( struct caps_inif_table dst,
const char *  level,
const char *  section,
const char *  key,
const char *  val 
)

Add a new entry with the specified level/section/key/value to the table

Parameters
[in]dstThe INI entry table to add the new entry to
[in]levelFirst part of the key triple (can be NULL)
[in]sectionSecond part of the key triple (can be NULL)
[in]keyThird part of the key triple
[in]valThe value to be set (can be NULL)
Return values
0New level/section/key/value added to dst
-EINVALLevel/section/key already has a value
Note
A val of NULL let the key be of boolean type, e.g. if it exists, it returns a 'true' later on
Note the difference between a NULL and an empty string for val!
All strings are copied
Does not return in case of memory failure

◆ caps_inif_cursor_create()

struct caps_inif_cursor * caps_inif_cursor_create ( void  )

Create a cursor to walk through a table

Returns
Pointer to an opaque structure
Note
This function does not return in case of a memory failurew
Do not forget to destroy the cursor after use with caps_inif_cursor_destroy()

◆ caps_inif_cursor_destroy()

void caps_inif_cursor_destroy ( struct caps_inif_cursor cursor)

Destroy a cursor to walk through a table

Parameters
[in]cursorWhat to destroy
Note
The cursor must be already initialised via caps_inif_cursor_create()

◆ caps_inif_next_key_get()

const char * caps_inif_next_key_get ( const struct caps_inif_table dst,
struct caps_inif_cursor cursor 
)

Move forward to the next key in the table

Parameters
[in]dstThe INI table to handle
[in,out]cursorWhere to store the cursor info for the next query
Return values
stringName of the 'key'
NULLIn case of end of section, end of level or end of dst table reached
Note
The cursor must be already initialised via caps_inif_cursor_create()

◆ caps_inif_next_section_get()

const char * caps_inif_next_section_get ( const struct caps_inif_table dst,
struct caps_inif_cursor cursor 
)

Move forward to the next section in the table

Parameters
[in]dstThe INI table to handle
[in,out]cursorWhere to store the cursor info for the next query
Return values
stringName of the 'section'
NULLIn case of end of level or end of dst table reached
Note
The cursor must be already initialised via caps_inif_cursor_create()

◆ caps_inif_next_level_get()

const char * caps_inif_next_level_get ( const struct caps_inif_table dst,
struct caps_inif_cursor cursor 
)

Move forward to the next level in the table

Parameters
[in]dstThe INI table to handle
[in,out]cursorWhere to store the cursor info for the next query
Return values
stringName of the 'level'
NULLIn case of end of dst table reached
Note
The cursor must be already initialised via caps_inif_cursor_create()

◆ caps_inif_option_count_get()

size_t caps_inif_option_count_get ( const struct caps_inif_table dst)

Return the count of elements in the table

Parameters
[in]dstThe INI table to handle
Return values
numberElement count
0If empty

This function should help to hide internals.

◆ caps_inif_option_list_print()

void caps_inif_option_list_print ( const struct caps_inif_table dst)

Print the whole list of option entries for debugging purposes

Parameters
[in]dstThe INI table to handle

The output is done via caps_print_debug(), e.g. nothing is printed if the verbosity isn't set to 'debug' (e.g. LIBCAPS_DEBUG)