tb_char_t const* tb_string_cstrncat(tb_string_ref_t string, tb_char_t const* s, tb_size_t n) { // check tb_assert_and_check_return_val(string && s && n, tb_null); // done tb_char_t* p = (tb_char_t*)tb_buffer_memncpyp(string, tb_string_size(string), (tb_byte_t const*)s, n + 1); if (p) p[tb_string_size(string)] = '\0'; return p; }
tb_char_t const* tb_string_chrncat(tb_string_ref_t string, tb_char_t c, tb_size_t n) { // check tb_assert_and_check_return_val(string, tb_null); // done tb_char_t* p = (tb_char_t*)tb_buffer_memnsetp(string, tb_string_size(string), c, n + 1); if (p) p[tb_string_size(string)] = '\0'; return p; }
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); }
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)); }
tb_char_t const* tb_string_cstr(tb_string_ref_t string) { // check tb_assert_and_check_return_val(string, tb_null); // the cstr return tb_string_size(string)? (tb_char_t const*)tb_buffer_data((tb_buffer_ref_t)string) : tb_null; }
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; }
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]; }
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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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); }
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; } }
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; }
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; }
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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
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; }
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); }
/* chunked_data * * head data tail * ea5\r\n ..........\r\n e65\r\n..............\r\n 0\r\n\r\n * ---------------------- ------------------------- --------- * chunk0 chunk1 end */ static tb_long_t tb_filter_chunked_spak(tb_filter_t* filter, tb_static_stream_ref_t istream, tb_static_stream_ref_t ostream, tb_long_t sync) { // check tb_filter_chunked_t* cfilter = tb_filter_chunked_cast(filter); tb_assert_and_check_return_val(cfilter && istream && ostream, -1); tb_assert_and_check_return_val(tb_static_stream_valid(istream) && tb_static_stream_valid(ostream), -1); // the idata tb_byte_t const* ip = tb_static_stream_pos(istream); tb_byte_t const* ie = tb_static_stream_end(istream); // trace tb_trace_d("[%p]: isize: %lu, beof: %d", cfilter, tb_static_stream_size(istream), filter->beof); // find the eof: '\r\n 0\r\n\r\n' if ( !filter->beof && ip + 6 < ie && ie[-7] == '\r' && ie[-6] == '\n' && ie[-5] == '0' && ie[-4] == '\r' && ie[-3] == '\n' && ie[-2] == '\r' && ie[-1] == '\n') { // is eof filter->beof = tb_true; } // the odata tb_byte_t* op = (tb_byte_t*)tb_static_stream_pos(ostream); tb_byte_t* oe = (tb_byte_t*)tb_static_stream_end(ostream); tb_byte_t* ob = op; // parse chunked head and chunked tail if (!cfilter->size || cfilter->read >= cfilter->size) { // walk while (ip < ie) { // the charactor tb_char_t ch = *ip++; // trace tb_trace_d("[%p]: character: %x", cfilter, ch); // check tb_assert_and_check_return_val(ch, -1); // append char to line if (ch != '\n') tb_string_chrcat(&cfilter->line, ch); // is line end? else { // check tb_char_t const* pb = tb_string_cstr(&cfilter->line); tb_size_t pn = tb_string_size(&cfilter->line); tb_assert_and_check_return_val(pb, -1); // trace tb_trace_d("[%p]: line: %s", cfilter, tb_string_cstr(&cfilter->line)); // strip '\r' if exists if (pb[pn - 1] == '\r') tb_string_strip(&cfilter->line, pn - 1); // is chunked tail? only "\r\n" if (!tb_string_size(&cfilter->line)) { // reset size cfilter->read = 0; cfilter->size = 0; // trace tb_trace_d("[%p]: tail", cfilter); // continue continue ; } // is chunked head? parse size else { // parse size cfilter->size = tb_s16tou32(pb); // trace tb_trace_d("[%p]: size: %lu", cfilter, cfilter->size); // clear data tb_string_clear(&cfilter->line); // is eof? "0\r\n\r\n" if (!cfilter->size) { // trace tb_trace_d("[%p]: eof", cfilter); // is eof filter->beof = tb_true; // continue to spak the end data continue ; } // ok break; } } } } // check tb_assert_and_check_return_val(cfilter->read <= cfilter->size, -1); // read chunked data tb_size_t size = tb_min3(ie - ip, oe - op, cfilter->size - cfilter->read); if (size) { // copy data tb_memcpy((tb_byte_t*)op, ip, size); ip += size; op += size; // update read cfilter->read += size; } // update stream tb_static_stream_goto(istream, (tb_byte_t*)ip); tb_static_stream_goto(ostream, (tb_byte_t*)op); // trace tb_trace_d("[%p]: read: %lu, size: %lu, beof: %u, ileft: %lu", cfilter, cfilter->read, cfilter->size, filter->beof, tb_static_stream_left(istream)); // ok return (op - ob); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
tb_string_t values; if (!tb_string_init(&values)) return tb_false; // 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);
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
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; }
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"); }
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); }
tb_size_t tb_xml_reader_next(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->rstream, TB_XML_READER_EVENT_NONE); // reset event impl->event = TB_XML_READER_EVENT_NONE; // next while (!impl->event) { // peek character tb_char_t* pc = tb_null; if (!tb_stream_need(impl->rstream, (tb_byte_t**)&pc, 1) || !pc) break; // is element? if (*pc == '<') { // parse element: <...> tb_char_t const* element = tb_xml_reader_element_parse(impl); tb_assert_and_check_break(element); // is document begin: <?xml version="..." charset=".." ?> tb_size_t size = tb_string_size(&impl->element); if (size > 4 && !tb_strnicmp(element, "?xml", 4)) { // update event impl->event = TB_XML_READER_EVENT_DOCUMENT; // update version & charset tb_xml_node_ref_t attr = (tb_xml_node_ref_t)tb_xml_reader_attributes(reader); for (; attr; attr = attr->next) { if (!tb_string_cstricmp(&attr->name, "version")) tb_string_strcpy(&impl->version, &attr->data); if (!tb_string_cstricmp(&attr->name, "encoding")) tb_string_strcpy(&impl->charset, &attr->data); } // transform stream => utf-8 if (tb_string_cstricmp(&impl->charset, "utf-8") && tb_string_cstricmp(&impl->charset, "utf8")) { // charset tb_size_t charset = TB_CHARSET_TYPE_UTF8; if (!tb_string_cstricmp(&impl->charset, "gb2312") || !tb_string_cstricmp(&impl->charset, "gbk")) charset = TB_CHARSET_TYPE_GB2312; else tb_trace_e("the charset: %s is not supported", tb_string_cstr(&impl->charset)); // init transform stream if (charset != TB_CHARSET_TYPE_UTF8) { #ifdef TB_CONFIG_MODULE_HAVE_CHARSET // init the filter stream if (!impl->fstream) impl->fstream = tb_stream_init_filter_from_charset(impl->istream, charset, TB_CHARSET_TYPE_UTF8); else { // ctrl stream if (!tb_stream_ctrl(impl->fstream, TB_STREAM_CTRL_FLTR_SET_STREAM, impl->istream)) break; // the filter tb_stream_filter_ref_t filter = tb_null; if (!tb_stream_ctrl(impl->fstream, TB_STREAM_CTRL_FLTR_GET_FILTER, &filter)) break; tb_assert_and_check_break(filter); // ctrl filter if (!tb_stream_filter_ctrl(filter, TB_STREAM_FILTER_CTRL_CHARSET_SET_FTYPE, charset)) break; } // open the filter stream if (impl->fstream && tb_stream_open(impl->fstream)) impl->rstream = impl->fstream; tb_string_cstrcpy(&impl->charset, "utf-8"); #else // trace tb_trace_e("unicode type is not supported, please enable charset module config if you want to use it!"); #endif } } } // is document type: <!DOCTYPE ... > else if (size > 8 && !tb_strnicmp(element, "!DOCTYPE", 8)) { // update event impl->event = TB_XML_READER_EVENT_DOCUMENT_TYPE; } // is element end: </name> else if (size > 1 && element[0] == '/') { // check tb_check_break(impl->level); // update event impl->event = TB_XML_READER_EVENT_ELEMENT_END; // leave impl->level--; } // is comment: <!-- text --> else if (size >= 3 && !tb_strncmp(element, "!--", 3)) { // no comment end? if (element[size - 2] != '-' || element[size - 1] != '-') { // patch '>' tb_string_chrcat(&impl->element, '>'); // seek to comment end tb_char_t ch = '\0'; tb_int_t n = 0; while ((ch = tb_stream_bread_s8(impl->rstream))) { // --> if (n == 2 && ch == '>') break; else { // append it tb_string_chrcat(&impl->element, ch); if (ch == '-') n++; else n = 0; } } // update event if (ch != '\0') impl->event = TB_XML_READER_EVENT_COMMENT; } else impl->event = TB_XML_READER_EVENT_COMMENT; } // is cdata: <![CDATA[ text ]]> else if (size >= 8 && !tb_strnicmp(element, "![CDATA[", 8)) { if (element[size - 2] != ']' || element[size - 1] != ']') { // patch '>' tb_string_chrcat(&impl->element, '>'); // seek to cdata end tb_char_t ch = '\0'; tb_int_t n = 0; while ((ch = tb_stream_bread_s8(impl->rstream))) { // ]]> if (n == 2 && ch == '>') break; else { // append it tb_string_chrcat(&impl->element, ch); if (ch == ']') n++; else n = 0; } } // update event if (ch != '\0') impl->event = TB_XML_READER_EVENT_CDATA; } else impl->event = TB_XML_READER_EVENT_CDATA; } // is empty element: <name/> else if (size > 1 && element[size - 1] == '/') { // update event impl->event = TB_XML_READER_EVENT_ELEMENT_EMPTY; } // is element begin: <name> else { // update event impl->event = TB_XML_READER_EVENT_ELEMENT_BEG; // enter impl->level++; } // trace // tb_trace_d("<%s>", element); } // is text: <> text </> else if (*pc) { // parse text: <> ... <> tb_char_t const* text = tb_xml_reader_text_parse(impl); if (text && tb_string_cstrcmp(&impl->text, "\r\n") && tb_string_cstrcmp(&impl->text, "\n")) impl->event = TB_XML_READER_EVENT_TEXT; // trace // tb_trace_d("%s", text); } else { // skip the invalid character if (!tb_stream_skip(impl->rstream, 1)) break; } } // ok? return impl->event; }