diff options
| author | Clecio Jung | 2023-03-18 20:43:43 -0300 |
|---|---|---|
| committer | Clecio Jung | 2023-03-18 20:43:43 -0300 |
| commit | 0113ec2c4358a5a6f4ad473372a63d2aa3c249c0 (patch) | |
| tree | 18c1faa2ccebd38ca28511597cdbf031fc69e16b | |
| parent | a3942b3241189a003414874a96732e373e63ccae (diff) | |
| download | libini-0113ec2c4358a5a6f4ad473372a63d2aa3c249c0.tar.xz libini-0113ec2c4358a5a6f4ad473372a63d2aa3c249c0.tar.zst | |
Improve parsing
| -rw-r--r-- | README.md | 12 | ||||
| -rw-r--r-- | examples/cfg.ini | 56 | ||||
| -rw-r--r-- | examples/incorrect.ini | 5 | ||||
| -rw-r--r-- | ini_file.c | 75 | ||||
| -rw-r--r-- | ini_file.h | 11 |
5 files changed, 117 insertions, 42 deletions
@@ -31,18 +31,30 @@ This library provides a set of functions for reading and writing INI files. Here int main(const int argc, const char **const argv) { struct Ini_File *ini_file; + + // Check that the user provided an argument specifying the INI file name if (argc < 2) { fprintf(stderr, "Usage: %s ini_file_name\n", argv[0]); return EXIT_FAILURE; } + + // Parse the INI file and store the resulting data structure in a variable ini_file = ini_file_parse(argv[1], NULL); + + // Check that the INI file was parsed successfully if (ini_file == NULL) { fprintf(stderr, "Was not possible to parse the ini_file \"%s\"\n", argv[1]); return EXIT_FAILURE; } + + // Print the properties from the INI file to the console printf("\nThe properties retrieved from the the ini file \"%s\" are:\n\n", argv[1]); ini_file_print_to(ini_file, stdout); + + // Free the memory used by the INI file data structure ini_file_free(ini_file); + + // Return 0 to indicate success return EXIT_SUCCESS; } ``` diff --git a/examples/cfg.ini b/examples/cfg.ini new file mode 100644 index 0000000..ae0ae42 --- /dev/null +++ b/examples/cfg.ini @@ -0,0 +1,56 @@ +[InitialConfiguration] +;Optional, display language can only be one of the installed language +Language=en-us +;Optional, The name of a script that runs after setupComplete.cmd but before the initial configuration begins. +;Optional +Locale=en-us +;Optional +Country=US +;Optional +Keyboard=0409:00000409 +AcceptEula=true +;This is only required on a server where an OEM EULA has been specified +;by using the OOBE.xml file +AcceptOEMEula=true +;Optional. Example: My Company Name +CompanyName=EnterCompanyName +ServerName=EnterServerName +; Example: CONTOSO +NetbiosName=EnterNetbiosDomainName +; Example: contoso.local +DNSName=EnterDNSDomain +; Used to set the user name for the domain admin +UserName=EnterDomainAdminUserName +;The password has to be strong and at least 8 characters +PlainTextPassword=EnterAdminPassword +;. Used to set the user name for the domain standard user account. Ignored in migration mode. +StdUserName=EnterDomainStandardUserName +;. The password for the domain standard user account has to be strong and at least 8 characters +StdUserPlainTextPassword=EnterStandardUserPassword +;Controls the Watson and automatic update settings +Settings=All or Updates or None +WebDomainName=www.abc.com +TrustedCertFileName=c:\cert\a.pfx +TrustedCertPassword=Enteryourpassword +EnableVPN=true +EnableRWA=true +IPv4DNSForwarder=<IPV4Address,IPV4Address,¦> +IPv6DNSForwarder=<IPV6Address,IPV6Address,¦> +VpnIPv4StartAddress=<IPV4Address> +VpnIPv4EndAddress=<IPV4Address> +VpnBaseIPv6Address=<IPV6Address> +VpnIPv6PrefixLength=<number> +;All these section are optional. + [PostOSInstall] +;Optional, The name of a script that runs after setupComplete.cmd but before the initial configuration begins. + +IsHosted=true +StaticIPv4Address=<IPV4Address> +StaticIPv4Gateway=<IPV4Address> +StaticIPv4SubnetMask=<IPV4SubnetMask> +StaticIPv6Address=<IPV6Address> +StaticIPv6SubnetPrefixLength=<number> +StaticIPv6Gateway=<IPV6Address> +ClientBackupOn=true +FileHistoryOn=true +LaunchPadHiddenTasks=<Microsoft.LaunchPad.AdminDashboard,Microsoft.LaunchPad.Backup>
\ No newline at end of file diff --git a/examples/incorrect.ini b/examples/incorrect.ini index 317ce8a..42dd5f2 100644 --- a/examples/incorrect.ini +++ b/examples/incorrect.ini @@ -10,6 +10,11 @@ a = 1 test=2 beta=96 +# We allow for spaces and special characters inside values, but not on keys +erro r = 56 +correct = al bel gam + +# Section names can have special characters and spaces [ section 2 ] test2 = 65 a = ; 15 @@ -27,9 +27,9 @@ size_t get_file_size(FILE *const file) { } /* Remember to free the memory allocated for the returned string */ -char *get_content_from_file(const char *const file_name) { +char *get_content_from_file(const char *const filename) { char *buffer = NULL; - FILE *const file = fopen(file_name, "rb"); + FILE *const file = fopen(filename, "rb"); if (file != NULL) { const size_t file_size = get_file_size(file); /* Allocate memory to store the entire file */ @@ -101,12 +101,19 @@ void ini_section_print_to(const struct Ini_Section *const ini_section, FILE *con } void ini_file_print_to(const struct Ini_File *const ini_file, FILE *const sink) { - size_t section_index; + size_t section_index, property_index; if (ini_file == NULL) { return; } for (section_index = 0; section_index < ini_file->sections_size; section_index++) { - ini_section_print_to(&ini_file->sections[section_index], sink); + if (section_index != 0) { + fprintf(sink, "[%s]\n", ini_file->sections[section_index].name); + } + for (property_index = 0; property_index < ini_file->sections[section_index].properties_size; property_index++) { + fprintf(sink, "%s = %s\n", + ini_file->sections[section_index].properties[property_index].key, + ini_file->sections[section_index].properties[property_index].value); + } putchar('\n'); } } @@ -119,7 +126,9 @@ char *ini_file_error_to_string(const enum Ini_File_Errors error) { "Couldn't open file", "Expected closing square bracket ']'", "Expected equals sign '='", - "Expected a value, but found a comment", + "A section name was not provided", + "A key was not provided", + "A value was not provided", "Didn't found the requested section", "Didn't found the requested property", "The requested property is not a valid integer number", @@ -166,10 +175,7 @@ static int ini_file_parse_handle_error(Ini_File_Error_Callback callback, const c } /* TODO: Check for repeated section and key names? */ -/* TODO: Check for spaces inside of section and key names? */ /* TODO: Sort the sections and keys? This would allow us to use binary search */ -/* TODO: we could allow keys and values to be strings delimited by "" or '', - * which would allow us to use the characters "=,#,;" inside keys and values */ /* Remember to free the memory allocated for the returned ini file structure */ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callback callback) { @@ -204,14 +210,14 @@ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callb cursor++; advance_white_spaces(&cursor); name = cursor; - advance_string_until(&cursor, "]#;\n"); + advance_string_until(&cursor, "]#;\r\n"); if (*cursor != ']') { if (ini_file_parse_handle_error(callback, filename, line_number, line, ini_expected_clocing_bracket) != 0) { goto ini_file_parse_error; } continue; } - /* Compute length of the key string and remove trailing whitespaces */ + /* Compute length of the name string and remove trailing whitespaces */ name_len = (size_t)(cursor - name); while ((name_len > 0) && (isspace((unsigned char)name[name_len - 1]))) { name_len--; @@ -226,35 +232,20 @@ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callb continue; } key = cursor; - advance_string_until(&cursor, "=#;\n"); + advance_string_until(&cursor, "=#; \t\r\n"); + /* Compute length of the string name */ + key_len = (size_t)(cursor - key); + advance_white_spaces(&cursor); if (*cursor != '=') { - /* Found an error, so we report it to the user using the callback provided. - * In case of an error, if the callback returns an integer different from zero, - * we end the parsing and return NULL. */ if (ini_file_parse_handle_error(callback, filename, line_number, line, ini_expected_equals) != 0) { goto ini_file_parse_error; } continue; } - /* Compute length of the key string and remove trailing whitespaces */ - key_len = (size_t)(cursor - key); - while ((key_len > 0) && (isspace((unsigned char)key[key_len - 1]))) { - key_len--; - } cursor++; advance_white_spaces(&cursor); - /* If it is a commment, we found an error */ - if (strchr("#;", *cursor) != NULL) { - /* Found an error, so we report it to the user using the callback provided. - * In case of an error, if the callback returns an integer different from zero, - * we end the parsing and return NULL. */ - if (ini_file_parse_handle_error(callback, filename, line_number, line, ini_expected_value_got_comment) != 0) { - goto ini_file_parse_error; - } - continue; - } value = cursor; - advance_string_until(&cursor, "#;\n"); + advance_string_until(&cursor, "#;\r\n"); /* Compute length of the value string and remove trailing whitespaces */ value_len = (size_t)(cursor - value); while ((value_len > 0) && (isspace((unsigned char)value[value_len - 1]))) { @@ -277,11 +268,11 @@ ini_file_parse_error: enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len) { struct Ini_Section *section; - if ((ini_file == NULL) || (name == NULL)) { + if (ini_file == NULL) { return ini_invalid_parameters; } - if (name_len == 0) { - return ini_invalid_parameters; + if ((name == NULL) || (name_len == 0)) { + return ini_section_not_provided; } if ((ini_file->sections_size + 1) >= ini_file->sections_capacity) { const size_t new_cap = 2 * ini_file->sections_capacity; @@ -310,7 +301,7 @@ enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name) { if (name == NULL) { - return ini_invalid_parameters; + return ini_section_not_provided; } return ini_file_add_section_sized(ini_file, name, strlen(name)); } @@ -318,11 +309,14 @@ enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len) { struct Ini_Section *section; struct Key_Value_Pair *property; - if ((ini_file == NULL) || (key == NULL) || (value == NULL)) { + if (ini_file == NULL) { return ini_invalid_parameters; } - if ((key_len == 0) || (value_len == 0)) { - return ini_invalid_parameters; + if ((key == NULL) || (key_len == 0)) { + return ini_key_not_provided; + } + if ((value == NULL) || (value_len == 0)) { + return ini_value_not_provided; } if (ini_file->sections_size == 0) { return ini_allocation; @@ -353,8 +347,11 @@ enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file } enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value) { - if ((key == NULL) || (value == NULL)) { - return ini_invalid_parameters; + if (key == NULL) { + return ini_key_not_provided; + } + if (value == NULL) { + return ini_value_not_provided; } return ini_file_add_property_sized(ini_file, key, strlen(key), value, strlen(value)); } @@ -54,7 +54,9 @@ enum Ini_File_Errors { ini_couldnt_open_file, ini_expected_clocing_bracket, ini_expected_equals, - ini_expected_value_got_comment, + ini_section_not_provided, + ini_key_not_provided, + ini_value_not_provided, ini_no_such_section, ini_no_such_property, ini_not_integer, @@ -70,7 +72,7 @@ typedef int (*Ini_File_Error_Callback)(const char *const filename, const size_t size_t get_file_size(FILE *const file); /* Remember to free the memory allocated for the returned string */ -char *get_content_from_file(const char *const file_name); +char *get_content_from_file(const char *const filename); struct Ini_File *ini_file_new(void); void ini_file_free(struct Ini_File *const ini_file); @@ -81,12 +83,15 @@ char *ini_file_error_to_string(const enum Ini_File_Errors error); /* Remember to free the memory allocated for the returned ini file structure */ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callback callback); -/* These functions returns (ini_no_error = 0) if everything worked correctly */ +/* These functions returns ini_no_error = 0 if everything worked correctly */ enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len); enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name); enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len); enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value); enum Ini_File_Errors ini_file_save(const struct Ini_File *const ini_file, const char *const filename); + +/* These functions use sequential search algorithm to find the requested section and properties */ +/* These functions returns ini_no_error = 0 if everything worked correctly */ enum Ini_File_Errors ini_file_find_section(struct Ini_File *const ini_file, const char *const section, struct Ini_Section **ini_section); enum Ini_File_Errors ini_file_find_property(struct Ini_File *const ini_file, const char *const section, const char *const key, char **value); enum Ini_File_Errors ini_file_find_integer(struct Ini_File *const ini_file, const char *const section, const char *const key, long *integer); |
