/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_object_ref_t tb_object_json_reader_func_null(tb_object_json_reader_t* reader, tb_char_t type) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init data tb_static_string_t data; tb_char_t buff[256]; if (!tb_static_string_init(&data, buff, 256)) return tb_null; // done tb_object_ref_t null = tb_null; do { // append character tb_static_string_chrcat(&data, type); // walk tb_bool_t failed = tb_false; while (!failed && tb_stream_left(reader->stream)) { // need one character tb_byte_t* p = tb_null; if (!tb_stream_need(reader->stream, &p, 1) && p) { failed = tb_true; break; } // the character tb_char_t ch = *p; // append character if (tb_isalpha(ch)) tb_static_string_chrcat(&data, ch); else break; // skip it tb_stream_skip(reader->stream, 1); } // failed? tb_check_break(!failed); // check tb_assert_and_check_break(tb_static_string_size(&data)); // trace tb_trace_d("null: %s", tb_static_string_cstr(&data)); // null? if (!tb_stricmp(tb_static_string_cstr(&data), "null")) null = tb_object_null_init(); } while (0); // exit data tb_static_string_exit(&data); // ok? return null; }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_long_t tb_ifaddrs_netlink_socket_init() { // done tb_long_t sock = -1; tb_bool_t ok = tb_false; do { // make socket sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); tb_check_break(sock >= 0); // bind socket struct sockaddr_nl addr; memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) break; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (sock >= 0) close(sock); sock = -1; } // ok? return sock; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t tb_native_memory_init() { // enter tb_spinlock_enter_without_profiler(&g_lock); // done tb_bool_t ok = tb_false; do { // have been inited? tb_check_break_state(!g_heap, ok, tb_true); // make heap g_heap = (tb_handle_t)HeapCreate(0, 0, 0); tb_check_break(g_heap); // ok ok = tb_true; } while (0); // leave tb_spinlock_leave(&g_lock); // ok? return ok; }
tb_size_t tb_directory_home(tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && maxn, 0); // the home directory tb_bool_t ok = tb_false; tb_handle_t pidl = tb_null; tb_wchar_t home[TB_PATH_MAXN] = {0}; do { // get the appdata folder location if (S_OK != tb_shell32()->SHGetSpecialFolderLocation(tb_null, 0x1a /* CSIDL_APPDATA */, &pidl)) break; tb_check_break(pidl); // get the home directory if (!tb_shell32()->SHGetPathFromIDListW(pidl, home)) break; // ok ok = tb_true; } while (0); // exit pidl if (pidl) GlobalFree(pidl); pidl = tb_null; // wtoa tb_size_t size = ok? tb_wtoa(path, home, maxn) : 0; // ok? return size != -1? size : 0; }
static tb_long_t tb_dns_looker_resp(tb_dns_looker_impl_t* impl, tb_ipaddr_ref_t addr) { // check tb_check_return_val(!(impl->step & TB_DNS_LOOKER_STEP_RESP), 1); // need wait if no data impl->step &= ~TB_DNS_LOOKER_STEP_NEVT; // recv response data tb_byte_t rpkt[4096]; while (1) { // read data tb_long_t read = tb_socket_urecv(impl->sock, tb_null, rpkt, 4096); //tb_trace_d("read %d", read); tb_assert_and_check_return_val(read >= 0, -1); // no data? if (!read) { // end? read x, read 0 tb_check_break(!tb_static_buffer_size(&impl->rpkt)); // abort? read 0, read 0 tb_check_return_val(!impl->tryn, -1); // tryn++ impl->tryn++; // continue return 0; } else impl->tryn = 0; // copy data tb_static_buffer_memncat(&impl->rpkt, rpkt, read); } // done if (!tb_dns_looker_resp_done(impl, addr)) return -1; // check tb_assert_and_check_return_val(tb_static_string_size(&impl->name) && !tb_ipaddr_ip_is_empty(addr), -1); // save address to cache tb_dns_cache_set(tb_static_string_cstr(&impl->name), addr); // finish it impl->step |= TB_DNS_LOOKER_STEP_RESP; impl->tryn = 0; // reset rpkt impl->size = 0; tb_static_buffer_clear(&impl->rpkt); // ok tb_trace_d("response: ok"); return 1; }
tb_long_t tb_dns_looker_spak(tb_dns_looker_ref_t self, tb_ipaddr_ref_t addr) { // check tb_dns_looker_t* looker = (tb_dns_looker_t*)self; tb_assert_and_check_return_val(looker && addr, -1); // init tb_long_t r = -1; do { // request r = tb_dns_looker_reqt(looker); tb_check_break(r > 0); // response r = tb_dns_looker_resp(looker, addr); tb_check_break(r > 0); } while (0); // failed? if (r < 0) { // next if (looker->itor + 1 <= looker->maxn) looker->itor++; else looker->itor = 0; // has next? if (looker->itor) { // reset step, no event now, need not wait looker->step = TB_DNS_LOOKER_STEP_NONE | TB_DNS_LOOKER_STEP_NEVT; // reset rpkt looker->size = 0; tb_static_buffer_clear(&looker->rpkt); // continue r = 0; } } // ok? return r; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_dns_looker_ref_t tb_dns_looker_init(tb_char_t const* name) { // check tb_assert_and_check_return_val(name, tb_null); // must be not address tb_assert(!tb_ipaddr_ip_cstr_set(tb_null, name, TB_IPADDR_FAMILY_NONE)); // done tb_bool_t ok = tb_false; tb_dns_looker_t* looker = tb_null; do { // make looker looker = tb_malloc0_type(tb_dns_looker_t); tb_assert_and_check_return_val(looker, tb_null); // dump server // tb_dns_server_dump(); // get the dns server list looker->maxn = tb_dns_server_get(looker->list); tb_check_break(looker->maxn && looker->maxn <= tb_arrayn(looker->list)); // init name if (!tb_static_string_init(&looker->name, (tb_char_t*)looker->data, TB_DNS_NAME_MAXN)) break; tb_static_string_cstrcpy(&looker->name, name); // init rpkt if (!tb_static_buffer_init(&looker->rpkt, looker->data + TB_DNS_NAME_MAXN, TB_DNS_RPKT_MAXN)) break; // init family looker->family = TB_IPADDR_FAMILY_IPV4; // init sock looker->sock = tb_socket_init(TB_SOCKET_TYPE_UDP, looker->family); tb_assert_and_check_break(looker->sock); // init itor looker->itor = 1; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (looker) tb_dns_looker_exit((tb_dns_looker_ref_t)looker); looker = tb_null; } // ok? return (tb_dns_looker_ref_t)looker; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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 */ 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_thread_pool_task_ref_t tb_thread_pool_task_init(tb_thread_pool_ref_t pool, tb_char_t const* name, tb_thread_pool_task_done_func_t done, tb_thread_pool_task_exit_func_t exit, tb_cpointer_t priv, tb_bool_t urgent) { // check tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)pool; tb_assert_and_check_return_val(impl && done, tb_null); // init the post size tb_size_t post_size = 0; // enter tb_spinlock_enter(&impl->lock); // done tb_bool_t ok = tb_false; tb_thread_pool_job_t* job = tb_null; do { // stoped? tb_check_break(!impl->bstoped); // init task tb_thread_pool_task_t task = {0}; task.name = name; task.done = done; task.exit = exit; task.priv = priv; task.urgent = urgent; // post task job = tb_thread_pool_jobs_post_task(impl, &task, &post_size); tb_assert_and_check_break(job); // refn++ job->refn++; // ok ok = tb_true; } while (0); // leave tb_spinlock_leave(&impl->lock); // post the workers if (ok && post_size) tb_thread_pool_worker_post(impl, post_size); // failed? else if (!ok) job = tb_null; // ok? return (tb_thread_pool_task_ref_t)job; }
static tb_void_t tb_heap_check(tb_heap_impl_t* impl) { // init tb_byte_t* data = impl->data; tb_size_t tail = impl->size; tb_size_t step = impl->func.size; tb_size_t parent = 0; // walk for (; parent < tail; parent++) { // the left child node tb_size_t lchild = (parent << 1) + 1; tb_check_break(lchild < tail); // the parent data tb_pointer_t parent_data = impl->func.data(&impl->func, data + parent * step); // check? if (impl->func.comp(&impl->func, impl->func.data(&impl->func, data + lchild * step), parent_data) < 0) { tb_trace_d("lchild[%lu]: invalid, parent: %lu", lchild, parent); break; } // the right child node tb_size_t rchild = (parent << 1) + 2; tb_check_break(rchild < tail); // check? if (impl->func.comp(&impl->func, impl->func.data(&impl->func, data + rchild * step), parent_data) < 0) { tb_trace_d("rchild[%lu]: invalid, parent: %lu", rchild, parent); break; } } }
static tb_bool_t tb_async_transfer_ostream_open_func(tb_async_stream_ref_t stream, tb_size_t state, tb_cpointer_t priv) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)priv; tb_assert_and_check_return_val(stream && impl && impl->open.func, tb_false); // trace tb_trace_d("open: ostream: %s, state: %s", tb_url_cstr(tb_async_stream_url(stream)), tb_state_cstr(state)); // done tb_bool_t ok = tb_true; do { // ok? tb_check_break(state == TB_STATE_OK); // reset state state = TB_STATE_UNKNOWN_ERROR; // check tb_assert_and_check_break(impl->istream); // killed? if (TB_STATE_KILLING == tb_atomic_get(&impl->state)) { state = TB_STATE_KILLED; break; } // done func ok = tb_async_transfer_open_func(impl, TB_STATE_OK, tb_async_stream_offset(impl->istream), tb_async_stream_size(impl->istream), impl->open.func, impl->open.priv); // ok state = TB_STATE_OK; } while (0); // failed? if (state != TB_STATE_OK) { // done func ok = tb_async_transfer_open_func(impl, state, 0, 0, impl->open.func, impl->open.priv); } // ok return ok; }
static tb_fixed_pool_slot_t* tb_fixed_pool_slot_find(tb_fixed_pool_impl_t* impl, tb_pointer_t data) { // check tb_assert_and_check_return_val(impl && data, tb_null); // done tb_fixed_pool_slot_t* slot = tb_null; do { // belong to the current slot? if (impl->current_slot && tb_fixed_pool_slot_exists(impl->current_slot, data)) { slot = impl->current_slot; break; } // find the slot from the partial slots tb_for_all_if(tb_fixed_pool_slot_t*, partial_slot, tb_list_entry_itor(&impl->partial_slots), partial_slot) { // is this? if (tb_fixed_pool_slot_exists(partial_slot, data)) { slot = partial_slot; break; } } // no found? tb_check_break(!slot); // find the slot from the full slots tb_for_all_if(tb_fixed_pool_slot_t*, full_slot, tb_list_entry_itor(&impl->full_slots), full_slot) { // is this? if (tb_fixed_pool_slot_exists(full_slot, data)) { slot = full_slot; break; } } } while (0); // ok? return slot; }
tb_bool_t tb_ssl_clos(tb_ssl_ref_t self) { // the ssl tb_ssl_t* ssl = (tb_ssl_t*)self; tb_assert_and_check_return_val(ssl, tb_false); // open it tb_long_t ok = -1; while (!(ok = tb_ssl_clos_try(self))) { // wait it ok = tb_ssl_wait(self, TB_SOCKET_EVENT_RECV | TB_SOCKET_EVENT_SEND, ssl->timeout); tb_check_break(ok > 0); } // ok? return ok > 0? tb_true : tb_false; }
tb_long_t tb_thread_pool_task_wait_all(tb_thread_pool_ref_t pool, tb_long_t timeout) { // check tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)pool; tb_assert_and_check_return_val(impl, -1); // wait it tb_size_t size = 0; tb_hong_t time = tb_cache_time_spak(); while ((timeout < 0 || tb_cache_time_spak() < time + timeout)) { // enter tb_spinlock_enter(&impl->lock); // the jobs count size = impl->jobs_pool? tb_fixed_pool_size(impl->jobs_pool) : 0; // trace tb_trace_d("wait: jobs: %lu, waiting: %lu, pending: %lu, urgent: %lu: .." , size , tb_list_entry_size(&impl->jobs_waiting) , tb_list_entry_size(&impl->jobs_pending) , tb_list_entry_size(&impl->jobs_urgent)); #if 0 tb_for_all_if (tb_thread_pool_job_t*, job, tb_list_entry_itor(&impl->jobs_pending), job) { tb_trace_d("wait: job: %s from pending", tb_state_cstr(tb_atomic_get(&job->state))); } #endif // leave tb_spinlock_leave(&impl->lock); // ok? tb_check_break(size); // wait some time tb_msleep(200); } // ok? return !size? 1 : 0; }
static tb_void_t tb_lo_scheduler_io_loop(tb_lo_coroutine_ref_t coroutine, tb_cpointer_t priv) { // check tb_lo_scheduler_io_ref_t scheduler_io = (tb_lo_scheduler_io_ref_t)priv; tb_assert(scheduler_io && scheduler_io->poller); // the scheduler tb_lo_scheduler_t* scheduler = scheduler_io->scheduler; tb_assert(scheduler); // enter coroutine tb_lo_coroutine_enter(coroutine) { // loop while (!scheduler->stopped) { // finish all other ready coroutines first while (tb_lo_scheduler_ready_count(scheduler) > 1) { // yield it tb_lo_coroutine_yield(); #ifndef TB_CONFIG_MICRO_ENABLE // spak timer if (!tb_lo_scheduler_io_timer_spak(scheduler_io)) break; #endif } // no more suspended coroutines? loop end tb_check_break(tb_lo_scheduler_suspend_count(scheduler)); // trace tb_trace_d("loop: wait %ld ms ..", tb_lo_scheduler_io_timer_delay(scheduler_io)); // no more ready coroutines? wait io events and timers (TODO) if (tb_poller_wait(scheduler_io->poller, tb_lo_scheduler_io_events, tb_lo_scheduler_io_timer_delay(scheduler_io)) < 0) break; #ifndef TB_CONFIG_MICRO_ENABLE // spak timer if (!tb_lo_scheduler_io_timer_spak(scheduler_io)) break; #endif } } }
static tb_bool_t tb_async_transfer_open_done_func(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_cpointer_t priv) { // the impl tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)priv; tb_assert_and_check_return_val(impl && impl->done.func, tb_false); // trace tb_trace_d("open_done: offset: %llu, size: %lld, state: %s", offset, size, tb_state_cstr(state)); // done tb_bool_t ok = tb_true; do { // ok? tb_check_break(state == TB_STATE_OK); // reset state state = TB_STATE_UNKNOWN_ERROR; // killed? if (TB_STATE_KILLING == tb_atomic_get(&impl->state)) { state = TB_STATE_KILLED; break; } // done it if (!tb_async_transfer_done((tb_async_transfer_ref_t)impl, impl->done.func, impl->done.priv)) break; // ok state = TB_STATE_OK; } while (0); // failed? if (state != TB_STATE_OK) { // done func for closing it ok = tb_async_transfer_done_func(impl, state); } // ok? return ok; }
tb_bool_t tb_async_transfer_resume(tb_async_transfer_ref_t transfer) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)transfer; tb_assert_and_check_return_val(impl && impl->aicp, tb_false); // done tb_bool_t ok = tb_false; tb_size_t state_pause = TB_STATE_OK; do { // must be opened? tb_check_break(TB_STATE_OPENED == tb_atomic_get(&impl->state)); // resume it tb_size_t state_pause = tb_atomic_fetch_and_set(&impl->state_pause, TB_STATE_OK); // pausing or ok? return ok directly tb_check_return_val(state_pause == TB_STATE_PAUSED, tb_true); // check tb_assert_and_check_break(impl->istream); tb_assert_and_check_break(impl->ostream); // init some rate info impl->done.base_time = tb_aicp_time(impl->aicp); impl->done.base_time1s = impl->done.base_time; impl->done.saved_size1s = 0; impl->done.current_rate = 0; // read it if (!tb_async_stream_read(impl->istream, (tb_size_t)tb_atomic_get(&impl->limited_rate), tb_async_transfer_istream_read_func, impl)) break; // ok ok = tb_true; } while (0); // failed? restore state if (!ok && state_pause != TB_STATE_OK) tb_atomic_pset(&impl->state_pause, TB_STATE_OK, state_pause); // ok? return ok; }
tb_void_t tb_timer_task_kill(tb_timer_ref_t timer, tb_timer_task_ref_t task) { // check tb_timer_impl_t* impl = (tb_timer_impl_t*)timer; tb_timer_task_impl_t* task_impl = (tb_timer_task_impl_t*)task; tb_assert_and_check_return(impl && impl->pool && task_impl); // trace tb_trace_d("kill: when: %lld, period: %u, refn: %u", task_impl->when, task_impl->period, task_impl->refn); // enter tb_spinlock_enter(&impl->lock); // done do { // expired or removed? tb_check_break(task_impl->refn == 2); // find it tb_size_t itor = tb_find_all_if(impl->heap, tb_timer_comp_by_task, task_impl); tb_assert_and_check_break(itor != tb_iterator_tail(impl->heap)); // del this task_impl tb_heap_del(impl->heap, itor); // killed task_impl->killed = 1; // no repeat task_impl->repeat = 0; // modify when => now task_impl->when = tb_timer_now(impl); // re-add task_impl tb_heap_put(impl->heap, task_impl); } while (0); // leave tb_spinlock_leave(&impl->lock); }
/* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_void_t tb_demo_database_sql_test_done(tb_database_sql_ref_t database, tb_char_t const* sql) { // check tb_assert_and_check_return(database && sql); // done do { // done sql if (!tb_database_sql_done(database, sql)) { // trace tb_trace_e("done %s failed, error: %s", sql, tb_state_cstr(tb_database_sql_state(database))); break ; } // load result // tb_iterator_ref_t result = tb_database_sql_result_load(database, tb_true); tb_iterator_ref_t result = tb_database_sql_result_load(database, tb_false); tb_check_break(result); // trace tb_trace_i("=============================================================================="); tb_trace_i("row: size: %lu", tb_iterator_size(result)); // walk result tb_for_all_if (tb_iterator_ref_t, row, result, row) { // trace tb_tracef_i("[row: %lu, col: size: %lu]: ", row_itor, tb_iterator_size(row)); // walk items tb_for_all_if (tb_database_sql_value_t*, value, row, value) { // trace tb_tracet_i("[%s:%s] ", tb_database_sql_value_name(value), tb_database_sql_value_text(value)); } // trace tb_tracet_i(__tb_newline__); }
tb_void_t tb_timer_loop(tb_timer_ref_t timer) { // check tb_timer_impl_t* impl = (tb_timer_impl_t*)timer; tb_assert_and_check_return(impl); // work++ tb_atomic_fetch_and_inc(&impl->work); // init event tb_spinlock_enter(&impl->lock); if (!impl->event) impl->event = tb_event_init(); tb_spinlock_leave(&impl->lock); // loop while (!tb_atomic_get(&impl->stop)) { // the delay tb_size_t delay = tb_timer_delay(timer); if (delay) { // the event tb_spinlock_enter(&impl->lock); tb_event_ref_t event = impl->event; tb_spinlock_leave(&impl->lock); tb_check_break(event); // wait some time if (tb_event_wait(event, delay) < 0) break; } // spak ctime if (impl->ctime) tb_cache_time_spak(); // spak it if (!tb_timer_spak(timer)) break; } // work-- tb_atomic_fetch_and_dec(&impl->work); }
tb_bool_t vm86_parser_get_instruction_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; // skip name while (p < e && tb_isalpha(*p)) p++; tb_check_break(p <= e && p - b < maxn); // not instruction name? if (p < e && !tb_isspace(*p)) break; // save name 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; }
tb_long_t tb_transfer_pool_wait_all(tb_transfer_pool_ref_t pool, tb_long_t timeout) { // check tb_transfer_pool_impl_t* impl = (tb_transfer_pool_impl_t*)pool; tb_assert_and_check_return_val(impl, -1); // wait it tb_size_t size = 0; tb_hong_t time = tb_cache_time_spak(); while ((timeout < 0 || tb_cache_time_spak() < time + timeout)) { // enter tb_spinlock_enter(&impl->lock); // the size tb_size_t size = tb_list_entry_size(&impl->work); // trace tb_trace_d("wait: %lu: ..", size); // trace work #ifdef __tb_debug__ if (size) tb_walk_all(tb_list_entry_itor(&impl->work), tb_transfer_pool_work_wait, tb_null); #endif // leave tb_spinlock_leave(&impl->lock); // ok? tb_check_break(size); // wait some time tb_msleep(200); } // ok? return !size? 1 : 0; }
tb_long_t tb_aicp_wait_all(tb_aicp_ref_t aicp, tb_long_t timeout) { // check tb_aicp_impl_t* impl = (tb_aicp_impl_t*)aicp; tb_assert_and_check_return_val(impl, -1); // trace tb_trace_d("wait: all: .."); // wait it tb_size_t size = 0; tb_hong_t time = tb_cache_time_spak(); while ((timeout < 0 || tb_cache_time_spak() < time + timeout)) { // enter tb_spinlock_enter(&impl->lock); // the aico count size = impl->pool? tb_fixed_pool_size(impl->pool) : 0; // trace tb_trace_d("wait: count: %lu: ..", size); // leave tb_spinlock_leave(&impl->lock); // ok? tb_check_break(size); // wait some time tb_msleep(200); } // ok? return !size? 1 : 0; }
static tb_void_t tb_async_transfer_istream_clos_func(tb_async_stream_ref_t stream, tb_size_t state, tb_cpointer_t priv) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)priv; tb_assert_and_check_return(stream && impl); // trace tb_trace_d("clos: istream: %s, state: %s", tb_url_cstr(tb_async_stream_url(stream)), tb_state_cstr(state)); // done do { // ok? tb_check_break(state == TB_STATE_OK); // reset state state = TB_STATE_UNKNOWN_ERROR; // clos it if (!tb_async_stream_clos(impl->ostream, tb_async_transfer_ostream_clos_func, impl)) break; // ok state = TB_STATE_OK; } while (0); // failed? if (state != TB_STATE_OK) { // trace tb_trace_e("clos: failed: %s", tb_state_cstr(state)); // done func tb_async_transfer_clos_func(impl, state); } }
tb_char_t const* tb_regex_replace(tb_regex_ref_t self, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_char_t const* replace_cstr, tb_size_t replace_size, tb_size_t* plength) { // check tb_regex_t* regex = (tb_regex_t*)self; tb_assert_and_check_return_val(regex && regex->code && cstr && replace_cstr, tb_null); // done tb_char_t const* result = tb_null; do { // clear length first if (plength) *plength = 0; // end? tb_check_break(start < size); // init options #ifdef __tb_debug__ tb_uint32_t options = 0; #else tb_uint32_t options = PCRE2_NO_UTF_CHECK; #endif if (regex->mode & TB_REGEX_MODE_GLOBAL) options |= PCRE2_SUBSTITUTE_GLOBAL; // init buffer if (!regex->buffer_data) { regex->buffer_maxn = tb_max(size + replace_size + 64, 256); regex->buffer_data = (PCRE2_UCHAR*)tb_malloc_bytes(regex->buffer_maxn); } tb_assert_and_check_break(regex->buffer_data); // done tb_long_t ok = -1; PCRE2_SIZE length = 0; while (1) { // replace it length = (PCRE2_SIZE)regex->buffer_maxn; ok = pcre2_substitute(regex->code, (PCRE2_SPTR)cstr, (PCRE2_SIZE)size, (PCRE2_SIZE)start, options, tb_null, tb_null, (PCRE2_SPTR)replace_cstr, (PCRE2_SIZE)replace_size, regex->buffer_data, &length); // no space? if (ok == PCRE2_ERROR_NOMEMORY) { // grow buffer regex->buffer_maxn <<= 1; regex->buffer_data = (PCRE2_UCHAR*)tb_ralloc_bytes(regex->buffer_data, regex->buffer_maxn); tb_assert_and_check_break(regex->buffer_data); } // failed else if (ok < 0) { #if defined(__tb_debug__) && !defined(TB_CONFIG_OS_WINDOWS) // get error info PCRE2_UCHAR info[256]; pcre2_get_error_message(ok, info, sizeof(info)); // trace tb_trace_d("replace failed at offset %lu: error: %ld, %s\n", start, ok, info); #endif // end break; } else break; } // check tb_check_break(ok > 0); tb_assert_and_check_break(length < regex->buffer_maxn); // end regex->buffer_data[length] = '\0'; // trace tb_trace_d(" replace: [%lu]: %s", length, regex->buffer_data); // save length if (plength) *plength = (tb_size_t)length; // ok result = (tb_char_t const*)regex->buffer_data; } while (0); // ok? return result; }
tb_long_t tb_regex_match(tb_regex_ref_t self, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_size_t* plength, tb_vector_ref_t* presults) { // check tb_regex_t* regex = (tb_regex_t*)self; tb_assert_and_check_return_val(regex && regex->code && regex->match_data && cstr, -1); // done tb_long_t ok = -1; do { // clear length first if (plength) *plength = 0; // end? tb_check_break(start < size); // init options #ifdef __tb_debug__ tb_uint32_t options = 0; #else tb_uint32_t options = PCRE2_NO_UTF_CHECK; #endif // match it tb_long_t count = pcre2_match(regex->code, (PCRE2_SPTR)cstr, (PCRE2_SIZE)size, (PCRE2_SIZE)start, options, regex->match_data, tb_null); if (count < 0) { // no match? tb_check_break(count != PCRE2_ERROR_NOMATCH); #if defined(__tb_debug__) && !defined(TB_CONFIG_OS_WINDOWS) // get error info PCRE2_UCHAR info[256]; pcre2_get_error_message(count, info, sizeof(info)); // trace tb_trace_d("match failed at offset %lu: error: %ld, %s\n", start, count, info); #endif // end break; } // check tb_assertf_and_check_break(count, "ovector has not enough space!"); // get output vector PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(regex->match_data); tb_assert_and_check_break(ovector); // get the match offset and length tb_size_t offset = (tb_size_t)ovector[0]; tb_size_t length = (tb_size_t)ovector[1] - ovector[0]; tb_assert_and_check_break(offset + length <= size); // trace tb_trace_d("matched count: %lu, offset: %lu, length: %lu", count, offset, length); // save results if (presults) { // init results if not exists tb_vector_ref_t results = *presults; if (!results) { // init it if (!regex->results) regex->results = tb_vector_init(16, tb_element_mem(sizeof(tb_regex_match_t), tb_regex_match_exit, tb_null)); // save it *presults = results = regex->results; } tb_assert_and_check_break(results); // clear it first tb_vector_clear(results); // done tb_long_t i = 0; tb_regex_match_t entry; for (i = 0; i < count; i++) { // get substring offset and length tb_size_t substr_offset = ovector[i << 1]; tb_size_t substr_length = ovector[(i << 1) + 1] - ovector[i << 1]; tb_assert_and_check_break(substr_offset + substr_length <= size); // make match entry entry.cstr = tb_strndup(cstr + substr_offset, substr_length); entry.size = substr_length; entry.start = substr_offset; tb_assert_and_check_break(entry.cstr); // trace tb_trace_d(" matched: [%lu, %lu]: %s", entry.start, entry.size, entry.cstr); // append it tb_vector_insert_tail(results, &entry); } tb_assert_and_check_break(i == count); } // save length if (plength) *plength = length; // ok ok = offset; } while (0); // ok? return ok; }
static tb_object_ref_t tb_object_json_reader_func_number(tb_object_json_reader_t* reader, tb_char_t type) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init data tb_static_string_t data; tb_char_t buff[256]; if (!tb_static_string_init(&data, buff, 256)) return tb_null; // done tb_object_ref_t number = tb_null; do { // append character tb_static_string_chrcat(&data, type); // walk tb_bool_t bs = (type == '-')? tb_true : tb_false; tb_bool_t bf = (type == '.')? tb_true : tb_false; tb_bool_t failed = tb_false; while (!failed && tb_stream_left(reader->stream)) { // need one character tb_byte_t* p = tb_null; if (!tb_stream_need(reader->stream, &p, 1) && p) { failed = tb_true; break; } // the character tb_char_t ch = *p; // is float? if (!bf && ch == '.') bf = tb_true; else if (bf && ch == '.') { failed = tb_true; break; } // append character if (tb_isdigit10(ch) || ch == '.' || ch == 'e' || ch == 'E' || ch == '-' || ch == '+') tb_static_string_chrcat(&data, ch); else break; // skip it tb_stream_skip(reader->stream, 1); } // failed? tb_check_break(!failed); // check tb_assert_and_check_break(tb_static_string_size(&data)); // trace tb_trace_d("number: %s", tb_static_string_cstr(&data)); // init number #ifdef TB_CONFIG_TYPE_FLOAT if (bf) number = tb_object_number_init_from_float(tb_stof(tb_static_string_cstr(&data))); #else if (bf) tb_trace_noimpl(); #endif else if (bs) { tb_sint64_t value = tb_stoi64(tb_static_string_cstr(&data)); tb_size_t bytes = tb_object_need_bytes(-value); switch (bytes) { case 1: number = tb_object_number_init_from_sint8((tb_sint8_t)value); break; case 2: number = tb_object_number_init_from_sint16((tb_sint16_t)value); break; case 4: number = tb_object_number_init_from_sint32((tb_sint32_t)value); break; case 8: number = tb_object_number_init_from_sint64((tb_sint64_t)value); break; default: break; } } else { tb_uint64_t value = tb_stou64(tb_static_string_cstr(&data)); tb_size_t bytes = tb_object_need_bytes(value); switch (bytes) { case 1: number = tb_object_number_init_from_uint8((tb_uint8_t)value); break; case 2: number = tb_object_number_init_from_uint16((tb_uint16_t)value); break; case 4: number = tb_object_number_init_from_uint32((tb_uint32_t)value); break; case 8: number = tb_object_number_init_from_uint64((tb_uint64_t)value); break; default: break; } } } while (0); // exit data tb_static_string_exit(&data); // ok? return number; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_database_sql_ref_t tb_database_sql_init(tb_char_t const* url) { // check tb_assert_and_check_return_val(url, tb_null); // done tb_bool_t ok = tb_false; tb_database_sql_ref_t database = tb_null; tb_url_t database_url; do { // trace tb_trace_d("init: %s: ..", url); // init url if (!tb_url_init(&database_url)) break; // make url if (!tb_url_cstr_set(&database_url, url)) break; // check protocol tb_size_t protocol = tb_url_protocol(&database_url); tb_assert_and_check_break(protocol == TB_URL_PROTOCOL_SQL || protocol == TB_URL_PROTOCOL_FILE); // the probe func static tb_size_t (*s_probe[])(tb_url_ref_t) = { tb_null #ifdef TB_CONFIG_PACKAGE_HAVE_MYSQL , tb_database_mysql_probe #endif #ifdef TB_CONFIG_PACKAGE_HAVE_SQLITE3 , tb_database_sqlite3_probe #endif }; // the init func static tb_database_sql_ref_t (*s_init[])(tb_url_ref_t) = { tb_null #ifdef TB_CONFIG_PACKAGE_HAVE_MYSQL , tb_database_mysql_init #endif #ifdef TB_CONFIG_PACKAGE_HAVE_SQLITE3 , tb_database_sqlite3_init #endif }; // probe the database type tb_size_t i = 1; tb_size_t n = tb_arrayn(s_probe); tb_size_t s = 0; tb_size_t m = 0; for (; i < n; i++) { if (s_probe[i]) { // probe it tb_size_t score = s_probe[i](&database_url); if (score > s) { // save the max score s = score; m = i; // ok? if (score == 100) break; } } } tb_check_break(m < n && s_init[m]); // init it database = s_init[m](&database_url); tb_assert_and_check_break(database); // trace tb_trace_d("init: %s: ok", url); // ok ok = tb_true; } while (0); // exit url tb_url_exit(&database_url); // failed? if (!ok) { // trace tb_trace_d("init: %s: no", url); // exit database if (database) tb_database_sql_exit(database); database = tb_null; } // ok? return database; }
tb_bool_t tb_file_copy(tb_char_t const* path, tb_char_t const* dest) { // check tb_assert_and_check_return_val(path && dest, tb_false); #ifdef TB_CONFIG_POSIX_HAVE_COPYFILE // the full path tb_char_t full0[TB_PATH_MAXN]; path = tb_path_absolute(path, full0, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_false); // the dest path tb_char_t full1[TB_PATH_MAXN]; dest = tb_path_absolute(dest, full1, TB_PATH_MAXN); tb_assert_and_check_return_val(dest, tb_false); // attempt to copy it directly if (!copyfile(path, dest, 0, COPYFILE_ALL)) return tb_true; else { // attempt to copy it again after creating directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) return !copyfile(path, dest, 0, COPYFILE_ALL); } // failed return tb_false; #else tb_int_t ifd = -1; tb_int_t ofd = -1; tb_bool_t ok = tb_false; do { // get the absolute source path tb_char_t data[8192]; path = tb_path_absolute(path, data, sizeof(data)); tb_assert_and_check_break(path); // get stat.st_mode first #ifdef TB_CONFIG_POSIX_HAVE_STAT64 struct stat64 st = {0}; if (stat64(path, &st)) break; #else struct stat st = {0}; if (stat(path, &st)) break; #endif // open source file ifd = open(path, O_RDONLY); tb_check_break(ifd >= 0); // get the absolute source path dest = tb_path_absolute(dest, data, sizeof(data)); tb_assert_and_check_break(dest); // open destinate file and copy file mode ofd = open(dest, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (ofd < 0) { // attempt to open it again after creating directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) ofd = open(dest, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } tb_check_break(ofd >= 0); // get file size tb_hize_t size = tb_file_size(tb_fd2file(ifd)); // init write size tb_hize_t writ = 0; // attempt to copy file using `sendfile` #ifdef TB_CONFIG_POSIX_HAVE_SENDFILE while (writ < size) { off_t seek = writ; tb_hong_t real = sendfile(ofd, ifd, &seek, (size_t)(size - writ)); if (real > 0) writ += real; else break; } /* attempt to copy file directly if sendfile failed * * sendfile() supports regular file only after "since Linux 2.6.33". */ if (writ != size) { lseek(ifd, 0, SEEK_SET); lseek(ofd, 0, SEEK_SET); } else { ok = tb_true; break; } #endif // copy file using `read` and `write` writ = 0; while (writ < size) { // read some data tb_int_t real = read(ifd, data, (size_t)tb_min(size - writ, sizeof(data))); if (real > 0) { real = write(ofd, data, real); if (real > 0) writ += real; else break; } else break; } // ok? ok = (writ == size); } while (0); // close source file if (ifd >= 0) close(ifd); ifd = -1; // close destinate file if (ofd >= 0) close(ofd); ofd = -1; // ok? return ok; #endif }