Compare commits

...

26 Commits

Author SHA1 Message Date
84df46489a meta: update clang-format config 2026-02-03 14:47:36 +00:00
0d5a186d80 test: core: add bstr tests; update rope tests 2026-02-03 14:47:25 +00:00
2632feac32 cmd: add support for dynamically generating command options at runtime 2026-02-03 14:46:40 +00:00
f5c4fa561f ds: uuid: convert uuid bytes struct to union 2026-02-03 14:45:30 +00:00
5639aefd61 ds: string: set iterator value to B_WCHAR_INVALID when end of string is reached 2026-02-03 14:44:36 +00:00
30a9db17dc ds: list: update iterator interface 2026-02-03 14:43:35 +00:00
ce50cfd18b ds: hashmap: update iterator interface 2026-02-03 14:43:17 +00:00
9b48fc2b45 ds: convert (stub) bitbuffer implementation to (stub) b_object sub-class 2026-02-03 14:42:05 +00:00
5889426478 core: rope: add bstr support 2026-02-03 14:39:33 +00:00
c13b7a7e3a core: stream: add bstr support
despite not being a b_object, the b_stream interface can now detect when
a b_bstr instance has been passed as a stream parameter and use the correct
functions to handle writing to it.

this allows any function that expects a b_stream parameter to be called
with a b_bstr instance instead, allowing complex stream-based I/O operations
to be directed towards bounded character arrays with no heap allocation
required.
2026-02-03 14:36:48 +00:00
23aba2a27f core: add bstr data structure
bstr is very similar to b_stringstream, with the key difference being it can be
stack-allocated. this allows you to write a complex formatted string to a
stack-allocated character buffer with no heap memory allocation required.
bstr also supports automatically-managed dynamic string buffers for unbounded
string construction.
2026-02-03 14:34:58 +00:00
bdcd4163c7 core: stringstream: added read-support
any characters written to a stringstream can be optionally read back again
using the b_stream read API.

this functions similar to a ringbuffer, with two key differences:
 1) the buffer is not circular, and will continuously expand to accomodate all incoming data.
 2) reading data from the stringstream does not remove it from the buffer.
2026-02-03 14:33:06 +00:00
add05ef478 core: iterator: added inline definition of is_valid() 2026-02-03 14:32:15 +00:00
68ab79fe2a core: hash: add support for hashing the contents of ropes 2026-02-03 14:31:35 +00:00
ce9195c130 core: queue: implement moving queue entries
this works exactly the same as moving btree nodes.
2026-02-03 14:30:53 +00:00
837a42e249 core: btree: implement moving btree nodes
moving a btree node is similar to simply using memmove() or memcpy(), with the added
bonus of updating the pointers in the wider data structure to the new node memory
and zeroing the old node memory so that it isn't used accidentally after the move
is complete.
2026-02-03 14:28:58 +00:00
d14a1fc61f io: directory: update error api usage 2025-11-04 10:03:21 +00:00
6b65727535 core: error: rename b_error_release to b_error_discard 2025-11-04 10:03:10 +00:00
5c6030488b test: fix some memory leaks 2025-11-03 21:29:59 +00:00
bd2fe50ec9 test: move all module tests to the test/ directory 2025-11-01 10:12:18 +00:00
a68b9f7ba7 test: update tests 2025-11-01 10:04:41 +00:00
9e21e0c4b2 serial: toml: update iterator usage 2025-11-01 10:04:28 +00:00
5d3a987b0e io: directory: implement new b_iterator interface 2025-11-01 10:03:59 +00:00
ec500c04ad cmd: remove internal usage of legacy iterator interface 2025-11-01 10:02:42 +00:00
c94f976751 ds: string: implement b_iterable interface 2025-11-01 10:01:59 +00:00
3db808d4c4 ds: array: fix iterable_begin not setting iterator status 2025-11-01 10:01:17 +00:00
71 changed files with 1760 additions and 670 deletions

View File

@@ -4,7 +4,6 @@ IndentWidth: 8
Language: Cpp Language: Cpp
DerivePointerAlignment: false DerivePointerAlignment: false
PointerAlignment: Right PointerAlignment: Right
ReferenceAlignment: Left
ColumnLimit: 80 ColumnLimit: 80
AlignAfterOpenBracket: AlwaysBreak AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: None AlignConsecutiveAssignments: None
@@ -53,9 +52,67 @@ PenaltyBreakOpenParenthesis: 5
PenaltyBreakBeforeFirstCallParameter: 5 PenaltyBreakBeforeFirstCallParameter: 5
PenaltyIndentedWhitespace: 0 PenaltyIndentedWhitespace: 0
AttributeMacros: AttributeMacros:
- BLUE_API - BLUELIB_API
ForEachMacros: ForEachMacros:
- b_btree_foreach - b_btree_foreach
- b_queue_foreach - b_queue_foreach
MacroBlockBegin: "^B_(TYPE|PARAM)_.*_BEGIN$" MacroBlockBegin: "B_TYPE_.*_BEGIN"
MacroBlockEnd: "^B_(TYPE|PARAM)_.*_END$" 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"

View File

@@ -22,12 +22,12 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
foreach (module ${b_modules}) foreach (module ${b_modules})
add_subdirectory(${module}) 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}") 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 add_executable(blue-${module}-units
${module}-test/${module}-units.c test/${module}/${module}-units.c
misc/AllTests.c misc/AllTests.c
misc/CuTest.c misc/CuTest.c
misc/CuTest.h) misc/CuTest.h)
@@ -37,8 +37,8 @@ foreach (module ${b_modules})
endif () endif ()
file(GLOB test_sources ${module}-test/*.c) file(GLOB test_sources test/${module}/*.c)
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/${module}-test/${module}-units.c") list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c")
foreach (test_file ${test_sources}) foreach (test_file ${test_sources})
get_filename_component(test_name ${test_file} NAME_WE) get_filename_component(test_name ${test_file} NAME_WE)

View File

@@ -24,7 +24,7 @@ struct argv_parser {
struct b_command *cmd; struct b_command *cmd;
struct b_arglist *arglist; struct b_arglist *arglist;
b_queue_iterator arg_it; b_queue_entry *arg_it;
int nr_values_cur_arg; int nr_values_cur_arg;
int argc; int argc;
@@ -66,7 +66,7 @@ static void move_to_subcommand(struct argv_parser *parser, struct b_command *cmd
{ {
parser->cmd = cmd; parser->cmd = cmd;
parser->arglist->list_command = 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; 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) 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; return B_SUCCESS;
} }
struct b_command_arg *arg 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) { if (!arg) {
return B_SUCCESS; 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 *arg = b_unbox(
struct b_command_arg, parser->arg_it.entry, arg_entry); struct b_command_arg, parser->arg_it, arg_entry);
if (!arg) { if (!arg) {
b_arglist_report_unexpected_arg(parser->arglist, value); 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) { 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; parser->nr_values_cur_arg = 0;
continue; continue;
} }
if (parser->nr_values_cur_arg == arg->arg_nr_values) { 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; parser->nr_values_cur_arg = 0;
continue; continue;
} }
@@ -357,25 +357,19 @@ static b_status parse_short_opt(struct argv_parser *parser)
arglist_opt->opt_id = opt->opt_id; arglist_opt->opt_id = opt->opt_id;
put_arglist_option(&parser->arglist->list_options, arglist_opt); put_arglist_option(&parser->arglist->list_options, arglist_opt);
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
b_queue_iterator_begin(&opt->opt_args, &it);
const char *value = flags; const char *value = flags;
if (*value == '\0') { if (*value == '\0') {
advance(parser); advance(parser);
} }
while (b_queue_iterator_is_valid(&it)) { while (entry) {
value = peek(parser); value = peek(parser);
if (!value || *value == '-') { if (!value || *value == '-') {
value = NULL; value = NULL;
} }
arg = b_unbox(struct b_command_arg, it.entry, arg_entry); arg = b_unbox(struct b_command_arg, entry, arg_entry);
if (!arg) {
b_queue_iterator_next(&it);
continue;
}
if (!value || *value == '\0' || *value == '-') { if (!value || *value == '\0' || *value == '-') {
value = NULL; 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) { if (arg->arg_nr_values == B_ARG_0_OR_1_VALUES) {
b_queue_iterator_next(&it);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
goto next_value; goto next_value;
} }
if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) { if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) {
b_queue_iterator_next(&it);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
goto next_value; goto next_value;
} }
if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) { if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) {
if (nr_args_cur_opt > 0) { if (nr_args_cur_opt > 0) {
b_queue_iterator_next(&it);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
goto next_value; 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) { if (nr_args_cur_opt == arg->arg_nr_values) {
b_queue_iterator_next(&it);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
goto next_value; goto next_value;
} }
@@ -435,6 +425,7 @@ static b_status parse_short_opt(struct argv_parser *parser)
return B_ERR_BAD_FORMAT; return B_ERR_BAD_FORMAT;
} }
next_value: next_value:
entry = b_queue_next(entry);
value = advance(parser); value = advance(parser);
} }
@@ -493,16 +484,11 @@ static b_status parse_long_opt(struct argv_parser *parser)
arglist_opt->opt_id = opt->opt_id; arglist_opt->opt_id = opt->opt_id;
put_arglist_option(&parser->arglist->list_options, arglist_opt); put_arglist_option(&parser->arglist->list_options, arglist_opt);
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
b_queue_iterator_begin(&opt->opt_args, &it); struct b_command_arg *arg = NULL;
struct b_command_arg *arg
= b_unbox(struct b_command_arg, it.entry, arg_entry);
while (b_queue_iterator_is_valid(&it)) { while (entry) {
arg = b_unbox(struct b_command_arg, it.entry, arg_entry); arg = b_unbox(struct b_command_arg, entry, arg_entry);
if (!arg) {
break;
}
const char *value = peek(parser); const char *value = peek(parser);
if (!value || value[0] == '-') { 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) { 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; nr_args_cur_opt = 0;
continue; continue;
} }
if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) { 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; nr_args_cur_opt = 0;
continue; continue;
} }
if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) { if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) {
if (nr_args_cur_opt > 0) { if (nr_args_cur_opt > 0) {
b_queue_iterator_next(&it); entry = b_queue_next(entry);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
continue; continue;
} }
@@ -553,7 +539,7 @@ static b_status parse_long_opt(struct argv_parser *parser)
} }
if (nr_args_cur_opt == arg->arg_nr_values) { if (nr_args_cur_opt == arg->arg_nr_values) {
b_queue_iterator_next(&it); entry = b_queue_next(entry);
nr_args_cur_opt = 0; nr_args_cur_opt = 0;
continue; continue;
} }
@@ -666,34 +652,33 @@ static void arglist_value_destroy(struct b_arglist_value *val)
void b_arglist_destroy(struct b_arglist *args) 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); opt_it = b_btree_first(&args->list_options);
while (b_btree_iterator_is_valid(&opt_it)) { while (opt_it) {
struct b_arglist_option *opt 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) { args_it = b_btree_first(&opt->opt_values);
b_btree_iterator_next(&opt_it); while (args_it) {
continue;
}
b_btree_iterator_begin(&opt->opt_values, &args_it);
while (b_btree_iterator_is_valid(&args_it)) {
struct b_arglist_value *val = b_unbox( 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) { if (val) {
b_btree_iterator_next(&args_it); b_btree_delete(&opt->opt_values, args_it);
continue; arglist_value_destroy(val);
} }
b_btree_iterator_erase(&args_it); args_it = args_next;
arglist_value_destroy(val);
} }
b_btree_iterator_erase(&opt_it); b_btree_delete(&args->list_options, opt_it);
arglist_option_destroy(opt); arglist_option_destroy(opt);
opt_it = opt_next;
} }
free(args); free(args);
@@ -775,12 +760,13 @@ b_status b_arglist_get_option(
const b_arglist *args, unsigned int opt_id, unsigned int index, const b_arglist *args, unsigned int opt_id, unsigned int index,
b_arglist_option **out) b_arglist_option **out)
{ {
b_btree_iterator it = {0}; struct b_btree_node *node = b_btree_first(&args->list_options);
b_btree_foreach (&it, &args->list_options) {
b_arglist_option *cur while (node) {
= b_unbox(b_arglist_option, it.node, opt_node); b_arglist_option *cur = b_unbox(b_arglist_option, node, opt_node);
if (cur->opt_id != opt_id) { if (cur->opt_id != opt_id) {
node = b_btree_next(node);
continue; continue;
} }
@@ -789,6 +775,7 @@ b_status b_arglist_get_option(
return B_SUCCESS; return B_SUCCESS;
} }
node = b_btree_next(node);
index--; index--;
} }
@@ -813,11 +800,12 @@ b_status b_arglist_option_get_value(
const b_arglist_option *opt, unsigned int arg_id, unsigned int index, const b_arglist_option *opt, unsigned int arg_id, unsigned int index,
b_arglist_value **out) b_arglist_value **out)
{ {
b_btree_iterator it = {0}; struct b_btree_node *node = b_btree_first(&opt->opt_values);
b_btree_foreach (&it, &opt->opt_values) { while (node) {
b_arglist_value *cur = b_unbox(b_arglist_value, it.node, val_node); b_arglist_value *cur = b_unbox(b_arglist_value, node, val_node);
if (cur->val_id != arg_id) { if (cur->val_id != arg_id) {
node = b_btree_next(node);
continue; continue;
} }
@@ -826,6 +814,7 @@ b_status b_arglist_option_get_value(
return B_SUCCESS; return B_SUCCESS;
} }
node = b_btree_next(node);
index--; index--;
} }
@@ -834,24 +823,14 @@ b_status b_arglist_option_get_value(
/************************ arglist iterator functions **************************/ /************************ 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) static struct b_arglist_option *advance_to_next_opt(struct b_arglist_iterator *it)
{ {
struct b_arglist_option *opt; struct b_arglist_option *opt;
// b_btree_iterator_next(&it->_opt_it); // b_btree_iterator_next(&it->_opt_it);
while (b_btree_iterator_is_valid(&it->_opt_it)) { while (it->_opt_it) {
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 if (opt
&& (opt->opt_id == it->_opt_filter && (opt->opt_id == it->_opt_filter
|| it->_opt_filter == B_COMMAND_INVALID_ID)) { || 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; return opt;
} }
b_btree_iterator_next(&it->_opt_it); it->_opt_it = b_btree_next(it->_opt_it);
} }
return NULL; 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); // b_btree_iterator_next(&it->_arg_it);
while (b_btree_iterator_is_valid(&it->_arg_it)) { while (it->_arg_it) {
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 if (val
&& (val->val_id == it->_arg_filter && (val->val_id == it->_arg_filter
|| it->_arg_filter == B_COMMAND_INVALID_ID)) { || 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; return val;
} }
b_btree_iterator_next(&it->_arg_it); it->_arg_it = b_btree_next(it->_arg_it);
} }
return NULL; 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( int b_arglist_iterator_begin(
const struct b_arglist *args, unsigned int opt_filter, const struct b_arglist *args, unsigned int opt_filter,
unsigned int arg_filter, struct b_arglist_iterator *it) 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->opt_id = B_COMMAND_INVALID_ID;
it->_base.it_ops = &it_ops;
it->_opt_filter = opt_filter; it->_opt_filter = opt_filter;
it->_arg_filter = arg_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_option *opt = NULL;
struct b_arglist_value *val = NULL; struct b_arglist_value *val = NULL;
while (1) { while (1) {
if (!b_btree_iterator_is_valid(&it->_opt_it)) { if (!it->_opt_it) {
opt = NULL; opt = NULL;
return -1; 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 if (!opt
|| (opt_filter != opt->opt_id || (opt_filter != opt->opt_id
&& opt_filter != B_COMMAND_INVALID_ID)) { && opt_filter != B_COMMAND_INVALID_ID)) {
b_btree_iterator_next(&it->_opt_it); it->_opt_it = b_btree_next(it->_opt_it);
continue; continue;
} }
b_btree_iterator_begin(&opt->opt_values, &it->_arg_it); it->_arg_it = b_btree_first(&opt->opt_values);
bool done = false; bool done = false;
while (1) { while (1) {
if (!b_btree_iterator_is_valid(&it->_arg_it)) { if (!it->_arg_it) {
if (arg_filter == B_COMMAND_INVALID_ID) { if (arg_filter == B_COMMAND_INVALID_ID) {
done = true; done = true;
} }
@@ -933,12 +906,11 @@ int b_arglist_iterator_begin(
break; break;
} }
val = b_unbox( val = b_unbox(struct b_arglist_value, it->_arg_it, val_node);
struct b_arglist_value, it->_arg_it.node, val_node);
if (!val if (!val
|| (arg_filter != val->val_id || (arg_filter != val->val_id
&& arg_filter != B_COMMAND_INVALID_ID)) { && arg_filter != B_COMMAND_INVALID_ID)) {
b_btree_iterator_next(&it->_arg_it); it->_arg_it = b_btree_next(it->_arg_it);
continue; continue;
} }
@@ -950,7 +922,7 @@ int b_arglist_iterator_begin(
break; break;
} }
b_btree_iterator_next(&it->_opt_it); it->_opt_it = b_btree_next(it->_opt_it);
} }
it->opt_id = opt->opt_id; 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_option *opt;
struct b_arglist_value *val; struct b_arglist_value *val;
b_btree_iterator_next(&it->_arg_it); it->_arg_it = b_btree_next(it->_arg_it);
while (1) { while (1) {
val = advance_to_next_arg(it); val = advance_to_next_arg(it);
@@ -975,7 +947,7 @@ bool b_arglist_iterator_next(struct b_arglist_iterator *it)
return true; return true;
} }
b_btree_iterator_next(&it->_opt_it); it->_opt_it = b_btree_next(it->_opt_it);
opt = advance_to_next_opt(it); opt = advance_to_next_opt(it);
if (!opt) { if (!opt) {
it->value = NULL; it->value = NULL;
@@ -983,7 +955,7 @@ bool b_arglist_iterator_next(struct b_arglist_iterator *it)
return false; 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) { if (it->_arg_filter == B_COMMAND_INVALID_ID) {
return true; return true;
@@ -998,27 +970,13 @@ bool b_arglist_iterator_is_valid(const struct b_arglist_iterator *it)
/********************* arglist option iterator functions **********************/ /********************* 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( static struct b_arglist_option *advance_to_next_opt2(
struct b_arglist_option_iterator *it) struct b_arglist_option_iterator *it)
{ {
struct b_arglist_option *opt; struct b_arglist_option *opt;
// b_btree_iterator_next(&it->_opt_it); while (it->_opt_it) {
opt = b_unbox(struct b_arglist_option, it->_opt_it, opt_node);
while (b_btree_iterator_is_valid(&it->_opt_it)) {
opt = b_unbox(struct b_arglist_option, it->_opt_it.node, opt_node);
if (opt if (opt
&& (opt->opt_id == it->_opt_filter && (opt->opt_id == it->_opt_filter
|| it->_opt_filter == B_COMMAND_INVALID_ID)) { || it->_opt_filter == B_COMMAND_INVALID_ID)) {
@@ -1026,17 +984,12 @@ static struct b_arglist_option *advance_to_next_opt2(
return opt; return opt;
} }
b_btree_iterator_next(&it->_opt_it); it->_opt_it = b_btree_next(it->_opt_it);
} }
return NULL; 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( int b_arglist_option_iterator_begin(
const struct b_arglist *args, unsigned int opt_filter, const struct b_arglist *args, unsigned int opt_filter,
struct b_arglist_option_iterator *it) struct b_arglist_option_iterator *it)
@@ -1045,26 +998,26 @@ int b_arglist_option_iterator_begin(
it->opt_id = B_COMMAND_INVALID_ID; it->opt_id = B_COMMAND_INVALID_ID;
it->_base.it_ops = &it_ops;
it->_opt_filter = opt_filter; 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_option *opt = NULL;
struct b_arglist_value *val = NULL; struct b_arglist_value *val = NULL;
while (1) { while (1) {
if (!b_btree_iterator_is_valid(&it->_opt_it)) { if (!it->_opt_it) {
opt = NULL; opt = NULL;
return -1; 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 if (opt
&& (opt_filter == opt->opt_id && (opt_filter == opt->opt_id
|| opt_filter == B_COMMAND_INVALID_ID)) { || opt_filter == B_COMMAND_INVALID_ID)) {
break; break;
} }
b_btree_iterator_next(&it->_opt_it);
it->_opt_it = b_btree_next(it->_opt_it);
} }
it->opt_id = opt->opt_id; 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_option *opt;
struct b_arglist_value *val; 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); opt = advance_to_next_opt2(it);
if (!opt) { if (!opt) {
it->opt = NULL; it->opt = NULL;

View File

@@ -24,16 +24,18 @@ enum item_type {
static void command_list_cleanup(void) static void command_list_cleanup(void)
{ {
struct b_btree_iterator it = {0}; struct b_btree_node *node = b_btree_first(&command_list);
b_btree_iterator_begin(&command_list, &it); while (node) {
while (b_btree_iterator_is_valid(&it)) { struct b_command *cmd = b_unbox(struct b_command, node, b_node);
struct b_command *cmd = b_unbox(struct b_command, it.node, b_node);
if (!cmd) { if (!cmd) {
break; 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); 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) static void command_usage_destroy(struct b_command_usage *usage)
{ {
struct b_queue_iterator it = {0}; struct b_queue_entry *entry = b_queue_first(&usage->u_parts);
while (entry) {
b_queue_iterator_begin(&usage->u_parts, &it); struct b_command_usage_entry *arg
while (b_queue_iterator_is_valid(&it)) { = b_unbox(struct b_command_usage_entry, entry, e_entry);
struct b_command_usage_entry *arg = b_unbox(
struct b_command_usage_entry, it.entry, e_entry);
if (!arg) { if (!arg) {
continue; continue;
} }
b_queue_iterator_erase(&it); struct b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&usage->u_parts, entry);
free(arg); free(arg);
entry = next;
} }
free(usage); free(usage);
@@ -72,8 +75,6 @@ static void command_usage_destroy(struct b_command_usage *usage)
void b_command_destroy(struct b_command *cmd) void b_command_destroy(struct b_command *cmd)
{ {
struct b_queue_iterator it = {0};
if (cmd->b_name) { if (cmd->b_name) {
free(cmd->b_name); free(cmd->b_name);
} }
@@ -86,52 +87,71 @@ void b_command_destroy(struct b_command *cmd)
free(cmd->b_description); free(cmd->b_description);
} }
b_queue_iterator_begin(&cmd->b_opt, &it); struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
while (b_queue_iterator_is_valid(&it)) { struct b_queue_entry *next = NULL;
while (entry) {
struct b_command_option *opt 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) { if (!opt) {
break; break;
} }
b_queue_iterator_erase(&it); next = b_queue_next(entry);
b_queue_delete(&cmd->b_opt, entry);
b_command_option_destroy(opt); b_command_option_destroy(opt);
entry = next;
} }
b_queue_iterator_begin(&cmd->b_arg, &it); entry = b_queue_first(&cmd->b_arg);
while (b_queue_iterator_is_valid(&it)) { while (entry) {
struct b_command_arg *arg 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) { if (!arg) {
break; break;
} }
b_queue_iterator_erase(&it); next = b_queue_next(entry);
b_queue_delete(&cmd->b_arg, entry);
b_command_arg_destroy(arg); b_command_arg_destroy(arg);
entry = next;
} }
b_queue_iterator_begin(&cmd->b_arg, &it); #if 0
while (b_queue_iterator_is_valid(&it)) { entry = b_queue_first(&cmd->b_subcommands);
while (entry) {
struct b_command *subcmd struct b_command *subcmd
= b_unbox(struct b_command, it.entry, b_entry); = b_unbox(struct b_command, entry, b_entry);
if (!subcmd) { if (!subcmd) {
break; break;
} }
b_queue_iterator_erase(&it); next = b_queue_next(entry);
b_command_destroy(subcmd);
}
b_queue_iterator_begin(&cmd->b_usage, &it); b_command_destroy(subcmd);
while (b_queue_iterator_is_valid(&it)) {
entry = next;
}
#endif
entry = b_queue_first(&cmd->b_usage);
while (entry) {
struct b_command_usage *usage 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) { if (!usage) {
break; break;
} }
b_queue_iterator_erase(&it); next = b_queue_next(entry);
b_queue_delete(&cmd->b_usage, entry);
command_usage_destroy(usage); command_usage_destroy(usage);
entry = next;
} }
free(cmd); free(cmd);
@@ -262,6 +282,24 @@ struct b_command_usage *b_command_add_usage(struct b_command *cmd)
return usage; 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( b_status b_command_usage_add_option(
struct b_command_usage *usage, struct b_command_option *opt) 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) static void prepend_command_name(struct b_command *cmd, b_string *out)
{ {
int nr_names = 0; int nr_names = 0;
cmd->b_name&& nr_names++; cmd->b_name &&nr_names++;
cmd->b_long_name&& nr_names++; cmd->b_long_name &&nr_names++;
cmd->b_short_name&& nr_names++; cmd->b_short_name &&nr_names++;
if (nr_names > 1) { if (nr_names > 1) {
b_string_prepend_cstr(out, "}"); b_string_prepend_cstr(out, "}");
@@ -382,10 +420,10 @@ static void get_usage_string(
b_string *cmd_name = b_string_create(); b_string *cmd_name = b_string_create();
b_queue_iterator it; struct b_queue_entry *q_entry = b_queue_first(&usage->u_parts);
b_queue_foreach (&it, &usage->u_parts) { while (q_entry) {
struct b_command_usage_entry *entry = b_unbox( struct b_command_usage_entry *entry
struct b_command_usage_entry, it.entry, e_entry); = b_unbox(struct b_command_usage_entry, q_entry, e_entry);
if (!entry) { if (!entry) {
break; break;
@@ -426,6 +464,8 @@ static void get_usage_string(
default: default:
break; break;
} }
q_entry = b_queue_next(q_entry);
} }
b_string_unref(cmd_name); b_string_unref(cmd_name);
@@ -445,13 +485,15 @@ b_string *z__b_command_default_usage_string(
b_string_append_cstr(str, " [OPTIONS]"); b_string_append_cstr(str, " [OPTIONS]");
} }
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
b_queue_foreach (&it, &cmd->b_arg) { while (entry) {
struct b_command_arg *arg 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, " "); b_string_append_cstr(str, " ");
z__b_get_arg_usage_string(arg, false, str); z__b_get_arg_usage_string(arg, false, str);
entry = b_queue_next(entry);
} }
if (!b_queue_empty(&cmd->b_subcommands)) { 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 *opt_str = b_string_create();
b_string *desc_str = b_string_create(); b_string *desc_str = b_string_create();
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
b_queue_foreach (&it, &cmd->b_opt) { while (entry) {
struct b_command_option *opt 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;
}
b_string_clear(opt_str); b_string_clear(opt_str);
b_string_clear(desc_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); desc_str, B_STRLEN_IGNORE_ESC | B_STRLEN_IGNORE_MOD);
if (description_on_separate_line(opt_len, desc_len)) { if (description_on_separate_line(opt_len, desc_len)) {
continue; goto skip;
} }
if (opt_len > desb_margin) { if (opt_len > desb_margin) {
desb_margin = opt_len; desb_margin = opt_len;
} }
skip:
entry = b_queue_next(entry);
} }
b_paragraph_format format = {0}; b_paragraph_format format = {0};
@@ -558,11 +600,12 @@ static void print_options_list(struct b_command *cmd)
format.p_right_margin = 4; format.p_right_margin = 4;
size_t i = 0; 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 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) { if (!opt) {
continue; break;
} }
b_string_clear(opt_str); b_string_clear(opt_str);
@@ -609,6 +652,8 @@ static void print_options_list(struct b_command *cmd)
if (new_paragraph) { if (new_paragraph) {
b_tty_putc(OUTPUT_STREAM, 0, '\n'); b_tty_putc(OUTPUT_STREAM, 0, '\n');
} }
entry = b_queue_next(entry);
} }
b_string_unref(opt_str); b_string_unref(opt_str);
@@ -622,10 +667,11 @@ static void print_args_list(struct b_command *cmd)
size_t desb_margin = 0; size_t desb_margin = 0;
b_string *str = b_string_create(); b_string *str = b_string_create();
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
b_queue_foreach (&it, &cmd->b_arg) {
while (entry) {
struct b_command_arg *arg 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); b_string_clear(str);
z__b_get_arg_usage_string(arg, true, 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) { if (len > desb_margin) {
desb_margin = len; desb_margin = len;
} }
entry = b_queue_next(entry);
} }
b_paragraph_format format = {0}; b_paragraph_format format = {0};
@@ -644,9 +692,10 @@ static void print_args_list(struct b_command *cmd)
format.p_right_margin = 4; format.p_right_margin = 4;
size_t i = 0; 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 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); b_string_clear(str);
z__b_get_arg_usage_string(arg, true, 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); z__b_get_arg_description(arg, str);
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format); b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
entry = b_queue_next(entry);
} }
b_string_unref(str); b_string_unref(str);
@@ -678,10 +728,9 @@ static void print_commands_list(struct b_command *cmd)
size_t desb_margin = 0; size_t desb_margin = 0;
b_string *str = b_string_create(); b_string *str = b_string_create();
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
b_queue_foreach (&it, &cmd->b_subcommands) { while (entry) {
struct b_command *sub struct b_command *sub = b_unbox(struct b_command, entry, b_entry);
= b_unbox(struct b_command, it.entry, b_entry);
b_string_clear(str); b_string_clear(str);
get_command_string(sub, str); get_command_string(sub, str);
@@ -692,6 +741,8 @@ static void print_commands_list(struct b_command *cmd)
if (len > desb_margin) { if (len > desb_margin) {
desb_margin = len; desb_margin = len;
} }
entry = b_queue_next(entry);
} }
b_paragraph_format format = {0}; b_paragraph_format format = {0};
@@ -700,9 +751,9 @@ static void print_commands_list(struct b_command *cmd)
format.p_right_margin = 4; format.p_right_margin = 4;
size_t i = 0; size_t i = 0;
b_queue_foreach (&it, &cmd->b_subcommands) { entry = b_queue_first(&cmd->b_subcommands);
struct b_command *sub while (entry) {
= b_unbox(struct b_command, it.entry, b_entry); struct b_command *sub = b_unbox(struct b_command, entry, b_entry);
b_string_clear(str); b_string_clear(str);
get_command_string(sub, str); get_command_string(sub, str);
@@ -722,6 +773,8 @@ static void print_commands_list(struct b_command *cmd)
get_command_description(sub, str); get_command_description(sub, str);
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format); b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
entry = b_queue_next(entry);
} }
b_string_unref(str); 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 *b_command_get_subcommand_with_name(
struct b_command *cmd, const char *name) struct b_command *cmd, const char *name)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
b_queue_foreach (&it, &cmd->b_subcommands) { while (entry) {
struct b_command *subcmd 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) { if (!subcmd || !subcmd->b_name) {
continue; goto skip;
} }
if (!strcmp(subcmd->b_name, name)) { if (!strcmp(subcmd->b_name, name)) {
return subcmd; return subcmd;
} }
skip:
entry = b_queue_next(entry);
} }
return NULL; 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 *b_command_get_subcommand_with_long_name(
struct b_command *cmd, const char *long_name) struct b_command *cmd, const char *long_name)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
b_queue_foreach (&it, &cmd->b_subcommands) { while (entry) {
struct b_command *subcmd 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) { if (!subcmd || !subcmd->b_long_name) {
continue; goto skip;
} }
if (!strcmp(subcmd->b_name, long_name)) { if (!strcmp(subcmd->b_name, long_name)) {
return subcmd; return subcmd;
} }
skip:
entry = b_queue_next(entry);
} }
return NULL; 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 *b_command_get_subcommand_with_short_name(
struct b_command *cmd, char short_name) struct b_command *cmd, char short_name)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_subcommands);
b_queue_foreach (&it, &cmd->b_subcommands) { while (entry) {
struct b_command *subcmd 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) { if (!subcmd || !subcmd->b_short_name) {
continue; goto skip;
} }
if (subcmd->b_short_name == short_name) { if (subcmd->b_short_name == short_name) {
return subcmd; return subcmd;
} }
skip:
entry = b_queue_next(entry);
} }
return NULL; 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_option *b_command_get_option_with_long_name(
struct b_command *cmd, const char *long_name) struct b_command *cmd, const char *long_name)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
b_queue_foreach (&it, &cmd->b_opt) { while (entry) {
struct b_command_option *opt 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) { if (!opt || !opt->opt_long_name) {
continue; goto skip;
} }
if (!strcmp(opt->opt_long_name, long_name)) { if (!strcmp(opt->opt_long_name, long_name)) {
return opt; return opt;
} }
skip:
entry = b_queue_next(entry);
} }
return NULL; 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_option *b_command_get_option_with_short_name(
struct b_command *cmd, char short_name) struct b_command *cmd, char short_name)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
b_queue_foreach (&it, &cmd->b_opt) { while (entry) {
struct b_command_option *opt 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) { if (!opt || !opt->opt_long_name) {
continue; goto skip;
} }
if (opt->opt_short_name == short_name) { if (opt->opt_short_name == short_name) {
return opt; return opt;
} }
skip:
entry = b_queue_next(entry);
} }
return NULL; 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_option *b_command_get_option_with_id(
struct b_command *cmd, unsigned int id) struct b_command *cmd, unsigned int id)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_opt);
b_queue_foreach (&it, &cmd->b_opt) { while (entry) {
struct b_command_option *opt 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;
}
if (opt->opt_id == id) { if (opt->opt_id == id) {
return opt; return opt;
} }
entry = b_queue_next(entry);
} }
return NULL; 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_arg *b_command_get_arg_with_id(
struct b_command *cmd, unsigned int id) struct b_command *cmd, unsigned int id)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_arg);
b_queue_foreach (&it, &cmd->b_arg) { while (entry) {
struct b_command_arg *arg 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;
}
if (arg->arg_id == id) { if (arg->arg_id == id) {
return arg; return arg;
} }
entry = b_queue_next(entry);
} }
return NULL; 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_string *str = b_string_create();
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&cmd->b_usage);
b_queue_foreach (&it, &cmd->b_usage) { while (entry) {
struct b_command_usage *usage 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_string_clear(str); b_string_clear(str);
get_usage_string(cmd, args, usage, str); get_usage_string(cmd, args, usage, str);
b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format); b_print_paragraph(b_string_ptr(str), OUTPUT_STREAM, &format);
entry = b_queue_next(entry);
} }
b_string_unref(str); 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) static int resolve_command_parents(struct b_btree *commands)
{ {
struct b_btree_iterator it; struct b_btree_node *node = b_btree_first(commands);
b_btree_foreach (&it, commands) { while (node) {
struct b_command *cmd = b_unbox(struct b_command, it.node, b_node); struct b_command *cmd = b_unbox(struct b_command, node, b_node);
if (cmd->b_parent_id == B_COMMAND_INVALID_ID) { if (cmd->b_parent_id == B_COMMAND_INVALID_ID) {
continue; goto skip;
} }
cmd->b_parent = get_command(commands, cmd->b_parent_id); 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); add_subcommand(cmd->b_parent, cmd);
skip:
node = b_btree_next(node);
} }
return 0; return 0;

View File

@@ -61,6 +61,12 @@
this_opt = opt_##id; \ this_opt = opt_##id; \
if (this_opt) 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() \ #define B_COMMAND_HELP_OPTION() \
do { \ do { \
b_command_option *opt \ b_command_option *opt \
@@ -164,24 +170,22 @@ typedef struct b_arglist_value {
} b_arglist_value; } b_arglist_value;
typedef struct b_arglist_iterator { typedef struct b_arglist_iterator {
b_iterator _base;
size_t i; size_t i;
unsigned int opt_id; unsigned int opt_id;
struct b_arglist_value *value; 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; unsigned int _opt_filter, _arg_filter;
} b_arglist_iterator; } b_arglist_iterator;
typedef struct b_arglist_option_iterator { typedef struct b_arglist_option_iterator {
b_iterator _base;
size_t i; size_t i;
unsigned int opt_id; unsigned int opt_id;
struct b_arglist_option *opt; struct b_arglist_option *opt;
b_btree_iterator _opt_it; b_btree_node *_opt_it;
unsigned int _opt_filter; unsigned int _opt_filter;
} b_arglist_option_iterator; } 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_arg *b_command_add_arg(b_command *cmd, int id);
BLUE_API b_command_usage *b_command_add_usage(b_command *cmd); 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( BLUE_API b_status b_command_option_set_long_name(
b_command_option *opt, const char *name); b_command_option *opt, const char *name);
BLUE_API b_status b_command_option_set_short_name(b_command_option *opt, char name); BLUE_API b_status b_command_option_set_short_name(b_command_option *opt, char name);

View File

@@ -26,23 +26,37 @@ void b_command_option_destroy(struct b_command_option *opt)
free(opt->opt_description); 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 (entry) {
while (b_queue_iterator_is_valid(&it)) {
struct b_command_arg *arg 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; 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); b_command_arg_destroy(arg);
entry = next;
} }
free(opt); 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( b_status b_command_option_set_long_name(
struct b_command_option *opt, const char *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); size_t nr_args = b_queue_length(&opt->opt_args);
bool close_bracket = false; bool close_bracket = false;
b_queue_iterator it; size_t i = 0;
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 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) { if (!arg || !arg->arg_allowed_values) {
continue; goto skip;
} }
if (it.i > 0) { if (i > 0) {
b_string_append_cstr(out, "; "); b_string_append_cstr(out, "; ");
} else { } else {
b_string_append_cstr(out, " [["); 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, out, " " F_GREEN "%s" F_RESET,
arg->arg_allowed_values[i]); arg->arg_allowed_values[i]);
} }
skip:
i++;
entry = b_queue_next(entry);
} }
if (close_bracket) { if (close_bracket) {
@@ -175,12 +194,12 @@ void z__b_get_option_usage_string(
b_string_append_cstr(out, "}"); b_string_append_cstr(out, "}");
} }
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
b_queue_foreach (&it, &opt->opt_args) { while (entry) {
struct b_command_arg *arg 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) { if (!arg) {
continue; goto skip;
} }
bool optional = false, multi = false; bool optional = false, multi = false;
@@ -228,23 +247,26 @@ void z__b_get_option_usage_string(
if (flags & CMD_STR_COLOUR) { if (flags & CMD_STR_COLOUR) {
b_string_append_cstr(out, F_RESET); 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_arg *b_command_option_get_arg_with_id(
struct b_command_option *opt, unsigned int id) struct b_command_option *opt, unsigned int id)
{ {
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
b_queue_foreach (&it, &opt->opt_args) {
while (entry) {
struct b_command_arg *arg 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;
}
if (arg->arg_id == id) { if (arg->arg_id == id) {
return arg; return arg;
} }
entry = b_queue_next(entry);
} }
return NULL; return NULL;

View File

@@ -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;
}

View File

@@ -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
View 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);
}

View File

@@ -736,6 +736,32 @@ b_btree_node *b_btree_prev(const struct b_btree_node *node)
return prev_node(node, &d); 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 *b_btree_begin(struct b_btree *tree)
{ {
b_iterator *it_obj = b_object_create(B_TYPE_BTREE_ITERATOR); b_iterator *it_obj = b_object_create(B_TYPE_BTREE_ITERATOR);

View File

@@ -471,7 +471,7 @@ enum b_status z__b_error_add_submsg_template(
return B_SUCCESS; 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_delete(&allocated_errors, &error->err_entry);
b_queue_push_back(&free_errors, &error->err_entry); b_queue_push_back(&free_errors, &error->err_entry);

View File

@@ -1,6 +1,8 @@
#include "hash.h" #include "hash.h"
#include <blue/core/hash.h> #include <blue/core/hash.h>
#include <blue/core/rope.h>
#include <inttypes.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.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; 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( enum b_status b_hash_ctx_finish(
struct b_hash_ctx *ctx, void *out_digest, size_t out_max) struct b_hash_ctx *ctx, void *out_digest, size_t out_max)
{ {

View 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

View File

@@ -335,6 +335,8 @@ static inline b_btree_node *b_btree_parent(b_btree_node *node)
return node->b_parent; 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`. /* get the height of `node`.
the height of a node is defined as the length of the longest path the height of a node is defined as the length of the longest path

View File

@@ -372,7 +372,7 @@ BLUE_API enum b_status z__b_error_add_submsg_template(
error, type, msg_id, \ error, type, msg_id, \
(b_error_template_parameter[]) {__VA_ARGS__, {}})) (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 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); BLUE_API const b_error_vendor *b_error_get_vendor(const b_error *error);

View File

@@ -29,6 +29,7 @@
#define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256 #define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256
struct b_hash_function_ops; struct b_hash_function_ops;
struct b_rope;
typedef enum b_hash_function { typedef enum b_hash_function {
B_HASH_NONE = 0, 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_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_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(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( BLUE_API b_status b_hash_ctx_finish(
b_hash_ctx *ctx, void *out_digest, size_t out_max); b_hash_ctx *ctx, void *out_digest, size_t out_max);

View File

@@ -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 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 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_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; B_DECLS_END;

View File

@@ -35,24 +35,24 @@ static inline void b_queue_init(b_queue *q)
} }
static inline bool b_queue_empty(const 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) 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) 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) 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) 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); 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_front(b_queue *q);
BLUE_API b_queue_entry *b_queue_pop_back(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(b_queue *q, b_queue_entry *entry);
BLUE_API void b_queue_delete_all(b_queue *q); BLUE_API void b_queue_delete_all(b_queue *q);

View File

@@ -3,10 +3,12 @@
#include <blue/core/hash.h> #include <blue/core/hash.h>
#include <blue/core/misc.h> #include <blue/core/misc.h>
#include <blue/core/stream.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
struct b_string; struct b_string;
struct b_bstr;
#define B_ROPE_TYPE(f) ((f) & 0xFF) #define B_ROPE_TYPE(f) ((f) & 0xFF)
@@ -17,7 +19,7 @@ struct b_string;
.r_v = {.v_char = (c) } \ .r_v = {.v_char = (c) } \
} }
#define B_ROPE_CSTR(str) \ #define B_ROPE_CSTR(str) \
{ \ { \
.r_flags = B_ROPE_F_CSTR_BORROWED, \ .r_flags = B_ROPE_F_CSTR_BORROWED, \
.r_len_total = strlen(str), \ .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_flags = B_ROPE_F_CSTR_STATIC, \
.r_len_total = strlen(str), \ .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_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 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_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_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 #endif

View File

@@ -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); 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; B_DECLS_END;
#endif #endif

View File

@@ -68,7 +68,7 @@ struct _b_object *b_object_create(b_type type)
struct _b_object *out = NULL; struct _b_object *out = NULL;
b_result result = b_object_instantiate(type_reg, &out); b_result result = b_object_instantiate(type_reg, &out);
if (b_result_is_error(result)) { if (b_result_is_error(result)) {
b_error_release(result); b_error_discard(result);
return NULL; return NULL;
} }

View File

@@ -102,6 +102,27 @@ struct b_queue_entry *b_queue_pop_back(struct b_queue *q)
return x; 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) void b_queue_delete(struct b_queue *q, struct b_queue_entry *entry)
{ {
if (!entry) { if (!entry) {

View File

@@ -1,3 +1,4 @@
#include <blue/core/bstr.h>
#include <blue/core/rope.h> #include <blue/core/rope.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.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) size_t b_rope_get_size(const struct b_rope *rope)
{ {
return rope->r_len_total; return rope->r_len_total;
@@ -181,56 +199,77 @@ static void rope_iterate(
} }
} }
struct to_cstr_args { static void to_bstr(const struct b_rope *rope, void *arg)
char *str;
size_t max;
size_t ptr;
};
static void to_cstr(const struct b_rope *rope, void *arg)
{ {
struct to_cstr_args *str = arg; b_bstr *str = arg;
if (str->ptr >= str->max) {
return;
}
unsigned int type = B_ROPE_TYPE(rope->r_flags); 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) { switch (type) {
case B_ROPE_F_CHAR: 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; break;
case B_ROPE_F_CSTR: case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED: case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC: 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; break;
case B_ROPE_F_INT: case B_ROPE_F_INT:
nr_written b_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
= snprintf(dest, capacity, "%" PRIdPTR, rope->r_v.v_int);
break; break;
case B_ROPE_F_UINT: case B_ROPE_F_UINT:
nr_written b_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
= snprintf(dest, capacity, "%" PRIuPTR, rope->r_v.v_uint);
break; break;
default: default:
break; 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 = { b_stream *out = arg;
.str = out,
.max = max,
.ptr = 0,
};
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;
} }

View File

@@ -1,10 +1,14 @@
#include "printf.h" #include "printf.h"
#include <blue/core/bstr.h>
#include <blue/core/stream.h> #include <blue/core/stream.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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 B_TYPE_STDIO_STREAM (b_stdio_stream_get_type())
#define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \ #define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \
@@ -369,6 +373,39 @@ static enum b_status stream_read_line_s(
return status; 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( static enum b_status stream_write_bytes(
struct stream_data *stream, const void *buf, size_t count, size_t *nr_written) 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; 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( static enum b_status stream_write_string(
struct stream_data *stream, const char *s, size_t *nr_written) 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) 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_CLASS_DISPATCH_VIRTUAL(
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_reserve, stream, b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_reserve, stream,
len); len);
@@ -650,6 +742,10 @@ enum b_status b_stream_reserve(b_stream *stream, size_t len)
enum b_status b_stream_seek( enum b_status b_stream_seek(
b_stream *stream, long long offset, b_stream_seek_origin origin) 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_CLASS_DISPATCH_VIRTUAL(
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_seek, stream, b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_seek, stream,
offset, origin); offset, origin);
@@ -657,37 +753,65 @@ enum b_status b_stream_seek(
size_t b_stream_cursor(const b_stream *stream) 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); STREAM_DISPATCH_VIRTUAL_0(stream_cursor, stream);
} }
enum b_status b_stream_push_indent(b_stream *strp, int indent) 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); STREAM_DISPATCH_VIRTUAL(stream_push_indent, strp, indent);
} }
enum b_status b_stream_pop_indent(b_stream *strp) 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); STREAM_DISPATCH_VIRTUAL_0(stream_pop_indent, strp);
} }
enum b_status b_stream_read_char(b_stream *strp, int *c) 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); STREAM_DISPATCH_VIRTUAL(stream_read_char, strp, c);
} }
enum b_status b_stream_read_bytes( enum b_status b_stream_read_bytes(
b_stream *strp, void *buf, size_t count, size_t *nr_read) 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); 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) 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); STREAM_DISPATCH_VIRTUAL(stream_read_line, strp, s, max);
} }
enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest) 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; enum b_status status;
struct stream_data src_p, dest_p; 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; return status;
} }
if (IS_BSTR(dest)) {
return stream_read_line_to_bstr(&src_p, (b_bstr *)dest);
}
status = stream_get_data(dest, &dest_p); status = stream_get_data(dest, &dest_p);
if (!B_OK(status)) { if (!B_OK(status)) {
return 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( enum b_status b_stream_read_all_bytes(
b_stream *stream, void *p, size_t max, size_t *out_nr_read) 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); STREAM_DISPATCH_VIRTUAL(stream_read_all_bytes, stream, p, max, out_nr_read);
} }
enum b_status b_stream_read_all_bytes_s( enum b_status b_stream_read_all_bytes_s(
b_stream *src, b_stream *dest, b_stream_buffer *buffer, size_t *out_nr_read) 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; enum b_status status;
struct stream_data src_p, dest_p; struct stream_data src_p, dest_p;
struct b_stream_buffer_p *buffer_p; struct b_stream_buffer_p *buffer_p;
@@ -722,39 +858,66 @@ enum b_status b_stream_read_all_bytes_s(
return status; 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); buffer_p = b_object_get_private(buffer, B_TYPE_STREAM_BUFFER);
if (!buffer_p) { if (!buffer_p) {
return B_ERR_INVALID_ARGUMENT; 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); 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) 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); STREAM_DISPATCH_VIRTUAL(stream_write_char, stream, c);
} }
enum b_status b_stream_write_string( enum b_status b_stream_write_string(
b_stream *stream, const char *s, size_t *nr_written) 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); STREAM_DISPATCH_VIRTUAL(stream_write_string, stream, s, nr_written);
} }
enum b_status b_stream_write_bytes( enum b_status b_stream_write_bytes(
b_stream *stream, const void *buf, size_t count, size_t *nr_written) 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); STREAM_DISPATCH_VIRTUAL(stream_write_bytes, stream, buf, count, nr_written);
} }
enum b_status b_stream_write_fmt( enum b_status b_stream_write_fmt(
b_stream *stream, size_t *nr_written, const char *format, ...) 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; struct stream_data p;
enum b_status status = stream_get_data(stream, &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( enum b_status b_stream_write_vfmt(
b_stream *stream, size_t *nr_written, const char *format, va_list arg) 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; struct stream_data p;
enum b_status status = stream_get_data(stream, &p); enum b_status status = stream_get_data(stream, &p);

View File

@@ -10,6 +10,7 @@
struct b_stringstream_p { struct b_stringstream_p {
char *ss_buf; char *ss_buf;
size_t ss_ptr;
size_t ss_len; size_t ss_len;
size_t ss_max; size_t ss_max;
unsigned char ss_alloc; unsigned char ss_alloc;
@@ -17,6 +18,50 @@ struct b_stringstream_p {
/*** PRIVATE FUNCTIONS ********************************************************/ /*** 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( static enum b_status __puts(
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written) 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); 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); 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_buf = buf;
p->ss_max = max; 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); 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); 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); p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
if (!p->ss_buf) { 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( enum b_status stream_write(
b_stream *stream, const void *buf, size_t count, size_t *nr_written) 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_close) = NULL;
B_INTERFACE_ENTRY(s_seek) = NULL; B_INTERFACE_ENTRY(s_seek) = NULL;
B_INTERFACE_ENTRY(s_tell) = NULL; B_INTERFACE_ENTRY(s_tell) = NULL;
B_INTERFACE_ENTRY(s_getc) = NULL; B_INTERFACE_ENTRY(s_getc) = stream_getc;
B_INTERFACE_ENTRY(s_read) = NULL; B_INTERFACE_ENTRY(s_read) = stream_read;
B_INTERFACE_ENTRY(s_write) = stream_write; B_INTERFACE_ENTRY(s_write) = stream_write;
B_INTERFACE_ENTRY(s_reserve) = NULL; B_INTERFACE_ENTRY(s_reserve) = NULL;
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM) B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)

View File

@@ -371,6 +371,7 @@ static b_iterator *iterable_begin(b_object *obj)
if (it->_a_p->ar_len > 0) { if (it->_a_p->ar_len > 0) {
it->value = it->_a_p->ar_data[0]; it->value = it->_a_p->ar_data[0];
} else { } else {
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
it->value = NULL; it->value = NULL;
} }
@@ -389,6 +390,7 @@ static const b_iterator *iterable_cbegin(const b_object *obj)
if (it->_a_p->ar_len > 0) { if (it->_a_p->ar_len > 0) {
it->value = it->_a_p->ar_data[0]; it->value = it->_a_p->ar_data[0];
} else { } else {
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
it->value = NULL; it->value = NULL;
} }

View File

@@ -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)

View File

View File

@@ -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_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 ********************************************************/ /*** VIRTUAL FUNCTIONS ********************************************************/
static void hashmap_init(b_object *obj, void *priv) static void hashmap_init(b_object *obj, void *priv)
@@ -410,54 +458,6 @@ static void hashmap_fini(b_object *obj, void *priv)
/*** ITERATOR FUNCTIONS *******************************************************/ /*** 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) static enum b_status iterator_move_next(const b_iterator *obj)
{ {
struct b_hashmap_iterator_p *it 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->_cbn = next_node;
it->_cqe = next_entry; it->_cqe = next_entry;
return true; return B_SUCCESS;
} }
static enum b_status iterator_erase(b_iterator *obj) 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_END(b_object, B_TYPE_OBJECT)
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE) B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
B_INTERFACE_ENTRY(it_begin) = iterable_begin; B_INTERFACE_ENTRY(it_begin) = b_hashmap_begin;
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin; B_INTERFACE_ENTRY(it_cbegin) = b_hashmap_cbegin;
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE) B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
B_TYPE_CLASS_DEFINITION_END(b_hashmap) B_TYPE_CLASS_DEFINITION_END(b_hashmap)

View File

@@ -1,22 +1,15 @@
#ifndef BLUE_OBJECT_BITBUFFER_H_ #ifndef BLUE_DS_BITBUFFER_H_
#define BLUE_OBJECT_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); B_TYPE_CLASS_DECLARATION_BEGIN(b_bitbuffer)
;
static inline b_bitbuffer *b_bitbuffer_retain(b_bitbuffer *buf) B_TYPE_CLASS_DECLARATION_END(b_bitbuffer);
{
return B_BITBUFFER(b_retain(B_DSREF(buf)));
}
static inline void b_bitbuffer_release(b_bitbuffer *buf)
{
b_release(B_DSREF(buf));
}
BLUE_API b_status b_bitbuffer_put_bit(b_bitbuffer *buf, int bit); 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); 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( BLUE_API b_status b_bitbuffer_put_string(
b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char); b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
B_DECLS_END;
#endif #endif

View File

@@ -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 size_t b_hashmap_get_size(const b_hashmap *hashmap);
BLUE_API bool b_hashmap_is_empty(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; B_DECLS_END;
#endif #endif

View File

@@ -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 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_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; B_DECLS_END;

View File

@@ -17,8 +17,11 @@ B_DECLARE_TYPE(b_uuid);
B_TYPE_CLASS_DECLARATION_BEGIN(b_uuid) B_TYPE_CLASS_DECLARATION_BEGIN(b_uuid)
B_TYPE_CLASS_DECLARATION_END(b_uuid) B_TYPE_CLASS_DECLARATION_END(b_uuid)
typedef struct b_uuid_bytes { typedef union b_uuid_bytes {
unsigned char uuid_bytes[B_UUID_NBYTES]; 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; } b_uuid_bytes;
BLUE_API b_type b_uuid_get_type(void); BLUE_API b_type b_uuid_get_type(void);

View File

@@ -365,22 +365,7 @@ void *b_list_entry_value(const struct b_list_entry *entry)
return entry ? entry->e_data : NULL; return entry ? entry->e_data : NULL;
} }
/*** VIRTUAL FUNCTIONS ********************************************************/ b_iterator *b_list_begin(b_list *q)
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_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR); b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
struct b_list_iterator_p *it struct b_list_iterator_p *it
@@ -399,7 +384,7 @@ static b_iterator *iterable_begin(b_list *q)
return 0; 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); b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
struct b_list_iterator_p *it struct b_list_iterator_p *it
@@ -418,6 +403,21 @@ static const b_iterator *iterable_cbegin(const b_list *q)
return 0; 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) static enum b_status iterator_move_next(const b_iterator *obj)
{ {
struct b_list_iterator_p *it 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_END(b_object, B_TYPE_OBJECT)
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE) B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
B_INTERFACE_ENTRY(it_begin) = iterable_begin; B_INTERFACE_ENTRY(it_begin) = b_list_begin;
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin; B_INTERFACE_ENTRY(it_cbegin) = b_list_cbegin;
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE) B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
B_TYPE_CLASS_DEFINITION_END(b_list) B_TYPE_CLASS_DEFINITION_END(b_list)

View File

@@ -8,7 +8,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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 STRING_INLINE_CAPACITY 15
#define IS_VALID_UTF8_SCALAR(x) \ #define IS_VALID_UTF8_SCALAR(x) \
@@ -48,7 +49,6 @@ struct b_string_iterator_p {
const char **_d; const char **_d;
size_t _nd, _ds; size_t _nd, _ds;
b_status status;
size_t iteration_index; size_t iteration_index;
size_t byte_index; size_t byte_index;
size_t codepoint_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; bool is_now_inline = capacity == STRING_INLINE_CAPACITY;
if (capacity == old_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; 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); struct b_string_p *p = b_object_get_private(obj, B_TYPE_STRING);
if (!p->s_len) { if (!p->s_len) {
it->status = B_ERR_NO_DATA; b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj; return it_obj;
} }
@@ -1422,12 +1423,17 @@ static b_iterator *iterator_begin(b_object *obj)
it->char_value = b_wchar_utf8_codepoint_decode(s); it->char_value = b_wchar_utf8_codepoint_decode(s);
if (it->char_value == B_WCHAR_INVALID) { 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; 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) static enum b_status chars_iterator_move_next(struct b_string_iterator_p *it)
{ {
if (!it->_s_p) { 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; it->codepoint_index += 1;
if (it->byte_index >= it->_s_p->s_len) { if (it->byte_index >= it->_s_p->s_len) {
it->char_value = B_WCHAR_INVALID;
return B_ERR_NO_DATA; 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 *********************************************************/ /*** CLASS DEFINITION *********************************************************/
// ---- b_string 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_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
B_INTERFACE_ENTRY(to_string) = string_to_string; B_INTERFACE_ENTRY(to_string) = string_to_string;
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) 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_CLASS_DEFINITION_END(b_string)
B_TYPE_DEFINITION_BEGIN(b_string) B_TYPE_DEFINITION_BEGIN(b_string)
B_TYPE_ID(0x200194f6, 0x0327, 0x4a82, 0xb9c9, 0xb62ddd038c33); B_TYPE_ID(0x200194f6, 0x0327, 0x4a82, 0xb9c9, 0xb62ddd038c33);
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
B_TYPE_CLASS(b_string_class); B_TYPE_CLASS(b_string_class);
B_TYPE_INSTANCE_PRIVATE(struct b_string_p); B_TYPE_INSTANCE_PRIVATE(struct b_string_p);
B_TYPE_INSTANCE_INIT(string_init); 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_move_next) = iterator_move_next;
B_INTERFACE_ENTRY(it_erase) = NULL; B_INTERFACE_ENTRY(it_erase) = NULL;
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value; 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_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
B_TYPE_CLASS_DEFINITION_END(b_string_iterator) B_TYPE_CLASS_DEFINITION_END(b_string_iterator)

View File

@@ -9,7 +9,7 @@
/*** PRIVATE DATA *************************************************************/ /*** PRIVATE DATA *************************************************************/
struct b_uuid_p { struct b_uuid_p {
struct b_uuid_bytes uuid_bytes; union b_uuid_bytes uuid_bytes;
}; };
/*** PRIVATE FUNCTIONS ********************************************************/ /*** PRIVATE FUNCTIONS ********************************************************/
@@ -39,12 +39,12 @@ static void uuid_get_bytes(
} }
static void uuid_get_uuid_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); 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; 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) b_uuid *b_uuid_create_from_cstr(const char *str)
{ {
struct b_uuid_bytes bytes; union b_uuid_bytes bytes;
bool valid = true; bool valid = true;
bool is_guid = false; 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); 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); 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); B_CLASS_DISPATCH_STATIC_0(B_TYPE_UUID, uuid_ptr, uuid);
} }
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/ /*** 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); return b_uuid_create_from_bytev(bytes->uuid_bytes);
} }

View File

@@ -14,13 +14,18 @@ B_DECLS_BEGIN;
struct b_directory_p; 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);
B_DECLARE_TYPE(b_directory_iterator);
B_TYPE_CLASS_DECLARATION_BEGIN(b_directory) B_TYPE_CLASS_DECLARATION_BEGIN(b_directory)
B_TYPE_CLASS_DECLARATION_END(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; struct z__b_directory_iterator;
typedef enum b_directory_iterator_flags { 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_DELETE_ON_CLOSE = 0x04u,
} b_directory_open_flags; } b_directory_open_flags;
typedef struct b_directory_iterator { typedef struct b_directory_entry {
b_iterator _base;
struct z__b_directory_iterator *_z;
struct b_directory_p *_p;
b_directory_iterator_flags flags;
b_directory *root;
const b_path *filepath; const b_path *filepath;
char *filename; char *filename;
b_file_info info; b_file_info info;
} b_directory_iterator; } b_directory_entry;
#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))
BLUE_API b_type b_directory_get_type(void); 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( BLUE_API b_result b_directory_open(
b_directory *root, const b_path *path, b_directory_open_flags flags, 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( BLUE_API b_result b_directory_path_unlink(
const b_directory *root, const b_path *path); const b_directory *root, const b_path *path);
BLUE_API int b_directory_iterator_begin( BLUE_API b_iterator *b_directory_begin(
b_directory *directory, b_directory_iterator *it, b_directory *dir, b_directory_iterator_flags flags);
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);
B_DECLS_END; B_DECLS_END;

View File

@@ -25,9 +25,16 @@ struct b_directory_p {
b_path *d_path_abs; b_path *d_path_abs;
}; };
struct z__b_directory_iterator { struct b_directory_iterator_p {
struct b_directory_p *_p;
FTS *fts; FTS *fts;
FTSENT *ent; FTSENT *ent;
b_directory_iterator_flags flags;
b_directory *root;
b_directory_entry entry;
}; };
/*** PRIVATE FUNCTIONS ********************************************************/ /*** 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; enum b_status status = B_SUCCESS;
struct b_directory_iterator it; b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_LAST);
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST); while (B_OK(b_iterator_get_status(it))) {
while (b_directory_iterator_is_valid(&it)) { b_iterator_erase(it);
status = b_directory_iterator_erase(&it); }
if (!B_OK(status)) {
return B_RESULT_STATUS(status); 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); 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( static b_result create_directory_hierarchy(
struct b_directory_p *root, const char *path) 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); char *path_buf = b_strdup(path);
if (!path_buf) { if (!path_buf) {
@@ -417,22 +425,6 @@ static void directory_fini(b_object *obj, void *priv)
b_path_unref(dir->d_path_abs); 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 *******************************************************/ /*** ITERATOR FUNCTIONS *******************************************************/
static int ftsent_compare(const FTSENT **one, const FTSENT **two) 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)); 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->entry.filepath) {
b_path_unref((b_path *)it->entry.filepath);
if (it->filepath) { it->entry.filepath = NULL;
b_path_unref((b_path *)it->filepath);
it->filepath = NULL;
} }
FTSENT *ent = it_data->ent; FTSENT *ent = it->ent;
b_path *path = b_path_create_from_cstr( b_path *path = b_path_create_from_cstr(
ent->fts_path + b_path_length(it->_p->d_path_abs) + 1); ent->fts_path + b_path_length(it->_p->d_path_abs) + 1);
it->filename = ent->fts_name; it->entry.filename = ent->fts_name;
it->filepath = path; 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)) { 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)) { 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)) { 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)) { 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)) { 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) { struct b_directory_iterator_p *it = priv;
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;
} }
struct z__b_directory_iterator *it_data = it->_z; if (it->fts) {
memset(it, 0x0, sizeof *it); fts_close(it->fts);
if (!it_data) {
return;
} }
if (it_data->fts) {
fts_close(it_data->fts);
}
free(it_data);
} }
int b_directory_iterator_begin( b_iterator *b_directory_begin(
b_directory *directory, struct b_directory_iterator *it, b_directory *directory, enum b_directory_iterator_flags flags)
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->flags = flags;
it->root = directory; it->root = directory;
it->_p = b_object_get_private(directory, B_TYPE_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; int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
const char *path_list[] = { const char *path_list[] = {
@@ -530,24 +504,23 @@ int b_directory_iterator_begin(
NULL, NULL,
}; };
it_data->fts it->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare);
= fts_open((char *const *)path_list, fts_flags, ftsent_compare);
bool done = false; bool done = false;
while (!done) { while (!done) {
it_data->ent = fts_read(it_data->fts); it->ent = fts_read(it->fts);
if (!it_data->ent) { if (!it->ent) {
cleanup_iterator(it); b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return -1; return it_obj;
} }
if (it_data->ent->fts_level == 0) { if (it->ent->fts_level == 0) {
continue; continue;
} }
switch (it_data->ent->fts_info) { switch (it->ent->fts_info) {
case FTS_DOT: case FTS_DOT:
continue; continue;
case FTS_F: case FTS_F:
@@ -573,31 +546,41 @@ int b_directory_iterator_begin(
} }
update_iterator_data(it); 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; return b_directory_begin(obj, B_DIRECTORY_ITERATE_PARENT_FIRST);
if (!it_data || !it_data->fts) { }
return false;
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; bool done = false;
while (!done) { while (!done) {
it_data->ent = fts_read(it_data->fts); it->ent = fts_read(it->fts);
if (!it_data->ent) { if (!it->ent) {
cleanup_iterator(it); return B_ERR_NO_DATA;
return false;
} }
if (it_data->ent->fts_level == 0) { if (it->ent->fts_level == 0) {
continue; continue;
} }
switch (it_data->ent->fts_info) { switch (it->ent->fts_info) {
case FTS_DOT: case FTS_DOT:
continue; continue;
case FTS_F: case FTS_F:
@@ -622,31 +605,79 @@ bool b_directory_iterator_next(struct b_directory_iterator *it)
} }
update_iterator_data(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; 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) { struct b_directory_iterator_p *it
return false; = 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 iterator_move_next(obj);
return false;
}
return true;
} }
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)

View File

@@ -111,7 +111,7 @@ struct ctx {
b_stream *ctx_src; b_stream *ctx_src;
b_string *ctx_wordbuf; b_string *ctx_wordbuf;
b_string *ctx_linebuf; b_string *ctx_linebuf;
b_string_iterator ctx_linebuf_ptr; b_iterator *ctx_linebuf_ptr;
enum b_status ctx_status; enum b_status ctx_status;
b_hashmap *ctx_objects_flags; b_hashmap *ctx_objects_flags;
@@ -207,16 +207,16 @@ static enum b_status data_available(struct ctx *ctx)
return B_ERR_NO_DATA; return B_ERR_NO_DATA;
} }
if (!B_OK(ctx->ctx_linebuf_ptr.status)) { return b_iterator_get_status(ctx->ctx_linebuf_ptr);
return ctx->ctx_linebuf_ptr.status;
}
return b_string_iterator_is_valid(&ctx->ctx_linebuf_ptr) ? B_SUCCESS
: B_ERR_NO_DATA;
} }
static enum b_status refill_linebuf(struct ctx *ctx) 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_string_clear(ctx->ctx_linebuf);
b_stringstream *buf = b_stringstream_create(); b_stringstream *buf = b_stringstream_create();
@@ -233,7 +233,7 @@ static enum b_status refill_linebuf(struct ctx *ctx)
b_stringstream_unref(buf); 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; return B_SUCCESS;
} }
@@ -282,19 +282,15 @@ static b_wchar advance_char(struct ctx *ctx)
} }
const char *s = b_string_ptr(ctx->ctx_linebuf); 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)) { if (!is_valid_char(c)) {
ctx->ctx_status = B_ERR_BAD_FORMAT; ctx->ctx_status = B_ERR_BAD_FORMAT;
return -1; return -1;
} }
b_string_iterator_next(&ctx->ctx_linebuf_ptr); b_iterator_move_next(ctx->ctx_linebuf_ptr);
return c; return c;
} }
@@ -318,12 +314,8 @@ static b_wchar peek_char(struct ctx *ctx)
} }
const char *s = b_string_ptr(ctx->ctx_linebuf); 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)) { if (!is_valid_char(c)) {
ctx->ctx_status = B_ERR_BAD_FORMAT; ctx->ctx_status = B_ERR_BAD_FORMAT;
@@ -909,23 +901,26 @@ static void split_word(struct ctx *ctx, b_string *wordbuf)
#endif #endif
const char *delims[] = {"."}; const char *delims[] = {"."};
size_t nr_delims = sizeof delims / sizeof delims[0]; size_t nr_delims = sizeof delims / sizeof delims[0];
b_string_iterator it; b_iterator *it = b_string_tokenise(
b_string_tokenise( wordbuf, delims, nr_delims, B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS);
wordbuf, delims, nr_delims, B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS,
&it);
while (b_string_iterator_is_valid(&it)) { size_t i = 0;
if (it.iteration_index > 0) { b_foreach_c(const char *, tok, it)
{
if (i > 0) {
enqueue_token(ctx, TOK_DOT); 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); 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) static void read_number(struct ctx *ctx)
@@ -1012,17 +1007,17 @@ static void read_word(struct ctx *ctx)
return; return;
} }
b_string_iterator it; b_iterator *it = b_iterator_begin(wordbuf);
b_string_foreach(&it, wordbuf) b_foreach(b_wchar, c, it)
{ {
/* only allow ASCII numbers/letters here */ /* only allow ASCII numbers/letters here */
bool ok = isalnum(it.char_value) || it.char_value == '_' bool ok = isalnum(c) || c == '_' || c == '-' || c == '.';
|| it.char_value == '-' || it.char_value == '.';
if (!ok) { if (!ok) {
ctx->ctx_status = B_ERR_BAD_FORMAT; ctx->ctx_status = B_ERR_BAD_FORMAT;
return; return;
} }
} }
b_iterator_unref(it);
split_word(ctx, wordbuf); split_word(ctx, wordbuf);
} }
@@ -1514,6 +1509,11 @@ static struct token *peek_token(struct ctx *ctx)
static void ctx_cleanup(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) { if (ctx->ctx_linebuf) {
b_string_unref(ctx->ctx_linebuf); b_string_unref(ctx->ctx_linebuf);
ctx->ctx_linebuf = NULL; ctx->ctx_linebuf = NULL;

View File

@@ -74,19 +74,21 @@ void test_btree_iterate(CuTest *tc)
} }
int prev = -1; int prev = -1;
b_btree_iterator it; b_btree_node *bnode = b_btree_first(&tree);
b_btree_foreach (&it, &tree) { while (bnode) {
struct test_tree_node *node 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); CuAssertPtrNotNull(tc, node);
if (prev == -1) { if (prev == -1) {
prev = node->value; prev = node->value;
bnode = b_btree_next(bnode);
continue; continue;
} }
CuAssertTrue(tc, prev <= node->value); CuAssertTrue(tc, prev <= node->value);
prev = node->value; prev = node->value;
bnode = b_btree_next(bnode);
} }
free(nodes); free(nodes);
@@ -134,19 +136,21 @@ void test_queue_iterate(CuTest *tc)
} }
int prev = -1; int prev = -1;
b_queue_iterator it; struct b_queue_entry *entry = b_queue_first(&q);
b_queue_foreach (&it, &q) { while (entry) {
struct test_queue_entry *e 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); CuAssertPtrNotNull(tc, e);
if (prev == -1) { if (prev == -1) {
prev = e->value; prev = e->value;
continue; goto skip;
} }
CuAssertTrue(tc, prev < e->value); CuAssertTrue(tc, prev < e->value);
prev = e->value; prev = e->value;
skip:
entry = b_queue_next(entry);
} }
} }

84
test/core/ropes.c Normal file
View 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
View 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;
}

View File

@@ -9,11 +9,12 @@ int main(void)
b_array_append(array, B_RV_INT(64)); b_array_append(array, B_RV_INT(64));
b_array_append(array, B_RV_INT(128)); b_array_append(array, B_RV_INT(128));
b_array_iterator it; b_iterator *it = b_iterator_begin(array);
b_array_foreach(&it, 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); b_array_unref(array);
return 0; return 0;

View File

@@ -1,4 +1,5 @@
#include <blue/core/btree.h> #include <blue/core/btree.h>
#include <blue/core/iterator.h>
#include <blue/ds/dict.h> #include <blue/ds/dict.h>
#include <blue/ds/number.h> #include <blue/ds/number.h>
#include <blue/ds/tree.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) int main(void)
{ {
b_dict_item items[] b_dict *dict = b_dict_create();
= {B_DICT_ITEM("hello", B_RV_INT(32)), b_dict_put(dict, "hello", B_RV_INT(32));
B_DICT_ITEM("world", B_RV_INT(64)), b_dict_put(dict, "world", B_RV_INT(64));
B_DICT_ITEM("more", B_RV_INT(128)), b_dict_put(dict, "more", B_RV_INT(128));
B_DICT_ITEM("other", B_RV_INT(256)), B_DICT_ITEM_END}; 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; size_t i = 0;
b_dict_foreach(&it, dict) b_foreach(b_dict_item *, item, it)
{ {
printf("item %zu: %s=%d\n", it.i, b_string_ptr(it.key), printf("item %zu: %s=%d\n", i++, b_string_ptr(item->key),
b_number_get_int(it.value)); b_number_get_int(item->value));
} }
b_iterator_unref(it);
b_tree *tree = b_tree_create(); b_tree *tree = b_tree_create();
struct tree_item items2[NITEMS]; 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[1].node, &items2[5].node);
b_tree_node_add_child(&items2[4].node, &items2[6].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_iterator it2;
b_tree_foreach(&it2, tree) b_tree_foreach(&it2, tree)
{ {
@@ -113,6 +118,7 @@ int main(void)
} }
b_tree_unref(tree); b_tree_unref(tree);
#endif
b_dict_unref(dict); b_dict_unref(dict);
return 0; return 0;

View File

@@ -12,15 +12,16 @@ int main(void)
printf("len: %zu\n", b_string_get_size(str, B_STRLEN_NORMAL)); printf("len: %zu\n", b_string_get_size(str, B_STRLEN_NORMAL));
printf("codepoints: %zu\n", b_string_get_size(str, B_STRLEN_CODEPOINTS)); printf("codepoints: %zu\n", b_string_get_size(str, B_STRLEN_CODEPOINTS));
b_string_iterator it;
const char *delims[] = {"в"}; const char *delims[] = {"в"};
size_t nr_delims = sizeof delims / sizeof delims[0]; size_t nr_delims = sizeof delims / sizeof delims[0];
b_string_tokenise(str, delims, nr_delims, 0, &it); b_iterator *it = b_string_tokenise(str, delims, nr_delims, 0);
while (b_string_iterator_is_valid(&it)) { b_foreach(const char *, tok, it)
printf("%s\n", it.string_value); {
b_string_iterator_next(&it); printf("%s\n", tok);
} }
b_iterator_unref(it);
b_string_unref(str);
return 0; return 0;
} }

View File

@@ -19,5 +19,8 @@ int main(int argc, const char **argv)
b_stream_read_all_bytes_s(b_stdin, dest, buf, &nr_read); b_stream_read_all_bytes_s(b_stdin, dest, buf, &nr_read);
printf("done. read %zu bytes total.\n", nr_read); printf("done. read %zu bytes total.\n", nr_read);
b_path_unref(path);
b_file_unref(dest);
return 0; return 0;
} }

View File

@@ -20,12 +20,13 @@ int main(int argc, const char **argv)
return -1; return -1;
} }
b_directory_iterator it = {0}; b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_FIRST);
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_FIRST); b_foreach(b_directory_entry *, entry, it)
while (b_directory_iterator_is_valid(&it)) { {
printf("%s\n", b_path_ptr(it.filepath)); printf("%s\n", b_path_ptr(entry->filepath));
b_directory_iterator_next(&it);
} }
b_iterator_unref(it);
return 0; return 0;
} }

View File

@@ -12,11 +12,9 @@ void write_raw_string(const b_string *data)
{ {
b_stream_write_string(b_stdout, "\"", NULL); b_stream_write_string(b_stdout, "\"", NULL);
b_string_iterator it; const b_iterator *it = b_iterator_cbegin(data);
b_string_foreach(&it, data) b_foreach_c(b_wchar, c, it)
{ {
b_wchar c = it.char_value;
if (c >= 0x10000) { if (c >= 0x10000) {
c -= 0x10000; c -= 0x10000;
long hi = 0xD800 | ((c >> 10) & 0x3FF); 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_stream_write_char(b_stdout, c);
} }
} }
b_iterator_unref(it);
b_stream_write_string(b_stdout, "\"", NULL); b_stream_write_string(b_stdout, "\"", NULL);
} }
@@ -134,17 +133,18 @@ void write_tagged_dict(b_dict *data)
int i = 0; int i = 0;
b_dict_iterator it; b_iterator *it = b_iterator_begin(data);
b_dict_foreach(&it, data) b_foreach(b_dict_item *, item, it)
{ {
if (i++ > 0) { if (i++ > 0) {
b_stream_write_string(b_stdout, ", ", NULL); b_stream_write_string(b_stdout, ", ", NULL);
} }
write_raw_string(it.key); write_raw_string(item->key);
b_stream_write_string(b_stdout, ": ", NULL); 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); 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); b_stream_write_string(b_stdout, "[ ", NULL);
int i = 0; int i = 0;
b_array_iterator it; b_iterator *it = b_iterator_begin(data);
b_array_foreach(&it, data) b_foreach(b_object *, obj, it)
{ {
if (i++ > 0) { if (i++ > 0) {
b_stream_write_string(b_stdout, ", ", NULL); 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); b_stream_write_string(b_stdout, " ]", NULL);
} }

View File

@@ -1 +1,4 @@
k = "v" # "No newlines are allowed between the curly braces unless they are valid within
# a value"
a = []