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_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 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); }
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_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); }
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); }
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); }
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); }
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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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_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(""); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
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; }
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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
// 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);
// 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);
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_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_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; }
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)); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
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); }
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; }
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"); }