コード例 #1
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t const* tb_string_ltrim(tb_string_ref_t string)
{
    // check
    tb_assert_and_check_return_val(string, tb_null);

    // init
    tb_char_t*  s = (tb_char_t*)tb_string_cstr(string);
    tb_size_t   n = tb_string_size(string);
    tb_check_return_val(s && n, tb_null);

    // done
    tb_char_t*  p = s;
    tb_char_t*  e = s + n;
    while (p < e && tb_isspace(*p)) p++;

    // strip it
    if (p < e)
    {
        // move it if exists spaces
        if (p > s) tb_buffer_memmov(string, p - s);
    }
    // clear it
    else tb_string_clear(string);

    // ok?
    return tb_string_cstr(string);
}
コード例 #2
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_xml_node_ref_t tb_xml_reader_attributes(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl && ( impl->event == TB_XML_READER_EVENT_DOCUMENT
                                            ||  impl->event == TB_XML_READER_EVENT_ELEMENT_BEG
                                            ||  impl->event == TB_XML_READER_EVENT_ELEMENT_END
                                            ||  impl->event == TB_XML_READER_EVENT_ELEMENT_EMPTY), tb_null);

    // init
    tb_char_t const* p = tb_string_cstr(&impl->element);
    tb_char_t const* e = p + tb_string_size(&impl->element);

    // skip name
    while (p < e && *p && !tb_isspace(*p)) p++;
    while (p < e && *p && tb_isspace(*p)) p++;

    // parse attributes
    tb_size_t n = 0;
    while (p < e)
    {
        // parse name
        tb_string_clear(&impl->attribute_name);
        for (; p < e && *p != '='; p++) if (!tb_isspace(*p)) tb_string_chrcat(&impl->attribute_name, *p);
        if (*p != '=') break;

        // parse data
        tb_string_clear(&impl->attribute_data);
        for (p++; p < e && (*p != '\'' && *p != '\"'); p++) ;
        if (*p != '\'' && *p != '\"') break;
        for (p++; p < e && (*p != '\'' && *p != '\"'); p++) tb_string_chrcat(&impl->attribute_data, *p);
        if (*p != '\'' && *p != '\"') break;
        p++;

        // append node
        if (tb_string_cstr(&impl->attribute_name) && tb_string_cstr(&impl->attribute_data))
        {
            // node
            tb_xml_node_ref_t prev = n > 0? (tb_xml_node_ref_t)&impl->attributes[n - 1] : tb_null;
            tb_xml_node_ref_t node = (tb_xml_node_ref_t)&impl->attributes[n];

            // init node
            tb_string_strcpy(&node->name, &impl->attribute_name);
            tb_string_strcpy(&node->data, &impl->attribute_data);

            // append node
            if (prev) prev->next = node;
            node->next = tb_null;

            // next
            n++;
        }
    }

    // ok?
    return n? (tb_xml_node_ref_t)&impl->attributes[0] : tb_null;
}
コード例 #3
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_char_t const* tb_xml_reader_cdata(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl && impl->event == TB_XML_READER_EVENT_CDATA, tb_null);

    // init
    tb_char_t const*    p = tb_string_cstr(&impl->element);
    tb_size_t           n = tb_string_size(&impl->element);
    tb_assert_and_check_return_val(p && n >= 11, tb_null);

    // comment
    tb_string_cstrncpy(&impl->text, p + 8, n - 10);
    return tb_string_cstr(&impl->text);
}
コード例 #4
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t const* tb_string_strcat(tb_string_ref_t string, tb_string_ref_t s)
{
    // check
    tb_assert_and_check_return_val(s, tb_null);

    // done
    return tb_string_cstrncat(string, tb_string_cstr(s), tb_string_size(s));
}
コード例 #5
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_char_t const* tb_xml_reader_text(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl && impl->event == TB_XML_READER_EVENT_TEXT, tb_null);

    // text
    return tb_string_cstr(&impl->text);
}
コード例 #6
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_char_t const* tb_xml_reader_charset(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl, tb_null);

    // text
    return tb_string_cstr(&impl->charset);
}
コード例 #7
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t tb_string_charat(tb_string_ref_t string, tb_size_t p)
{
    // check
    tb_char_t const*    s = tb_string_cstr(string);
    tb_size_t           n = tb_string_size(string);
    tb_assert_and_check_return_val(s && p < n, '\0');

    // get it
    return s[p];
}
コード例 #8
0
ファイル: string.c プロジェクト: richwu/tbox
tb_long_t tb_string_cstrirstr(tb_string_ref_t string, tb_size_t p, tb_char_t const* s2)
{
    // check
    tb_char_t const*    s = tb_string_cstr(string);
    tb_size_t           n = tb_string_size(string);
    tb_assert_and_check_return_val(s && p && p < n, -1);

    // done
    tb_char_t* q = tb_strnirstr(s + p, n, s2);
    return (q? q - s : -1);
}
コード例 #9
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t const* tb_string_rtrim(tb_string_ref_t string)
{
    // check
    tb_assert_and_check_return_val(string, tb_null);

    // init
    tb_char_t*  s = (tb_char_t*)tb_string_cstr(string);
    tb_size_t   n = tb_string_size(string);
    tb_check_return_val(s && n, tb_null);

    // done
    tb_char_t*  e = s + n - 1;
    while (e >= s && tb_isspace(*e)) e--;

    // strip it
    if (e >= s) tb_string_strip(string, e - s + 1);
    // clear it
    else tb_string_clear(string);

    // ok?
    return tb_string_cstr(string);
}
コード例 #10
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_char_t const* tb_xml_reader_doctype(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl && impl->event == TB_XML_READER_EVENT_DOCUMENT_TYPE, tb_null);

    // doctype
    tb_char_t const* p = tb_string_cstr(&impl->element);
    tb_assert_and_check_return_val(p, tb_null);

    // skip !DOCTYPE
    return (p + 9);
}
コード例 #11
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_size_t tb_environment_load(tb_environment_ref_t environment, tb_char_t const* name)
{
    // check
    tb_assert_and_check_return_val(environment && name, 0);

    // clear environment first
    tb_vector_clear(environment);

    // get values
    tb_char_t const* values = tb_environment_get_impl(name, tb_null);
    tb_check_return_val(values, 0);

    // init value string
    tb_string_t value;
    if (tb_string_init(&value)) 
    {
        // done
        tb_char_t const*    p = values;
        tb_char_t           c = '\0';
        while (1)
        {
            // the character
            c = *p++;

            // make value
            if (c != ';' && c) tb_string_chrcat(&value, c);
            else 
            {
                // save value to environment
                if (tb_string_size(&value)) 
                    tb_vector_insert_tail(environment, tb_string_cstr(&value));

                // clear value 
                tb_string_clear(&value);

                // end?
                tb_check_break(c);
            }
        }

        // exit value string
        tb_string_exit(&value);
    }

    // exit values
    if (values) tb_free(values);
    values = tb_null;

    // ok?
    return tb_vector_size(environment);
}
コード例 #12
0
tb_void_t tb_http_status_dump(tb_http_status_t* status)
{
    // check
    tb_assert_and_check_return(status);

    // dump status
    tb_trace_i("======================================================================");
    tb_trace_i("status: ");
    tb_trace_i("status: code: %d", status->code);
    tb_trace_i("status: version: HTTP/1.%1u", status->version);
    tb_trace_i("status: content:type: %s", tb_string_cstr(&status->content_type));
    tb_trace_i("status: content:size: %lld", status->content_size);
    tb_trace_i("status: document:size: %lld", status->document_size);
    tb_trace_i("status: location: %s", tb_string_cstr(&status->location));
    tb_trace_i("status: bgzip: %s", status->bgzip? "true" : "false");
    tb_trace_i("status: bdeflate: %s", status->bdeflate? "true" : "false");
    tb_trace_i("status: balived: %s", status->balived? "true" : "false");
    tb_trace_i("status: bseeked: %s", status->bseeked? "true" : "false");
    tb_trace_i("status: bchunked: %s", status->bchunked? "true" : "false");

    // dump end
    tb_trace_i("");
}
コード例 #13
0
ファイル: reader.c プロジェクト: 1060460048/tbox
/* //////////////////////////////////////////////////////////////////////////////////////
 * parser implementation
 */
static tb_char_t const* tb_xml_reader_element_parse(tb_xml_reader_impl_t* reader)
{
    // clear element
    tb_string_clear(&reader->element);

    // parse element
    tb_char_t ch = '\0';
    tb_size_t in = 0;
    while ((ch = tb_stream_bread_s8(reader->rstream)))
    {
        // append element
        if (!in && ch == '<') in = 1;
        else if (in)
        {
            if (ch != '>') tb_string_chrcat(&reader->element, ch);
            else return tb_string_cstr(&reader->element);
        }
    }

    // failed
    tb_assertf_abort(0, "invalid element: %s from %s", tb_string_cstr(&reader->element), tb_url_get(tb_stream_url(reader->istream)));
    return tb_null;
}
コード例 #14
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t const* tb_string_strcpy(tb_string_ref_t string, tb_string_ref_t s)
{
    // check
    tb_assert_and_check_return_val(s, tb_null);

    // done
    tb_size_t n = tb_string_size(s);
    if (n) return tb_string_cstrncpy(string, tb_string_cstr(s), n);
    else
    {
        tb_string_clear(string);
        return tb_null;
    }
}
コード例 #15
0
ファイル: environment.c プロジェクト: BailiShanghai/tbox
tb_size_t tb_environment_get(tb_char_t const* name, tb_char_t* values, tb_size_t maxn)
{
    // check
    tb_assert_and_check_return_val(name && values && maxn, 0);

    // init values
    tb_string_t valuestrs;
    if (!tb_string_init(&valuestrs)) return 0;

    // init environment
    tb_environment_ref_t environment = tb_environment_init();
    if (environment)
    {
        // load variable
        if (tb_environment_load(environment, name))
        {
            // make values
            tb_bool_t is_first = tb_true;
            tb_for_all_if (tb_char_t const*, value, environment, value)
            {
                // append separator
                if (!is_first) tb_string_chrcat(&valuestrs, TM_ENVIRONMENT_SEP);
                else is_first = tb_false;

                // append value
                tb_string_cstrcat(&valuestrs, value);
            }
        }

        // exit environment
        tb_environment_exit(environment);
    }

    // save result
    tb_size_t           size = tb_string_size(&valuestrs);
    tb_char_t const*    cstr = tb_string_cstr(&valuestrs);
    if (size && cstr) 
    {
        // copy it
        size = tb_strlcpy(values, cstr, maxn);
        tb_assert(size < maxn);
    }

    // exit values
    tb_string_exit(&valuestrs);

    // ok?
    return size;
}
コード例 #16
0
ファイル: string.c プロジェクト: richwu/tbox
tb_char_t const* tb_string_strip(tb_string_ref_t string, tb_size_t n)
{
    // check
    tb_assert_and_check_return_val(string, tb_null);

    // out?
    tb_check_return_val(n < tb_string_size(string), tb_string_cstr(string));

    // strip
    tb_char_t* p = (tb_char_t*)tb_buffer_resize(string, n + 1);
    if (p) p[n] = '\0';

    // ok?
    return p;
}
コード例 #17
0
ファイル: getenv.c プロジェクト: JamesLinus/xmake
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_int_t xm_os_getenv(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // get the name  
    tb_char_t const* name = luaL_checkstring(lua, 1);
    tb_check_return_val(name, 0);

    // init values
    tb_string_t values;
    if (!tb_string_init(&values)) return 0;

    // init environment
    tb_environment_ref_t environment = tb_environment_init();
    if (environment)
    {
        // load variable
        if (tb_environment_load(environment, name))
        {
            // make values
            tb_bool_t is_first = tb_true;
            tb_for_all_if (tb_char_t const*, value, environment, value)
            {
                // append separator
                if (!is_first) tb_string_chrcat(&values, XM_OS_ENV_SEP);
                else is_first = tb_false;

                // append value
                tb_string_cstrcat(&values, value);
            }
        }

        // exit environment
        tb_environment_exit(environment);
    }

    // save result
    if (tb_string_size(&values)) lua_pushstring(lua, tb_string_cstr(&values));
    else lua_pushnil(lua);

    // exit values
    tb_string_exit(&values);

    // ok
    return 1;
}
コード例 #18
0
ファイル: reader.c プロジェクト: 1060460048/tbox
static tb_char_t const* tb_xml_reader_text_parse(tb_xml_reader_impl_t* reader)
{
    // clear text
    tb_string_clear(&reader->text);

    // parse text
    tb_char_t* pc = tb_null;
    while (tb_stream_need(reader->rstream, (tb_byte_t**)&pc, 1) && pc)
    {
        // is end? </ ..>
        if (pc[0] == '<') return tb_string_cstr(&reader->text);
        else
        {
            tb_string_chrcat(&reader->text, *pc);
            if (!tb_stream_skip(reader->rstream, 1)) return tb_null;
        }
    }
    return tb_null;
}
コード例 #19
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_char_t const* tb_xml_reader_element(tb_xml_reader_ref_t reader)
{
    // check
    tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader;
    tb_assert_and_check_return_val(impl && ( impl->event == TB_XML_READER_EVENT_ELEMENT_BEG
                                            ||  impl->event == TB_XML_READER_EVENT_ELEMENT_END
                                            ||  impl->event == TB_XML_READER_EVENT_ELEMENT_EMPTY), tb_null);

    // init
    tb_char_t const* p = tb_null;
    tb_char_t const* b = tb_string_cstr(&impl->element);
    tb_char_t const* e = b + tb_string_size(&impl->element);
    tb_assert_and_check_return_val(b, tb_null);

    // </name> or <name ... />
    if (b < e && *b == '/') b++;
    for (p = b; p < e && *p && !tb_isspace(*p) && *p != '/'; p++) ;

    // ok?
    return p > b? tb_string_cstrncpy(&impl->element_name, b, p - b) : tb_null;
}
コード例 #20
0
ファイル: async_stream.c プロジェクト: 1060460048/tbox
/* //////////////////////////////////////////////////////////////////////////////////////
 * main
 */ 
tb_int_t tb_demo_stream_async_stream_main(tb_int_t argc, tb_char_t** argv)
{
    // done
    tb_demo_context_t   context = {0};
    do
    {
        // init option
        context.option = tb_option_init("astream", "the astream demo", g_options);
        tb_assert_and_check_break(context.option);
    
        // done option
        if (tb_option_done(context.option, argc - 1, &argv[1]))
        {
            // debug and verbose
            context.debug   = tb_option_find(context.option, "debug")? tb_false : tb_true;
            context.verbose = tb_option_find(context.option, "no-verbose")? tb_false : tb_true;
        
            // done url
            if (tb_option_find(context.option, "url")) 
            {
                // init event
                context.event = tb_event_init();
                tb_assert_and_check_break(context.event);

                // init istream
                context.istream = tb_async_stream_init_from_url(tb_null, tb_option_item_cstr(context.option, "url"));
                tb_assert_and_check_break(context.istream);

                // ctrl http
                if (tb_async_stream_type(context.istream) == TB_STREAM_TYPE_HTTP) 
                {
                    // enable gzip?
                    if (tb_option_find(context.option, "gzip"))
                    {
                        // auto unzip
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break;

                        // need gzip
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break;
                    }

                    // enable debug?
                    if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, context.debug? tb_demo_istream_head_func : tb_null)) break;

                    // custem header?
                    if (tb_option_find(context.option, "header"))
                    {
                        // init
                        tb_string_t key;
                        tb_string_t val;
                        tb_string_init(&key);
                        tb_string_init(&val);

                        // done
                        tb_bool_t           k = tb_true;
                        tb_char_t const*    p = tb_option_item_cstr(context.option, "header");
                        while (*p)
                        {
                            // is key?
                            if (k)
                            {
                                if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++);
                                else if (*p == ':') 
                                {
                                    // skip ':'
                                    p++;

                                    // skip space
                                    while (*p && tb_isspace(*p)) p++;

                                    // is val now
                                    k = tb_false;
                                }
                                else p++;
                            }
                            // is val?
                            else
                            {
                                if (*p != ';') tb_string_chrcat(&val, *p++);
                                else
                                {
                                    // skip ';'
                                    p++;

                                    // skip space
                                    while (*p && tb_isspace(*p)) p++;

                                    // set header
                                    if (tb_string_size(&key) && tb_string_size(&val))
                                    {
                                        if (context.debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
                                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
                                    }

                                    // is key now
                                    k = tb_true;

                                    // clear key & val
                                    tb_string_clear(&key);
                                    tb_string_clear(&val);
                                }
                            }
                        }

                        // set header
                        if (tb_string_size(&key) && tb_string_size(&val))
                        {
                            if (context.debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
                            if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
                        }

                        // exit 
                        tb_string_exit(&key);
                        tb_string_exit(&val);
                    }

                    // keep alive?
                    if (tb_option_find(context.option, "keep-alive"))
                    {
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break;
                    }

                    // post-data?
                    if (tb_option_find(context.option, "post-data"))
                    {
                        tb_char_t const*    post_data = tb_option_item_cstr(context.option, "post-data");
                        tb_hize_t           post_size = tb_strlen(post_data);
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break;
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
                        if (context.debug) tb_printf("post: %llu\n", post_size);
                    }
                    // post-file?
                    else if (tb_option_find(context.option, "post-file"))
                    {
                        tb_char_t const* url = tb_option_item_cstr(context.option, "post-file");
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break;
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
                        if (context.debug) tb_printf("post: %s\n", url);
                    }
                }

                // set range
                if (tb_option_find(context.option, "range"))
                {
                    tb_char_t const* p = tb_option_item_cstr(context.option, "range");
                    if (p)
                    {
                        // the bof
                        tb_hize_t eof = 0;
                        tb_hize_t bof = tb_atoll(p);
                        while (*p && tb_isdigit(*p)) p++;
                        if (*p == '-')
                        {
                            p++;
                            eof = tb_atoll(p);
                        }
                        if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break;
                    }
                }

                // set timeout
                if (tb_option_find(context.option, "timeout"))
                {
                    tb_size_t timeout = tb_option_item_uint32(context.option, "timeout");
                    tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_SET_TIMEOUT, &timeout);
                }

                // print verbose info
                if (context.verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(context.option, "url"));

                // open istream
                if (!tb_async_stream_open(context.istream, tb_demo_istream_open_func, &context)) 
                {
                    // print verbose info
                    if (context.verbose) tb_printf("open: failed\n");
                    break;
                }

                // wait it
                tb_event_wait(context.event, -1);
            }
            else tb_option_help(context.option);
        }
        else tb_option_help(context.option);

    } while (0);

    // exit transfer
    if (context.transfer) tb_async_transfer_exit(context.transfer);
    context.transfer = tb_null;

    // exit istream
    if (context.istream) tb_async_stream_exit(context.istream);
    context.istream = tb_null;

    // exit ostream
    if (context.ostream) tb_async_stream_exit(context.ostream);
    context.ostream = tb_null;

    // exit option
    if (context.option) tb_option_exit(context.option);
    context.option = tb_null;

    // exit event
    if (context.event) tb_event_exit(context.event);
    context.event = tb_null;

    return 0;
}
コード例 #21
0
ファイル: environment.c プロジェクト: BailiShanghai/tbox
    // make values string
    tb_for_all_if (tb_char_t const*, value, environment, value)
    {
        // the single value cannot exist ':'
        tb_assertf(!tb_strchr(value, ':'), "invalid value: %s", value);

        // append value
        tb_string_cstrcat(&values, value);
        tb_string_chrcat(&values, ':');
    }

    // strip the last ':'
    tb_string_strip(&values, tb_string_size(&values) - 1);

    // save variable
    tb_bool_t ok = !setenv(name, tb_string_cstr(&values), 1);

    // exit values string
    tb_string_exit(&values);

    // ok?
    return ok;
}
tb_size_t tb_environment_first(tb_char_t const* name, tb_char_t* value, tb_size_t maxn)
{
    // check
    tb_assert_and_check_return_val(name && value && maxn, 0);

    // get it
    tb_char_t const* data = getenv(name);
    tb_check_return_val(data, 0);
コード例 #22
0
    // make values string
    tb_for_all_if (tb_char_t const*, value, environment, value)
    {
        // the single value cannot exist ';'
        tb_assertf(!tb_strchr(value, ';'), "invalid value: %s", value);

        // append value
        tb_string_cstrcat(&values, value);
        tb_string_chrcat(&values, ';');
    }

    // strip the last ';'
    tb_string_strip(&values, tb_string_size(&values) - 1);

    // save variable
    tb_bool_t ok = tb_environment_set_impl(name, tb_string_cstr(&values));

    // exit values string
    tb_string_exit(&values);

    // ok?
    return ok;
}
tb_size_t tb_environment_first(tb_char_t const* name, tb_char_t* value, tb_size_t maxn)
{
    // check
    tb_assert_and_check_return_val(name && value && maxn, 0);

    // get it
    tb_size_t   size = 0;
    tb_char_t*  data = tb_environment_get_impl(name, &size);
コード例 #23
0
ファイル: spider.c プロジェクト: ahnan4arch/tbox
static tb_size_t tb_demo_spider_parser_get_url(tb_xml_reader_ref_t reader, tb_url_ref_t url)
{
    // check
    tb_assert_and_check_return_val(reader && url, tb_false);

    // done
    tb_size_t ok = 0;
    tb_size_t event = TB_XML_READER_EVENT_NONE;
    while (!ok && (event = tb_xml_reader_next(reader)))
    {
        switch (event)
        {
        case TB_XML_READER_EVENT_ELEMENT_EMPTY: 
        case TB_XML_READER_EVENT_ELEMENT_BEG: 
            {
                // the element name
                tb_char_t const* name = tb_xml_reader_element(reader);
                tb_check_break(name);

                // <a href="" />? 
                // <link href="" /> 
                // <img src="" />? 
                // <script src="" />? 
                // <source src="" />? 
                // <frame src="" />? 
                if (    !tb_stricmp(name, "a")
                    ||  !tb_stricmp(name, "link")
                    ||  !tb_stricmp(name, "img")
                    ||  !tb_stricmp(name, "frame")
                    ||  !tb_stricmp(name, "source"))
                {
                    // walk attributes
                    tb_xml_node_ref_t attr = (tb_xml_node_ref_t)tb_xml_reader_attributes(reader); 
                    for (; attr; attr = attr->next)
                    {
                        // href or src?
                        if (    tb_string_size(&attr->data)
                            &&  (   !tb_string_cstricmp(&attr->name, "href")
                                ||  !tb_string_cstricmp(&attr->name, "src")))
                        {
                            // the url protocol
                            tb_size_t protocol = tb_url_protocol_probe(tb_string_cstr(&attr->data));

                            // http?
                            if(protocol == TB_URL_PROTOCOL_HTTP)
                            {
                                // save url
                                ok = tb_url_set(url, tb_string_cstr(&attr->data));
                            }
                            // file?
                            else if (protocol == TB_URL_PROTOCOL_FILE)
                            {
                                // save path
                                tb_url_path_set(url, tb_string_cstr(&attr->data));

                                // ok
                                ok = tb_true;
                            }
                        }
                    }
                }
            }
            break;
        default:
            break;
        }
    }

    // ok?
    return ok;
}
コード例 #24
0
ファイル: string.c プロジェクト: richwu/tbox
tb_long_t tb_string_strimp(tb_string_ref_t string, tb_string_ref_t s)
{
    // check
    tb_assert_and_check_return_val(string && s, 0);
    return tb_string_cstrnicmp(string, tb_string_cstr(s), tb_string_size(s) + 1);
}
コード例 #25
0
ファイル: reader.c プロジェクト: 1060460048/tbox
tb_xml_node_ref_t tb_xml_reader_load(tb_xml_reader_ref_t reader)
{
    // check
    tb_assert_and_check_return_val(reader, tb_null);

    // done
    tb_bool_t           ok = tb_true;
    tb_xml_node_ref_t   node = tb_null;
    tb_size_t           event = TB_XML_READER_EVENT_NONE;
    while (ok && (event = tb_xml_reader_next(reader)))
    {
        // init document node
        if (!node)
        {
            node = tb_xml_node_init_document(tb_xml_reader_version(reader), tb_xml_reader_charset(reader));
            tb_assert_and_check_break_state(node && !node->parent, ok, tb_false);
        }

        switch (event)
        {
        case TB_XML_READER_EVENT_DOCUMENT:
            break;
        case TB_XML_READER_EVENT_DOCUMENT_TYPE:
            {
                // init
                tb_xml_node_ref_t doctype = tb_xml_node_init_document_type(tb_xml_reader_doctype(reader));
                tb_assert_and_check_break_state(doctype, ok, tb_false);
                
                // append
                tb_xml_node_append_ctail(node, doctype); 
                tb_assert_and_check_break_state(doctype->parent, ok, tb_false);
            }
            break;
        case TB_XML_READER_EVENT_ELEMENT_EMPTY: 
            {
                // init
                tb_xml_node_ref_t element = tb_xml_node_init_element(tb_xml_reader_element(reader));
                tb_assert_and_check_break_state(element, ok, tb_false);
                
                // attributes
                tb_xml_node_ref_t attr = tb_xml_reader_attributes(reader);
                for (; attr; attr = attr->next)
                    tb_xml_node_append_atail(element, tb_xml_node_init_attribute(tb_string_cstr(&attr->name), tb_string_cstr(&attr->data)));
                
                // append
                tb_xml_node_append_ctail(node, element); 
                tb_assert_and_check_break_state(element->parent, ok, tb_false);
            }
            break;
        case TB_XML_READER_EVENT_ELEMENT_BEG: 
            {
                // init
                tb_xml_node_ref_t element = tb_xml_node_init_element(tb_xml_reader_element(reader));
                tb_assert_and_check_break_state(element, ok, tb_false);

                // attributes
                tb_xml_node_ref_t attr = tb_xml_reader_attributes(reader);
                for (; attr; attr = attr->next)
                    tb_xml_node_append_atail(element, tb_xml_node_init_attribute(tb_string_cstr(&attr->name), tb_string_cstr(&attr->data)));
                
                // append
                tb_xml_node_append_ctail(node, element); 
                tb_assert_and_check_break_state(element->parent, ok, tb_false);

                // enter
                node = element;
            }
            break;
        case TB_XML_READER_EVENT_ELEMENT_END: 
            {
                // check
                tb_assert_and_check_break_state(node, ok, tb_false);

                // the parent node
                node = node->parent;
            }
            break;
        case TB_XML_READER_EVENT_TEXT: 
            {
                // init
                tb_xml_node_ref_t text = tb_xml_node_init_text(tb_xml_reader_text(reader));
                tb_assert_and_check_break_state(text, ok, tb_false);
                
                // append
                tb_xml_node_append_ctail(node, text); 
                tb_assert_and_check_break_state(text->parent, ok, tb_false);
            }
            break;
        case TB_XML_READER_EVENT_CDATA: 
            {
                // init
                tb_xml_node_ref_t cdata = tb_xml_node_init_cdata(tb_xml_reader_cdata(reader));
                tb_assert_and_check_break_state(cdata, ok, tb_false);
                
                // append
                tb_xml_node_append_ctail(node, cdata); 
                tb_assert_and_check_break_state(cdata->parent, ok, tb_false);

            }
            break;
        case TB_XML_READER_EVENT_COMMENT: 
            {
                // init
                tb_xml_node_ref_t comment = tb_xml_node_init_comment(tb_xml_reader_comment(reader));
                tb_assert_and_check_break_state(comment, ok, tb_false);
                
                // append
                tb_xml_node_append_ctail(node, comment); 
                tb_assert_and_check_break_state(comment->parent, ok, tb_false);
            }
            break;
        default:
            break;
        }
    }

    // failed?
    if (!ok)
    {
        // exit it
        if (node) tb_xml_node_exit(node);
        node = tb_null;
    }

    // ok
    return node;
}
コード例 #26
0
ファイル: string.c プロジェクト: richwu/tbox
tb_long_t tb_string_strirstr(tb_string_ref_t string, tb_size_t p, tb_string_ref_t s)
{
    return tb_string_cstrirstr(string, p, tb_string_cstr(s));
}
コード例 #27
0
ファイル: stream.c プロジェクト: AlexShiLucky/tbox
/* //////////////////////////////////////////////////////////////////////////////////////
 * main
 */ 
tb_int_t tb_demo_stream_main(tb_int_t argc, tb_char_t** argv)
{
    // done
    tb_option_ref_t     option = tb_null;
    tb_stream_ref_t     istream = tb_null;
    tb_stream_ref_t     ostream = tb_null;
    tb_stream_ref_t     pstream = tb_null;
    do
    {
        // init option
        option = tb_option_init("stream", "the stream demo", g_options);
        tb_assert_and_check_break(option);
    
        // done option
        if (tb_option_done(option, argc - 1, &argv[1]))
        {
            // debug & verbose
            tb_bool_t debug = tb_option_find(option, "debug");
            tb_bool_t verbose = tb_option_find(option, "no-verbose")? tb_false : tb_true;
        
            // done url
            if (tb_option_find(option, "url")) 
            {
                // init istream
                istream = tb_stream_init_from_url(tb_option_item_cstr(option, "url"));
                tb_assert_and_check_break(istream);
    
                // ctrl http
                if (tb_stream_type(istream) == TB_STREAM_TYPE_HTTP) 
                {
                    // enable gzip?
                    if (tb_option_find(option, "gzip"))
                    {
                        // auto unzip
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break;

                        // need gzip
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break;
                    }

                    // enable debug?
                    if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, debug? tb_demo_stream_head_func : tb_null)) break;

                    // custem header?
                    if (tb_option_find(option, "header"))
                    {
                        // init
                        tb_string_t key;
                        tb_string_t val;
                        tb_string_init(&key);
                        tb_string_init(&val);

                        // done
                        tb_bool_t           k = tb_true;
                        tb_char_t const*    p = tb_option_item_cstr(option, "header");
                        while (*p)
                        {
                            // is key?
                            if (k)
                            {
                                if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++);
                                else if (*p == ':') 
                                {
                                    // skip ':'
                                    p++;

                                    // skip space
                                    while (*p && tb_isspace(*p)) p++;

                                    // is val now
                                    k = tb_false;
                                }
                                else p++;
                            }
                            // is val?
                            else
                            {
                                if (*p != ';') tb_string_chrcat(&val, *p++);
                                else
                                {
                                    // skip ';'
                                    p++;

                                    // skip space
                                    while (*p && tb_isspace(*p)) p++;

                                    // set header
                                    if (tb_string_size(&key) && tb_string_size(&val))
                                    {
                                        if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
                                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
                                    }

                                    // is key now
                                    k = tb_true;

                                    // clear key & val
                                    tb_string_clear(&key);
                                    tb_string_clear(&val);
                                }
                            }
                        }

                        // set header
                        if (tb_string_size(&key) && tb_string_size(&val))
                        {
                            if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
                            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
                        }

                        // exit 
                        tb_string_exit(&key);
                        tb_string_exit(&val);
                    }

                    // keep alive?
                    if (tb_option_find(option, "keep-alive"))
                    {
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break;
                    }

                    // post-data?
                    if (tb_option_find(option, "post-data"))
                    {
                        tb_char_t const*    post_data = tb_option_item_cstr(option, "post-data");
                        tb_hize_t           post_size = tb_strlen(post_data);
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break;
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
                        if (debug) tb_printf("post: %llu\n", post_size);
                    }
                    // post-file?
                    else if (tb_option_find(option, "post-file"))
                    {
                        tb_char_t const* url = tb_option_item_cstr(option, "post-file");
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break;
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
                        if (debug) tb_printf("post: %s\n", url);
                    }
                }

                // set range
                if (tb_option_find(option, "range"))
                {
                    tb_char_t const* p = tb_option_item_cstr(option, "range");
                    if (p)
                    {
                        // the bof
                        tb_hize_t eof = 0;
                        tb_hize_t bof = tb_atoll(p);
                        while (*p && tb_isdigit(*p)) p++;
                        if (*p == '-')
                        {
                            p++;
                            eof = tb_atoll(p);
                        }
                        if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break;
                    }
                }

                // set timeout
                if (tb_option_find(option, "timeout"))
                {
                    tb_size_t timeout = tb_option_item_uint32(option, "timeout");
                    if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_SET_TIMEOUT, timeout)) break;
                }

                // print verbose info
                if (verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(option, "url"));

                // open istream
                if (!tb_stream_open(istream)) 
                {
                    // print verbose info
                    if (verbose) tb_printf("open: %s\n", tb_state_cstr(tb_stream_state(istream)));
                    break;
                }

                // print verbose info
                if (verbose) tb_printf("open: ok\n");

                // init ostream
                if (tb_option_find(option, "more0"))
                {
                    // the path
                    tb_char_t const* path = tb_option_item_cstr(option, "more0");

                    // init
                    ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);

                    // print verbose info
                    if (verbose) tb_printf("save: %s\n", path);
                }
                else 
                {
                    // the name
                    tb_char_t const* name = tb_strrchr(tb_option_item_cstr(option, "url"), '/');
                    if (!name) name = tb_strrchr(tb_option_item_cstr(option, "url"), '\\');
                    if (!name) name = "/stream.file";

                    // the path
                    tb_char_t path[TB_PATH_MAXN] = {0};
                    if (tb_directory_current(path, TB_PATH_MAXN))
                        tb_strcat(path, name);
                    else break;

                    // init file
                    ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);

                    // print verbose info
                    if (verbose) tb_printf("save: %s\n", path);
                }
                tb_assert_and_check_break(ostream);

                // the limit rate
                tb_size_t limitrate = 0;
                if (tb_option_find(option, "limitrate"))
                    limitrate = tb_option_item_uint32(option, "limitrate");

                // save it
                tb_hong_t           save = 0;
                tb_demo_context_t   context = {0}; 
                context.verbose     = verbose;
                if ((save = tb_transfer_done(istream, ostream, limitrate, tb_demo_stream_save_func, &context)) < 0) break;
            }
            else tb_option_help(option);
        }
        else tb_option_help(option);

    } while (0);

    // exit pstream
    if (pstream) tb_stream_exit(pstream);
    pstream = tb_null;

    // exit istream
    if (istream) tb_stream_exit(istream);
    istream = tb_null;

    // exit ostream
    if (ostream) tb_stream_exit(ostream);
    ostream = tb_null;

    // exit option
    if (option) tb_option_exit(option);
    option = tb_null;

    return 0;
}
コード例 #28
0
ファイル: string.c プロジェクト: richwu/tbox
tb_long_t tb_string_cstrnicmp(tb_string_ref_t string, tb_char_t const* s, tb_size_t n)
{
    // check
    tb_assert_and_check_return_val(string && s, 0);
    return tb_strnicmp(tb_string_cstr(string), s, n);
}
コード例 #29
0
ファイル: json.c プロジェクト: luxuan/tbox
static tb_object_ref_t tb_object_json_reader_func_string(tb_object_json_reader_t* reader, tb_char_t type)
{
    // check
    tb_assert_and_check_return_val(reader && reader->stream && (type == '\"' || type == '\''), tb_null);

    // init data
    tb_string_t data;
    if (!tb_string_init(&data)) return tb_null;

    // walk
    tb_char_t ch;
    while (tb_stream_left(reader->stream)) 
    {
        // read one character
        ch = tb_stream_bread_s8(reader->stream);

        // end?
        if (ch == '\"' || ch == '\'') break;
        // the escaped character?
        else if (ch == '\\')
        {
            // read one character
            ch = tb_stream_bread_s8(reader->stream);
            // unicode?
            if (ch == 'u')
            {
#ifdef TB_CONFIG_MODULE_HAVE_CHARSET
                // the unicode string
                tb_char_t unicode_str[5];
                unicode_str[0] = tb_stream_bread_s8(reader->stream);
                unicode_str[1] = tb_stream_bread_s8(reader->stream);
                unicode_str[2] = tb_stream_bread_s8(reader->stream);
                unicode_str[3] = tb_stream_bread_s8(reader->stream);
                unicode_str[4] = '\0';

                // the unicode value
                tb_uint16_t unicode_val = tb_s16toi32(unicode_str);

                // the utf8 stream
                tb_char_t           utf8_data[16] = {0};
                tb_static_stream_t  utf8_stream;
                tb_static_stream_init(&utf8_stream, (tb_byte_t*)utf8_data, sizeof(utf8_data));

                // the unicode stream
                tb_static_stream_t  unicode_stream = {0};
                tb_static_stream_init(&unicode_stream, (tb_byte_t*)&unicode_val, 2);

                // unicode to utf8
                tb_long_t utf8_size = tb_charset_conv_bst(TB_CHARSET_TYPE_UCS2 | TB_CHARSET_TYPE_NE, TB_CHARSET_TYPE_UTF8, &unicode_stream, &utf8_stream);
                if (utf8_size > 0) tb_string_cstrncat(&data, utf8_data, utf8_size);
#else
                // trace
                tb_trace1_e("unicode type is not supported, please enable charset module config if you want to use it!");

                // only append it
                tb_string_chrcat(&data, ch);
#endif
            }
            // append escaped character
            else tb_string_chrcat(&data, ch);
        }
        // append character
        else tb_string_chrcat(&data, ch);
    }

    // init string
    tb_object_ref_t string = tb_object_string_init_from_cstr(tb_string_cstr(&data));

    // trace
    tb_trace_d("string: %s", tb_string_cstr(&data));

    // exit data
    tb_string_exit(&data);

    // ok?
    return string;
}
コード例 #30
0
ファイル: option.c プロジェクト: waruqi/tbox
tb_void_t tb_option_help(tb_option_ref_t option)
{
    // check
    tb_option_impl_t* impl = (tb_option_impl_t*)option;
    tb_assert_and_check_return(impl && impl->opts);

    // dump usage head
    tb_printf("======================================================================\n");
    tb_printf("[usage]: %s", impl->name);

    // dump usage item
    tb_bool_t               bopt = tb_false;
    tb_option_item_t const* item = impl->opts;
    while (item)
    {
        // dump options
        if (bopt && item->mode != TB_OPTION_MODE_KEY && item->mode != TB_OPTION_MODE_KEY_VAL)
        {
            tb_printf(" [options]");
            bopt = tb_false;
        }

        // dump item
        switch (item->mode)
        {
        case TB_OPTION_MODE_KEY:
        case TB_OPTION_MODE_KEY_VAL:
            {
                bopt = tb_true;
                item++;
            }
            break;
        case TB_OPTION_MODE_VAL:
            {
                tb_printf(" %s", item->lname);
                item++;
            }
            break;
        case TB_OPTION_MODE_MORE:
            tb_printf(" ...");
        case TB_OPTION_MODE_END:
        default:
            item = tb_null;
            break;
        }
    }

    // dump usage tail
    tb_printf("\n\n");

    // dump help
    if (tb_string_size(&impl->help)) 
        tb_printf("[help]:  %s\n\n", tb_string_cstr(&impl->help));

    // dump options head
    tb_printf("[options]: \n");
    for (item = impl->opts; item; )
    {
        // dump item
        tb_size_t spaces = 32;
        switch (item->mode)
        {
        case TB_OPTION_MODE_KEY:
        case TB_OPTION_MODE_KEY_VAL:
            {
                // dump spaces
                tb_printf("  "); spaces -= 3;

                // has short name?
                if (tb_isalpha(item->sname))
                {
                    // dump short name
                    tb_printf("-%c", item->sname);
                    spaces -= 2;

                    // dump long name
                    if (item->lname) 
                    {
                        tb_printf(", --%s", item->lname);
                        spaces -= 4;
                        if (tb_strlen(item->lname) <= spaces) spaces -= tb_strlen(item->lname);
                    }
                }
                // dump long name
                else if (item->lname) 
                {
                    tb_printf("    --%s", item->lname);
                    spaces -= 6;
                    if (tb_strlen(item->lname) <= spaces) spaces -= tb_strlen(item->lname);
                }

                // dump value
                if (item->mode == TB_OPTION_MODE_KEY_VAL)
                {
                    switch (item->type)
                    {
                    case TB_OPTION_TYPE_BOOL:
                        tb_printf("=BOOL"); spaces -= 5;
                        break;
                    case TB_OPTION_TYPE_CSTR:
                        tb_printf("=STRING"); spaces -= 7;
                        break;
                    case TB_OPTION_TYPE_INTEGER:
                        tb_printf("=INTEGER"); spaces -= 8;
                        break;
                    case TB_OPTION_TYPE_FLOAT:
                        tb_printf("=FLOAT"); spaces -= 6;
                        break;
                    default:
                        break;
                    }
                }

                // dump help
                if (item->help) 
                {
                    tb_char_t           line[8192] = {0};
                    tb_char_t const*    pb = item->help;
                    tb_char_t*          qb = line;
                    tb_char_t*          qe = line + 8192;
                    while (qb < qe)
                    {
                        if (*pb != '\n' && *pb) *qb++ = *pb++;
                        else
                        {
                            // strip line and next
                            *qb = '\0'; qb = line;

                            // dump spaces
                            while (spaces--) tb_printf(" ");

                            // dump help line
                            tb_printf("%s", line);

                            // reset spaces
                            spaces = 32;

                            // next or end?
                            if (*pb) 
                            {
                                // dump new line
                                tb_printf("\n");
                                pb++;
                            }
                            else break;
                        }
                    }
                }

                // dump newline
                tb_printf("\n");

                // next
                item++;
            }
            break;
        case TB_OPTION_MODE_VAL:
            item++;
            break;
        case TB_OPTION_MODE_MORE:
        case TB_OPTION_MODE_END:
        default:
            item = tb_null;
            break;
        }
    }

    // dump options tail
    tb_printf("\n\n");

    // dump values head
    tb_printf("[values]: \n");
    for (item = impl->opts; item; )
    {
        // dump item
        tb_size_t spaces = 32;
        switch (item->mode)
        {
        case TB_OPTION_MODE_KEY:
        case TB_OPTION_MODE_KEY_VAL:
            item++;
            break;
        case TB_OPTION_MODE_VAL:
            {
                // dump spaces
                tb_printf("  "); spaces -= 3;

                // dump long name
                if (item->lname) 
                {
                    tb_printf("%s", item->lname);
                    if (tb_strlen(item->lname) <= spaces) spaces -= tb_strlen(item->lname);
                }

                // dump help
                if (item->help) 
                {
                    tb_char_t           line[8192] = {0};
                    tb_char_t const*    pb = item->help;
                    tb_char_t*          qb = line;
                    tb_char_t*          qe = line + 8192;
                    while (qb < qe)
                    {
                        if (*pb != '\n' && *pb) *qb++ = *pb++;
                        else
                        {
                            // strip line and next
                            *qb = '\0'; qb = line;

                            // dump spaces
                            while (spaces--) tb_printf(" ");

                            // dump help line
                            tb_printf("%s", line);

                            // reset spaces
                            spaces = 32;

                            // next or end?
                            if (*pb) 
                            {
                                // dump new line
                                tb_printf("\n");
                                pb++;
                            }
                            else break;
                        }
                    }
                }

                // dump newline
                tb_printf("\n");

                // next
                item++;
            }
            break;
        case TB_OPTION_MODE_MORE:
            tb_printf("  ...\n");
        case TB_OPTION_MODE_END:
        default:
            item = tb_null;
            break;
        }
    }

    // dump values tail
    tb_printf("\n");
}