fix memory leaks

This commit is contained in:
2024-10-27 19:43:05 +00:00
parent a86291ca75
commit 87d8767d11
9 changed files with 236 additions and 35 deletions

View File

@@ -16,6 +16,27 @@ struct b_command_arg *b_command_arg_create(void)
return out; return out;
} }
void b_command_arg_destroy(struct b_command_arg *arg)
{
if (arg->arg_name) {
free(arg->arg_name);
}
if (arg->arg_description) {
free(arg->arg_description);
}
if (arg->arg_allowed_values) {
for (unsigned int i = 0; arg->arg_allowed_values[i]; i++) {
free(arg->arg_allowed_values[i]);
}
free(arg->arg_allowed_values);
}
free(arg);
}
b_status b_command_arg_set_name(struct b_command_arg *arg, const char *name) b_status b_command_arg_set_name(struct b_command_arg *arg, const char *name)
{ {
char *n = b_strdup(name); char *n = b_strdup(name);

View File

@@ -1,6 +1,7 @@
#include "command.h" #include "command.h"
#include <blue/cmd.h> #include <blue/cmd.h>
#include <blue/core/btree.h>
#include <blue/object/string.h> #include <blue/object/string.h>
#include <blue/term.h> #include <blue/term.h>
#include <stdio.h> #include <stdio.h>
@@ -20,6 +21,21 @@ enum item_type {
ITEM_SUBCOMMAND, ITEM_SUBCOMMAND,
}; };
static void command_list_cleanup(void)
{
struct b_btree_iterator it = {0};
b_btree_iterator_begin(&command_list, &it);
while (b_btree_iterator_is_valid(&it)) {
struct b_command *cmd = b_unbox(struct b_command, it.node, b_node);
if (!cmd) {
break;
}
b_btree_iterator_erase(&it);
b_command_destroy(cmd);
}
}
struct b_command *b_command_create(unsigned int id) struct b_command *b_command_create(unsigned int id)
{ {
struct b_command *out = malloc(sizeof *out); struct b_command *out = malloc(sizeof *out);
@@ -34,8 +50,102 @@ struct b_command *b_command_create(unsigned int id)
return out; return out;
} }
static void command_usage_destroy(struct b_command_usage *usage)
{
struct b_queue_iterator it = {0};
b_queue_iterator_begin(&usage->u_arg, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_usage_arg *arg = b_unbox(
struct b_command_usage_arg, it.entry, arg_entry);
if (!arg) {
continue;
}
b_queue_iterator_erase(&it);
free(arg);
}
b_queue_iterator_begin(&usage->u_opt, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_usage_opt *opt = b_unbox(
struct b_command_usage_opt, it.entry, opt_entry);
if (!opt) {
continue;
}
b_queue_iterator_erase(&it);
free(opt);
}
free(usage);
}
void b_command_destroy(struct b_command *cmd) void b_command_destroy(struct b_command *cmd)
{ {
struct b_queue_iterator it = {0};
if (cmd->b_name) {
free(cmd->b_name);
}
if (cmd->b_long_name) {
free(cmd->b_long_name);
}
if (cmd->b_description) {
free(cmd->b_description);
}
b_queue_iterator_begin(&cmd->b_opt, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_option *opt
= b_unbox(struct b_command_option, it.entry, opt_entry);
if (!opt) {
break;
}
b_queue_iterator_erase(&it);
b_command_option_destroy(opt);
}
b_queue_iterator_begin(&cmd->b_arg, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_arg *arg
= b_unbox(struct b_command_arg, it.entry, arg_entry);
if (!arg) {
break;
}
b_queue_iterator_erase(&it);
b_command_arg_destroy(arg);
}
b_queue_iterator_begin(&cmd->b_arg, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command *subcmd
= b_unbox(struct b_command, it.entry, b_entry);
if (!subcmd) {
break;
}
b_queue_iterator_erase(&it);
b_command_destroy(subcmd);
}
b_queue_iterator_begin(&cmd->b_usage, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_usage *usage
= b_unbox(struct b_command_usage, it.entry, u_entry);
if (!usage) {
break;
}
b_queue_iterator_erase(&it);
command_usage_destroy(usage);
}
free(cmd);
} }
b_status b_command_register(struct b_command *cmd) b_status b_command_register(struct b_command *cmd)
@@ -45,6 +155,10 @@ b_status b_command_register(struct b_command *cmd)
return B_ERR_NAME_EXISTS; return B_ERR_NAME_EXISTS;
} }
if (b_btree_empty(&command_list)) {
atexit(command_list_cleanup);
}
put_command(&command_list, cmd); put_command(&command_list, cmd);
return B_SUCCESS; return B_SUCCESS;
} }
@@ -336,6 +450,18 @@ static void get_command_description(struct b_command *cmd, b_string *out)
b_string_append_cstr(out, cmd->b_description); b_string_append_cstr(out, cmd->b_description);
} }
/* criteria for printing the option description on a separate line:
* 1) the length of the usage string exceeds the newline threshold; and
* 2) the length of the description string exceeds the remaining line length
* (once the usage string has been printed.
* or,
* 3) the length of the description string is more than three terminal lines.
*/
#define description_on_separate_line(opt_len, desc_len) \
((opt_len >= newline_threshold \
&& desc_len >= (term_width - newline_threshold)) \
|| desc_len > (3 * term_width - newline_threshold))
static void print_options_list(struct b_command *cmd) static void print_options_list(struct b_command *cmd)
{ {
unsigned int term_width = 0; unsigned int term_width = 0;
@@ -344,13 +470,14 @@ static void print_options_list(struct b_command *cmd)
unsigned int newline_threshold = 1000000; unsigned int newline_threshold = 1000000;
if (term_width) { if (term_width) {
newline_threshold = term_width - 12 - 25; newline_threshold = term_width - 12 - 35;
} }
b_fprintf(OUTPUT_STREAM, "\n" F_YELLOW "OPTIONS:" F_RESET "\n"); b_fprintf(OUTPUT_STREAM, "\n" F_YELLOW "OPTIONS:" F_RESET "\n");
size_t desb_margin = 0; size_t desb_margin = 0;
b_string *str = b_string_create(); b_string *opt_str = b_string_create();
b_string *desc_str = b_string_create();
b_queue_iterator it; b_queue_iterator it;
b_queue_foreach (&it, &cmd->b_opt) { b_queue_foreach (&it, &cmd->b_opt) {
@@ -360,16 +487,21 @@ static void print_options_list(struct b_command *cmd)
continue; continue;
} }
b_string_clear(str); b_string_clear(opt_str);
z__b_get_option_usage_string(opt, CMD_STR_COLOUR, str); b_string_clear(desc_str);
size_t len = b_string_get_size(str, B_STRLEN_IGNORE_ESC) + 4; z__b_get_option_usage_string(opt, CMD_STR_COLOUR, opt_str);
z__b_get_option_description(opt, desc_str);
if (len >= newline_threshold) { size_t opt_len
= b_string_get_size(opt_str, B_STRLEN_IGNORE_ESC) + 4;
size_t desc_len = b_string_get_size(desc_str, B_STRLEN_IGNORE_ESC);
if (description_on_separate_line(opt_len, desc_len)) {
continue; continue;
} }
if (len > desb_margin) { if (opt_len > desb_margin) {
desb_margin = len; desb_margin = opt_len;
} }
} }
@@ -386,18 +518,26 @@ static void print_options_list(struct b_command *cmd)
continue; continue;
} }
b_string_clear(str); b_string_clear(opt_str);
z__b_get_option_usage_string(opt, CMD_STR_COLOUR, str); b_string_clear(desc_str);
size_t opt_len = b_string_get_size(str, B_STRLEN_IGNORE_ESC) + 4;
if (opt_len >= newline_threshold) { z__b_get_option_usage_string(opt, CMD_STR_COLOUR, opt_str);
z__b_get_option_description(opt, desc_str);
size_t opt_len
= b_string_get_size(opt_str, B_STRLEN_IGNORE_ESC) + 4;
size_t desc_len = b_string_get_size(desc_str, B_STRLEN_IGNORE_ESC);
bool new_paragraph
= description_on_separate_line(opt_len, desc_len);
if (new_paragraph) {
fputc('\n', OUTPUT_STREAM); fputc('\n', OUTPUT_STREAM);
} }
fputs(" ", OUTPUT_STREAM); fputs(" ", OUTPUT_STREAM);
b_fputs(b_string_ptr(str), OUTPUT_STREAM); b_fputs(b_string_ptr(opt_str), OUTPUT_STREAM);
if (opt_len >= newline_threshold) { if (new_paragraph) {
format.p_flags = 0; format.p_flags = 0;
format.p_left_margin = 8; format.p_left_margin = 8;
format.p_right_margin = 4; format.p_right_margin = 4;
@@ -408,23 +548,21 @@ static void print_options_list(struct b_command *cmd)
format.p_right_margin = 4; format.p_right_margin = 4;
} }
unsigned int len = b_string_get_size(str, B_STRLEN_IGNORE_ESC) + 4; unsigned int len = opt_len;
while (len < format.p_left_margin) { while (len < format.p_left_margin) {
fputc(' ', OUTPUT_STREAM); fputc(' ', OUTPUT_STREAM);
len++; len++;
} }
b_string_clear(str); b_print_paragraph(b_string_ptr(desc_str), OUTPUT_STREAM, &format);
z__b_get_option_description(opt, str);
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format); if (new_paragraph) {
if (opt_len >= newline_threshold) {
fputc('\n', OUTPUT_STREAM); fputc('\n', OUTPUT_STREAM);
} }
} }
b_string_release(str); b_string_release(opt_str);
b_string_release(desc_str);
} }
static void print_args_list(struct b_command *cmd) static void print_args_list(struct b_command *cmd)

View File

@@ -73,16 +73,6 @@ struct b_command_option {
struct b_queue_entry opt_entry; struct b_queue_entry opt_entry;
}; };
struct b_arglist_option {
unsigned int opt_id;
struct b_btree opt_values;
struct b_btree_node opt_node;
};
struct b_arglist {
struct b_btree list_options;
};
struct b_command_arg { struct b_command_arg {
unsigned int arg_id; unsigned int arg_id;
char *arg_name; char *arg_name;
@@ -94,6 +84,16 @@ struct b_command_arg {
struct b_queue_entry arg_entry; struct b_queue_entry arg_entry;
}; };
struct b_arglist_option {
unsigned int opt_id;
struct b_btree opt_values;
struct b_btree_node opt_node;
};
struct b_arglist {
struct b_btree list_options;
};
extern struct b_command *b_command_get_subcommand_with_name( extern struct b_command *b_command_get_subcommand_with_name(
struct b_command *cmd, const char *name); struct b_command *cmd, const char *name);
extern struct b_command *b_command_get_subcommand_with_long_name( extern struct b_command *b_command_get_subcommand_with_long_name(
@@ -107,7 +107,11 @@ extern struct b_command_option *b_command_get_option_with_short_name(
struct b_command *cmd, char short_name); struct b_command *cmd, char short_name);
extern struct b_command_option *b_command_option_create(void); extern struct b_command_option *b_command_option_create(void);
extern void b_command_option_destroy(struct b_command_option *opt);
extern struct b_command_arg *b_command_arg_create(void); extern struct b_command_arg *b_command_arg_create(void);
extern void b_command_arg_destroy(struct b_command_arg *arg);
extern struct b_arglist *b_arglist_create(void); extern struct b_arglist *b_arglist_create(void);
extern b_status b_arglist_parse( extern b_status b_arglist_parse(
struct b_arglist *args, struct b_command **cmd, int argc, struct b_arglist *args, struct b_command **cmd, int argc,

View File

@@ -16,6 +16,33 @@ struct b_command_option *b_command_option_create(void)
return out; return out;
} }
void b_command_option_destroy(struct b_command_option *opt)
{
if (opt->opt_long_name) {
free(opt->opt_long_name);
}
if (opt->opt_description) {
free(opt->opt_description);
}
b_queue_iterator it = {0};
b_queue_iterator_begin(&opt->opt_args, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_arg *arg
= b_unbox(struct b_command_arg, it.entry, arg_entry);
if (!arg) {
break;
}
b_queue_iterator_erase(&it);
b_command_arg_destroy(arg);
}
free(opt);
}
b_status b_command_option_set_long_name( b_status b_command_option_set_long_name(
struct b_command_option *opt, const char *name) struct b_command_option *opt, const char *name)
{ {

View File

@@ -7,15 +7,19 @@ CuSuite *get_all_tests(void);
int RunAllTests(void) int RunAllTests(void)
{ {
CuString *output = CuStringNew(); CuString *output = CuStringNew();
CuSuite *suite = CuSuiteNew(); CuSuite *suite = get_all_tests();
CuSuiteAddSuite(suite, get_all_tests());
CuSuiteRun(suite); CuSuiteRun(suite);
CuSuiteSummary(suite, output); CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output); CuSuiteDetails(suite, output);
printf("%s\n", output->buffer); printf("%s\n", output->buffer);
return suite->failCount;
int r = suite->failCount;
CuSuiteDelete(suite);
CuStringDelete(output);
return r;
} }
int main(void) int main(void)

View File

@@ -15,5 +15,6 @@ int main(void)
printf("object %p\n", it.value); printf("object %p\n", it.value);
} }
b_array_release(array);
return 0; return 0;
} }

View File

@@ -6,5 +6,6 @@ int main(void)
b_number *number = b_number_create_float(6.8); b_number *number = b_number_create_float(6.8);
printf("number=%zd\n", B_NUMBER_IVAL(number)); printf("number=%zd\n", B_NUMBER_IVAL(number));
b_number_release(number);
return 0; return 0;
} }

View File

@@ -112,5 +112,8 @@ int main(void)
printf("%d\n", item->value); printf("%d\n", item->value);
} }
b_tree_release(tree);
b_dict_release(dict);
return 0; return 0;
} }

View File

@@ -8,5 +8,7 @@ int main(void)
char str[B_UUID_STRING_MAX]; char str[B_UUID_STRING_MAX];
b_uuid_to_cstr(uuid, str); b_uuid_to_cstr(uuid, str);
printf("%s\n", str); printf("%s\n", str);
b_uuid_release(uuid);
return 0; return 0;
} }