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;
|
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);
|
||||||
|
|||||||
180
cmd/command.c
180
cmd/command.c
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
27
cmd/option.c
27
cmd/option.c
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user