Compare commits
26 Commits
734c80c527
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 84df46489a | |||
| 0d5a186d80 | |||
| 2632feac32 | |||
| f5c4fa561f | |||
| 5639aefd61 | |||
| 30a9db17dc | |||
| ce50cfd18b | |||
| 9b48fc2b45 | |||
| 5889426478 | |||
| c13b7a7e3a | |||
| 23aba2a27f | |||
| bdcd4163c7 | |||
| add05ef478 | |||
| 68ab79fe2a | |||
| ce9195c130 | |||
| 837a42e249 | |||
| d14a1fc61f | |||
| 6b65727535 | |||
| 5c6030488b | |||
| bd2fe50ec9 | |||
| a68b9f7ba7 | |||
| 9e21e0c4b2 | |||
| 5d3a987b0e | |||
| ec500c04ad | |||
| c94f976751 | |||
| 3db808d4c4 |
@@ -4,7 +4,6 @@ IndentWidth: 8
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ReferenceAlignment: Left
|
||||
ColumnLimit: 80
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
@@ -53,9 +52,67 @@ PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- BLUE_API
|
||||
- BLUELIB_API
|
||||
ForEachMacros:
|
||||
- b_btree_foreach
|
||||
- b_queue_foreach
|
||||
MacroBlockBegin: "^B_(TYPE|PARAM)_.*_BEGIN$"
|
||||
MacroBlockEnd: "^B_(TYPE|PARAM)_.*_END$"
|
||||
MacroBlockBegin: "B_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "B_TYPE_.*_END"
|
||||
---
|
||||
Language: ObjC
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
BreakBeforeBraces: Linux
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
IncludeBlocks: Regroup
|
||||
SortIncludes: true
|
||||
IndentRequires: true
|
||||
NamespaceIndentation: Inner
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 5
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- BLUELIB_API
|
||||
ForEachMacros:
|
||||
- b_btree_foreach
|
||||
- b_queue_foreach
|
||||
MacroBlockBegin: "B_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "B_TYPE_.*_END"
|
||||
|
||||
@@ -22,12 +22,12 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
||||
foreach (module ${b_modules})
|
||||
add_subdirectory(${module})
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${module}-test)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/${module})
|
||||
message(STATUS "Building unit tests for module ${module}")
|
||||
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${module}-test/${module}-units.c)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c)
|
||||
add_executable(blue-${module}-units
|
||||
${module}-test/${module}-units.c
|
||||
test/${module}/${module}-units.c
|
||||
misc/AllTests.c
|
||||
misc/CuTest.c
|
||||
misc/CuTest.h)
|
||||
@@ -37,8 +37,8 @@ foreach (module ${b_modules})
|
||||
|
||||
endif ()
|
||||
|
||||
file(GLOB test_sources ${module}-test/*.c)
|
||||
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/${module}-test/${module}-units.c")
|
||||
file(GLOB test_sources test/${module}/*.c)
|
||||
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c")
|
||||
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
|
||||
195
cmd/arglist.c
195
cmd/arglist.c
@@ -24,7 +24,7 @@ struct argv_parser {
|
||||
struct b_command *cmd;
|
||||
struct b_arglist *arglist;
|
||||
|
||||
b_queue_iterator arg_it;
|
||||
b_queue_entry *arg_it;
|
||||
int nr_values_cur_arg;
|
||||
|
||||
int argc;
|
||||
@@ -66,7 +66,7 @@ static void move_to_subcommand(struct argv_parser *parser, struct b_command *cmd
|
||||
{
|
||||
parser->cmd = cmd;
|
||||
parser->arglist->list_command = cmd;
|
||||
b_queue_iterator_begin(&cmd->b_arg, &parser->arg_it);
|
||||
parser->arg_it = b_queue_first(&cmd->b_arg);
|
||||
parser->nr_values_cur_arg = 0;
|
||||
}
|
||||
|
||||
@@ -182,12 +182,12 @@ static void report_unexpected_arg(struct argv_parser *parser, const char *value)
|
||||
|
||||
static b_status check_required_args(struct argv_parser *parser)
|
||||
{
|
||||
if (!b_queue_iterator_is_valid(&parser->arg_it)) {
|
||||
if (!parser->arg_it) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, parser->arg_it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, parser->arg_it, arg_entry);
|
||||
if (!arg) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ static b_status parse_arg(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
struct b_command_arg *arg = b_unbox(
|
||||
struct b_command_arg, parser->arg_it.entry, arg_entry);
|
||||
struct b_command_arg, parser->arg_it, arg_entry);
|
||||
|
||||
if (!arg) {
|
||||
b_arglist_report_unexpected_arg(parser->arglist, value);
|
||||
@@ -258,13 +258,13 @@ static b_status parse_arg(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_0_OR_1_VALUES) {
|
||||
b_queue_iterator_next(&parser->arg_it);
|
||||
parser->arg_it = b_queue_next(parser->arg_it);
|
||||
parser->nr_values_cur_arg = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parser->nr_values_cur_arg == arg->arg_nr_values) {
|
||||
b_queue_iterator_next(&parser->arg_it);
|
||||
parser->arg_it = b_queue_next(parser->arg_it);
|
||||
parser->nr_values_cur_arg = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -357,25 +357,19 @@ static b_status parse_short_opt(struct argv_parser *parser)
|
||||
arglist_opt->opt_id = opt->opt_id;
|
||||
put_arglist_option(&parser->arglist->list_options, arglist_opt);
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_iterator_begin(&opt->opt_args, &it);
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
const char *value = flags;
|
||||
if (*value == '\0') {
|
||||
advance(parser);
|
||||
}
|
||||
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
while (entry) {
|
||||
value = peek(parser);
|
||||
if (!value || *value == '-') {
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
arg = b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
|
||||
if (!arg) {
|
||||
b_queue_iterator_next(&it);
|
||||
continue;
|
||||
}
|
||||
arg = b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
if (!value || *value == '\0' || *value == '-') {
|
||||
value = NULL;
|
||||
@@ -398,20 +392,17 @@ static b_status parse_short_opt(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_0_OR_1_VALUES) {
|
||||
b_queue_iterator_next(&it);
|
||||
nr_args_cur_opt = 0;
|
||||
goto next_value;
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) {
|
||||
b_queue_iterator_next(&it);
|
||||
nr_args_cur_opt = 0;
|
||||
goto next_value;
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) {
|
||||
if (nr_args_cur_opt > 0) {
|
||||
b_queue_iterator_next(&it);
|
||||
nr_args_cur_opt = 0;
|
||||
goto next_value;
|
||||
}
|
||||
@@ -423,7 +414,6 @@ static b_status parse_short_opt(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
if (nr_args_cur_opt == arg->arg_nr_values) {
|
||||
b_queue_iterator_next(&it);
|
||||
nr_args_cur_opt = 0;
|
||||
goto next_value;
|
||||
}
|
||||
@@ -435,6 +425,7 @@ static b_status parse_short_opt(struct argv_parser *parser)
|
||||
return B_ERR_BAD_FORMAT;
|
||||
}
|
||||
next_value:
|
||||
entry = b_queue_next(entry);
|
||||
value = advance(parser);
|
||||
}
|
||||
|
||||
@@ -493,16 +484,11 @@ static b_status parse_long_opt(struct argv_parser *parser)
|
||||
arglist_opt->opt_id = opt->opt_id;
|
||||
put_arglist_option(&parser->arglist->list_options, arglist_opt);
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_iterator_begin(&opt->opt_args, &it);
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
struct b_command_arg *arg = NULL;
|
||||
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
arg = b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
if (!arg) {
|
||||
break;
|
||||
}
|
||||
while (entry) {
|
||||
arg = b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
const char *value = peek(parser);
|
||||
if (!value || value[0] == '-') {
|
||||
@@ -528,20 +514,20 @@ static b_status parse_long_opt(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_0_OR_1_VALUES) {
|
||||
b_queue_iterator_next(&it);
|
||||
entry = b_queue_next(entry);
|
||||
nr_args_cur_opt = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) {
|
||||
b_queue_iterator_next(&it);
|
||||
entry = b_queue_next(entry);
|
||||
nr_args_cur_opt = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) {
|
||||
if (nr_args_cur_opt > 0) {
|
||||
b_queue_iterator_next(&it);
|
||||
entry = b_queue_next(entry);
|
||||
nr_args_cur_opt = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -553,7 +539,7 @@ static b_status parse_long_opt(struct argv_parser *parser)
|
||||
}
|
||||
|
||||
if (nr_args_cur_opt == arg->arg_nr_values) {
|
||||
b_queue_iterator_next(&it);
|
||||
entry = b_queue_next(entry);
|
||||
nr_args_cur_opt = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -666,34 +652,33 @@ static void arglist_value_destroy(struct b_arglist_value *val)
|
||||
|
||||
void b_arglist_destroy(struct b_arglist *args)
|
||||
{
|
||||
b_btree_iterator opt_it, args_it;
|
||||
b_btree_node *opt_it, *args_it;
|
||||
b_btree_node *opt_next, *args_next;
|
||||
|
||||
b_btree_iterator_begin(&args->list_options, &opt_it);
|
||||
while (b_btree_iterator_is_valid(&opt_it)) {
|
||||
opt_it = b_btree_first(&args->list_options);
|
||||
while (opt_it) {
|
||||
struct b_arglist_option *opt
|
||||
= b_unbox(struct b_arglist_option, opt_it.node, opt_node);
|
||||
= b_unbox(struct b_arglist_option, opt_it, opt_node);
|
||||
opt_next = b_btree_next(opt_it);
|
||||
|
||||
if (!opt) {
|
||||
b_btree_iterator_next(&opt_it);
|
||||
continue;
|
||||
}
|
||||
|
||||
b_btree_iterator_begin(&opt->opt_values, &args_it);
|
||||
while (b_btree_iterator_is_valid(&args_it)) {
|
||||
args_it = b_btree_first(&opt->opt_values);
|
||||
while (args_it) {
|
||||
struct b_arglist_value *val = b_unbox(
|
||||
struct b_arglist_value, args_it.node, val_node);
|
||||
struct b_arglist_value, args_it, val_node);
|
||||
args_next = b_btree_next(args_it);
|
||||
|
||||
if (!val) {
|
||||
b_btree_iterator_next(&args_it);
|
||||
continue;
|
||||
if (val) {
|
||||
b_btree_delete(&opt->opt_values, args_it);
|
||||
arglist_value_destroy(val);
|
||||
}
|
||||
|
||||
b_btree_iterator_erase(&args_it);
|
||||
arglist_value_destroy(val);
|
||||
args_it = args_next;
|
||||
}
|
||||
|
||||
b_btree_iterator_erase(&opt_it);
|
||||
b_btree_delete(&args->list_options, opt_it);
|
||||
arglist_option_destroy(opt);
|
||||
|
||||
opt_it = opt_next;
|
||||
}
|
||||
|
||||
free(args);
|
||||
@@ -775,12 +760,13 @@ b_status b_arglist_get_option(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int index,
|
||||
b_arglist_option **out)
|
||||
{
|
||||
b_btree_iterator it = {0};
|
||||
b_btree_foreach (&it, &args->list_options) {
|
||||
b_arglist_option *cur
|
||||
= b_unbox(b_arglist_option, it.node, opt_node);
|
||||
struct b_btree_node *node = b_btree_first(&args->list_options);
|
||||
|
||||
while (node) {
|
||||
b_arglist_option *cur = b_unbox(b_arglist_option, node, opt_node);
|
||||
|
||||
if (cur->opt_id != opt_id) {
|
||||
node = b_btree_next(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -789,6 +775,7 @@ b_status b_arglist_get_option(
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
node = b_btree_next(node);
|
||||
index--;
|
||||
}
|
||||
|
||||
@@ -813,11 +800,12 @@ b_status b_arglist_option_get_value(
|
||||
const b_arglist_option *opt, unsigned int arg_id, unsigned int index,
|
||||
b_arglist_value **out)
|
||||
{
|
||||
b_btree_iterator it = {0};
|
||||
b_btree_foreach (&it, &opt->opt_values) {
|
||||
b_arglist_value *cur = b_unbox(b_arglist_value, it.node, val_node);
|
||||
struct b_btree_node *node = b_btree_first(&opt->opt_values);
|
||||
while (node) {
|
||||
b_arglist_value *cur = b_unbox(b_arglist_value, node, val_node);
|
||||
|
||||
if (cur->val_id != arg_id) {
|
||||
node = b_btree_next(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -826,6 +814,7 @@ b_status b_arglist_option_get_value(
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
node = b_btree_next(node);
|
||||
index--;
|
||||
}
|
||||
|
||||
@@ -834,24 +823,14 @@ b_status b_arglist_option_get_value(
|
||||
|
||||
/************************ arglist iterator functions **************************/
|
||||
|
||||
static bool arglist_iterator_next(struct b_iterator *it)
|
||||
{
|
||||
return b_arglist_iterator_next((struct b_arglist_iterator *)it);
|
||||
}
|
||||
|
||||
static bool arglist_iterator_is_valid(const struct b_iterator *it)
|
||||
{
|
||||
return b_arglist_iterator_is_valid((const struct b_arglist_iterator *)it);
|
||||
}
|
||||
|
||||
static struct b_arglist_option *advance_to_next_opt(struct b_arglist_iterator *it)
|
||||
{
|
||||
struct b_arglist_option *opt;
|
||||
|
||||
// b_btree_iterator_next(&it->_opt_it);
|
||||
|
||||
while (b_btree_iterator_is_valid(&it->_opt_it)) {
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it.node, opt_node);
|
||||
while (it->_opt_it) {
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it, opt_node);
|
||||
if (opt
|
||||
&& (opt->opt_id == it->_opt_filter
|
||||
|| it->_opt_filter == B_COMMAND_INVALID_ID)) {
|
||||
@@ -859,7 +838,7 @@ static struct b_arglist_option *advance_to_next_opt(struct b_arglist_iterator *i
|
||||
return opt;
|
||||
}
|
||||
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -871,8 +850,8 @@ static struct b_arglist_value *advance_to_next_arg(struct b_arglist_iterator *it
|
||||
|
||||
// b_btree_iterator_next(&it->_arg_it);
|
||||
|
||||
while (b_btree_iterator_is_valid(&it->_arg_it)) {
|
||||
val = b_unbox(struct b_arglist_value, it->_arg_it.node, val_node);
|
||||
while (it->_arg_it) {
|
||||
val = b_unbox(struct b_arglist_value, it->_arg_it, val_node);
|
||||
if (val
|
||||
&& (val->val_id == it->_arg_filter
|
||||
|| it->_arg_filter == B_COMMAND_INVALID_ID)) {
|
||||
@@ -880,17 +859,12 @@ static struct b_arglist_value *advance_to_next_arg(struct b_arglist_iterator *it
|
||||
return val;
|
||||
}
|
||||
|
||||
b_btree_iterator_next(&it->_arg_it);
|
||||
it->_arg_it = b_btree_next(it->_arg_it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static b_iterator_ops it_ops = {
|
||||
.it_next = arglist_iterator_next,
|
||||
.it_is_valid = arglist_iterator_is_valid,
|
||||
};
|
||||
|
||||
int b_arglist_iterator_begin(
|
||||
const struct b_arglist *args, unsigned int opt_filter,
|
||||
unsigned int arg_filter, struct b_arglist_iterator *it)
|
||||
@@ -899,33 +873,32 @@ int b_arglist_iterator_begin(
|
||||
|
||||
it->opt_id = B_COMMAND_INVALID_ID;
|
||||
|
||||
it->_base.it_ops = &it_ops;
|
||||
it->_opt_filter = opt_filter;
|
||||
it->_arg_filter = arg_filter;
|
||||
|
||||
b_btree_iterator_begin(&args->list_options, &it->_opt_it);
|
||||
it->_opt_it = b_btree_first(&args->list_options);
|
||||
struct b_arglist_option *opt = NULL;
|
||||
struct b_arglist_value *val = NULL;
|
||||
|
||||
while (1) {
|
||||
if (!b_btree_iterator_is_valid(&it->_opt_it)) {
|
||||
if (!it->_opt_it) {
|
||||
opt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it.node, opt_node);
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it, opt_node);
|
||||
if (!opt
|
||||
|| (opt_filter != opt->opt_id
|
||||
&& opt_filter != B_COMMAND_INVALID_ID)) {
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
continue;
|
||||
}
|
||||
|
||||
b_btree_iterator_begin(&opt->opt_values, &it->_arg_it);
|
||||
it->_arg_it = b_btree_first(&opt->opt_values);
|
||||
bool done = false;
|
||||
|
||||
while (1) {
|
||||
if (!b_btree_iterator_is_valid(&it->_arg_it)) {
|
||||
if (!it->_arg_it) {
|
||||
if (arg_filter == B_COMMAND_INVALID_ID) {
|
||||
done = true;
|
||||
}
|
||||
@@ -933,12 +906,11 @@ int b_arglist_iterator_begin(
|
||||
break;
|
||||
}
|
||||
|
||||
val = b_unbox(
|
||||
struct b_arglist_value, it->_arg_it.node, val_node);
|
||||
val = b_unbox(struct b_arglist_value, it->_arg_it, val_node);
|
||||
if (!val
|
||||
|| (arg_filter != val->val_id
|
||||
&& arg_filter != B_COMMAND_INVALID_ID)) {
|
||||
b_btree_iterator_next(&it->_arg_it);
|
||||
it->_arg_it = b_btree_next(it->_arg_it);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -950,7 +922,7 @@ int b_arglist_iterator_begin(
|
||||
break;
|
||||
}
|
||||
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
}
|
||||
|
||||
it->opt_id = opt->opt_id;
|
||||
@@ -964,7 +936,7 @@ bool b_arglist_iterator_next(struct b_arglist_iterator *it)
|
||||
struct b_arglist_option *opt;
|
||||
struct b_arglist_value *val;
|
||||
|
||||
b_btree_iterator_next(&it->_arg_it);
|
||||
it->_arg_it = b_btree_next(it->_arg_it);
|
||||
|
||||
while (1) {
|
||||
val = advance_to_next_arg(it);
|
||||
@@ -975,7 +947,7 @@ bool b_arglist_iterator_next(struct b_arglist_iterator *it)
|
||||
return true;
|
||||
}
|
||||
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
opt = advance_to_next_opt(it);
|
||||
if (!opt) {
|
||||
it->value = NULL;
|
||||
@@ -983,7 +955,7 @@ bool b_arglist_iterator_next(struct b_arglist_iterator *it)
|
||||
return false;
|
||||
}
|
||||
|
||||
b_btree_iterator_begin(&opt->opt_values, &it->_arg_it);
|
||||
it->_arg_it = b_btree_first(&opt->opt_values);
|
||||
|
||||
if (it->_arg_filter == B_COMMAND_INVALID_ID) {
|
||||
return true;
|
||||
@@ -998,27 +970,13 @@ bool b_arglist_iterator_is_valid(const struct b_arglist_iterator *it)
|
||||
|
||||
/********************* arglist option iterator functions **********************/
|
||||
|
||||
static bool arglist_option_iterator_next(struct b_iterator *it)
|
||||
{
|
||||
return b_arglist_option_iterator_next(
|
||||
(struct b_arglist_option_iterator *)it);
|
||||
}
|
||||
|
||||
static bool arglist_option_iterator_is_valid(const struct b_iterator *it)
|
||||
{
|
||||
return b_arglist_option_iterator_is_valid(
|
||||
(const struct b_arglist_option_iterator *)it);
|
||||
}
|
||||
|
||||
static struct b_arglist_option *advance_to_next_opt2(
|
||||
struct b_arglist_option_iterator *it)
|
||||
{
|
||||
struct b_arglist_option *opt;
|
||||
|
||||
// b_btree_iterator_next(&it->_opt_it);
|
||||
|
||||
while (b_btree_iterator_is_valid(&it->_opt_it)) {
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it.node, opt_node);
|
||||
while (it->_opt_it) {
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it, opt_node);
|
||||
if (opt
|
||||
&& (opt->opt_id == it->_opt_filter
|
||||
|| it->_opt_filter == B_COMMAND_INVALID_ID)) {
|
||||
@@ -1026,17 +984,12 @@ static struct b_arglist_option *advance_to_next_opt2(
|
||||
return opt;
|
||||
}
|
||||
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static b_iterator_ops option_it_ops = {
|
||||
.it_next = arglist_option_iterator_next,
|
||||
.it_is_valid = arglist_option_iterator_is_valid,
|
||||
};
|
||||
|
||||
int b_arglist_option_iterator_begin(
|
||||
const struct b_arglist *args, unsigned int opt_filter,
|
||||
struct b_arglist_option_iterator *it)
|
||||
@@ -1045,26 +998,26 @@ int b_arglist_option_iterator_begin(
|
||||
|
||||
it->opt_id = B_COMMAND_INVALID_ID;
|
||||
|
||||
it->_base.it_ops = &it_ops;
|
||||
it->_opt_filter = opt_filter;
|
||||
|
||||
b_btree_iterator_begin(&args->list_options, &it->_opt_it);
|
||||
it->_opt_it = b_btree_first(&args->list_options);
|
||||
struct b_arglist_option *opt = NULL;
|
||||
struct b_arglist_value *val = NULL;
|
||||
|
||||
while (1) {
|
||||
if (!b_btree_iterator_is_valid(&it->_opt_it)) {
|
||||
if (!it->_opt_it) {
|
||||
opt = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it.node, opt_node);
|
||||
opt = b_unbox(struct b_arglist_option, it->_opt_it, opt_node);
|
||||
if (opt
|
||||
&& (opt_filter == opt->opt_id
|
||||
|| opt_filter == B_COMMAND_INVALID_ID)) {
|
||||
break;
|
||||
}
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
}
|
||||
|
||||
it->opt_id = opt->opt_id;
|
||||
@@ -1078,7 +1031,7 @@ bool b_arglist_option_iterator_next(struct b_arglist_option_iterator *it)
|
||||
struct b_arglist_option *opt;
|
||||
struct b_arglist_value *val;
|
||||
|
||||
b_btree_iterator_next(&it->_opt_it);
|
||||
it->_opt_it = b_btree_next(it->_opt_it);
|
||||
opt = advance_to_next_opt2(it);
|
||||
if (!opt) {
|
||||
it->opt = NULL;
|
||||
|
||||
279
cmd/command.c
279
cmd/command.c
@@ -24,16 +24,18 @@ enum item_type {
|
||||
|
||||
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);
|
||||
struct b_btree_node *node = b_btree_first(&command_list);
|
||||
while (node) {
|
||||
struct b_command *cmd = b_unbox(struct b_command, node, b_node);
|
||||
if (!cmd) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_btree_iterator_erase(&it);
|
||||
struct b_btree_node *next = b_btree_next(node);
|
||||
b_btree_delete(&command_list, node);
|
||||
b_command_destroy(cmd);
|
||||
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,18 +55,19 @@ struct b_command *b_command_create(unsigned int id)
|
||||
|
||||
static void command_usage_destroy(struct b_command_usage *usage)
|
||||
{
|
||||
struct b_queue_iterator it = {0};
|
||||
|
||||
b_queue_iterator_begin(&usage->u_parts, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct b_command_usage_entry *arg = b_unbox(
|
||||
struct b_command_usage_entry, it.entry, e_entry);
|
||||
struct b_queue_entry *entry = b_queue_first(&usage->u_parts);
|
||||
while (entry) {
|
||||
struct b_command_usage_entry *arg
|
||||
= b_unbox(struct b_command_usage_entry, entry, e_entry);
|
||||
if (!arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
struct b_queue_entry *next = b_queue_next(entry);
|
||||
b_queue_delete(&usage->u_parts, entry);
|
||||
free(arg);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
|
||||
free(usage);
|
||||
@@ -72,8 +75,6 @@ static void command_usage_destroy(struct b_command_usage *usage)
|
||||
|
||||
void b_command_destroy(struct b_command *cmd)
|
||||
{
|
||||
struct b_queue_iterator it = {0};
|
||||
|
||||
if (cmd->b_name) {
|
||||
free(cmd->b_name);
|
||||
}
|
||||
@@ -86,52 +87,71 @@ void b_command_destroy(struct b_command *cmd)
|
||||
free(cmd->b_description);
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&cmd->b_opt, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
|
||||
struct b_queue_entry *next = NULL;
|
||||
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
if (!opt) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
next = b_queue_next(entry);
|
||||
b_queue_delete(&cmd->b_opt, entry);
|
||||
|
||||
b_command_option_destroy(opt);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&cmd->b_arg, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
entry = b_queue_first(&cmd->b_arg);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
if (!arg) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
next = b_queue_next(entry);
|
||||
b_queue_delete(&cmd->b_arg, entry);
|
||||
|
||||
b_command_arg_destroy(arg);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&cmd->b_arg, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
#if 0
|
||||
entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *subcmd
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
= b_unbox(struct b_command, entry, b_entry);
|
||||
if (!subcmd) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
b_command_destroy(subcmd);
|
||||
}
|
||||
next = b_queue_next(entry);
|
||||
|
||||
b_queue_iterator_begin(&cmd->b_usage, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
b_command_destroy(subcmd);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
#endif
|
||||
|
||||
entry = b_queue_first(&cmd->b_usage);
|
||||
while (entry) {
|
||||
struct b_command_usage *usage
|
||||
= b_unbox(struct b_command_usage, it.entry, u_entry);
|
||||
= b_unbox(struct b_command_usage, entry, u_entry);
|
||||
if (!usage) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
next = b_queue_next(entry);
|
||||
b_queue_delete(&cmd->b_usage, entry);
|
||||
|
||||
command_usage_destroy(usage);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
@@ -262,6 +282,24 @@ struct b_command_usage *b_command_add_usage(struct b_command *cmd)
|
||||
return usage;
|
||||
}
|
||||
|
||||
const struct b_command_option *b_command_get_option(
|
||||
const struct b_command *cmd, int id)
|
||||
{
|
||||
struct b_queue_entry *cur = b_queue_first(&cmd->b_opt);
|
||||
while (cur) {
|
||||
const struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, cur, opt_entry);
|
||||
|
||||
if (opt->opt_id == id) {
|
||||
return opt;
|
||||
}
|
||||
|
||||
cur = b_queue_next(cur);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_status b_command_usage_add_option(
|
||||
struct b_command_usage *usage, struct b_command_option *opt)
|
||||
{
|
||||
@@ -315,9 +353,9 @@ b_status b_command_usage_add_command(b_command_usage *usage, unsigned int cmd_id
|
||||
static void prepend_command_name(struct b_command *cmd, b_string *out)
|
||||
{
|
||||
int nr_names = 0;
|
||||
cmd->b_name&& nr_names++;
|
||||
cmd->b_long_name&& nr_names++;
|
||||
cmd->b_short_name&& nr_names++;
|
||||
cmd->b_name &&nr_names++;
|
||||
cmd->b_long_name &&nr_names++;
|
||||
cmd->b_short_name &&nr_names++;
|
||||
|
||||
if (nr_names > 1) {
|
||||
b_string_prepend_cstr(out, "}");
|
||||
@@ -382,10 +420,10 @@ static void get_usage_string(
|
||||
|
||||
b_string *cmd_name = b_string_create();
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &usage->u_parts) {
|
||||
struct b_command_usage_entry *entry = b_unbox(
|
||||
struct b_command_usage_entry, it.entry, e_entry);
|
||||
struct b_queue_entry *q_entry = b_queue_first(&usage->u_parts);
|
||||
while (q_entry) {
|
||||
struct b_command_usage_entry *entry
|
||||
= b_unbox(struct b_command_usage_entry, q_entry, e_entry);
|
||||
|
||||
if (!entry) {
|
||||
break;
|
||||
@@ -426,6 +464,8 @@ static void get_usage_string(
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
q_entry = b_queue_next(q_entry);
|
||||
}
|
||||
|
||||
b_string_unref(cmd_name);
|
||||
@@ -445,13 +485,15 @@ b_string *z__b_command_default_usage_string(
|
||||
b_string_append_cstr(str, " [OPTIONS]");
|
||||
}
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_arg) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
b_string_append_cstr(str, " ");
|
||||
z__b_get_arg_usage_string(arg, false, str);
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
if (!b_queue_empty(&cmd->b_subcommands)) {
|
||||
@@ -523,13 +565,10 @@ static void print_options_list(struct b_command *cmd)
|
||||
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) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
if (!opt) {
|
||||
continue;
|
||||
}
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
|
||||
b_string_clear(opt_str);
|
||||
b_string_clear(desc_str);
|
||||
@@ -544,12 +583,15 @@ static void print_options_list(struct b_command *cmd)
|
||||
desc_str, B_STRLEN_IGNORE_ESC | B_STRLEN_IGNORE_MOD);
|
||||
|
||||
if (description_on_separate_line(opt_len, desc_len)) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (opt_len > desb_margin) {
|
||||
desb_margin = opt_len;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_paragraph_format format = {0};
|
||||
@@ -558,11 +600,12 @@ static void print_options_list(struct b_command *cmd)
|
||||
format.p_right_margin = 4;
|
||||
|
||||
size_t i = 0;
|
||||
b_queue_foreach (&it, &cmd->b_opt) {
|
||||
entry = b_queue_first(&cmd->b_opt);
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
if (!opt) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
b_string_clear(opt_str);
|
||||
@@ -609,6 +652,8 @@ static void print_options_list(struct b_command *cmd)
|
||||
if (new_paragraph) {
|
||||
b_tty_putc(OUTPUT_STREAM, 0, '\n');
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_string_unref(opt_str);
|
||||
@@ -622,10 +667,11 @@ static void print_args_list(struct b_command *cmd)
|
||||
size_t desb_margin = 0;
|
||||
b_string *str = b_string_create();
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_arg) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
|
||||
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
b_string_clear(str);
|
||||
z__b_get_arg_usage_string(arg, true, str);
|
||||
@@ -636,6 +682,8 @@ static void print_args_list(struct b_command *cmd)
|
||||
if (len > desb_margin) {
|
||||
desb_margin = len;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_paragraph_format format = {0};
|
||||
@@ -644,9 +692,10 @@ static void print_args_list(struct b_command *cmd)
|
||||
format.p_right_margin = 4;
|
||||
|
||||
size_t i = 0;
|
||||
b_queue_foreach (&it, &cmd->b_arg) {
|
||||
entry = b_queue_first(&cmd->b_arg);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
b_string_clear(str);
|
||||
z__b_get_arg_usage_string(arg, true, str);
|
||||
@@ -666,6 +715,7 @@ static void print_args_list(struct b_command *cmd)
|
||||
z__b_get_arg_description(arg, str);
|
||||
|
||||
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_string_unref(str);
|
||||
@@ -678,10 +728,9 @@ static void print_commands_list(struct b_command *cmd)
|
||||
size_t desb_margin = 0;
|
||||
b_string *str = b_string_create();
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_subcommands) {
|
||||
struct b_command *sub
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *sub = b_unbox(struct b_command, entry, b_entry);
|
||||
|
||||
b_string_clear(str);
|
||||
get_command_string(sub, str);
|
||||
@@ -692,6 +741,8 @@ static void print_commands_list(struct b_command *cmd)
|
||||
if (len > desb_margin) {
|
||||
desb_margin = len;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_paragraph_format format = {0};
|
||||
@@ -700,9 +751,9 @@ static void print_commands_list(struct b_command *cmd)
|
||||
format.p_right_margin = 4;
|
||||
|
||||
size_t i = 0;
|
||||
b_queue_foreach (&it, &cmd->b_subcommands) {
|
||||
struct b_command *sub
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *sub = b_unbox(struct b_command, entry, b_entry);
|
||||
|
||||
b_string_clear(str);
|
||||
get_command_string(sub, str);
|
||||
@@ -722,6 +773,8 @@ static void print_commands_list(struct b_command *cmd)
|
||||
get_command_description(sub, str);
|
||||
|
||||
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_string_unref(str);
|
||||
@@ -730,17 +783,20 @@ static void print_commands_list(struct b_command *cmd)
|
||||
struct b_command *b_command_get_subcommand_with_name(
|
||||
struct b_command *cmd, const char *name)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_subcommands) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *subcmd
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
= b_unbox(struct b_command, entry, b_entry);
|
||||
if (!subcmd || !subcmd->b_name) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (!strcmp(subcmd->b_name, name)) {
|
||||
return subcmd;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -749,17 +805,20 @@ struct b_command *b_command_get_subcommand_with_name(
|
||||
struct b_command *b_command_get_subcommand_with_long_name(
|
||||
struct b_command *cmd, const char *long_name)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_subcommands) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *subcmd
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
= b_unbox(struct b_command, entry, b_entry);
|
||||
if (!subcmd || !subcmd->b_long_name) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (!strcmp(subcmd->b_name, long_name)) {
|
||||
return subcmd;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -768,17 +827,20 @@ struct b_command *b_command_get_subcommand_with_long_name(
|
||||
struct b_command *b_command_get_subcommand_with_short_name(
|
||||
struct b_command *cmd, char short_name)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_subcommands) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
|
||||
while (entry) {
|
||||
struct b_command *subcmd
|
||||
= b_unbox(struct b_command, it.entry, b_entry);
|
||||
= b_unbox(struct b_command, entry, b_entry);
|
||||
if (!subcmd || !subcmd->b_short_name) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (subcmd->b_short_name == short_name) {
|
||||
return subcmd;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -787,17 +849,20 @@ struct b_command *b_command_get_subcommand_with_short_name(
|
||||
struct b_command_option *b_command_get_option_with_long_name(
|
||||
struct b_command *cmd, const char *long_name)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_opt) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
if (!opt || !opt->opt_long_name) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (!strcmp(opt->opt_long_name, long_name)) {
|
||||
return opt;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -806,17 +871,20 @@ struct b_command_option *b_command_get_option_with_long_name(
|
||||
struct b_command_option *b_command_get_option_with_short_name(
|
||||
struct b_command *cmd, char short_name)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_opt) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
if (!opt || !opt->opt_long_name) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (opt->opt_short_name == short_name) {
|
||||
return opt;
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -825,17 +893,16 @@ struct b_command_option *b_command_get_option_with_short_name(
|
||||
struct b_command_option *b_command_get_option_with_id(
|
||||
struct b_command *cmd, unsigned int id)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_opt) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
|
||||
while (entry) {
|
||||
struct b_command_option *opt
|
||||
= b_unbox(struct b_command_option, it.entry, opt_entry);
|
||||
if (!opt) {
|
||||
continue;
|
||||
}
|
||||
= b_unbox(struct b_command_option, entry, opt_entry);
|
||||
|
||||
if (opt->opt_id == id) {
|
||||
return opt;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -844,17 +911,16 @@ struct b_command_option *b_command_get_option_with_id(
|
||||
struct b_command_arg *b_command_get_arg_with_id(
|
||||
struct b_command *cmd, unsigned int id)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_arg) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
if (!arg) {
|
||||
continue;
|
||||
}
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
if (arg->arg_id == id) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -876,17 +942,16 @@ static void print_usage(struct b_command *cmd, struct b_arglist *args)
|
||||
}
|
||||
|
||||
b_string *str = b_string_create();
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &cmd->b_usage) {
|
||||
struct b_queue_entry *entry = b_queue_first(&cmd->b_usage);
|
||||
while (entry) {
|
||||
struct b_command_usage *usage
|
||||
= b_unbox(struct b_command_usage, it.entry, u_entry);
|
||||
if (!usage) {
|
||||
break;
|
||||
}
|
||||
= b_unbox(struct b_command_usage, entry, u_entry);
|
||||
|
||||
b_string_clear(str);
|
||||
get_usage_string(cmd, args, usage, str);
|
||||
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_string_unref(str);
|
||||
@@ -960,12 +1025,12 @@ static b_status add_subcommand(struct b_command *parent, struct b_command *child
|
||||
|
||||
static int resolve_command_parents(struct b_btree *commands)
|
||||
{
|
||||
struct b_btree_iterator it;
|
||||
b_btree_foreach (&it, commands) {
|
||||
struct b_command *cmd = b_unbox(struct b_command, it.node, b_node);
|
||||
struct b_btree_node *node = b_btree_first(commands);
|
||||
while (node) {
|
||||
struct b_command *cmd = b_unbox(struct b_command, node, b_node);
|
||||
|
||||
if (cmd->b_parent_id == B_COMMAND_INVALID_ID) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
cmd->b_parent = get_command(commands, cmd->b_parent_id);
|
||||
@@ -974,6 +1039,8 @@ static int resolve_command_parents(struct b_btree *commands)
|
||||
}
|
||||
|
||||
add_subcommand(cmd->b_parent, cmd);
|
||||
skip:
|
||||
node = b_btree_next(node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
this_opt = opt_##id; \
|
||||
if (this_opt)
|
||||
|
||||
#define B_COMMAND_OPTION_GEN(id) \
|
||||
b_command_option *z__b_unique_name() \
|
||||
= b_command_add_option(this_cmd, (id)); \
|
||||
this_opt = z__b_unique_name(); \
|
||||
if (this_opt)
|
||||
|
||||
#define B_COMMAND_HELP_OPTION() \
|
||||
do { \
|
||||
b_command_option *opt \
|
||||
@@ -164,24 +170,22 @@ typedef struct b_arglist_value {
|
||||
} b_arglist_value;
|
||||
|
||||
typedef struct b_arglist_iterator {
|
||||
b_iterator _base;
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct b_arglist_value *value;
|
||||
|
||||
b_btree_iterator _opt_it, _arg_it;
|
||||
b_btree_node *_opt_it, *_arg_it;
|
||||
unsigned int _opt_filter, _arg_filter;
|
||||
} b_arglist_iterator;
|
||||
|
||||
typedef struct b_arglist_option_iterator {
|
||||
b_iterator _base;
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct b_arglist_option *opt;
|
||||
|
||||
b_btree_iterator _opt_it;
|
||||
b_btree_node *_opt_it;
|
||||
unsigned int _opt_filter;
|
||||
} b_arglist_option_iterator;
|
||||
|
||||
@@ -212,6 +216,11 @@ BLUE_API b_command_option *b_command_add_option(b_command *cmd, int id);
|
||||
BLUE_API b_command_arg *b_command_add_arg(b_command *cmd, int id);
|
||||
BLUE_API b_command_usage *b_command_add_usage(b_command *cmd);
|
||||
|
||||
BLUE_API const b_command_option *b_command_get_option(const b_command *cmd, int id);
|
||||
|
||||
BLUE_API const char *b_command_option_get_long_name(const b_command_option *opt);
|
||||
BLUE_API char b_command_option_get_short_name(const b_command_option *opt);
|
||||
BLUE_API const char *b_command_option_get_description(b_command_option *opt);
|
||||
BLUE_API b_status b_command_option_set_long_name(
|
||||
b_command_option *opt, const char *name);
|
||||
BLUE_API b_status b_command_option_set_short_name(b_command_option *opt, char name);
|
||||
|
||||
68
cmd/option.c
68
cmd/option.c
@@ -26,23 +26,37 @@ void b_command_option_destroy(struct b_command_option *opt)
|
||||
free(opt->opt_description);
|
||||
}
|
||||
|
||||
b_queue_iterator it = {0};
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
|
||||
b_queue_iterator_begin(&opt->opt_args, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
if (!arg) {
|
||||
break;
|
||||
}
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
struct b_queue_entry *next = b_queue_next(entry);
|
||||
b_queue_delete(&opt->opt_args, entry);
|
||||
|
||||
b_queue_iterator_erase(&it);
|
||||
b_command_arg_destroy(arg);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
free(opt);
|
||||
}
|
||||
|
||||
const char *b_command_option_get_long_name(const struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_long_name;
|
||||
}
|
||||
|
||||
char b_command_option_get_short_name(const struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_short_name;
|
||||
}
|
||||
|
||||
const char *b_command_option_get_description(struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_description;
|
||||
}
|
||||
|
||||
b_status b_command_option_set_long_name(
|
||||
struct b_command_option *opt, const char *name)
|
||||
{
|
||||
@@ -107,15 +121,16 @@ void z__b_get_option_description(struct b_command_option *opt, b_string *out)
|
||||
size_t nr_args = b_queue_length(&opt->opt_args);
|
||||
bool close_bracket = false;
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &opt->opt_args) {
|
||||
size_t i = 0;
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
if (!arg || !arg->arg_allowed_values) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (it.i > 0) {
|
||||
if (i > 0) {
|
||||
b_string_append_cstr(out, "; ");
|
||||
} else {
|
||||
b_string_append_cstr(out, " [[");
|
||||
@@ -138,6 +153,10 @@ void z__b_get_option_description(struct b_command_option *opt, b_string *out)
|
||||
out, " " F_GREEN "%s" F_RESET,
|
||||
arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
skip:
|
||||
i++;
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
if (close_bracket) {
|
||||
@@ -175,12 +194,12 @@ void z__b_get_option_usage_string(
|
||||
b_string_append_cstr(out, "}");
|
||||
}
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &opt->opt_args) {
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
if (!arg) {
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
bool optional = false, multi = false;
|
||||
@@ -228,23 +247,26 @@ void z__b_get_option_usage_string(
|
||||
if (flags & CMD_STR_COLOUR) {
|
||||
b_string_append_cstr(out, F_RESET);
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct b_command_arg *b_command_option_get_arg_with_id(
|
||||
struct b_command_option *opt, unsigned int id)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &opt->opt_args) {
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, it.entry, arg_entry);
|
||||
if (!arg) {
|
||||
continue;
|
||||
}
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
if (arg->arg_id == id) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#include <blue/core/rope.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
b_rope a = B_ROPE_CHAR('a');
|
||||
b_rope b = B_ROPE_CSTR_STATIC("Hello, world!");
|
||||
b_rope c = B_ROPE_INT(-4096);
|
||||
b_rope d = B_ROPE_UINT(4096);
|
||||
|
||||
b_rope str;
|
||||
|
||||
const b_rope *ropes[] = {
|
||||
&a,
|
||||
&b,
|
||||
&c,
|
||||
&d,
|
||||
};
|
||||
|
||||
b_rope_join(&str, ropes, sizeof ropes / sizeof ropes[0]);
|
||||
|
||||
char cstr[1024];
|
||||
b_rope_to_cstr(&str, cstr, sizeof cstr);
|
||||
b_rope_destroy(&str);
|
||||
|
||||
printf("%s\n", cstr);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
b_stream_read_line_s(b_stdin, b_stdout);
|
||||
b_stream_write_char(b_stdout, '\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
375
core/bstr.c
Normal file
375
core/bstr.c
Normal file
@@ -0,0 +1,375 @@
|
||||
#include "printf.h"
|
||||
|
||||
#include <blue/core/bstr.h>
|
||||
#include <blue/core/rope.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK_FLAG(str, f) ((((str)->bstr_flags) & (f)) == (f))
|
||||
#define IS_DYNAMIC(p) (CHECK_FLAG(p, B_BSTR_F_ALLOC))
|
||||
/* number of bytes that bstr_buf is extended by when required */
|
||||
#define CAPACITY_STEP 32
|
||||
|
||||
void b_bstr_begin(struct b_bstr *str, char *buf, size_t max)
|
||||
{
|
||||
memset(str, 0x0, sizeof *str);
|
||||
|
||||
str->bstr_magic = B_BSTR_MAGIC;
|
||||
str->bstr_buf = buf;
|
||||
str->bstr_capacity = max;
|
||||
str->bstr_len = 0;
|
||||
str->bstr_flags = B_BSTR_F_NONE;
|
||||
}
|
||||
|
||||
void b_bstr_begin_dynamic(struct b_bstr *str)
|
||||
{
|
||||
memset(str, 0x0, sizeof *str);
|
||||
|
||||
str->bstr_magic = B_BSTR_MAGIC;
|
||||
str->bstr_buf = NULL;
|
||||
str->bstr_capacity = 0;
|
||||
str->bstr_len = 0;
|
||||
str->bstr_flags = B_BSTR_F_ALLOC;
|
||||
}
|
||||
|
||||
static char *truncate_buffer(char *s, size_t len)
|
||||
{
|
||||
if (!s || !len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *final = realloc(s, len + 1);
|
||||
if (!final) {
|
||||
return s;
|
||||
}
|
||||
|
||||
final[len] = '\0';
|
||||
|
||||
return final;
|
||||
}
|
||||
|
||||
char *b_bstr_end(struct b_bstr *str)
|
||||
{
|
||||
char *out = str->bstr_buf;
|
||||
size_t len = str->bstr_len;
|
||||
|
||||
if (IS_DYNAMIC(str) && str->bstr_capacity - 1 > str->bstr_len) {
|
||||
/* bstr_buf is larger than required to contain the string.
|
||||
* re-allocate it so it's only as large as necessary */
|
||||
out = truncate_buffer(out, len);
|
||||
}
|
||||
|
||||
if (str->bstr_istack) {
|
||||
free(str->bstr_istack);
|
||||
}
|
||||
|
||||
memset(str, 0x0, sizeof *str);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_reserve(struct b_bstr *strv, size_t len)
|
||||
{
|
||||
if (!IS_DYNAMIC(strv)) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
if (strv->bstr_capacity > 0 && strv->bstr_capacity - 1 >= len) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
char *new_buf = realloc(strv->bstr_buf, len + 1);
|
||||
if (!new_buf) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
strv->bstr_buf = new_buf;
|
||||
strv->bstr_capacity = len + 1;
|
||||
strv->bstr_buf[strv->bstr_len] = '\0';
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static int current_indent(struct b_bstr *str)
|
||||
{
|
||||
if (!str->bstr_istack || !str->bstr_istack_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str->bstr_istack[str->bstr_istack_ptr];
|
||||
}
|
||||
|
||||
static void __formatter_putchar(struct b_bstr *str, char c)
|
||||
{
|
||||
if (str->bstr_capacity > 0 && str->bstr_len < str->bstr_capacity - 1) {
|
||||
str->bstr_buf[str->bstr_len++] = c;
|
||||
str->bstr_buf[str->bstr_len] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(str, B_BSTR_F_ALLOC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t old_capacity = str->bstr_capacity;
|
||||
size_t new_capacity = old_capacity + CAPACITY_STEP;
|
||||
|
||||
char *new_buf = realloc(str->bstr_buf, new_capacity);
|
||||
if (!new_buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
str->bstr_buf = new_buf;
|
||||
str->bstr_capacity = new_capacity;
|
||||
str->bstr_buf[str->bstr_len++] = c;
|
||||
str->bstr_buf[str->bstr_len] = '\0';
|
||||
}
|
||||
|
||||
static void formatter_putchar(struct b_bstr *f, char c)
|
||||
{
|
||||
if (f->bstr_add_indent && c != '\n') {
|
||||
int indent = current_indent(f);
|
||||
for (int i = 0; i < indent; i++) {
|
||||
__formatter_putchar(f, ' ');
|
||||
__formatter_putchar(f, ' ');
|
||||
}
|
||||
|
||||
f->bstr_add_indent = 0;
|
||||
}
|
||||
|
||||
__formatter_putchar(f, c);
|
||||
|
||||
if (c == '\n') {
|
||||
f->bstr_add_indent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void bstr_fctprintf(char c, void *arg)
|
||||
{
|
||||
struct b_bstr *str = arg;
|
||||
formatter_putchar(str, c);
|
||||
}
|
||||
|
||||
static enum b_status bstr_putcs(
|
||||
struct b_bstr *str, const char *s, size_t len, size_t *nr_written)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
formatter_putchar(str, s[i]);
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = len;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status bstr_puts(struct b_bstr *str, const char *s, size_t *nr_written)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; s[i]; i++) {
|
||||
formatter_putchar(str, s[i]);
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = i;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_push_indent(struct b_bstr *str, int indent)
|
||||
{
|
||||
if (!str->bstr_istack) {
|
||||
str->bstr_istack = calloc(4, sizeof(int));
|
||||
str->bstr_istack_size = 4;
|
||||
str->bstr_istack_ptr = 0;
|
||||
}
|
||||
|
||||
if (str->bstr_istack_ptr + 1 > str->bstr_istack_size) {
|
||||
int *buf = realloc(
|
||||
str->bstr_istack,
|
||||
(str->bstr_istack_size + 4) * sizeof(int));
|
||||
if (!buf) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
str->bstr_istack = buf;
|
||||
str->bstr_istack_size += 4;
|
||||
}
|
||||
|
||||
int cur_indent = str->bstr_istack[str->bstr_istack_ptr];
|
||||
str->bstr_istack[++str->bstr_istack_ptr] = cur_indent + indent;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_pop_indent(struct b_bstr *strv)
|
||||
{
|
||||
if (strv->bstr_istack_ptr > 0) {
|
||||
strv->bstr_istack_ptr--;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_char(struct b_bstr *str, char c)
|
||||
{
|
||||
formatter_putchar(str, c);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_chars(
|
||||
struct b_bstr *str, const char *s, size_t len, size_t *nr_written)
|
||||
{
|
||||
return bstr_putcs(str, s, len, nr_written);
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_cstr(struct b_bstr *str, const char *s, size_t *nr_written)
|
||||
{
|
||||
return bstr_puts(str, s, nr_written);
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_cstr_list(
|
||||
struct b_bstr *str, const char **strs, size_t *nr_written)
|
||||
{
|
||||
size_t w = 0;
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
for (size_t i = 0; strs[i]; i++) {
|
||||
size_t tmp = 0;
|
||||
status = bstr_puts(str, strs[i], &tmp);
|
||||
w += tmp;
|
||||
|
||||
if (B_ERR(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = w;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_cstr_array(
|
||||
struct b_bstr *str, const char **strs, size_t count, size_t *nr_written)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
size_t w = 0;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!strs[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t tmp = 0;
|
||||
status = bstr_puts(str, strs[i], &tmp);
|
||||
w += tmp;
|
||||
|
||||
if (B_ERR(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = w;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_add_many(struct b_bstr *str, size_t *nr_written, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, nr_written);
|
||||
const char *s = NULL;
|
||||
size_t w = 0;
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
while ((s = va_arg(arg, const char *))) {
|
||||
size_t tmp = 0;
|
||||
status = bstr_puts(str, s, &tmp);
|
||||
w += tmp;
|
||||
|
||||
if (B_ERR(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = w;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_rope(
|
||||
b_bstr *strv, const struct b_rope *rope, size_t *nr_written)
|
||||
{
|
||||
size_t start = strv->bstr_len;
|
||||
enum b_status status = b_rope_to_bstr(rope, strv);
|
||||
size_t end = strv->bstr_len;
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = end - start;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_fmt(
|
||||
struct b_bstr *str, size_t *nr_written, const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
enum b_status result = b_bstr_write_vfmt(str, nr_written, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum b_status b_bstr_write_vfmt(
|
||||
struct b_bstr *str, size_t *nr_written, const char *format, va_list arg)
|
||||
{
|
||||
size_t start = str->bstr_len;
|
||||
z__b_fctprintf(bstr_fctprintf, str, format, arg);
|
||||
size_t end = str->bstr_len;
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = end - start;
|
||||
}
|
||||
|
||||
/* TODO update z__b_fctprintf to support propagating error codes */
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
char *b_bstr_rope(const struct b_rope *rope, size_t *nr_written)
|
||||
{
|
||||
struct b_bstr str;
|
||||
b_bstr_begin_dynamic(&str);
|
||||
b_bstr_write_rope(&str, rope, nr_written);
|
||||
|
||||
return b_bstr_end(&str);
|
||||
}
|
||||
|
||||
char *b_bstr_fmt(size_t *nr_written, const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char *s = b_bstr_vfmt(nr_written, format, arg);
|
||||
va_end(arg);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *b_bstr_vfmt(size_t *nr_written, const char *format, va_list arg)
|
||||
{
|
||||
struct b_bstr str;
|
||||
b_bstr_begin_dynamic(&str);
|
||||
b_bstr_write_vfmt(&str, nr_written, format, arg);
|
||||
|
||||
return b_bstr_end(&str);
|
||||
}
|
||||
26
core/btree.c
26
core/btree.c
@@ -736,6 +736,32 @@ b_btree_node *b_btree_prev(const struct b_btree_node *node)
|
||||
return prev_node(node, &d);
|
||||
}
|
||||
|
||||
void b_btree_move(
|
||||
struct b_btree *tree, struct b_btree_node *dest, struct b_btree_node *src)
|
||||
{
|
||||
if (src->b_parent) {
|
||||
if (src->b_parent->b_left == src) {
|
||||
src->b_parent->b_left = dest;
|
||||
} else {
|
||||
src->b_parent->b_right = dest;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->b_left) {
|
||||
src->b_left->b_parent = dest;
|
||||
}
|
||||
|
||||
if (src->b_right) {
|
||||
src->b_right->b_parent = dest;
|
||||
}
|
||||
|
||||
if (tree->b_root == src) {
|
||||
tree->b_root = dest;
|
||||
}
|
||||
|
||||
memmove(dest, src, sizeof *src);
|
||||
}
|
||||
|
||||
b_iterator *b_btree_begin(struct b_btree *tree)
|
||||
{
|
||||
b_iterator *it_obj = b_object_create(B_TYPE_BTREE_ITERATOR);
|
||||
|
||||
@@ -471,7 +471,7 @@ enum b_status z__b_error_add_submsg_template(
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
void b_error_release(struct b_error *error)
|
||||
void b_error_discard(struct b_error *error)
|
||||
{
|
||||
b_queue_delete(&allocated_errors, &error->err_entry);
|
||||
b_queue_push_back(&free_errors, &error->err_entry);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "hash.h"
|
||||
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/core/rope.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -116,6 +118,43 @@ enum b_status b_hash_ctx_update(struct b_hash_ctx *ctx, const void *p, size_t le
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void update_rope(const b_rope *rope, void *arg)
|
||||
{
|
||||
struct b_hash_ctx *ctx = arg;
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
char tmp[64];
|
||||
size_t len = 0;
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
b_hash_ctx_update(ctx, &rope->r_v.v_char, sizeof rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
b_hash_ctx_update(
|
||||
ctx, rope->r_v.v_cstr.s, strlen(rope->r_v.v_cstr.s));
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
len = snprintf(tmp, sizeof tmp, "%" PRIdPTR, rope->r_v.v_int);
|
||||
b_hash_ctx_update(ctx, tmp, len);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
len = snprintf(tmp, sizeof tmp, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
b_hash_ctx_update(ctx, tmp, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_update_rope(
|
||||
struct b_hash_ctx *ctx, const struct b_rope *rope)
|
||||
{
|
||||
b_rope_iterate(rope, update_rope, ctx);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_finish(
|
||||
struct b_hash_ctx *ctx, void *out_digest, size_t out_max)
|
||||
{
|
||||
|
||||
71
core/include/blue/core/bstr.h
Normal file
71
core/include/blue/core/bstr.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef BLUE_CORE_BSTR_H_
|
||||
#define BLUE_CORE_BSTR_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define B_BSTR_MAGIC 0x5005500550055005ULL
|
||||
|
||||
struct b_rope;
|
||||
|
||||
enum b_bstr_flags {
|
||||
B_BSTR_F_NONE = 0x00u,
|
||||
B_BSTR_F_ALLOC = 0x01u,
|
||||
};
|
||||
|
||||
typedef struct b_bstr {
|
||||
uint64_t bstr_magic;
|
||||
enum b_bstr_flags bstr_flags;
|
||||
char *bstr_buf;
|
||||
/* total number of characters in bstr_buf, not including null terminator */
|
||||
size_t bstr_len;
|
||||
/* number of bytes allocated for bstr_buf (includes space for the null
|
||||
* terminator) */
|
||||
size_t bstr_capacity;
|
||||
int *bstr_istack;
|
||||
int bstr_add_indent;
|
||||
size_t bstr_istack_ptr, bstr_istack_size;
|
||||
} b_bstr;
|
||||
|
||||
BLUE_API void b_bstr_begin(b_bstr *strv, char *buf, size_t max);
|
||||
BLUE_API void b_bstr_begin_dynamic(b_bstr *strv);
|
||||
BLUE_API char *b_bstr_end(b_bstr *strv);
|
||||
BLUE_API b_status b_bstr_reserve(b_bstr *strv, size_t len);
|
||||
|
||||
static inline size_t b_bstr_get_size(const b_bstr *str)
|
||||
{
|
||||
return str->bstr_len;
|
||||
}
|
||||
|
||||
static inline size_t b_bstr_get_capacity(const b_bstr *str)
|
||||
{
|
||||
return str->bstr_capacity;
|
||||
}
|
||||
|
||||
BLUE_API b_status b_bstr_push_indent(b_bstr *strv, int indent);
|
||||
BLUE_API b_status b_bstr_pop_indent(b_bstr *strv);
|
||||
|
||||
BLUE_API b_status b_bstr_write_char(b_bstr *strv, char c);
|
||||
BLUE_API b_status b_bstr_write_chars(
|
||||
b_bstr *strv, const char *cs, size_t len, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr(
|
||||
b_bstr *strv, const char *str, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_list(
|
||||
b_bstr *strv, const char **strs, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_array(
|
||||
b_bstr *strv, const char **strs, size_t count, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_varg(b_bstr *strv, size_t *nr_written, ...);
|
||||
BLUE_API b_status b_bstr_write_rope(
|
||||
b_bstr *strv, const struct b_rope *rope, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_fmt(
|
||||
b_bstr *strv, size_t *nr_written, const char *format, ...);
|
||||
BLUE_API b_status b_bstr_write_vfmt(
|
||||
b_bstr *strv, size_t *nr_written, const char *format, va_list arg);
|
||||
|
||||
BLUE_API char *b_bstr_rope(const struct b_rope *rope, size_t *nr_written);
|
||||
BLUE_API char *b_bstr_fmt(size_t *nr_written, const char *format, ...);
|
||||
BLUE_API char *b_bstr_vfmt(size_t *nr_written, const char *format, va_list arg);
|
||||
|
||||
#endif
|
||||
@@ -335,6 +335,8 @@ static inline b_btree_node *b_btree_parent(b_btree_node *node)
|
||||
return node->b_parent;
|
||||
}
|
||||
|
||||
BLUE_API void b_btree_move(b_btree *tree, b_btree_node *dest, b_btree_node *src);
|
||||
|
||||
/* get the height of `node`.
|
||||
|
||||
the height of a node is defined as the length of the longest path
|
||||
|
||||
@@ -372,7 +372,7 @@ BLUE_API enum b_status z__b_error_add_submsg_template(
|
||||
error, type, msg_id, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
|
||||
BLUE_API void b_error_release(b_error *error);
|
||||
BLUE_API void b_error_discard(b_error *error);
|
||||
|
||||
BLUE_API b_error_status_code b_error_get_status_code(const b_error *error);
|
||||
BLUE_API const b_error_vendor *b_error_get_vendor(const b_error *error);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256
|
||||
|
||||
struct b_hash_function_ops;
|
||||
struct b_rope;
|
||||
|
||||
typedef enum b_hash_function {
|
||||
B_HASH_NONE = 0,
|
||||
@@ -103,6 +104,7 @@ BLUE_API uint64_t b_hash_cstr_ex(const char *s, size_t *len);
|
||||
BLUE_API b_status b_hash_ctx_init(b_hash_ctx *ctx, b_hash_function func);
|
||||
BLUE_API b_status b_hash_ctx_reset(b_hash_ctx *ctx);
|
||||
BLUE_API b_status b_hash_ctx_update(b_hash_ctx *ctx, const void *p, size_t len);
|
||||
BLUE_API b_status b_hash_ctx_update_rope(b_hash_ctx *ctx, const struct b_rope *rope);
|
||||
BLUE_API b_status b_hash_ctx_finish(
|
||||
b_hash_ctx *ctx, void *out_digest, size_t out_max);
|
||||
|
||||
|
||||
@@ -83,7 +83,10 @@ BLUE_API b_status b_iterator_move_next(const b_iterator *it);
|
||||
BLUE_API b_iterator_value b_iterator_get_value(b_iterator *it);
|
||||
BLUE_API const b_iterator_value b_iterator_get_cvalue(const b_iterator *it);
|
||||
BLUE_API b_status b_iterator_erase(b_iterator *it);
|
||||
BLUE_API b_status b_iterator_is_valid(const b_iterator *it);
|
||||
static inline bool b_iterator_is_valid(const b_iterator *it)
|
||||
{
|
||||
return B_OK(b_iterator_get_status(it));
|
||||
}
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
|
||||
@@ -35,24 +35,24 @@ static inline void b_queue_init(b_queue *q)
|
||||
}
|
||||
static inline bool b_queue_empty(const b_queue *q)
|
||||
{
|
||||
return q->q_first == NULL;
|
||||
return q ? (q->q_first == NULL) : true;
|
||||
}
|
||||
|
||||
static inline b_queue_entry *b_queue_first(const b_queue *q)
|
||||
{
|
||||
return q->q_first;
|
||||
return q ? q->q_first : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_last(const b_queue *q)
|
||||
{
|
||||
return q->q_last;
|
||||
return q ? q->q_last : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_next(const b_queue_entry *entry)
|
||||
{
|
||||
return entry->qe_next;
|
||||
return entry ? entry->qe_next : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_prev(const b_queue_entry *entry)
|
||||
{
|
||||
return entry->qe_prev;
|
||||
return entry ? entry->qe_prev : NULL;
|
||||
}
|
||||
|
||||
BLUE_API b_type b_queue_iterator_get_type(void);
|
||||
@@ -70,6 +70,7 @@ BLUE_API void b_queue_push_back(b_queue *q, b_queue_entry *entry);
|
||||
BLUE_API b_queue_entry *b_queue_pop_front(b_queue *q);
|
||||
BLUE_API b_queue_entry *b_queue_pop_back(b_queue *q);
|
||||
|
||||
BLUE_API void b_queue_move(b_queue *q, b_queue_entry *dest, b_queue_entry *src);
|
||||
BLUE_API void b_queue_delete(b_queue *q, b_queue_entry *entry);
|
||||
BLUE_API void b_queue_delete_all(b_queue *q);
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
struct b_string;
|
||||
struct b_bstr;
|
||||
|
||||
#define B_ROPE_TYPE(f) ((f) & 0xFF)
|
||||
|
||||
@@ -17,7 +19,7 @@ struct b_string;
|
||||
.r_v = {.v_char = (c) } \
|
||||
}
|
||||
|
||||
#define B_ROPE_CSTR(str) \
|
||||
#define B_ROPE_CSTR(str) \
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_CSTR_BORROWED, \
|
||||
.r_len_total = strlen(str), \
|
||||
@@ -29,7 +31,7 @@ struct b_string;
|
||||
}, \
|
||||
}
|
||||
|
||||
#define B_ROPE_CSTR_STATIC(str) \
|
||||
#define B_ROPE_CSTR_STATIC(str) \
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_CSTR_STATIC, \
|
||||
.r_len_total = strlen(str), \
|
||||
@@ -94,10 +96,14 @@ BLUE_API void b_rope_init_uint(b_rope *rope, uintptr_t v);
|
||||
|
||||
BLUE_API void b_rope_destroy(b_rope *rope);
|
||||
|
||||
BLUE_API void b_rope_iterate(
|
||||
const b_rope *rope, void (*func)(const b_rope *, void *), void *arg);
|
||||
BLUE_API size_t b_rope_get_size(const b_rope *rope);
|
||||
BLUE_API void b_rope_concat(b_rope *result, const b_rope *left, const b_rope *right);
|
||||
BLUE_API void b_rope_join(b_rope *result, const b_rope **ropes, size_t nr_ropes);
|
||||
|
||||
BLUE_API void b_rope_to_cstr(const b_rope *rope, char *out, size_t max);
|
||||
BLUE_API b_status b_rope_to_cstr(const b_rope *rope, char *out, size_t max);
|
||||
BLUE_API b_status b_rope_to_bstr(const b_rope *rope, struct b_bstr *str);
|
||||
BLUE_API b_status b_rope_to_string(const b_rope *rope, b_stream *out);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,20 +30,6 @@ BLUE_API char *b_stringstream_steal(b_stringstream *strv);
|
||||
|
||||
BLUE_API size_t b_stringstream_get_length(const b_stringstream *strv);
|
||||
|
||||
#if 0
|
||||
BLUE_API void b_stringstream_push_indent(b_stringstream *strv, int indent);
|
||||
BLUE_API void b_stringstream_pop_indent(b_stringstream *strv);
|
||||
|
||||
BLUE_API b_status b_stringstream_add(b_stringstream *strv, const char *str);
|
||||
BLUE_API b_status b_stringstream_addf(b_stringstream *strv, const char *format, ...);
|
||||
BLUE_API b_status b_stringstream_addv(b_stringstream *strv, const char **strs);
|
||||
BLUE_API b_status b_stringstream_addvf(
|
||||
b_stringstream *strv, const char *format, va_list arg);
|
||||
BLUE_API b_status b_stringstream_addvl(
|
||||
b_stringstream *strv, const char **strs, size_t count);
|
||||
BLUE_API b_status b_stringstream_add_many(b_stringstream *strv, ...);
|
||||
#endif
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -68,7 +68,7 @@ struct _b_object *b_object_create(b_type type)
|
||||
struct _b_object *out = NULL;
|
||||
b_result result = b_object_instantiate(type_reg, &out);
|
||||
if (b_result_is_error(result)) {
|
||||
b_error_release(result);
|
||||
b_error_discard(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
21
core/queue.c
21
core/queue.c
@@ -102,6 +102,27 @@ struct b_queue_entry *b_queue_pop_back(struct b_queue *q)
|
||||
return x;
|
||||
}
|
||||
|
||||
void b_queue_move(b_queue *q, b_queue_entry *dest, b_queue_entry *src)
|
||||
{
|
||||
if (src->qe_next) {
|
||||
src->qe_next->qe_prev = dest;
|
||||
}
|
||||
|
||||
if (src->qe_prev) {
|
||||
src->qe_prev->qe_next = dest;
|
||||
}
|
||||
|
||||
if (q->q_first == src) {
|
||||
q->q_first = dest;
|
||||
}
|
||||
|
||||
if (q->q_last == src) {
|
||||
q->q_last = dest;
|
||||
}
|
||||
|
||||
memmove(dest, src, sizeof *src);
|
||||
}
|
||||
|
||||
void b_queue_delete(struct b_queue *q, struct b_queue_entry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
|
||||
99
core/rope.c
99
core/rope.c
@@ -1,3 +1,4 @@
|
||||
#include <blue/core/bstr.h>
|
||||
#include <blue/core/rope.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
@@ -86,6 +87,23 @@ void b_rope_destroy(struct b_rope *rope)
|
||||
}
|
||||
}
|
||||
|
||||
void b_rope_iterate(
|
||||
const struct b_rope *rope, void (*func)(const b_rope *, void *), void *arg)
|
||||
{
|
||||
if (B_ROPE_TYPE(rope->r_flags) != B_ROPE_F_COMPOSITE) {
|
||||
func(rope, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rope->r_v.v_composite.r_left) {
|
||||
b_rope_iterate(rope->r_v.v_composite.r_left, func, arg);
|
||||
}
|
||||
|
||||
if (rope->r_v.v_composite.r_right) {
|
||||
b_rope_iterate(rope->r_v.v_composite.r_right, func, arg);
|
||||
}
|
||||
}
|
||||
|
||||
size_t b_rope_get_size(const struct b_rope *rope)
|
||||
{
|
||||
return rope->r_len_total;
|
||||
@@ -181,56 +199,77 @@ static void rope_iterate(
|
||||
}
|
||||
}
|
||||
|
||||
struct to_cstr_args {
|
||||
char *str;
|
||||
size_t max;
|
||||
size_t ptr;
|
||||
};
|
||||
|
||||
static void to_cstr(const struct b_rope *rope, void *arg)
|
||||
static void to_bstr(const struct b_rope *rope, void *arg)
|
||||
{
|
||||
struct to_cstr_args *str = arg;
|
||||
if (str->ptr >= str->max) {
|
||||
return;
|
||||
}
|
||||
b_bstr *str = arg;
|
||||
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
char *dest = str->str + str->ptr;
|
||||
size_t capacity = str->max - str->ptr;
|
||||
size_t nr_written = 0;
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
nr_written = snprintf(dest, capacity, "%c", rope->r_v.v_char);
|
||||
b_bstr_write_char(str, rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
nr_written = snprintf(dest, capacity, "%s", rope->r_v.v_cstr.s);
|
||||
b_bstr_write_cstr(str, rope->r_v.v_cstr.s, NULL);
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
nr_written
|
||||
= snprintf(dest, capacity, "%" PRIdPTR, rope->r_v.v_int);
|
||||
b_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
nr_written
|
||||
= snprintf(dest, capacity, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
b_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
str->ptr += nr_written;
|
||||
}
|
||||
|
||||
void b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
|
||||
static void to_stream(const struct b_rope *rope, void *arg)
|
||||
{
|
||||
struct to_cstr_args args = {
|
||||
.str = out,
|
||||
.max = max,
|
||||
.ptr = 0,
|
||||
};
|
||||
b_stream *out = arg;
|
||||
|
||||
rope_iterate(rope, to_cstr, &args);
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
b_stream_write_char(out, rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
b_stream_write_string(out, rope->r_v.v_cstr.s, NULL);
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
b_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
b_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b_status b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
|
||||
{
|
||||
b_bstr str;
|
||||
b_bstr_begin(&str, out, max);
|
||||
rope_iterate(rope, to_bstr, &str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_rope_to_bstr(const struct b_rope *rope, b_bstr *str)
|
||||
{
|
||||
rope_iterate(rope, to_bstr, str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_rope_to_string(const struct b_rope *rope, b_stream *out)
|
||||
{
|
||||
rope_iterate(rope, to_stream, out);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
177
core/stream.c
177
core/stream.c
@@ -1,10 +1,14 @@
|
||||
#include "printf.h"
|
||||
|
||||
#include <blue/core/bstr.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define READ_MAGIC(p) (*(uint64_t *)p)
|
||||
#define IS_BSTR(p) (READ_MAGIC(p) == B_BSTR_MAGIC)
|
||||
|
||||
#define B_TYPE_STDIO_STREAM (b_stdio_stream_get_type())
|
||||
|
||||
#define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \
|
||||
@@ -369,6 +373,39 @@ static enum b_status stream_read_line_s(
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status stream_read_line_to_bstr(
|
||||
struct stream_data *src, struct b_bstr *dest)
|
||||
{
|
||||
if (!(src->s_cfg->s_mode & B_STREAM_READ)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
size_t i = 0;
|
||||
b_wchar c = 0;
|
||||
|
||||
while (1) {
|
||||
status = stream_read_char(src, &c);
|
||||
if (status != B_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
b_bstr_write_char(dest, c);
|
||||
i++;
|
||||
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == B_ERR_NO_DATA && i > 0) {
|
||||
status = B_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status stream_write_bytes(
|
||||
struct stream_data *stream, const void *buf, size_t count, size_t *nr_written)
|
||||
{
|
||||
@@ -469,6 +506,57 @@ static enum b_status stream_read_all_bytes_s(
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status stream_read_all_bytes_to_bstr_s(
|
||||
struct stream_data *src, struct b_bstr *dest,
|
||||
struct b_stream_buffer_p *buffer, size_t *out_nr_read)
|
||||
{
|
||||
if (!(src->s_cfg->s_mode & B_STREAM_READ)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (src->s_ops->s_seek) {
|
||||
size_t offset = stream_cursor(src);
|
||||
stream_seek(src, 0, B_STREAM_SEEK_END);
|
||||
size_t length = stream_cursor(src);
|
||||
stream_seek(src, offset, B_STREAM_SEEK_START);
|
||||
|
||||
b_bstr_reserve(dest, length);
|
||||
}
|
||||
|
||||
enum b_status status = B_SUCCESS;
|
||||
size_t nr_read = 0;
|
||||
|
||||
while (1) {
|
||||
size_t r = 0, w = 0;
|
||||
status = stream_read_bytes(
|
||||
src, buffer->p_buf, buffer->p_buf_len, &r);
|
||||
if (status != B_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
status = b_bstr_write_chars(dest, buffer->p_buf, r, &w);
|
||||
nr_read += w;
|
||||
|
||||
if (status != B_SUCCESS || w != buffer->p_buf_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == B_ERR_NO_DATA && nr_read > 0) {
|
||||
status = B_SUCCESS;
|
||||
}
|
||||
|
||||
if (out_nr_read) {
|
||||
*out_nr_read = nr_read;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status stream_write_string(
|
||||
struct stream_data *stream, const char *s, size_t *nr_written)
|
||||
{
|
||||
@@ -642,6 +730,10 @@ b_stream *b_stream_open_fp(FILE *fp)
|
||||
|
||||
enum b_status b_stream_reserve(b_stream *stream, size_t len)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
B_CLASS_DISPATCH_VIRTUAL(
|
||||
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_reserve, stream,
|
||||
len);
|
||||
@@ -650,6 +742,10 @@ enum b_status b_stream_reserve(b_stream *stream, size_t len)
|
||||
enum b_status b_stream_seek(
|
||||
b_stream *stream, long long offset, b_stream_seek_origin origin)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
B_CLASS_DISPATCH_VIRTUAL(
|
||||
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_seek, stream,
|
||||
offset, origin);
|
||||
@@ -657,37 +753,65 @@ enum b_status b_stream_seek(
|
||||
|
||||
size_t b_stream_cursor(const b_stream *stream)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return b_bstr_get_size((b_bstr *)stream);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL_0(stream_cursor, stream);
|
||||
}
|
||||
|
||||
enum b_status b_stream_push_indent(b_stream *strp, int indent)
|
||||
{
|
||||
if (IS_BSTR(strp)) {
|
||||
return b_bstr_push_indent((b_bstr *)strp, indent);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_push_indent, strp, indent);
|
||||
}
|
||||
|
||||
enum b_status b_stream_pop_indent(b_stream *strp)
|
||||
{
|
||||
if (IS_BSTR(strp)) {
|
||||
return b_bstr_pop_indent((b_bstr *)strp);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL_0(stream_pop_indent, strp);
|
||||
}
|
||||
|
||||
enum b_status b_stream_read_char(b_stream *strp, int *c)
|
||||
{
|
||||
if (IS_BSTR(strp)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_read_char, strp, c);
|
||||
}
|
||||
|
||||
enum b_status b_stream_read_bytes(
|
||||
b_stream *strp, void *buf, size_t count, size_t *nr_read)
|
||||
{
|
||||
if (IS_BSTR(strp)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_read_bytes, strp, buf, count, nr_read);
|
||||
}
|
||||
|
||||
enum b_status b_stream_read_line(b_stream *strp, char *s, size_t max)
|
||||
{
|
||||
if (IS_BSTR(strp)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_read_line, strp, s, max);
|
||||
}
|
||||
|
||||
enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
|
||||
{
|
||||
if (IS_BSTR(src)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
enum b_status status;
|
||||
struct stream_data src_p, dest_p;
|
||||
|
||||
@@ -696,6 +820,10 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (IS_BSTR(dest)) {
|
||||
return stream_read_line_to_bstr(&src_p, (b_bstr *)dest);
|
||||
}
|
||||
|
||||
status = stream_get_data(dest, &dest_p);
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
@@ -707,12 +835,20 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
|
||||
enum b_status b_stream_read_all_bytes(
|
||||
b_stream *stream, void *p, size_t max, size_t *out_nr_read)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_read_all_bytes, stream, p, max, out_nr_read);
|
||||
}
|
||||
|
||||
enum b_status b_stream_read_all_bytes_s(
|
||||
b_stream *src, b_stream *dest, b_stream_buffer *buffer, size_t *out_nr_read)
|
||||
{
|
||||
if (IS_BSTR(src)) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
enum b_status status;
|
||||
struct stream_data src_p, dest_p;
|
||||
struct b_stream_buffer_p *buffer_p;
|
||||
@@ -722,39 +858,66 @@ enum b_status b_stream_read_all_bytes_s(
|
||||
return status;
|
||||
}
|
||||
|
||||
status = stream_get_data(dest, &dest_p);
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
buffer_p = b_object_get_private(buffer, B_TYPE_STREAM_BUFFER);
|
||||
if (!buffer_p) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (IS_BSTR(dest)) {
|
||||
return stream_read_all_bytes_to_bstr_s(
|
||||
&src_p, (b_bstr *)dest, buffer_p, out_nr_read);
|
||||
}
|
||||
|
||||
status = stream_get_data(dest, &dest_p);
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return stream_read_all_bytes_s(&src_p, &dest_p, buffer_p, out_nr_read);
|
||||
}
|
||||
|
||||
enum b_status b_stream_write_char(b_stream *stream, b_wchar c)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return b_bstr_write_char((b_bstr *)stream, c);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_write_char, stream, c);
|
||||
}
|
||||
|
||||
enum b_status b_stream_write_string(
|
||||
b_stream *stream, const char *s, size_t *nr_written)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return b_bstr_write_cstr((b_bstr *)stream, s, nr_written);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_write_string, stream, s, nr_written);
|
||||
}
|
||||
|
||||
enum b_status b_stream_write_bytes(
|
||||
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return b_bstr_write_chars((b_bstr *)stream, buf, count, nr_written);
|
||||
}
|
||||
|
||||
STREAM_DISPATCH_VIRTUAL(stream_write_bytes, stream, buf, count, nr_written);
|
||||
}
|
||||
|
||||
enum b_status b_stream_write_fmt(
|
||||
b_stream *stream, size_t *nr_written, const char *format, ...)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
b_status w = b_bstr_write_vfmt(
|
||||
(b_bstr *)stream, nr_written, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
struct stream_data p;
|
||||
enum b_status status = stream_get_data(stream, &p);
|
||||
|
||||
@@ -773,6 +936,10 @@ enum b_status b_stream_write_fmt(
|
||||
enum b_status b_stream_write_vfmt(
|
||||
b_stream *stream, size_t *nr_written, const char *format, va_list arg)
|
||||
{
|
||||
if (IS_BSTR(stream)) {
|
||||
return b_bstr_write_vfmt((b_bstr *)stream, nr_written, format, arg);
|
||||
}
|
||||
|
||||
struct stream_data p;
|
||||
enum b_status status = stream_get_data(stream, &p);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
struct b_stringstream_p {
|
||||
char *ss_buf;
|
||||
size_t ss_ptr;
|
||||
size_t ss_len;
|
||||
size_t ss_max;
|
||||
unsigned char ss_alloc;
|
||||
@@ -17,6 +18,50 @@ struct b_stringstream_p {
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static enum b_status __getc(struct b_stringstream_p *ss, b_wchar *out)
|
||||
{
|
||||
size_t available = ss->ss_len - ss->ss_ptr;
|
||||
|
||||
const char *p = ss->ss_buf + ss->ss_ptr;
|
||||
|
||||
size_t to_copy = b_wchar_utf8_codepoint_stride(p);
|
||||
if (to_copy > available) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
b_wchar c = b_wchar_utf8_codepoint_decode(p);
|
||||
*out = c;
|
||||
|
||||
if (c == B_WCHAR_INVALID) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
ss->ss_ptr += to_copy;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status __gets(
|
||||
struct b_stringstream_p *ss, char *s, size_t len, size_t *nr_read)
|
||||
{
|
||||
size_t available = ss->ss_len - ss->ss_ptr;
|
||||
size_t to_copy = len;
|
||||
|
||||
if (available < to_copy) {
|
||||
to_copy = available;
|
||||
}
|
||||
|
||||
memcpy(s, ss->ss_buf + ss->ss_ptr, to_copy);
|
||||
|
||||
ss->ss_ptr += to_copy;
|
||||
|
||||
if (nr_read) {
|
||||
*nr_read = to_copy;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status __puts(
|
||||
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
|
||||
{
|
||||
@@ -111,7 +156,7 @@ b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max)
|
||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
||||
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
|
||||
p->ss_buf = buf;
|
||||
p->ss_max = max;
|
||||
@@ -131,7 +176,7 @@ b_stringstream *b_stringstream_create(void)
|
||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
||||
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
|
||||
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
||||
if (!p->ss_buf) {
|
||||
@@ -193,6 +238,26 @@ static void stringstream_fini(b_object *obj, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
enum b_status stream_getc(b_stream *stream, b_wchar *c)
|
||||
{
|
||||
struct b_stringstream_p *s
|
||||
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||
|
||||
enum b_status status = __getc(s, c);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status stream_read(b_stream *stream, void *buf, size_t count, size_t *nr_read)
|
||||
{
|
||||
struct b_stringstream_p *s
|
||||
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||
|
||||
enum b_status status = __gets(s, buf, count, nr_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status stream_write(
|
||||
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
||||
{
|
||||
@@ -215,8 +280,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream)
|
||||
B_INTERFACE_ENTRY(s_close) = NULL;
|
||||
B_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
B_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
B_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
B_INTERFACE_ENTRY(s_read) = NULL;
|
||||
B_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
B_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
B_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
B_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)
|
||||
|
||||
@@ -371,6 +371,7 @@ static b_iterator *iterable_begin(b_object *obj)
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
@@ -389,6 +390,7 @@ static const b_iterator *iterable_cbegin(const b_object *obj)
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <blue/ds/bitbuffer.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_bitbuffer_p {
|
||||
int x;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void bitbuffer_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
static void bitbuffer_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_bitbuffer)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_bitbuffer)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_bitbuffer)
|
||||
B_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
|
||||
B_TYPE_CLASS(b_bitbuffer_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_bitbuffer_p);
|
||||
B_TYPE_INSTANCE_INIT(bitbuffer_init);
|
||||
B_TYPE_INSTANCE_FINI(bitbuffer_fini);
|
||||
B_TYPE_DEFINITION_END(b_bitbuffer)
|
||||
|
||||
102
ds/hashmap.c
102
ds/hashmap.c
@@ -366,6 +366,54 @@ bool b_hashmap_is_empty(const b_hashmap *hashmap)
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_is_empty, hashmap);
|
||||
}
|
||||
|
||||
b_iterator *b_hashmap_begin(b_hashmap *hashmap)
|
||||
{
|
||||
b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR);
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
it->_h = hashmap;
|
||||
it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
|
||||
|
||||
it->i = 0;
|
||||
if (b_hashmap_is_empty(hashmap)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_hashmap_bucket_item *first_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap)
|
||||
{
|
||||
return b_hashmap_begin((b_hashmap *)hashmap);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void hashmap_init(b_object *obj, void *priv)
|
||||
@@ -410,54 +458,6 @@ static void hashmap_fini(b_object *obj, void *priv)
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static b_iterator *iterable_begin(b_hashmap *hashmap)
|
||||
{
|
||||
b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR);
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
it->_h = hashmap;
|
||||
it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
|
||||
|
||||
it->i = 0;
|
||||
if (b_hashmap_is_empty(hashmap)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_hashmap_bucket_item *first_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const b_iterator *iterable_cbegin(const b_hashmap *hashmap)
|
||||
{
|
||||
return iterable_begin((b_hashmap *)hashmap);
|
||||
}
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_hashmap_iterator_p *it
|
||||
@@ -485,7 +485,7 @@ static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return true;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
@@ -562,8 +562,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap)
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
B_INTERFACE_ENTRY(it_begin) = b_hashmap_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = b_hashmap_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_hashmap)
|
||||
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
#ifndef BLUE_OBJECT_BITBUFFER_H_
|
||||
#define BLUE_OBJECT_BITBUFFER_H_
|
||||
#ifndef BLUE_DS_BITBUFFER_H_
|
||||
#define BLUE_DS_BITBUFFER_H_
|
||||
|
||||
#include <blue/ds/object.h>
|
||||
#include <blue/core/macros.h>
|
||||
|
||||
#define B_BITBUFFER(p) ((b_bitbuffer *)(p))
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
typedef struct b_bitbuffer b_bitbuffer;
|
||||
B_DECLARE_TYPE(b_bitbuffer);
|
||||
|
||||
BLUE_API b_bitbuffer *b_bitbuffer_create(void);
|
||||
|
||||
static inline b_bitbuffer *b_bitbuffer_retain(b_bitbuffer *buf)
|
||||
{
|
||||
return B_BITBUFFER(b_retain(B_DSREF(buf)));
|
||||
}
|
||||
static inline void b_bitbuffer_release(b_bitbuffer *buf)
|
||||
{
|
||||
b_release(B_DSREF(buf));
|
||||
}
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_bitbuffer)
|
||||
;
|
||||
B_TYPE_CLASS_DECLARATION_END(b_bitbuffer);
|
||||
|
||||
BLUE_API b_status b_bitbuffer_put_bit(b_bitbuffer *buf, int bit);
|
||||
BLUE_API b_status b_bitbuffer_put_bool(b_bitbuffer *buf, bool b);
|
||||
@@ -27,4 +20,6 @@ BLUE_API b_status b_bitbuffer_put_bytes(
|
||||
BLUE_API b_status b_bitbuffer_put_string(
|
||||
b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -75,6 +75,9 @@ BLUE_API bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *k
|
||||
BLUE_API size_t b_hashmap_get_size(const b_hashmap *hashmap);
|
||||
BLUE_API bool b_hashmap_is_empty(const b_hashmap *hashmap);
|
||||
|
||||
BLUE_API b_iterator *b_hashmap_begin(b_hashmap *hashmap);
|
||||
BLUE_API const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -56,7 +56,7 @@ BLUE_API void b_list_delete_all(b_list *q);
|
||||
BLUE_API void *b_list_entry_value(const b_list_entry *entry);
|
||||
|
||||
BLUE_API b_iterator *b_list_begin(b_list *q);
|
||||
BLUE_API b_iterator *b_list_cbegin(const b_list *q);
|
||||
BLUE_API const b_iterator *b_list_cbegin(const b_list *q);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
|
||||
@@ -17,8 +17,11 @@ B_DECLARE_TYPE(b_uuid);
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_uuid)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_uuid)
|
||||
|
||||
typedef struct b_uuid_bytes {
|
||||
unsigned char uuid_bytes[B_UUID_NBYTES];
|
||||
typedef union b_uuid_bytes {
|
||||
uint8_t uuid_bytes[B_UUID_NBYTES];
|
||||
uint16_t uuid_words[B_UUID_NBYTES / 2];
|
||||
uint32_t uuid_dwords[B_UUID_NBYTES / 4];
|
||||
uint64_t uuid_qwords[B_UUID_NBYTES / 8];
|
||||
} b_uuid_bytes;
|
||||
|
||||
BLUE_API b_type b_uuid_get_type(void);
|
||||
|
||||
38
ds/list.c
38
ds/list.c
@@ -365,22 +365,7 @@ void *b_list_entry_value(const struct b_list_entry *entry)
|
||||
return entry ? entry->e_data : NULL;
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void list_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
}
|
||||
|
||||
static void list_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
list_delete_all(list);
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static b_iterator *iterable_begin(b_list *q)
|
||||
b_iterator *b_list_begin(b_list *q)
|
||||
{
|
||||
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
|
||||
struct b_list_iterator_p *it
|
||||
@@ -399,7 +384,7 @@ static b_iterator *iterable_begin(b_list *q)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const b_iterator *iterable_cbegin(const b_list *q)
|
||||
const b_iterator *b_list_cbegin(const b_list *q)
|
||||
{
|
||||
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
|
||||
struct b_list_iterator_p *it
|
||||
@@ -418,6 +403,21 @@ static const b_iterator *iterable_cbegin(const b_list *q)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void list_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
}
|
||||
|
||||
static void list_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
list_delete_all(list);
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_list_iterator_p *it
|
||||
@@ -493,8 +493,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_list)
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
B_INTERFACE_ENTRY(it_begin) = b_list_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = b_list_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_list)
|
||||
|
||||
|
||||
39
ds/string.c
39
ds/string.c
@@ -8,7 +8,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* maximum length of string that can be stored inline, not including null-terminator */
|
||||
/* maximum length of string that can be stored inline, not including
|
||||
* null-terminator */
|
||||
#define STRING_INLINE_CAPACITY 15
|
||||
|
||||
#define IS_VALID_UTF8_SCALAR(x) \
|
||||
@@ -48,7 +49,6 @@ struct b_string_iterator_p {
|
||||
const char **_d;
|
||||
size_t _nd, _ds;
|
||||
|
||||
b_status status;
|
||||
size_t iteration_index;
|
||||
size_t byte_index;
|
||||
size_t codepoint_index;
|
||||
@@ -244,7 +244,8 @@ static int string_change_capacity(struct b_string_p *str, size_t capacity)
|
||||
bool is_now_inline = capacity == STRING_INLINE_CAPACITY;
|
||||
|
||||
if (capacity == old_capacity) {
|
||||
/* this also handles the case where the old and new capacity both fit into the inline buffer. */
|
||||
/* this also handles the case where the old and new capacity
|
||||
* both fit into the inline buffer. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1412,7 +1413,7 @@ static b_iterator *iterator_begin(b_object *obj)
|
||||
struct b_string_p *p = b_object_get_private(obj, B_TYPE_STRING);
|
||||
|
||||
if (!p->s_len) {
|
||||
it->status = B_ERR_NO_DATA;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
@@ -1422,12 +1423,17 @@ static b_iterator *iterator_begin(b_object *obj)
|
||||
it->char_value = b_wchar_utf8_codepoint_decode(s);
|
||||
|
||||
if (it->char_value == B_WCHAR_INVALID) {
|
||||
it->status = B_ERR_BAD_FORMAT;
|
||||
b_iterator_set_status(it_obj, B_ERR_BAD_FORMAT);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const b_iterator *iterator_cbegin(const b_object *obj)
|
||||
{
|
||||
return iterator_begin((b_object *)obj);
|
||||
}
|
||||
|
||||
static enum b_status chars_iterator_move_next(struct b_string_iterator_p *it)
|
||||
{
|
||||
if (!it->_s_p) {
|
||||
@@ -1443,6 +1449,7 @@ static enum b_status chars_iterator_move_next(struct b_string_iterator_p *it)
|
||||
it->codepoint_index += 1;
|
||||
|
||||
if (it->byte_index >= it->_s_p->s_len) {
|
||||
it->char_value = B_WCHAR_INVALID;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
@@ -1513,6 +1520,21 @@ static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
}
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_string_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_STRING_ITERATOR);
|
||||
|
||||
switch (it->_m) {
|
||||
case ITERATOR_MODE_CHARS:
|
||||
return chars_iterator_get_value(it);
|
||||
case ITERATOR_MODE_TOKENS:
|
||||
return tokens_iterator_get_value(it);
|
||||
default:
|
||||
return B_ITERATOR_VALUE_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_string DEFINITION
|
||||
@@ -1520,10 +1542,16 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_string)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = string_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterator_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_string)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_string)
|
||||
B_TYPE_ID(0x200194f6, 0x0327, 0x4a82, 0xb9c9, 0xb62ddd038c33);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_CLASS(b_string_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_string_p);
|
||||
B_TYPE_INSTANCE_INIT(string_init);
|
||||
@@ -1540,6 +1568,7 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_string_iterator)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = NULL;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_string_iterator)
|
||||
|
||||
|
||||
14
ds/uuid.c
14
ds/uuid.c
@@ -9,7 +9,7 @@
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_uuid_p {
|
||||
struct b_uuid_bytes uuid_bytes;
|
||||
union b_uuid_bytes uuid_bytes;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
@@ -39,12 +39,12 @@ static void uuid_get_bytes(
|
||||
}
|
||||
|
||||
static void uuid_get_uuid_bytes(
|
||||
const struct b_uuid_p *uuid, struct b_uuid_bytes *bytes)
|
||||
const struct b_uuid_p *uuid, union b_uuid_bytes *bytes)
|
||||
{
|
||||
memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes);
|
||||
}
|
||||
|
||||
static struct b_uuid_bytes *uuid_ptr(struct b_uuid_p *uuid)
|
||||
static union b_uuid_bytes *uuid_ptr(struct b_uuid_p *uuid)
|
||||
{
|
||||
return &uuid->uuid_bytes;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES])
|
||||
|
||||
b_uuid *b_uuid_create_from_cstr(const char *str)
|
||||
{
|
||||
struct b_uuid_bytes bytes;
|
||||
union b_uuid_bytes bytes;
|
||||
|
||||
bool valid = true;
|
||||
bool is_guid = false;
|
||||
@@ -169,19 +169,19 @@ void b_uuid_get_bytes(const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES])
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_bytes, uuid, bytes);
|
||||
}
|
||||
|
||||
void b_uuid_get_uuid_bytes(const b_uuid *uuid, struct b_uuid_bytes *bytes)
|
||||
void b_uuid_get_uuid_bytes(const b_uuid *uuid, union b_uuid_bytes *bytes)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_uuid_bytes, uuid, bytes);
|
||||
}
|
||||
|
||||
struct b_uuid_bytes *b_uuid_ptr(b_uuid *uuid)
|
||||
union b_uuid_bytes *b_uuid_ptr(b_uuid *uuid)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_UUID, uuid_ptr, uuid);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
b_uuid *b_uuid_create_from_uuid_bytes(const struct b_uuid_bytes *bytes)
|
||||
b_uuid *b_uuid_create_from_uuid_bytes(const union b_uuid_bytes *bytes)
|
||||
{
|
||||
return b_uuid_create_from_bytev(bytes->uuid_bytes);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,18 @@ B_DECLS_BEGIN;
|
||||
|
||||
struct b_directory_p;
|
||||
|
||||
#define B_TYPE_DIRECTORY (b_directory_get_type())
|
||||
#define B_TYPE_DIRECTORY (b_directory_get_type())
|
||||
#define B_TYPE_DIRECTORY_ITERATOR (b_directory_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_directory);
|
||||
B_DECLARE_TYPE(b_directory_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_directory)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_directory)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_directory_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_directory_iterator)
|
||||
|
||||
struct z__b_directory_iterator;
|
||||
|
||||
typedef enum b_directory_iterator_flags {
|
||||
@@ -34,24 +39,14 @@ typedef enum b_directory_open_flags {
|
||||
B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u,
|
||||
} b_directory_open_flags;
|
||||
|
||||
typedef struct b_directory_iterator {
|
||||
b_iterator _base;
|
||||
struct z__b_directory_iterator *_z;
|
||||
struct b_directory_p *_p;
|
||||
|
||||
b_directory_iterator_flags flags;
|
||||
b_directory *root;
|
||||
|
||||
typedef struct b_directory_entry {
|
||||
const b_path *filepath;
|
||||
char *filename;
|
||||
b_file_info info;
|
||||
} b_directory_iterator;
|
||||
|
||||
#define b_directory_foreach(it, dir, flags) \
|
||||
for (int z__b_unique_name() = b_directory_iterator_begin(dir, it, flags); \
|
||||
b_directory_iterator_is_valid(it); b_directory_iterator_next(it))
|
||||
} b_directory_entry;
|
||||
|
||||
BLUE_API b_type b_directory_get_type(void);
|
||||
BLUE_API b_type b_directory_iterator_get_type(void);
|
||||
|
||||
BLUE_API b_result b_directory_open(
|
||||
b_directory *root, const b_path *path, b_directory_open_flags flags,
|
||||
@@ -72,12 +67,8 @@ BLUE_API b_result b_directory_path_stat(
|
||||
BLUE_API b_result b_directory_path_unlink(
|
||||
const b_directory *root, const b_path *path);
|
||||
|
||||
BLUE_API int b_directory_iterator_begin(
|
||||
b_directory *directory, b_directory_iterator *it,
|
||||
b_directory_iterator_flags flags);
|
||||
BLUE_API bool b_directory_iterator_next(b_directory_iterator *it);
|
||||
BLUE_API b_status b_directory_iterator_erase(b_directory_iterator *it);
|
||||
BLUE_API bool b_directory_iterator_is_valid(const b_directory_iterator *it);
|
||||
BLUE_API b_iterator *b_directory_begin(
|
||||
b_directory *dir, b_directory_iterator_flags flags);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
|
||||
@@ -25,9 +25,16 @@ struct b_directory_p {
|
||||
b_path *d_path_abs;
|
||||
};
|
||||
|
||||
struct z__b_directory_iterator {
|
||||
struct b_directory_iterator_p {
|
||||
struct b_directory_p *_p;
|
||||
|
||||
FTS *fts;
|
||||
FTSENT *ent;
|
||||
|
||||
b_directory_iterator_flags flags;
|
||||
b_directory *root;
|
||||
|
||||
b_directory_entry entry;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
@@ -55,13 +62,14 @@ static b_result directory_delete(b_directory *dir, struct b_directory_p *dir_p)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
struct b_directory_iterator it;
|
||||
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST);
|
||||
while (b_directory_iterator_is_valid(&it)) {
|
||||
status = b_directory_iterator_erase(&it);
|
||||
if (!B_OK(status)) {
|
||||
return B_RESULT_STATUS(status);
|
||||
}
|
||||
b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_LAST);
|
||||
while (B_OK(b_iterator_get_status(it))) {
|
||||
b_iterator_erase(it);
|
||||
}
|
||||
|
||||
status = b_iterator_get_status(it);
|
||||
if (!B_OK(status) && status != B_ERR_NO_DATA) {
|
||||
return B_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
status = b_path_unlink(dir_p->d_path_abs);
|
||||
@@ -190,7 +198,7 @@ static b_result create_directory(struct b_directory_p *root, const char *path)
|
||||
static b_result create_directory_hierarchy(
|
||||
struct b_directory_p *root, const char *path)
|
||||
{
|
||||
int root_fd = root->d_fd;
|
||||
int root_fd = root ? root->d_fd : AT_FDCWD;
|
||||
|
||||
char *path_buf = b_strdup(path);
|
||||
if (!path_buf) {
|
||||
@@ -417,22 +425,6 @@ static void directory_fini(b_object *obj, void *priv)
|
||||
b_path_unref(dir->d_path_abs);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_directory)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_directory)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_directory)
|
||||
B_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45);
|
||||
B_TYPE_CLASS(b_directory_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_directory_p);
|
||||
B_TYPE_INSTANCE_INIT(directory_init);
|
||||
B_TYPE_INSTANCE_FINI(directory_fini);
|
||||
B_TYPE_DEFINITION_END(b_directory)
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static int ftsent_compare(const FTSENT **one, const FTSENT **two)
|
||||
@@ -440,89 +432,71 @@ static int ftsent_compare(const FTSENT **one, const FTSENT **two)
|
||||
return (strcmp((*one)->fts_name, (*two)->fts_name));
|
||||
}
|
||||
|
||||
static void update_iterator_data(struct b_directory_iterator *it)
|
||||
static void update_iterator_data(struct b_directory_iterator_p *it)
|
||||
{
|
||||
struct z__b_directory_iterator *it_data = it->_z;
|
||||
|
||||
if (it->filepath) {
|
||||
b_path_unref((b_path *)it->filepath);
|
||||
it->filepath = NULL;
|
||||
if (it->entry.filepath) {
|
||||
b_path_unref((b_path *)it->entry.filepath);
|
||||
it->entry.filepath = NULL;
|
||||
}
|
||||
|
||||
FTSENT *ent = it_data->ent;
|
||||
FTSENT *ent = it->ent;
|
||||
|
||||
b_path *path = b_path_create_from_cstr(
|
||||
ent->fts_path + b_path_length(it->_p->d_path_abs) + 1);
|
||||
|
||||
it->filename = ent->fts_name;
|
||||
it->filepath = path;
|
||||
it->entry.filename = ent->fts_name;
|
||||
it->entry.filepath = path;
|
||||
|
||||
memset(&it->info, 0x0, sizeof it->info);
|
||||
memset(&it->entry.info, 0x0, sizeof it->entry.info);
|
||||
|
||||
it->info.length = ent->fts_statp->st_size;
|
||||
it->entry.info.length = ent->fts_statp->st_size;
|
||||
|
||||
if (S_ISREG(ent->fts_statp->st_mode)) {
|
||||
it->info.attrib |= B_FILE_ATTRIB_NORMAL;
|
||||
it->entry.info.attrib |= B_FILE_ATTRIB_NORMAL;
|
||||
}
|
||||
|
||||
if (S_ISDIR(ent->fts_statp->st_mode)) {
|
||||
it->info.attrib |= B_FILE_ATTRIB_DIRECTORY;
|
||||
it->entry.info.attrib |= B_FILE_ATTRIB_DIRECTORY;
|
||||
}
|
||||
|
||||
if (S_ISBLK(ent->fts_statp->st_mode)) {
|
||||
it->info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE;
|
||||
it->entry.info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISCHR(ent->fts_statp->st_mode)) {
|
||||
it->info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE;
|
||||
it->entry.info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISLNK(ent->fts_statp->st_mode)) {
|
||||
it->info.attrib |= B_FILE_ATTRIB_SYMLINK;
|
||||
it->entry.info.attrib |= B_FILE_ATTRIB_SYMLINK;
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup_iterator(struct b_directory_iterator *it)
|
||||
static void iterator_fini(b_object *obj, void *priv)
|
||||
{
|
||||
if (it->filepath) {
|
||||
b_path_unref((b_path *)it->filepath);
|
||||
it->filepath = NULL;
|
||||
struct b_directory_iterator_p *it = priv;
|
||||
|
||||
if (it->entry.filepath) {
|
||||
b_path_unref((b_path *)it->entry.filepath);
|
||||
it->entry.filepath = NULL;
|
||||
}
|
||||
|
||||
struct z__b_directory_iterator *it_data = it->_z;
|
||||
memset(it, 0x0, sizeof *it);
|
||||
|
||||
if (!it_data) {
|
||||
return;
|
||||
if (it->fts) {
|
||||
fts_close(it->fts);
|
||||
}
|
||||
|
||||
if (it_data->fts) {
|
||||
fts_close(it_data->fts);
|
||||
}
|
||||
|
||||
free(it_data);
|
||||
}
|
||||
|
||||
int b_directory_iterator_begin(
|
||||
b_directory *directory, struct b_directory_iterator *it,
|
||||
enum b_directory_iterator_flags flags)
|
||||
b_iterator *b_directory_begin(
|
||||
b_directory *directory, enum b_directory_iterator_flags flags)
|
||||
{
|
||||
memset(it, 0x0, sizeof *it);
|
||||
b_iterator *it_obj = b_object_create(B_TYPE_DIRECTORY_ITERATOR);
|
||||
struct b_directory_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
it->flags = flags;
|
||||
it->root = directory;
|
||||
it->_p = b_object_get_private(directory, B_TYPE_DIRECTORY);
|
||||
|
||||
struct z__b_directory_iterator *it_data = malloc(sizeof *it_data);
|
||||
|
||||
if (!it_data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(it_data, 0x0, sizeof *it_data);
|
||||
|
||||
it->_z = it_data;
|
||||
|
||||
int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
|
||||
|
||||
const char *path_list[] = {
|
||||
@@ -530,24 +504,23 @@ int b_directory_iterator_begin(
|
||||
NULL,
|
||||
};
|
||||
|
||||
it_data->fts
|
||||
= fts_open((char *const *)path_list, fts_flags, ftsent_compare);
|
||||
it->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare);
|
||||
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
it_data->ent = fts_read(it_data->fts);
|
||||
it->ent = fts_read(it->fts);
|
||||
|
||||
if (!it_data->ent) {
|
||||
cleanup_iterator(it);
|
||||
return -1;
|
||||
if (!it->ent) {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
if (it_data->ent->fts_level == 0) {
|
||||
if (it->ent->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it_data->ent->fts_info) {
|
||||
switch (it->ent->fts_info) {
|
||||
case FTS_DOT:
|
||||
continue;
|
||||
case FTS_F:
|
||||
@@ -573,31 +546,41 @@ int b_directory_iterator_begin(
|
||||
}
|
||||
|
||||
update_iterator_data(it);
|
||||
return 0;
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
bool b_directory_iterator_next(struct b_directory_iterator *it)
|
||||
static b_iterator *iterator_begin(b_object *obj)
|
||||
{
|
||||
struct z__b_directory_iterator *it_data = it->_z;
|
||||
if (!it_data || !it_data->fts) {
|
||||
return false;
|
||||
return b_directory_begin(obj, B_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
}
|
||||
|
||||
static const b_iterator *iterator_cbegin(const b_object *obj)
|
||||
{
|
||||
return b_directory_begin((b_object *)obj, B_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
}
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_directory_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
|
||||
if (!it || !it->fts) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
it_data->ent = fts_read(it_data->fts);
|
||||
it->ent = fts_read(it->fts);
|
||||
|
||||
if (!it_data->ent) {
|
||||
cleanup_iterator(it);
|
||||
return false;
|
||||
if (!it->ent) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (it_data->ent->fts_level == 0) {
|
||||
if (it->ent->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it_data->ent->fts_info) {
|
||||
switch (it->ent->fts_info) {
|
||||
case FTS_DOT:
|
||||
continue;
|
||||
case FTS_F:
|
||||
@@ -622,31 +605,79 @@ bool b_directory_iterator_next(struct b_directory_iterator *it)
|
||||
}
|
||||
|
||||
update_iterator_data(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
enum b_status b_directory_iterator_erase(struct b_directory_iterator *it)
|
||||
{
|
||||
b_result result = b_directory_path_unlink(it->root, it->filepath);
|
||||
if (b_result_is_error(result)) {
|
||||
enum b_status status = b_error_get_status_code(result);
|
||||
b_error_release(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
b_directory_iterator_next(it);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
bool b_directory_iterator_is_valid(const struct b_directory_iterator *it)
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
if (!it->_z) {
|
||||
return false;
|
||||
struct b_directory_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
|
||||
b_result result = b_directory_path_unlink(it->root, it->entry.filepath);
|
||||
if (b_result_is_error(result)) {
|
||||
enum b_status status = b_error_get_status_code(result);
|
||||
b_error_discard(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!it->_z->ent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return iterator_move_next(obj);
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_directory_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(&it->entry);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_directory_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(&it->entry);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_directory DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_directory)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterator_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_directory)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_directory)
|
||||
B_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45);
|
||||
B_TYPE_CLASS(b_directory_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_directory_p);
|
||||
B_TYPE_INSTANCE_INIT(directory_init);
|
||||
B_TYPE_INSTANCE_FINI(directory_fini);
|
||||
B_TYPE_DEFINITION_END(b_directory)
|
||||
|
||||
// ---- b_directory_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_directory_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_directory_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_directory_iterator)
|
||||
B_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_directory_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_directory_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_directory_iterator)
|
||||
|
||||
@@ -111,7 +111,7 @@ struct ctx {
|
||||
b_stream *ctx_src;
|
||||
b_string *ctx_wordbuf;
|
||||
b_string *ctx_linebuf;
|
||||
b_string_iterator ctx_linebuf_ptr;
|
||||
b_iterator *ctx_linebuf_ptr;
|
||||
enum b_status ctx_status;
|
||||
b_hashmap *ctx_objects_flags;
|
||||
|
||||
@@ -207,16 +207,16 @@ static enum b_status data_available(struct ctx *ctx)
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (!B_OK(ctx->ctx_linebuf_ptr.status)) {
|
||||
return ctx->ctx_linebuf_ptr.status;
|
||||
}
|
||||
|
||||
return b_string_iterator_is_valid(&ctx->ctx_linebuf_ptr) ? B_SUCCESS
|
||||
: B_ERR_NO_DATA;
|
||||
return b_iterator_get_status(ctx->ctx_linebuf_ptr);
|
||||
}
|
||||
|
||||
static enum b_status refill_linebuf(struct ctx *ctx)
|
||||
{
|
||||
if (ctx->ctx_linebuf_ptr) {
|
||||
b_iterator_unref(ctx->ctx_linebuf_ptr);
|
||||
ctx->ctx_linebuf_ptr = NULL;
|
||||
}
|
||||
|
||||
b_string_clear(ctx->ctx_linebuf);
|
||||
|
||||
b_stringstream *buf = b_stringstream_create();
|
||||
@@ -233,7 +233,7 @@ static enum b_status refill_linebuf(struct ctx *ctx)
|
||||
|
||||
b_stringstream_unref(buf);
|
||||
|
||||
b_string_iterator_begin(ctx->ctx_linebuf, &ctx->ctx_linebuf_ptr);
|
||||
ctx->ctx_linebuf_ptr = b_iterator_begin(ctx->ctx_linebuf);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
@@ -282,19 +282,15 @@ static b_wchar advance_char(struct ctx *ctx)
|
||||
}
|
||||
|
||||
const char *s = b_string_ptr(ctx->ctx_linebuf);
|
||||
if (!B_OK(ctx->ctx_linebuf_ptr.status)) {
|
||||
ctx->ctx_status = B_ERR_BAD_FORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
b_wchar c = ctx->ctx_linebuf_ptr.char_value;
|
||||
b_wchar c = b_iterator_get_value(ctx->ctx_linebuf_ptr).v_int;
|
||||
|
||||
if (!is_valid_char(c)) {
|
||||
ctx->ctx_status = B_ERR_BAD_FORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
b_string_iterator_next(&ctx->ctx_linebuf_ptr);
|
||||
b_iterator_move_next(ctx->ctx_linebuf_ptr);
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -318,12 +314,8 @@ static b_wchar peek_char(struct ctx *ctx)
|
||||
}
|
||||
|
||||
const char *s = b_string_ptr(ctx->ctx_linebuf);
|
||||
if (!B_OK(ctx->ctx_linebuf_ptr.status)) {
|
||||
ctx->ctx_status = B_ERR_BAD_FORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
b_wchar c = ctx->ctx_linebuf_ptr.char_value;
|
||||
b_wchar c = b_iterator_get_value(ctx->ctx_linebuf_ptr).v_int;
|
||||
|
||||
if (!is_valid_char(c)) {
|
||||
ctx->ctx_status = B_ERR_BAD_FORMAT;
|
||||
@@ -909,23 +901,26 @@ static void split_word(struct ctx *ctx, b_string *wordbuf)
|
||||
#endif
|
||||
const char *delims[] = {"."};
|
||||
size_t nr_delims = sizeof delims / sizeof delims[0];
|
||||
b_string_iterator it;
|
||||
b_string_tokenise(
|
||||
wordbuf, delims, nr_delims, B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS,
|
||||
&it);
|
||||
b_iterator *it = b_string_tokenise(
|
||||
wordbuf, delims, nr_delims, B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS);
|
||||
|
||||
while (b_string_iterator_is_valid(&it)) {
|
||||
if (it.iteration_index > 0) {
|
||||
size_t i = 0;
|
||||
b_foreach_c(const char *, tok, it)
|
||||
{
|
||||
if (i > 0) {
|
||||
enqueue_token(ctx, TOK_DOT);
|
||||
}
|
||||
|
||||
if (it.string_length > 0) {
|
||||
size_t len = strlen(tok);
|
||||
if (len > 0) {
|
||||
struct token *word = enqueue_token(ctx, TOK_WORD);
|
||||
word->tok_str = b_string_create_from_cstr(it.string_value);
|
||||
word->tok_str = b_string_create_from_cstr(tok);
|
||||
}
|
||||
|
||||
b_string_iterator_next(&it);
|
||||
i++;
|
||||
}
|
||||
|
||||
b_iterator_unref(it);
|
||||
}
|
||||
|
||||
static void read_number(struct ctx *ctx)
|
||||
@@ -1012,17 +1007,17 @@ static void read_word(struct ctx *ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
b_string_iterator it;
|
||||
b_string_foreach(&it, wordbuf)
|
||||
b_iterator *it = b_iterator_begin(wordbuf);
|
||||
b_foreach(b_wchar, c, it)
|
||||
{
|
||||
/* only allow ASCII numbers/letters here */
|
||||
bool ok = isalnum(it.char_value) || it.char_value == '_'
|
||||
|| it.char_value == '-' || it.char_value == '.';
|
||||
bool ok = isalnum(c) || c == '_' || c == '-' || c == '.';
|
||||
if (!ok) {
|
||||
ctx->ctx_status = B_ERR_BAD_FORMAT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
|
||||
split_word(ctx, wordbuf);
|
||||
}
|
||||
@@ -1514,6 +1509,11 @@ static struct token *peek_token(struct ctx *ctx)
|
||||
|
||||
static void ctx_cleanup(struct ctx *ctx)
|
||||
{
|
||||
if (ctx->ctx_linebuf_ptr) {
|
||||
b_iterator_unref(ctx->ctx_linebuf_ptr);
|
||||
ctx->ctx_linebuf_ptr = NULL;
|
||||
}
|
||||
|
||||
if (ctx->ctx_linebuf) {
|
||||
b_string_unref(ctx->ctx_linebuf);
|
||||
ctx->ctx_linebuf = NULL;
|
||||
|
||||
@@ -74,19 +74,21 @@ void test_btree_iterate(CuTest *tc)
|
||||
}
|
||||
|
||||
int prev = -1;
|
||||
b_btree_iterator it;
|
||||
b_btree_foreach (&it, &tree) {
|
||||
b_btree_node *bnode = b_btree_first(&tree);
|
||||
while (bnode) {
|
||||
struct test_tree_node *node
|
||||
= b_unbox(struct test_tree_node, it.node, node);
|
||||
= b_unbox(struct test_tree_node, bnode, node);
|
||||
CuAssertPtrNotNull(tc, node);
|
||||
|
||||
if (prev == -1) {
|
||||
prev = node->value;
|
||||
bnode = b_btree_next(bnode);
|
||||
continue;
|
||||
}
|
||||
|
||||
CuAssertTrue(tc, prev <= node->value);
|
||||
prev = node->value;
|
||||
bnode = b_btree_next(bnode);
|
||||
}
|
||||
|
||||
free(nodes);
|
||||
@@ -134,19 +136,21 @@ void test_queue_iterate(CuTest *tc)
|
||||
}
|
||||
|
||||
int prev = -1;
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &q) {
|
||||
struct b_queue_entry *entry = b_queue_first(&q);
|
||||
while (entry) {
|
||||
struct test_queue_entry *e
|
||||
= b_unbox(struct test_queue_entry, it.entry, entry);
|
||||
= b_unbox(struct test_queue_entry, entry, entry);
|
||||
CuAssertPtrNotNull(tc, e);
|
||||
|
||||
if (prev == -1) {
|
||||
prev = e->value;
|
||||
continue;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
CuAssertTrue(tc, prev < e->value);
|
||||
prev = e->value;
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
84
test/core/ropes.c
Normal file
84
test/core/ropes.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <blue/core/rope.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void print_rope(const struct b_rope *rope, int depth)
|
||||
{
|
||||
for (int i = 0; i < depth; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf("[%x:", rope->r_flags);
|
||||
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CHAR) && printf(" CHAR");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR) && printf(" CSTR");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR_BORROWED)
|
||||
&& printf(" CSTR_BORROWED");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR_STATIC)
|
||||
&& printf(" CSTR_STATIC");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_INT) && printf(" INT");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_UINT) && printf(" UINT");
|
||||
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_COMPOSITE)
|
||||
&& printf(" COMPOSITE");
|
||||
(rope->r_flags & B_ROPE_F_MALLOC) && printf(" MALLOC");
|
||||
printf("] ");
|
||||
|
||||
switch (B_ROPE_TYPE(rope->r_flags)) {
|
||||
case B_ROPE_F_CHAR:
|
||||
printf("%c", rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
printf("%s", rope->r_v.v_cstr.s);
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
printf("%" PRIdPTR, rope->r_v.v_int);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
printf("%" PRIuPTR, rope->r_v.v_uint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_COMPOSITE) {
|
||||
if (rope->r_v.v_composite.r_left) {
|
||||
print_rope(rope->r_v.v_composite.r_left, depth + 1);
|
||||
}
|
||||
|
||||
if (rope->r_v.v_composite.r_right) {
|
||||
print_rope(rope->r_v.v_composite.r_right, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
b_rope a = B_ROPE_CHAR('a');
|
||||
b_rope b = B_ROPE_CSTR_STATIC("Hello, world!");
|
||||
b_rope c = B_ROPE_INT(-4096);
|
||||
b_rope d = B_ROPE_UINT(4096);
|
||||
|
||||
b_rope str;
|
||||
|
||||
const b_rope *ropes[] = {
|
||||
&a,
|
||||
&b,
|
||||
&c,
|
||||
&d,
|
||||
};
|
||||
|
||||
b_rope_join(&str, ropes, sizeof ropes / sizeof ropes[0]);
|
||||
|
||||
print_rope(&str, 0);
|
||||
|
||||
char cstr[1024];
|
||||
b_rope_to_cstr(&str, cstr, sizeof cstr);
|
||||
b_rope_destroy(&str);
|
||||
|
||||
printf("%s\n", cstr);
|
||||
return 0;
|
||||
}
|
||||
21
test/core/streams.c
Normal file
21
test/core/streams.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <blue/core/bstr.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
b_stream_read_line_s(b_stdin, b_stdout);
|
||||
b_stream_write_char(b_stdout, '\n');
|
||||
|
||||
char s[16];
|
||||
b_bstr str;
|
||||
b_bstr_begin(&str, s, sizeof s);
|
||||
|
||||
b_stream_read_line_s(b_stdin, (b_stream *)&str);
|
||||
b_stream_write_char((b_stream *)&str, '\n');
|
||||
|
||||
const char *e = b_bstr_end(&str);
|
||||
fputs(e, stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -9,11 +9,12 @@ int main(void)
|
||||
b_array_append(array, B_RV_INT(64));
|
||||
b_array_append(array, B_RV_INT(128));
|
||||
|
||||
b_array_iterator it;
|
||||
b_array_foreach(&it, array)
|
||||
b_iterator *it = b_iterator_begin(array);
|
||||
b_foreach_ptr(b_object, obj, it)
|
||||
{
|
||||
printf("object %p\n", it.value);
|
||||
printf("object %p\n", obj);
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
|
||||
b_array_unref(array);
|
||||
return 0;
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/ds/dict.h>
|
||||
#include <blue/ds/number.h>
|
||||
#include <blue/ds/tree.h>
|
||||
@@ -21,21 +22,23 @@ B_BTREE_DEFINE_SIMPLE_INSERT(struct btree_item, node, value, put_node)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
b_dict_item items[]
|
||||
= {B_DICT_ITEM("hello", B_RV_INT(32)),
|
||||
B_DICT_ITEM("world", B_RV_INT(64)),
|
||||
B_DICT_ITEM("more", B_RV_INT(128)),
|
||||
B_DICT_ITEM("other", B_RV_INT(256)), B_DICT_ITEM_END};
|
||||
b_dict *dict = b_dict_create();
|
||||
b_dict_put(dict, "hello", B_RV_INT(32));
|
||||
b_dict_put(dict, "world", B_RV_INT(64));
|
||||
b_dict_put(dict, "more", B_RV_INT(128));
|
||||
b_dict_put(dict, "other", B_RV_INT(256));
|
||||
|
||||
b_dict *dict = b_dict_create_with_items(items);
|
||||
b_iterator *it = b_iterator_begin(dict);
|
||||
|
||||
b_dict_iterator it;
|
||||
b_dict_foreach(&it, dict)
|
||||
size_t i = 0;
|
||||
b_foreach(b_dict_item *, item, it)
|
||||
{
|
||||
printf("item %zu: %s=%d\n", it.i, b_string_ptr(it.key),
|
||||
b_number_get_int(it.value));
|
||||
printf("item %zu: %s=%d\n", i++, b_string_ptr(item->key),
|
||||
b_number_get_int(item->value));
|
||||
}
|
||||
|
||||
b_iterator_unref(it);
|
||||
|
||||
b_tree *tree = b_tree_create();
|
||||
struct tree_item items2[NITEMS];
|
||||
|
||||
@@ -54,6 +57,8 @@ int main(void)
|
||||
b_tree_node_add_child(&items2[1].node, &items2[5].node);
|
||||
b_tree_node_add_child(&items2[4].node, &items2[6].node);
|
||||
|
||||
#if 0
|
||||
it = b_iterator_begin(tree);
|
||||
b_tree_iterator it2;
|
||||
b_tree_foreach(&it2, tree)
|
||||
{
|
||||
@@ -113,6 +118,7 @@ int main(void)
|
||||
}
|
||||
|
||||
b_tree_unref(tree);
|
||||
#endif
|
||||
b_dict_unref(dict);
|
||||
|
||||
return 0;
|
||||
@@ -12,15 +12,16 @@ int main(void)
|
||||
printf("len: %zu\n", b_string_get_size(str, B_STRLEN_NORMAL));
|
||||
printf("codepoints: %zu\n", b_string_get_size(str, B_STRLEN_CODEPOINTS));
|
||||
|
||||
b_string_iterator it;
|
||||
const char *delims[] = {"в"};
|
||||
size_t nr_delims = sizeof delims / sizeof delims[0];
|
||||
|
||||
b_string_tokenise(str, delims, nr_delims, 0, &it);
|
||||
while (b_string_iterator_is_valid(&it)) {
|
||||
printf("%s\n", it.string_value);
|
||||
b_string_iterator_next(&it);
|
||||
b_iterator *it = b_string_tokenise(str, delims, nr_delims, 0);
|
||||
b_foreach(const char *, tok, it)
|
||||
{
|
||||
printf("%s\n", tok);
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
b_string_unref(str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -19,5 +19,8 @@ int main(int argc, const char **argv)
|
||||
b_stream_read_all_bytes_s(b_stdin, dest, buf, &nr_read);
|
||||
|
||||
printf("done. read %zu bytes total.\n", nr_read);
|
||||
|
||||
b_path_unref(path);
|
||||
b_file_unref(dest);
|
||||
return 0;
|
||||
}
|
||||
@@ -20,12 +20,13 @@ int main(int argc, const char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
b_directory_iterator it = {0};
|
||||
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
while (b_directory_iterator_is_valid(&it)) {
|
||||
printf("%s\n", b_path_ptr(it.filepath));
|
||||
b_directory_iterator_next(&it);
|
||||
b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
b_foreach(b_directory_entry *, entry, it)
|
||||
{
|
||||
printf("%s\n", b_path_ptr(entry->filepath));
|
||||
}
|
||||
|
||||
b_iterator_unref(it);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -12,11 +12,9 @@ void write_raw_string(const b_string *data)
|
||||
{
|
||||
b_stream_write_string(b_stdout, "\"", NULL);
|
||||
|
||||
b_string_iterator it;
|
||||
b_string_foreach(&it, data)
|
||||
const b_iterator *it = b_iterator_cbegin(data);
|
||||
b_foreach_c(b_wchar, c, it)
|
||||
{
|
||||
b_wchar c = it.char_value;
|
||||
|
||||
if (c >= 0x10000) {
|
||||
c -= 0x10000;
|
||||
long hi = 0xD800 | ((c >> 10) & 0x3FF);
|
||||
@@ -30,6 +28,7 @@ void write_raw_string(const b_string *data)
|
||||
b_stream_write_char(b_stdout, c);
|
||||
}
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
|
||||
b_stream_write_string(b_stdout, "\"", NULL);
|
||||
}
|
||||
@@ -134,17 +133,18 @@ void write_tagged_dict(b_dict *data)
|
||||
|
||||
int i = 0;
|
||||
|
||||
b_dict_iterator it;
|
||||
b_dict_foreach(&it, data)
|
||||
b_iterator *it = b_iterator_begin(data);
|
||||
b_foreach(b_dict_item *, item, it)
|
||||
{
|
||||
if (i++ > 0) {
|
||||
b_stream_write_string(b_stdout, ", ", NULL);
|
||||
}
|
||||
|
||||
write_raw_string(it.key);
|
||||
write_raw_string(item->key);
|
||||
b_stream_write_string(b_stdout, ": ", NULL);
|
||||
write_tagged_value(it.value);
|
||||
write_tagged_value(item->value);
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
|
||||
b_stream_write_string(b_stdout, " }", NULL);
|
||||
}
|
||||
@@ -154,15 +154,16 @@ void write_tagged_array(b_array *data)
|
||||
b_stream_write_string(b_stdout, "[ ", NULL);
|
||||
|
||||
int i = 0;
|
||||
b_array_iterator it;
|
||||
b_array_foreach(&it, data)
|
||||
b_iterator *it = b_iterator_begin(data);
|
||||
b_foreach(b_object *, obj, it)
|
||||
{
|
||||
if (i++ > 0) {
|
||||
b_stream_write_string(b_stdout, ", ", NULL);
|
||||
}
|
||||
|
||||
write_tagged_value(it.value);
|
||||
write_tagged_value(obj);
|
||||
}
|
||||
b_iterator_unref(it);
|
||||
|
||||
b_stream_write_string(b_stdout, " ]", NULL);
|
||||
}
|
||||
@@ -1 +1,4 @@
|
||||
k = "v"
|
||||
# "No newlines are allowed between the curly braces unless they are valid within
|
||||
# a value"
|
||||
|
||||
a = []
|
||||
|
||||
Reference in New Issue
Block a user