From 126f9ae842b947d9ca9d07da2b9f817c21432010 Mon Sep 17 00:00:00 2001 From: andy5995 Date: Sat, 24 Feb 2024 15:41:35 -0600 Subject: [PATCH] Get rid of attr linked list, yet another refactor --- canfigger.c | 220 ++++++++++++++++++------------- canfigger.h | 91 ++----------- example-01.c | 9 +- tests/test_multiple_attributes.c | 15 ++- tests/test_parse_file.c | 7 +- tests/test_parse_file_colons.c | 7 +- tests/test_unicode.c | 7 +- 7 files changed, 164 insertions(+), 192 deletions(-) diff --git a/canfigger.c b/canfigger.c index 2f1cb05..e7a4037 100644 --- a/canfigger.c +++ b/canfigger.c @@ -26,51 +26,61 @@ along with this program. If not, see . #include "canfigger.h" static int err_strdup = 0; +static int canfigger_delimiter = 0; +char *canfigger_attr = NULL; +static char *grab_str_segment(char *a, char **dest, const int c); -static void -cleanup_1(char **line, FILE **fp) +struct line { - if (*line) - free(*line); - - if (fclose(*fp) != 0) - perror("canfigger->fclose:"); - - return; -} + char *line; + char *start; + char *end; +}; - -void -canfigger_free_attr(st_canfigger_attr_node **node, st_canfigger_node **key) +static void +cleanup_1(char **buf) { - while (*node) - canfigger_get_next_attr(node, key); + if (*buf) + free(*buf); return; } void -canfigger_get_next_attr(st_canfigger_attr_node **attr_node, - st_canfigger_node **key) +canfigger_get_next_attr(struct attributes *attributes) { - if (*attr_node) + if (!attributes) { - if ((*attr_node)->str) - { - free((*attr_node)->str); - (*attr_node)->str = NULL; - } + canfigger_attr = NULL; + return; + } - st_canfigger_attr_node *temp_node = (*attr_node)->next; - free(*attr_node); - *attr_node = temp_node; + if (attributes->current && attributes->ptr) + free(attributes->current); - // Replace the pointer to the head attr_node - (*key)->attr_node = *attr_node; + if (!attributes->ptr) + { + free(attributes->current); + attributes->current = NULL; + canfigger_attr = NULL; + return; } + attributes->ptr = grab_str_segment(attributes->ptr, + &attributes->current, + canfigger_delimiter); + + canfigger_attr = attributes->current; + + return; +} + +void +canfigger_init_attrs(struct attributes *attributes) +{ + canfigger_get_next_attr(attributes); return; } @@ -79,7 +89,23 @@ canfigger_get_next_key(st_canfigger_list **node) { if (*node) { - canfigger_free_attr(&(*node)->attr_node, node); + if ((*node)->attributes) + { + if ((*node)->attributes->current) + { + free((*node)->attributes->current); + (*node)->attributes->current = NULL; + } + + if ((*node)->attributes->str) + { + free((*node)->attributes->str); + (*node)->attributes->str = NULL; + } + + free((*node)->attributes); + (*node)->attributes = NULL; + } if ((*node)->value) { @@ -195,12 +221,11 @@ grab_str_segment(char *a, char **dest, const int c) return b + 1; } + static int -add_attr_node(st_canfigger_attr_node **root, - st_canfigger_attr_node **cur_node) +add_key_node(st_canfigger_node **root, st_canfigger_node **cur_node) { - st_canfigger_attr_node *tmp_node = - malloc(sizeof(struct st_canfigger_attr_node)); + st_canfigger_node *tmp_node = malloc(sizeof(struct st_canfigger_node)); if (!tmp_node) { perror("canfigger->malloc:"); @@ -218,24 +243,45 @@ add_attr_node(st_canfigger_attr_node **root, } -static int -add_key_node(st_canfigger_node **root, st_canfigger_node **cur_node) +static void +free_cur_line_and_advance(struct line *line) { - st_canfigger_node *tmp_node = malloc(sizeof(struct st_canfigger_node)); - if (!tmp_node) + free(line->line); + line->line = NULL; + line->start = line->end; + line->end = grab_str_segment(line->start, &line->line, '\n'); + + return; +} + + +static char * +read_entire_file(const char *filename) +{ + FILE *file = fopen(filename, "rb"); + if (!file) { - perror("canfigger->malloc:"); - return -1; + perror("canfigger->fopen"); + return NULL; } - if (*root) - (*cur_node)->next = tmp_node; - else - *root = tmp_node; + fseek(file, 0, SEEK_END); + long file_size = ftell(file); + fseek(file, 0, SEEK_SET); - *cur_node = tmp_node; + char *buffer = malloc(file_size + 1); + if (!buffer) + { + perror("canfigger->malloc"); + fclose(file); + return NULL; + } - return 0; + fread(buffer, 1, file_size, file); + buffer[file_size] = '\0'; + + fclose(file); + return buffer; } @@ -243,43 +289,36 @@ st_canfigger_list * canfigger_parse_file(const char *file, const int delimiter) { err_strdup = 0; + canfigger_delimiter = delimiter; st_canfigger_node *root = NULL, *cur_node = NULL; + struct line line; - FILE *fp = fopen(file, "r"); - if (!fp) - { - perror("canfigger:"); + char *file_contents = read_entire_file(file); + if (file_contents == NULL) return NULL; - } - char *line = NULL; - size_t len = 0; - ssize_t read; + line.start = file_contents; + line.line = NULL; + line.end = grab_str_segment(line.start, &line.line, '\n'); - // getline() malloc's the memory needed for line - while ((read = getline(&line, &len, fp)) != -1) + while (line.end) { - if (!line) - { - fclose(fp); - return NULL; - } - - // fprintf(stderr, "Retrieved line of length %zu:\n", read); - trim_whitespace(line); - char *a = line; + char *a = line.line; while (isspace(*a)) a = erase_lead_char(*a, a); if (*a == '\0' || *a == '#') + { + free_cur_line_and_advance(&line); continue; + } int r = add_key_node(&root, &cur_node); if (r == -1) { canfigger_free(&root); - cleanup_1(&line, &fp); + cleanup_1(&file_contents); return NULL; } @@ -289,7 +328,7 @@ canfigger_parse_file(const char *file, const int delimiter) if (err_strdup) { - cleanup_1(&line, &fp); + cleanup_1(&file_contents); return NULL; } @@ -304,52 +343,45 @@ canfigger_parse_file(const char *file, const int delimiter) if (err_strdup) { - cleanup_1(&line, &fp); + cleanup_1(&file_contents); return NULL; } - // Get attributes - cur_node->attr_node = NULL; - st_canfigger_attr_node *attr_root = NULL, *cur_attr_node = NULL; - - while (b) + // Handle attributes + if (b) { - r = add_attr_node(&attr_root, &cur_attr_node); - if (r == -1) + cur_node->attributes = malloc(sizeof(struct attributes)); + if (!cur_node->attributes) { - canfigger_free_attr(&attr_root, &cur_node); - canfigger_free(&root); - cleanup_1(&line, &fp); + perror("canfigger->malloc:"); + free_cur_line_and_advance(&line); + return NULL; } - cur_attr_node->str = NULL; - a = b; - b = grab_str_segment(a, &cur_attr_node->str, delimiter); - if (strlen(cur_attr_node->str) == 0) - fputs("error\n", stderr); - - if (cur_attr_node->str == NULL) - fputs("error\n", stderr); - - if (err_strdup) + struct attributes *attr_ptr = cur_node->attributes; + attr_ptr->current = NULL; + attr_ptr->str = strdup(b); + if (!attr_ptr->str) { - cleanup_1(&line, &fp); - return NULL; } - - cur_attr_node->next = NULL; + // Handle error + attr_ptr->ptr = attr_ptr->str; } + else + cur_node->attributes = NULL; - cur_node->attr_node = attr_root; cur_node->next = NULL; + free_cur_line_and_advance(&line); } if (!root) { - cleanup_1(&line, &fp); + cleanup_1(&file_contents); + free(line.line); return NULL; } - cleanup_1(&line, &fp); + cleanup_1(&file_contents); + free(line.line); return root; } diff --git a/canfigger.h b/canfigger.h index b6b150c..60975bd 100644 --- a/canfigger.h +++ b/canfigger.h @@ -32,99 +32,36 @@ #define CANFIGGER_VERSION "0.2.0999" #endif -/** - * @struct st_canfigger_attr_node - * @brief Represents an attribute node in a linked list. - * - * Each node contains a string (`str`) that represents the attribute itself, - * and a pointer (`next`) to the next attribute node in the list, if any. - */ -typedef struct st_canfigger_attr_node +extern char *canfigger_attr; + +struct attributes { - char *str; ///< The attribute string. - struct st_canfigger_attr_node *next; ///< Pointer to the next attribute node. -} st_canfigger_attr_node; + char *str; + char *current; + char *ptr; +}; -/** - * @struct st_canfigger_node - * @brief Represents a node in the configuration linked list. - * - * Each node contains a key-value pair (`key` and `value`), a linked list of - * attributes associated with the key (`attr_node`), and a pointer (`next`) to - * the next configuration node in the list. - */ typedef struct st_canfigger_node { char *key; ///< Key string (left of '='). - char *value; ///< Value string (between '=' and delimiter). - st_canfigger_attr_node *attr_node; ///< Linked list of attributes. + char *value; + struct attributes *attributes; struct st_canfigger_node *next; ///< Pointer to the next configuration node. } st_canfigger_node; -/** - * @brief Alias for st_canfigger_node for readability and convenience. - */ typedef st_canfigger_node st_canfigger_list; -/** - * @brief Parses a configuration file into a linked list of key-value pairs. - * - * Parses the specified file, creating a linked list where each node represents - * a key-value pair with optional attributes. The list and all associated - * resources must be freed by the caller using canfigger_free(). - * - * @param file The path to the configuration file. - * @param delimiter The character used to separate attributes in the file. - * @return A pointer to the first node in the created list, or NULL on failure. - */ + st_canfigger_list *canfigger_parse_file(const char *file, const int delimiter); /** * \example example-01.c */ -/** - * @brief Advances to the next attribute node, freeing the current one. - * - * This function is used to traverse and free a list of attribute nodes. It - * frees the current attribute node and advances the pointer to the next node - * in the list. - * - * @param attr_node A pointer to the current attribute node pointer. - */ -void canfigger_get_next_attr(st_canfigger_attr_node ** attr_node, - st_canfigger_node ** key); - -/** - * @brief Advances to the next configuration node, freeing the current one. - * - * This function is used to traverse and free a list of configuration nodes. It - * frees the current node, including its key, value, and attributes, and - * advances the pointer to the next node in the list. - * - * @param list A pointer to the current configuration node pointer. - */ void canfigger_get_next_key(st_canfigger_list ** list); -/** - * @brief Frees the entire configuration linked list. - * - * Frees all nodes in the list, including their keys, values, and attributes. - * This function should be used to release all resources allocated by - * canfigger_parse_file(). - * - * @param node A pointer to the pointer of the root node of the list. - */ -void canfigger_free(st_canfigger_node ** node); +void canfigger_get_next_attr(struct attributes *attributes); -/** - * @brief Frees an entire list of attribute nodes. - * - * Frees all attribute nodes in the list, including their strings. This - * function is typically used internally by canfigger_free() and - * canfigger_get_next_key(). - * - * @param node A pointer to the pointer of the root attribute node of the list. - */ -void canfigger_free_attr(st_canfigger_attr_node ** node, - st_canfigger_node ** key); +void canfigger_init_attrs(struct attributes *attributes); + +void canfigger_free(st_canfigger_node ** node); diff --git a/example-01.c b/example-01.c index 5c33d4a..b16a1d8 100644 --- a/example-01.c +++ b/example-01.c @@ -12,12 +12,11 @@ main(void) config->value != NULL ? config->value : "NULL"); // Process attributes if necessary - st_canfigger_attr_node *attr = config->attr_node; - - while (attr) + canfigger_init_attrs(config->attributes); + while (canfigger_attr) { - printf("Attribute: %s\n", attr->str); - canfigger_get_next_attr(&attr, &config); + printf("Attribute: %s\n", canfigger_attr); + canfigger_get_next_attr(config->attributes); } // Move to the next node and automatically free the current node diff --git a/tests/test_multiple_attributes.c b/tests/test_multiple_attributes.c index 1d67c7c..4bafe20 100644 --- a/tests/test_multiple_attributes.c +++ b/tests/test_multiple_attributes.c @@ -36,30 +36,31 @@ main(void) printf("\n\ Key: %s\n\ Value: %s\n\ -Attribute: %s\n", list->key, list->value, list->attr_node->str); +Attribute: %s\n", list->key, list->value, list->attributes->current); // assert (strcmp (data[i].key, list->key) == 0); // assert (strcmp (data[i].value, list->value) == 0); int j = 0; - while (list->attr_node != NULL) + canfigger_init_attrs(list->attributes); + while (canfigger_attr) { - fprintf(stderr, "attr: %s\n", list->attr_node->str); + fprintf(stderr, "attr: %s\n", list->attributes->current); switch (i) { case 0: - assert(strcmp(data1[j], list->attr_node->str) == 0); + assert(strcmp(data1[j], list->attributes->current) == 0); break; case 1: - assert(strcmp(data2[j], list->attr_node->str) == 0); + assert(strcmp(data2[j], list->attributes->current) == 0); break; case 2: - assert(strcmp(data3[j], list->attr_node->str) == 0); + assert(strcmp(data3[j], list->attributes->current) == 0); break; } j++; - canfigger_get_next_attr(&list->attr_node, &list); + canfigger_get_next_attr(list->attributes); } fprintf(stderr, "j: %d\n", j); diff --git a/tests/test_parse_file.c b/tests/test_parse_file.c index e42cd23..3c05899 100644 --- a/tests/test_parse_file.c +++ b/tests/test_parse_file.c @@ -35,20 +35,21 @@ main(void) int i = 0; while (list) { + canfigger_init_attrs(list->attributes); fprintf(stderr, "\n\ Key: %s | Expected: %s\n\ Value: %s | Expected: %s\n\ -Attribute: %s | Expected: %s\n", list->key, data[i].key, list->value != NULL ? list->value : "NULL", data[i].value, list->attr_node != NULL ? list->attr_node->str : "NULL", data[i].attribute); +Attribute: %s | Expected: %s\n", list->key, data[i].key, list->value != NULL ? list->value : "NULL", data[i].value, list->attributes != NULL ? list->attributes->current : "NULL", data[i].attribute); assert(strcmp(data[i].key, list->key) == 0); assert(strcmp (data[i].value != NULL ? data[i].value : "NULL", list->value != NULL ? list->value : "NULL") == 0); fprintf(stderr, "attr: %s\n", - list->attr_node != NULL ? list->attr_node->str : "NULL"); + list->attributes != NULL ? list->attributes->current : "NULL"); assert(strcmp (data[i].attribute != NULL ? data[i].attribute : "NULL", - list->attr_node != NULL ? list->attr_node->str : "NULL") == 0); + list->attributes != NULL ? list->attributes->current : "NULL") == 0); i++; canfigger_get_next_key(&list); diff --git a/tests/test_parse_file_colons.c b/tests/test_parse_file_colons.c index fd4c7d3..1e6bdd2 100644 --- a/tests/test_parse_file_colons.c +++ b/tests/test_parse_file_colons.c @@ -26,16 +26,17 @@ main(void) int i = 0; while (list != NULL) { + canfigger_init_attrs(list->attributes); printf("\n\ Key: %s\n\ Value: %s\n\ -Attribute: %s\n", list->key, list->value, list->attr_node->str); +Attribute: %s\n", list->key, list->value, list->attributes->current); assert(strcmp(data[i].key, list->key) == 0); // printf ("value = '%s' '%s'\n", data[i].value, list->value); assert(strcmp(data[i].value, list->value) == 0); - fprintf(stderr, "attr: %s\n", list->attr_node->str); - assert(strcmp(data[i].attribute, list->attr_node->str) == 0); + fprintf(stderr, "attr: %s\n", list->attributes->current); + assert(strcmp(data[i].attribute, list->attributes->current) == 0); i++; canfigger_get_next_key(&list); diff --git a/tests/test_unicode.c b/tests/test_unicode.c index c30c15a..0dd61e8 100644 --- a/tests/test_unicode.c +++ b/tests/test_unicode.c @@ -33,20 +33,21 @@ main(void) int i = 0; while (list) { + canfigger_init_attrs(list->attributes); printf("\n\ Key: %s\n\ Value: %s\n\ -Attribute: %s\n", list->key, list->value != NULL ? list->value : "NULL", list->attr_node != NULL ? list->attr_node->str : "NULL"); +Attribute: %s\n", list->key, list->value != NULL ? list->value : "NULL", list->attributes != NULL ? list->attributes->current : "NULL"); assert(strcmp(data[i].key, list->key) == 0); assert(strcmp (data[i].value != NULL ? data[i].value : "NULL", list->value != NULL ? list->value : "NULL") == 0); fprintf(stderr, "attr: %s\n", - list->attr_node != NULL ? list->attr_node->str : NULL); + list->attributes != NULL ? list->attributes->current : NULL); assert(strcmp (data[i].attribute != NULL ? data[i].attribute : "NULL", - list->attr_node != NULL ? list->attr_node->str : "NULL") == 0); + list->attributes != NULL ? list->attributes->current : "NULL") == 0); i++; canfigger_get_next_key(&list);