fix memory leaks
This commit is contained in:
21
cmd/arg.c
21
cmd/arg.c
@@ -16,6 +16,27 @@ struct b_command_arg *b_command_arg_create(void)
|
||||
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)
|
||||
{
|
||||
char *n = b_strdup(name);
|
||||
|
||||
180
cmd/command.c
180
cmd/command.c
@@ -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)
|
||||
|
||||
@@ -73,16 +73,6 @@ struct b_command_option {
|
||||
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 {
|
||||
unsigned int arg_id;
|
||||
char *arg_name;
|
||||
@@ -94,6 +84,16 @@ struct b_command_arg {
|
||||
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(
|
||||
struct b_command *cmd, const char *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);
|
||||
|
||||
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 void b_command_arg_destroy(struct b_command_arg *arg);
|
||||
|
||||
extern struct b_arglist *b_arglist_create(void);
|
||||
extern b_status b_arglist_parse(
|
||||
struct b_arglist *args, struct b_command **cmd, int argc,
|
||||
|
||||
27
cmd/option.c
27
cmd/option.c
@@ -16,6 +16,33 @@ struct b_command_option *b_command_option_create(void)
|
||||
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(
|
||||
struct b_command_option *opt, const char *name)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user