/* ////////////////////////////////////////////////////////////////////////////////////// * thread */ static tb_char_t const* tb_demo_gets(tb_char_t* line, tb_size_t maxn) { // check tb_assert_and_check_return_val(line && maxn, tb_null); // done tb_char_t* p = line; tb_char_t* e = line + maxn; while (p < e) { // get character tb_char_t ch = getchar(); if (ch == '\r') getchar(); tb_check_break(ch != '\r' && ch != '\n'); // append digit if (tb_isdigit(ch)) *p++ = ch; else { // trace tb_trace_e("invalid character: %x, please input digit!", ch); } } // end if (p < e) *p = '\0'; // ok? return line; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_bool_t tb_dns_init() { // done tb_size_t count = 0; if (tb_file_info("/etc/resolv.conf", tb_null)) { /* try get list from "/etc/resolv.conf" * * # Generated by NetworkManager * nameserver 10.1.20.10 * nameserver 8.8.8.8 * */ tb_stream_ref_t stream = tb_stream_init_from_url("/etc/resolv.conf"); if (stream) { // open if (tb_stream_open(stream)) { // read tb_long_t size = 0; tb_char_t line[8192]; while ((size = tb_stream_bread_line(stream, line, 8192)) >= 0) { if (size && !tb_strnicmp(line, "nameserver", 10)) { // seek to server tb_char_t const* p = line + 10; while (*p && !tb_isdigit(*p)) p++; tb_check_continue(*p); // add server tb_dns_server_add(p); // count++ count++; } } } // exit tb_stream_exit(stream); } } // no server? add the default server if (!count) { tb_dns_server_add("8.8.8.8"); tb_dns_server_add("8.8.8.4"); } // ok return tb_true; }
static tb_void_t tb_check_is() { tb_int_t i = 0; for (i = 0; i < 256; i++) { if ((tb_isspace(i)? 1 : 0) != (isspace(i)? 1 : 0)) tb_printf("[e] isspace: 0x%02x\n", i); if ((tb_isalpha(i)? 1 : 0) != (isalpha(i)? 1 : 0)) tb_printf("[e] isalpha: 0x%02x\n", i); if ((tb_isdigit(i)? 1 : 0) != (isdigit(i)? 1 : 0)) tb_printf("[e] isdigit: 0x%02x\n", i); if ((tb_isupper(i)? 1 : 0) != (isupper(i)? 1 : 0)) tb_printf("[e] isupper: 0x%02x\n", i); if ((tb_islower(i)? 1 : 0) != (islower(i)? 1 : 0)) tb_printf("[e] islower: 0x%02x\n", i); if ((tb_isascii(i)? 1 : 0) != (isascii(i)? 1 : 0)) tb_printf("[e] isascii: 0x%02x\n", i); } }
static __tb_inline__ tb_bool_t tb_option_is_integer(tb_char_t const* data) { // check tb_assert_and_check_return_val(data, tb_false); // init tb_char_t const* p = data; // skip '-' & '+' if (*p == '-' || *p == '+') p++; // walk for (; *p && tb_isdigit(*p); p++); // ok? return *p? tb_false : tb_true; }
static tb_void_t g2_svg_element_polygon_points(g2_svg_element_polygon_t* element, tb_char_t const* data) { // init tb_char_t const* p = data; tb_assert_and_check_return(p); // size tb_size_t size = 0; // trace tb_trace_impl("polygon: points"); while (*p) { if (!tb_isspace(*p) && tb_isdigit(*p)) p = g2_svg_element_polygon_point(element, p, &size); else p++; } // close path if (element->path) g2_path_close(element->path); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t vm86_parser_get_variable_name(tb_char_t const** pp, tb_char_t const* e, tb_char_t* name, tb_size_t maxn) { // check tb_assert(pp && e && name && maxn); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // save base tb_char_t const* b = p; // check tb_check_break(p < e && (tb_isalpha(*p) || *p == '_')); p++; // get name while (p < e && (tb_isalpha(*p) || *p == '_' || tb_isdigit(*p))) p++; tb_check_break(p <= e && p - b < maxn); tb_memcpy(name, b, p - b); // end name[p - b] = '\0'; // skip the space while (p < e && tb_isspace(*p)) p++; // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_int_t tb_skip_atoi(tb_char_t const** s) { tb_int_t i = 0; while (tb_isdigit(**s)) i = i * 10 + *((*s)++) - '0'; return i; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_object_ref_t tb_object_xplist_reader_func_date(tb_object_xplist_reader_t* reader, tb_size_t event) { // check tb_assert_and_check_return_val(reader && reader->reader && event, tb_null); // empty? if (event == TB_XML_READER_EVENT_ELEMENT_EMPTY) return tb_object_date_init_from_time(0); // done tb_bool_t leave = tb_false; tb_object_ref_t date = tb_null; while (!leave && (event = tb_xml_reader_next(reader->reader))) { switch (event) { case TB_XML_READER_EVENT_ELEMENT_END: { // name tb_char_t const* name = tb_xml_reader_element(reader->reader); tb_assert_and_check_break_state(name, leave, tb_true); // is end? if (!tb_stricmp(name, "date")) { // empty? if (!date) date = tb_object_date_init_from_time(0); // leave it leave = tb_true; } } break; case TB_XML_READER_EVENT_TEXT: { // text tb_char_t const* text = tb_xml_reader_text(reader->reader); tb_assert_and_check_break_state(text, leave, tb_true); tb_trace_d("date: %s", text); // done date: %04ld-%02ld-%02ld %02ld:%02ld:%02ld tb_tm_t tm = {0}; tb_char_t const* p = text; tb_char_t const* e = text + tb_strlen(text); // init year while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.year = tb_atoi(p); // init month while (p < e && *p && tb_isdigit(*p)) p++; while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.month = tb_atoi(p); // init day while (p < e && *p && tb_isdigit(*p)) p++; while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.mday = tb_atoi(p); // init hour while (p < e && *p && tb_isdigit(*p)) p++; while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.hour = tb_atoi(p); // init minute while (p < e && *p && tb_isdigit(*p)) p++; while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.minute = tb_atoi(p); // init second while (p < e && *p && tb_isdigit(*p)) p++; while (p < e && *p && !tb_isdigit(*p)) p++; tb_assert_and_check_break_state(p < e, leave, tb_true); tm.second = tb_atoi(p); // time tb_time_t time = tb_mktime(&tm); tb_assert_and_check_break_state(time >= 0, leave, tb_true); // date date = tb_object_date_init_from_time(time); } break; default: break; } } // ok? return date; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_time_t tb_http_date_from_cstr(tb_char_t const* cstr, tb_size_t size) { // check tb_assert_and_check_return_val(cstr && size, 0); // done tb_tm_t tm = {0}; tb_time_t date = 0; tb_char_t const* p = cstr; tb_char_t const* e = cstr + size; do { // skip space while (p < e && tb_isspace(*p)) p++; // ignore #if 0 // parse week if ((p + 6 < e && !tb_strnicmp(p, "Monday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Mon", 3))) tm.week = 1; else if ((p + 7 < e && !tb_strnicmp(p, "Tuesday", 7)) || (p + 3 < e && !tb_strnicmp(p, "Tue", 3))) tm.week = 2; else if ((p + 9 < e && !tb_strnicmp(p, "Wednesday", 9)) || (p + 3 < e && !tb_strnicmp(p, "Wed", 3))) tm.week = 3; else if ((p + 8 < e && !tb_strnicmp(p, "Thursday", 8)) || (p + 3 < e && !tb_strnicmp(p, "Thu", 3))) tm.week = 4; else if ((p + 6 < e && !tb_strnicmp(p, "Friday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Fri", 3))) tm.week = 5; else if ((p + 8 < e && !tb_strnicmp(p, "Saturday", 8)) || (p + 3 < e && !tb_strnicmp(p, "Sat", 3))) tm.week = 6; else if ((p + 6 < e && !tb_strnicmp(p, "Sunday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Sun", 3))) tm.week = 7; #endif // skip week while (p < e && *p != ',' && !tb_isspace(*p)) p++; if (p < e && (*p == ',' || tb_isspace(*p))) p++; // skip space while (p < e && tb_isspace(*p)) p++; // is day? tb_bool_t year_suffix = tb_true; if (p < e && tb_isdigit(*p)) { /* prefix year * * .e.g * year_suffix == false: Sun, 06-Nov-1994 08:49:37 * year_suffix == true: Sun Nov 6 08:49:37 1994 */ year_suffix = tb_false; // parse day tm.mday = tb_s10tou32(p); // skip day while (p < e && *p != '-' && !tb_isspace(*p)) p++; if (p < e && (*p == '-' || tb_isspace(*p))) p++; } // parse month if (p + 3 < e && !tb_strnicmp(p, "Jan", 3)) tm.month = 1; else if (p + 3 < e && !tb_strnicmp(p, "Feb", 3)) tm.month = 2; else if (p + 3 < e && !tb_strnicmp(p, "Mar", 3)) tm.month = 3; else if (p + 3 < e && !tb_strnicmp(p, "Apr", 3)) tm.month = 4; else if (p + 3 < e && !tb_strnicmp(p, "May", 3)) tm.month = 5; else if (p + 3 < e && !tb_strnicmp(p, "Jun", 3)) tm.month = 6; else if (p + 3 < e && !tb_strnicmp(p, "Jul", 3)) tm.month = 7; else if (p + 3 < e && !tb_strnicmp(p, "Aug", 3)) tm.month = 8; else if (p + 3 < e && !tb_strnicmp(p, "Sep", 3)) tm.month = 9; else if (p + 3 < e && !tb_strnicmp(p, "Oct", 3)) tm.month = 10; else if (p + 3 < e && !tb_strnicmp(p, "Nov", 3)) tm.month = 11; else if (p + 3 < e && !tb_strnicmp(p, "Dec", 3)) tm.month = 12; // skip month while (p < e && *p != '-' && !tb_isspace(*p)) p++; if (p < e && (*p == '-' || tb_isspace(*p))) p++; // year suffix? if (year_suffix) { // parse day tm.mday = tb_s10tou32(p); } else { // parse year tm.year = tb_s10tou32(p); if (tm.year < 100) tm.year += 2000; } // skip year or day while (p < e && !tb_isspace(*p)) p++; while (p < e && tb_isspace(*p)) p++; // parse hour tm.hour = tb_s10tou32(p); // skip hour while (p < e && *p != ':') p++; if (p < e && *p == ':') p++; // parse minute tm.minute = tb_s10tou32(p); // skip minute while (p < e && *p != ':') p++; if (p < e && *p == ':') p++; // parse second tm.second = tb_s10tou32(p); // year suffix? if (year_suffix) { // skip time while (p < e && !tb_isspace(*p)) p++; while (p < e && tb_isspace(*p)) p++; // parse year tm.year = tb_s10tou32(p); if (tm.year < 100) tm.year += 1900; } // make date date = tb_gmmktime(&tm); } while (0); // ok? return date; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }