CAPS Universe documentation
1.0.4
All you need to know to be successful
|
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_lock * | caps_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_cursor * | caps_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) |
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:
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:
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:
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:
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.
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.
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:
1-this.ini
2-that.ini
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.
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:
void caps_libinif_init | ( | void | ) |
Initialize the library prior use
void caps_inif_table_init | ( | struct caps_inif_table * | dst | ) |
Initialize a table to store INI information
[in,out] | dst | Pointer to key/value table |
void caps_inif_table_cleanup | ( | struct caps_inif_table * | dst | ) |
Free all resources in the table
[in,out] | dst | Pointer to key/value table |
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
[in,out] | dst | Pointer to INI table |
[in] | level | Name of the level these entries correspond to (can be NULL) |
[in] | file_name | Full path and name of INI file to be read |
0 | on success |
-EACCES | Access to ini_file is not allowed |
-ENOENT | No such file or directory |
-EINVAL | INI 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
).
file_name
or the section/key read from the INI file already exists at level
in dst
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
[in,out] | dst | Pointer to INI table |
[in] | level | Name of the level these entries correspond to (can be NULL) |
[in] | file_name | Full path and name of INI file to be read |
pointer | Pointer to transparent lock info |
NULL | In 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.
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
[in] | dst | Pointer to INI table |
[in] | li | Pointer to transparent info caps_inif_locked_file_read() call |
0 | On success |
negative | errno |
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.
void caps_inif_locked_file_close | ( | struct caps_inif_lock * | li | ) |
Close and unlock a read INI file
[in] | li | Pointer 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
.
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
[in,out] | dst | The INI table to store the result to |
[in] | level | Name of the level these entries correspond to (can be NULL) |
[in] | dir | Directory where to load the INI files from |
0 | On success |
-ENOENT | The path in dir doesn't exist |
-ENOTDIR | The path in dir isn't a directory |
-EACCES | Access to dir or it's file(s) is not allowed |
-EINVAL | One 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.
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.
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
[in,out] | dst | The INI table to store the result to |
[in] | level | Name of the level these entries correspond to (can be NULL) |
[in] | dir | Directory where to load the INI files from |
0 | On success |
-ENOENT | The path in dir doesn't exist |
-ENOTDIR | The path in dir isn't a directory |
-EACCES | Access to dir or it's file(s) is not allowed |
-EINVAL | One 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).
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.
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
[in,out] | dst | The INI table to store the result to |
[in] | level | Name of the level these entries correspond to |
[in] | ini_file | Name of the INI file to merge (FQP) |
0 | On success |
-EACCES | Access to ini_file is not allowed |
-ENOENT | No such file or directory |
-EINVAL | INI file file_name contains an error |
This will replace existing entries at the same level
or add new entries into dst
.
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
[in] | dst | The INI table to search in |
[in] | level | First part of the key triple (can be NULL) |
[in] | section | Second part of the key triple (can be NULL) |
[in] | key | Third part of the key triple |
string | Pointer to the key's value |
NULL | If the key does not exist |
The returned value is predictable only, if all three (e.g. level, section and key) components are given. Else:
level
is NULL, the first match of section
and key
is returned.section
is NULL, the first match of level
and key
is returned.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.
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
[in] | dst | The INI entry table to add the new entry to |
[in] | level | First part of the key triple (can be NULL) |
[in] | section | Second part of the key triple (can be NULL) |
[in] | key | Third part of the key triple |
[in] | val | The value to be set (can be NULL) |
0 | New level/section/key/value added to dst |
-EINVAL | Level/section/key already has a value |
val
of NULL let the key
be of boolean type, e.g. if it exists, it returns a 'true' later on val!
struct caps_inif_cursor * caps_inif_cursor_create | ( | void | ) |
Create a cursor to walk through a table
void caps_inif_cursor_destroy | ( | struct caps_inif_cursor * | cursor | ) |
Destroy a cursor to walk through a table
[in] | cursor | What to destroy |
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
[in] | dst | The INI table to handle |
[in,out] | cursor | Where to store the cursor info for the next query |
string | Name of the 'key' |
NULL | In case of end of section , end of level or end of dst table reached |
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
[in] | dst | The INI table to handle |
[in,out] | cursor | Where to store the cursor info for the next query |
string | Name of the 'section' |
NULL | In case of end of level or end of dst table reached |
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
[in] | dst | The INI table to handle |
[in,out] | cursor | Where to store the cursor info for the next query |
string | Name of the 'level' |
NULL | In case of end of dst table reached |
size_t caps_inif_option_count_get | ( | const struct caps_inif_table * | dst | ) |
Return the count of elements in the table
[in] | dst | The INI table to handle |
number | Element count |
0 | If empty |
This function should help to hide internals.
void caps_inif_option_list_print | ( | const struct caps_inif_table * | dst | ) |
Print the whole list of option entries for debugging purposes
[in] | dst | The 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)