tb_version_t const* tb_version() { // init version tag for binary search static __tb_volatile__ tb_char_t const* s_vtag = "[tbox]: [vtag]: " TB_VERSION_STRING; tb_used(s_vtag); // init version static tb_version_t s_version = {0}; if (!s_version.major) { s_version.major = TB_VERSION_MAJOR; s_version.minor = TB_VERSION_MINOR; s_version.alter = TB_VERSION_ALTER; s_version.build = (tb_hize_t)tb_atoll(TB_VERSION_BUILD_STRING); } return &s_version; }
tb_bool_t tb_option_done(tb_option_ref_t option, tb_size_t argc, tb_char_t** argv) { // check tb_option_impl_t* impl = (tb_option_impl_t*)option; tb_assert_and_check_return_val(impl && impl->list && impl->opts, tb_false); // walk arguments tb_size_t i = 0; tb_size_t more = 0; tb_option_item_t const* item = impl->opts; tb_option_item_t const* last = tb_null; for (i = 0; i < argc; i++) { // the argument tb_char_t* p = argv[i]; tb_char_t* e = p + tb_strlen(p); tb_assert_and_check_return_val(p && p < e, tb_false); // is long key? if (p + 2 < e && p[0] == '-' && p[1] == '-' && tb_isalpha(p[2])) { // the key tb_char_t key[512] = {0}; { tb_char_t* k = key; tb_char_t* e = key + 511; for (p += 2; *p && *p != '=' && k < e; p++, k++) *k = *p; } // the val tb_char_t* val = (*p == '=')? (p + 1) : tb_null; // trace tb_trace_d("[lname]: %s => %s", key, val); // find the item tb_option_item_t const* find = tb_option_item_find(impl->opts, key, '\0'); if (find) { // check key & val if (!val == !(find->mode == TB_OPTION_MODE_KEY_VAL)) { // has value? tb_object_ref_t object = tb_null; if (val) { // init the value object switch (find->type) { case TB_OPTION_TYPE_CSTR: object = tb_oc_string_init_from_cstr(val); break; case TB_OPTION_TYPE_INTEGER: tb_assert_and_check_return_val(tb_option_is_integer(val), tb_false); object = tb_oc_number_init_from_sint64(tb_atoll(val)); break; case TB_OPTION_TYPE_BOOL: tb_assert_and_check_return_val(tb_option_is_bool(val), tb_false); object = tb_oc_boolean_init(!tb_stricmp(val, "y")? tb_true : tb_false); break; #ifdef TB_CONFIG_TYPE_HAVE_FLOAT case TB_OPTION_TYPE_FLOAT: tb_assert_and_check_return_val(tb_option_is_float(val), tb_false); object = tb_oc_number_init_from_double(tb_atof(val)); break; #endif default: tb_assert_and_check_return_val(0, tb_false); break; } } else { // check tb_assert_and_check_return_val(find->type == TB_OPTION_TYPE_BOOL, tb_false); // key => true object = tb_oc_boolean_init(tb_true); } // add the value object if (object) { tb_oc_dictionary_insert(impl->list, key, object); if (tb_isalpha(find->sname)) { tb_char_t ch[2] = {0}; ch[0] = find->sname; tb_oc_dictionary_insert(impl->list, ch, object); tb_object_retain(object); } } } else if (val) { // print tb_trace_e("%s: unrecognized option value '--%s=%s'", impl->name, key, val); // next continue ; } else { // print tb_trace_e("%s: no option value '--%s='", impl->name, key); // next continue ; } } else { // print tb_trace_e("%s: unrecognized option '--%s'", impl->name, key); // next continue ; } } // is short key? else if (p + 1 < e && p[0] == '-' && tb_isalpha(p[1])) { // the key tb_char_t key[512] = {0}; { tb_char_t* k = key; tb_char_t* e = key + 511; for (p += 1; *p && *p != '=' && k < e; p++, k++) *k = *p; } // the val tb_char_t const* val = (*p == '=')? (p + 1) : tb_null; // trace tb_trace_d("[sname]: %s => %s", key, val); // is short name? if (tb_strlen(key) != 1) { // print tb_trace_e("%s: unrecognized option '-%s'", impl->name, key); // next continue ; } // find the item tb_option_item_t const* find = tb_option_item_find(impl->opts, tb_null, key[0]); if (find) { // check key & val if (!val == !(find->mode == TB_OPTION_MODE_KEY_VAL)) { // has value? tb_object_ref_t object = tb_null; if (val) { // add value switch (find->type) { case TB_OPTION_TYPE_CSTR: object = tb_oc_string_init_from_cstr(val); break; case TB_OPTION_TYPE_INTEGER: tb_assert_and_check_return_val(tb_option_is_integer(val), tb_false); object = tb_oc_number_init_from_sint64(tb_atoll(val)); break; case TB_OPTION_TYPE_BOOL: tb_assert_and_check_return_val(tb_option_is_bool(val), tb_false); object = tb_oc_boolean_init(!tb_stricmp(val, "y")? tb_true : tb_false); break; #ifdef TB_CONFIG_TYPE_HAVE_FLOAT case TB_OPTION_TYPE_FLOAT: tb_assert_and_check_return_val(tb_option_is_float(val), tb_false); object = tb_oc_number_init_from_double(tb_atof(val)); break; #endif default: tb_assert_and_check_return_val(0, tb_false); break; } } else { // check tb_assert_and_check_return_val(find->type == TB_OPTION_TYPE_BOOL, tb_false); // key => true object = tb_oc_boolean_init(tb_true); } // add the value object if (object) { tb_oc_dictionary_insert(impl->list, key, object); if (find->lname) { tb_oc_dictionary_insert(impl->list, find->lname, object); tb_object_retain(object); } } } else if (val) { // print tb_trace_e("%s: unrecognized option value '--%s=%s'", impl->name, key, val); // next continue ; } else { // print tb_trace_e("%s: no option value '--%s='", impl->name, key); // next continue ; } } else { // print tb_trace_e("%s: unrecognized option '-%s'", impl->name, key); // next continue ; } } // is value? else { // trace tb_trace_d("[val]: %s", p); // find the value item while (item && item->mode != TB_OPTION_MODE_VAL && item->mode != TB_OPTION_MODE_END && item->mode != TB_OPTION_MODE_MORE) item++; // has value item? if (item->mode == TB_OPTION_MODE_VAL) { // check tb_assert_and_check_return_val(item->lname, tb_false); // add value switch (item->type) { case TB_OPTION_TYPE_CSTR: tb_oc_dictionary_insert(impl->list, item->lname, tb_oc_string_init_from_cstr(p)); break; case TB_OPTION_TYPE_INTEGER: tb_assert_and_check_return_val(tb_option_is_integer(p), tb_false); tb_oc_dictionary_insert(impl->list, item->lname, tb_oc_number_init_from_sint64(tb_atoll(p))); break; case TB_OPTION_TYPE_BOOL: tb_assert_and_check_return_val(tb_option_is_bool(p), tb_false); tb_oc_dictionary_insert(impl->list, item->lname, tb_oc_boolean_init(!tb_stricmp(p, "y")? tb_true : tb_false)); break; #ifdef TB_CONFIG_TYPE_HAVE_FLOAT case TB_OPTION_TYPE_FLOAT: tb_assert_and_check_return_val(tb_option_is_float(p), tb_false); tb_oc_dictionary_insert(impl->list, item->lname, tb_oc_number_init_from_double(tb_atof(p))); break; #endif default: tb_assert_and_check_return_val(0, tb_false); break; } // save last last = item; // next item item++; } // has more item? else if (item->mode == TB_OPTION_MODE_MORE && last) { // the more name tb_char_t name[64] = {0}; tb_snprintf(name, 63, "more%lu", more); // add value switch (last->type) { case TB_OPTION_TYPE_CSTR: tb_oc_dictionary_insert(impl->list, name, tb_oc_string_init_from_cstr(p)); break; case TB_OPTION_TYPE_INTEGER: tb_assert_and_check_return_val(tb_option_is_integer(p), tb_false); tb_oc_dictionary_insert(impl->list, name, tb_oc_number_init_from_sint64(tb_atoll(p))); break; case TB_OPTION_TYPE_BOOL: tb_assert_and_check_return_val(tb_option_is_bool(p), tb_false); tb_oc_dictionary_insert(impl->list, name, tb_oc_boolean_init(!tb_stricmp(p, "y")? tb_true : tb_false)); break; #ifdef TB_CONFIG_TYPE_HAVE_FLOAT case TB_OPTION_TYPE_FLOAT: tb_assert_and_check_return_val(tb_option_is_float(p), tb_false); tb_oc_dictionary_insert(impl->list, name, tb_oc_number_init_from_double(tb_atof(p))); break; #endif default: tb_assert_and_check_return_val(0, tb_false); break; } // next more more++; } } } // ok return tb_true;//tb_option_check(impl); }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }