static tb_bool_t tb_directory_walk_impl(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return_val(path && func, tb_false); // last tb_long_t last = tb_strlen(path) - 1; tb_assert_and_check_return_val(last >= 0, tb_false); // done tb_bool_t ok = tb_true; tb_char_t temp[4096] = {0}; DIR* directory = tb_null; if ((directory = opendir(path))) { // walk struct dirent* item = tb_null; while ((item = readdir(directory))) { // check tb_assert_and_check_continue(item->d_reclen); // the item name tb_char_t name[1024] = {0}; tb_strncpy(name, item->d_name, tb_min(item->d_reclen, sizeof(name) - 1)); if (tb_strcmp(name, ".") && tb_strcmp(name, "..")) { // the temp path tb_long_t n = tb_snprintf(temp, 4095, "%s%s%s", path, path[last] == '/'? "" : "/", name); if (n >= 0) temp[n] = '\0'; // the file info tb_file_info_t info = {0}; if (tb_file_info(temp, &info)) { // do callback if (prefix) ok = func(temp, &info, priv); tb_check_break(ok); // walk to the next directory if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) ok = tb_directory_walk_impl(temp, recursion, prefix, func, priv); tb_check_break(ok); // do callback if (!prefix) ok = func(temp, &info, priv); tb_check_break(ok); } } } // exit directory closedir(directory); } // continue ? return ok; }
static tb_long_t tb_element_str_comp(tb_element_ref_t element, tb_cpointer_t ldata, tb_cpointer_t rdata) { // check tb_assert_and_check_return_val(element && ldata && rdata, 0); // compare it return element->flag? tb_strcmp((tb_char_t const*)ldata, (tb_char_t const*)rdata) : tb_stricmp((tb_char_t const*)ldata, (tb_char_t const*)rdata); }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_long_t tb_iterator_str_comp(tb_iterator_ref_t iterator, tb_cpointer_t litem, tb_cpointer_t ritem) { // check tb_assert(litem && ritem); // compare it return tb_strcmp((tb_char_t const*)litem, (tb_char_t const*)ritem); }
tb_bool_t tb_ifaddrs_ipaddr(tb_ifaddrs_ref_t ifaddrs, tb_char_t const* name, tb_bool_t reload, tb_size_t family, tb_ipaddr_ref_t ipaddr) { // check tb_assert_and_check_return_val(ifaddrs && ipaddr, tb_false); // clear it first tb_ipaddr_clear(ipaddr); // the iterator tb_iterator_ref_t iterator = tb_ifaddrs_itor(ifaddrs, reload); tb_assert_and_check_return_val(iterator, tb_false); // reload it if the cached interfaces is empty if (!reload && !tb_iterator_size(iterator)) iterator = tb_ifaddrs_itor(ifaddrs, tb_true); // the ipaddr flags tb_uint32_t ipflags = 0; if (family == TB_IPADDR_FAMILY_IPV4) ipflags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; else if (family == TB_IPADDR_FAMILY_IPV6) ipflags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; // done tb_bool_t ok = tb_false; tb_for_all_if (tb_ifaddrs_interface_ref_t, interface, iterator, interface) { // is this? if ( (name || !(interface->flags & TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK)) && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) && (!name || (interface->name && !tb_strcmp(interface->name, name)))) { // ipv4? if ( interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4 && (!family || family == TB_IPADDR_FAMILY_IPV4)) { // save ipaddr4 tb_ipaddr_ipv4_set(ipaddr, &interface->ipaddr4); // ok ok = tb_true; break; } // ipv6? else if ( interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6 && (!family || family == TB_IPADDR_FAMILY_IPV6)) { // save ipaddr6 tb_ipaddr_ipv6_set(ipaddr, &interface->ipaddr6); // ok ok = tb_true; break; } } } // ok? return ok; }
tb_bool_t tb_ifaddrs_hwaddr(tb_ifaddrs_ref_t ifaddrs, tb_char_t const* name, tb_bool_t reload, tb_hwaddr_ref_t hwaddr) { // check tb_assert_and_check_return_val(ifaddrs && hwaddr, tb_false); // clear it first tb_hwaddr_clear(hwaddr); // the iterator tb_iterator_ref_t iterator = tb_ifaddrs_itor(ifaddrs, reload); tb_assert_and_check_return_val(iterator, tb_false); // reload it if the cached interfaces is empty if (!reload && !tb_iterator_size(iterator)) iterator = tb_ifaddrs_itor(ifaddrs, tb_true); // done tb_bool_t ok = tb_false; tb_for_all_if (tb_ifaddrs_interface_ref_t, interface, iterator, interface) { // get hwaddr from the given interface name? if (name) { // is this? if ( (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR) && (interface->name && !tb_strcmp(interface->name, name))) { // save hwaddr tb_hwaddr_copy(hwaddr, &interface->hwaddr); // ok ok = tb_true; break; } } else { // is this? if ( (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR) && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) && !(interface->flags & TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK)) { // save hwaddr tb_hwaddr_copy(hwaddr, &interface->hwaddr); // ok ok = tb_true; break; } } } // ok? return ok; }
/* ////////////////////////////////////////////////////////////////////////////////////// * compare */ static tb_void_t tb_test_strcmp(tb_char_t const* s1, tb_char_t const* s2) { __tb_volatile__ tb_long_t n = 1000000; __tb_volatile__ tb_long_t r = 0; tb_hong_t t = tb_mclock(); while (n--) { r = tb_strcmp(s1, s2); } t = tb_mclock() - t; tb_printf("%lld ms, tb_test_strcmp(%s, %s) = %ld\n", t, s1, s2, r); }
static __tb_inline__ tb_option_item_t const* tb_option_item_find(tb_option_item_t const* opts, tb_char_t const* lname, tb_char_t sname) { // check tb_assert_and_check_return_val(opts, tb_null); // walk tb_bool_t ok = tb_false; tb_option_item_t const* item = opts; while (item && !ok) { switch (item->mode) { case TB_OPTION_MODE_KEY: case TB_OPTION_MODE_KEY_VAL: { // find lname if (item->lname && lname && !tb_strcmp(lname, item->lname)) { ok = tb_true; break; } // find sname if (item->sname && sname && (sname == item->sname) && (sname != '-')) { ok = tb_true; break; } // 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; } } // ok? return ok? item : tb_null; }
static tb_void_t tb_sort_str_test_perf_heap(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_iterator_make_for_str(&array_iterator, data, n); // make tb_random_clear(tb_null); tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%x", tb_random_range(tb_null, 0, TB_MAXU32)); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_heap_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_heap_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_os_find_walk(tb_char_t const* path, tb_file_info_t const* info, tb_cpointer_t priv) { // check tb_value_ref_t tuple = (tb_value_ref_t)priv; tb_assert_and_check_return_val(path && info && tuple, tb_false); // the lua lua_State* lua = (lua_State*)tuple[0].ptr; tb_assert_and_check_return_val(lua, tb_false); // the pattern tb_char_t const* pattern = (tb_char_t const*)tuple[1].cstr; tb_assert_and_check_return_val(pattern, tb_false); // find directory? tb_bool_t findir = tuple[2].b; // the count tb_size_t* pcount = &(tuple[3].ul); // trace tb_trace_d("path[%c]: %s", info->type == TB_FILE_TYPE_DIRECTORY? 'd' : 'f', path); // find file or directory? if ((findir && info->type == TB_FILE_TYPE_DIRECTORY) || (!findir && info->type == TB_FILE_TYPE_FILE)) { // done path:match(pattern) lua_getfield(lua, -1, "match"); lua_pushstring(lua, path); lua_pushstring(lua, pattern); if (lua_pcall(lua, 2, 1, 0)) { // trace tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, pattern, lua_tostring(lua, -1)); // failed return tb_false; } // match ok? if (lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1))) { // exists excludes? tb_bool_t excluded = tb_false; if (lua_istable(lua, 5)) { // the root directory size_t rootlen = 0; tb_char_t const* rootdir = luaL_checklstring(lua, 1, &rootlen); tb_assert_and_check_return_val(rootdir && rootlen, tb_false); // check tb_assert(!tb_strcmp(path, rootdir)); tb_assert(rootlen + 1 <= tb_strlen(path)); // skip the rootdir path += rootlen + 1; // exclude pathes tb_size_t i = 0; tb_size_t count = luaL_getn(lua, 5); for (i = 0; i < count && !excluded; i++) { // get exclude lua_rawgeti(lua, 5, i + 1); tb_char_t const* exclude = lua_tostring(lua, -1); if (exclude) { // done path:match(exclude) lua_getfield(lua, -3, "match"); lua_pushstring(lua, path); lua_pushstring(lua, exclude); if (lua_pcall(lua, 2, 1, 0)) { // trace tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, exclude, lua_tostring(lua, -1)); } // matched? excluded = lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1)); // pop the match result lua_pop(lua, 1); } // pop exclude lua_pop(lua, 1); } } // save this path if (!excluded) lua_rawseti(lua, -3, ++*pcount); // pop this return value else lua_pop(lua, 1); } // pop this return value else lua_pop(lua, 1); } // continue return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t xm_os_find_walk(tb_char_t const* path, tb_file_info_t const* info, tb_cpointer_t priv) { // check tb_value_ref_t tuple = (tb_value_ref_t)priv; tb_assert_and_check_return_val(path && info && tuple, tb_false); // the lua lua_State* lua = (lua_State*)tuple[0].ptr; tb_assert_and_check_return_val(lua, tb_false); // the pattern tb_char_t const* pattern = (tb_char_t const*)tuple[1].cstr; tb_assert_and_check_return_val(pattern, tb_false); // remove ./ for path if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) path = path + 2; // the match mode tb_long_t mode = tuple[2].l; // the count tb_size_t* pcount = &(tuple[3].ul); // trace tb_trace_d("path[%c]: %s", info->type == TB_FILE_TYPE_DIRECTORY? 'd' : 'f', path); // find file or directory? tb_size_t match = (mode == 1)? TB_FILE_TYPE_DIRECTORY : ((mode == 0)? TB_FILE_TYPE_FILE : (TB_FILE_TYPE_FILE | TB_FILE_TYPE_DIRECTORY)); if (info->type & match) { // done path:match(pattern) lua_getfield(lua, -1, "match"); lua_pushstring(lua, path); lua_pushstring(lua, pattern); if (lua_pcall(lua, 2, 1, 0)) { // trace tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, pattern, lua_tostring(lua, -1)); // failed return tb_false; } // match ok? if (lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1))) { // exists excludes? tb_bool_t excluded = tb_false; if (lua_istable(lua, 5)) { // the root directory size_t rootlen = 0; tb_char_t const* rootdir = luaL_checklstring(lua, 1, &rootlen); tb_assert_and_check_return_val(rootdir && rootlen, tb_false); // check tb_assert(!tb_strcmp(path, rootdir)); tb_assert(rootlen + 1 <= tb_strlen(path)); // skip the rootdir if not "." if (tb_strcmp(rootdir, ".")) path += rootlen + 1; // exclude pathes tb_int_t i = 0; tb_int_t count = (tb_int_t)lua_objlen(lua, 5); for (i = 0; i < count && !excluded; i++) { // get exclude lua_rawgeti(lua, 5, i + 1); tb_char_t const* exclude = lua_tostring(lua, -1); if (exclude) { // done path:match(exclude) lua_getfield(lua, -3, "match"); lua_pushstring(lua, path); lua_pushstring(lua, exclude); if (lua_pcall(lua, 2, 1, 0)) { // trace tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, exclude, lua_tostring(lua, -1)); } // matched? excluded = lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1)); // pop the match result lua_pop(lua, 1); } // pop exclude lua_pop(lua, 1); } } // does not exclude this path? if (!excluded) { // save it lua_rawseti(lua, -3, (tb_int_t)(++*pcount)); // do callback function if (lua_isfunction(lua, 6)) { // do callback(path, isdir) lua_pushvalue(lua, 6); lua_pushstring(lua, path); lua_pushboolean(lua, info->type == TB_FILE_TYPE_DIRECTORY); lua_call(lua, 2, 1); // is continue? tb_bool_t is_continue = lua_toboolean(lua, -1); lua_pop(lua, 1); if (!is_continue) return tb_false; } } // pop this return value else lua_pop(lua, 1); } // pop this return value else lua_pop(lua, 1); } // continue return tb_true; }
/* select version * * local versioninfo, errors = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"lastest", "dev"}) */ tb_int_t xm_semver_select(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // select version tb_bool_t ok = tb_false; tb_bool_t is_range = tb_false; tb_char_t const* range_str = tb_null; semver_t semver = {0}; semvers_t matches = {0}; semver_range_t range = {0}; do { // get the version range string range_str = luaL_checkstring(lua, 1); tb_check_break(range_str); // get the range string length tb_size_t range_len = tb_strlen(range_str); // parse the version range string is_range = semver_rangen(&range, range_str, range_len) == 0; if (is_range) { // attempt to select version from the versions list first if (xm_semver_select_from_versions_tags(lua, 2, &semver, &range, &matches)) { ok = tb_true; break; } // attempt to select version from the tags list if (xm_semver_select_from_versions_tags(lua, 3, &semver, &range, &matches)) { ok = tb_true; break; } } // attempt to select version from the branches if (xm_semver_select_from_branches(lua, 4, range_str, range_len)) { ok = tb_true; break; } // select the lastest version from the tags and versions if be lastest if (!tb_strcmp(range_str, "lastest")) { // attempt to select lastest version from the versions list if (xm_semver_select_lastest_from_versions_tags(lua, 2, &semver, &matches)) { ok = tb_true; break; } // attempt to select lastest version from the tags list if (xm_semver_select_lastest_from_versions_tags(lua, 3, &semver, &matches)) { ok = tb_true; break; } } } while (0); // exit matches semvers_dtor(matches); // exit range semver_range_dtor(&range); // failed? if (!ok) { if (!is_range) { lua_pushnil(lua); lua_pushfstring(lua, "unable to parse semver range '%s'", range_str); } lua_pushnil(lua); lua_pushfstring(lua, "unable to select version for range '%s'", range_str); return 2; } // ok return 1; }