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

@@ -1,6 +1,7 @@
#include "command.h"
#include <blue/cmd.h>
#include <blue/core/btree.h>
#include <blue/object/string.h>
#include <blue/term.h>
#include <stdio.h>
@@ -20,6 +21,21 @@ enum item_type {
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 *out = malloc(sizeof *out);
@@ -34,8 +50,102 @@ struct b_command *b_command_create(unsigned int id)
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)
{
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)
@@ -45,6 +155,10 @@ b_status b_command_register(struct b_command *cmd)
return B_ERR_NAME_EXISTS;
}
if (b_btree_empty(&command_list)) {
atexit(command_list_cleanup);
}
put_command(&command_list, cmd);
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);
}
/* 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)
{
unsigned int term_width = 0;
@@ -344,13 +470,14 @@ static void print_options_list(struct b_command *cmd)
unsigned int newline_threshold = 1000000;
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");
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_foreach (&it, &cmd->b_opt) {
@@ -360,16 +487,21 @@ static void print_options_list(struct b_command *cmd)
continue;
}
b_string_clear(str);
z__b_get_option_usage_string(opt, CMD_STR_COLOUR, str);
size_t len = b_string_get_size(str, B_STRLEN_IGNORE_ESC) + 4;
b_string_clear(opt_str);
b_string_clear(desc_str);
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;
}
if (len > desb_margin) {
desb_margin = len;
if (opt_len > desb_margin) {
desb_margin = opt_len;
}
}
@@ -386,18 +518,26 @@ static void print_options_list(struct b_command *cmd)
continue;
}
b_string_clear(str);
z__b_get_option_usage_string(opt, CMD_STR_COLOUR, str);
size_t opt_len = b_string_get_size(str, B_STRLEN_IGNORE_ESC) + 4;
b_string_clear(opt_str);
b_string_clear(desc_str);
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);
}
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_left_margin = 8;
format.p_right_margin = 4;
@@ -408,23 +548,21 @@ static void print_options_list(struct b_command *cmd)
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) {
fputc(' ', OUTPUT_STREAM);
len++;
}
b_string_clear(str);
z__b_get_option_description(opt, str);
b_print_paragraph(b_string_ptr(desc_str), OUTPUT_STREAM, &format);
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
if (opt_len >= newline_threshold) {
if (new_paragraph) {
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)