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; }
tb_char_t const* tb_path_relative_to(tb_char_t const* root, tb_char_t const* path, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && data && maxn, tb_null); // trace tb_trace_d("path: %s", path); // the root is the current and the path is absolute? return path directly if (!root && !tb_path_is_absolute(path)) { // copy it tb_strlcpy(data, path, maxn); // translate it return tb_path_translate(data, 0, maxn)? data : tb_null; } // get the absolute path tb_size_t path_size = 0; tb_char_t path_absolute[TB_PATH_MAXN]; tb_size_t path_maxn = sizeof(path_absolute); path = tb_path_absolute(path, path_absolute, path_maxn); path_size = tb_strlen(path); tb_assert_and_check_return_val(path && path_size && path_size < path_maxn, tb_null); // trace tb_trace_d("path_absolute: %s", path); // get the absolute root tb_size_t root_size = 0; tb_char_t root_absolute[TB_PATH_MAXN]; tb_size_t root_maxn = sizeof(root_absolute); if (root) { // get the absolute root root = tb_path_absolute(root, root_absolute, root_maxn); root_size = tb_strlen(root); } else { // get the current directory if (!(root_size = tb_directory_current(root_absolute, root_maxn))) return tb_null; // translate it if (!(root_size = tb_path_translate(root_absolute, root_size, root_maxn))) return tb_null; root = root_absolute; } tb_assert_and_check_return_val(root && root_size && root_size < root_maxn, tb_null); // trace tb_trace_d("root_absolute: %s", root); // same directory? return "." if (path_size == root_size && !tb_strncmp(path, root, root_size)) { // check tb_assert_and_check_return_val(maxn >= 2, "."); // return "." data[0] = '.'; data[1] = '\0'; return data; } // append separator if (path_size + 1 < path_maxn) { path_absolute[path_size++] = TB_PATH_SEPARATOR; path_absolute[path_size] = '\0'; } if (root_size + 1 < root_maxn) { root_absolute[root_size++] = TB_PATH_SEPARATOR; root_absolute[root_size] = '\0'; } // find the common leading directory tb_char_t const* p = path; tb_char_t const* q = root; tb_long_t last = -1; for (; *p && *q && *p == *q; q++, p++) { // save the last separator if (*p == TB_PATH_SEPARATOR) last = q - root; } // is different directory or outside the windows drive root? using the absolute path if (last <= 0 || (last == 2 && root[1] == ':')) { // the path size tb_size_t size = tb_min(path_size - 1, maxn); // copy it tb_strncpy(data, path, size); data[size] = '\0'; } // exists same root? else { // count the remaining levels in root tb_size_t count = 0; tb_char_t const* l = root + last + 1; for (; *l; l++) { if (*l == TB_PATH_SEPARATOR) count++; } // append "../" or "..\\" tb_char_t* d = data; tb_char_t* e = data + maxn; while (count--) { if (d + 3 < e) { d[0] = '.'; d[1] = '.'; d[2] = TB_PATH_SEPARATOR; d += 3; } } // append the left path l = path + last + 1; while (*l && d < e) *d++ = *l++; // remove the last separator if (d > data) d--; // end *d = '\0'; } // trace tb_trace_d("relative: %s", data); // ok? return data; }
tb_bool_t tb_environment_add(tb_char_t const* name, tb_char_t const* values, tb_bool_t to_head) { // check tb_assert_and_check_return_val(name && values, tb_false); // find the first separator position tb_bool_t ok = tb_false; tb_char_t const* p = values? tb_strchr(values, TM_ENVIRONMENT_SEP) : tb_null; if (p) { // init filter tb_hash_set_ref_t filter = tb_hash_set_init(8, tb_element_str(tb_true)); // init environment tb_char_t data[TB_PATH_MAXN]; tb_environment_ref_t environment = tb_environment_init(); if (environment) { // load the previous values tb_environment_load(environment, name); // make environment tb_char_t const* b = values; tb_char_t const* e = b + tb_strlen(values); do { // not empty? if (b < p) { // the size tb_size_t size = tb_min(p - b, sizeof(data) - 1); // copy it tb_strncpy(data, b, size); data[size] = '\0'; // have been not inserted? if (!filter || !tb_hash_set_get(filter, data)) { // append the environment tb_environment_insert(environment, data, to_head); // save it to the filter tb_hash_set_insert(filter, data); } } // end? tb_check_break(p + 1 < e); // find the next separator position b = p + 1; p = tb_strchr(b, TM_ENVIRONMENT_SEP); if (!p) p = e; } while (1); // set environment variables ok = tb_environment_save(environment, name); // exit environment tb_environment_exit(environment); } // exit filter if (filter) tb_hash_set_exit(filter); filter = tb_null; } // only one? else { // set environment variables tb_environment_ref_t environment = tb_environment_init(); if (environment) { // load the previous values tb_environment_load(environment, name); // append the environment tb_environment_insert(environment, values, to_head); // set environment variables ok = tb_environment_save(environment, name); // exit environment tb_environment_exit(environment); } } // ok? return ok; }
tb_char_t const* tb_path_absolute_to(tb_char_t const* root, tb_char_t const* path, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && data && maxn, tb_null); // trace tb_trace_d("path: %s", path); // the path is absolute? if (tb_path_is_absolute(path)) { // copy it tb_strlcpy(data, path, maxn); // translate it return tb_path_translate(data, 0, maxn)? data : tb_null; } // get the root directory tb_size_t size = 0; if (root) { // copy it size = tb_strlcpy(data, root, maxn); tb_assert_and_check_return_val(size < maxn, tb_null); } else { // get the current directory if (!(size = tb_directory_current(data, maxn))) return tb_null; } // translate the root directory size = tb_path_translate(data, size, maxn); // trace tb_trace_d("root: %s, size: %lu", data, size); // is windows path? skip the drive prefix tb_char_t* absolute = data; if (size > 2 && tb_isalpha(absolute[0]) && absolute[1] == ':' && absolute[2] == TB_PATH_SEPARATOR) { // skip it absolute += 2; size -= 2; } // path => data tb_char_t const* p = path; tb_char_t const* t = p; tb_char_t* q = absolute + size; tb_char_t const* e = absolute + maxn - 1; while (1) { if (tb_path_is_separator(*p) || !*p) { // the item size tb_size_t n = p - t; // ..? remove item if (n == 2 && t[0] == '.' && t[1] == '.') { // find the last separator for (; q > absolute && *q != TB_PATH_SEPARATOR; q--) ; // strip it *q = '\0'; } // .? continue it else if (n == 1 && t[0] == '.') ; // append item else if (n && q + 1 + n < e) { *q++ = TB_PATH_SEPARATOR; tb_strncpy(q, t, n); q += n; } // empty item? remove repeat else if (!n) ; // too small? else { // trace tb_trace_e("the data path is too small for %s", path); return tb_null; } // break tb_check_break(*p); // next t = p + 1; } // next p++; } // end if (q > absolute) *q = '\0'; // root? else { *q++ = TB_PATH_SEPARATOR; *q = '\0'; } // trace tb_trace_d("absolute: %s", data); // ok? return data; }