diff --git a/core/dap_config.c b/core/dap_config.c index 4a06883c3fdbe1341f71e957cc16330b155bc91f..7e788a86de986654749f9d2a4c1e1df254e12b47 100755 --- a/core/dap_config.c +++ b/core/dap_config.c @@ -2,8 +2,8 @@ #include <string.h> #include <errno.h> #include <ctype.h> +#include "dap_file_utils.h" #include "uthash.h" -#include "file_utils.h" #include "dap_common.h" #include "dap_config.h" @@ -52,12 +52,12 @@ int dap_config_init(const char * a_configs_path) if( a_configs_path ) { #ifdef _WIN32 // Check up under Windows, in Linux is not required - if(!valid_ascii_symbols(a_configs_path)) { + if(!dap_valid_ascii_symbols(a_configs_path)) { log_it(L_ERROR, "Supported only ASCII symbols for directory path"); return -1; } #endif - if(dir_test(a_configs_path) || !mkdir_with_parents(a_configs_path)) { + if(dap_dir_test(a_configs_path) || !dap_mkdir_with_parents(a_configs_path)) { strncpy(s_configs_path, a_configs_path,sizeof(s_configs_path)); return 0; } diff --git a/core/dap_file_utils.c b/core/dap_file_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..eca23beb20d57e117d71d9eb212842d722d41be8 --- /dev/null +++ b/core/dap_file_utils.c @@ -0,0 +1,347 @@ +/* + * Authors: + * Aleksandr Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2018 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> +#if (OS_TARGET == OS_MACOS) + #include <stdio.h> +#else + #include <malloc.h> +#endif +#include <string.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <windows.h> +#include <io.h> +#endif + +#include "dap_common.h" +#include "dap_strfuncs.h" +#include "dap_file_utils.h" + +/** + * Check the directory path for unsupported symbols + * + * @string + * @return true, if the directory path contains only ASCII symbols + */ +bool dap_valid_ascii_symbols(const char *a_string) +{ + if(!a_string) + return true; + for(size_t i = 0; i < strlen(a_string); i++) { + if((uint8_t) a_string[i] > 0x7f) + return false; + } + return true; +} + +/** + * Check the directory for exists + * + * @dir_path directory pathname + * @return true, if the file is a directory + */ +bool dap_dir_test(const char * a_dir_path) +{ + if(!a_dir_path) + return false; +#ifdef _WIN32 + int attr = GetFileAttributesA(a_dir_path); + if(attr != -1 && (attr & FILE_ATTRIBUTE_DIRECTORY)) + return true; +#else + struct stat st; + if (!stat(a_dir_path, &st)) { + if (S_ISDIR(st.st_mode)) + return true; + } +#endif + return false; +} + +/** + * Create a new directory with intermediate sub-directories + * + * @dir_path new directory pathname + * @return 0, if the directory was created or already exist, else -1 + */ +int dap_mkdir_with_parents(const char *a_dir_path) +{ + + char *path, *p; + // validation of a pointer + if(a_dir_path == NULL || a_dir_path[0] == '\0') { + errno = EINVAL; + return -1; + } + path = strdup(a_dir_path); + // skip the root component if it is present, i.e. the "/" in Unix or "C:\" in Windows +#ifdef _WIN32 + if(((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) + && (path[1] == ':') && DAP_IS_DIR_SEPARATOR(path[2])) { + p = path + 3; + } +#else + if (DAP_IS_DIR_SEPARATOR(path[0])) { + p = path + 1; + } +#endif + else + p = path; + + do { + while(*p && !DAP_IS_DIR_SEPARATOR(*p)) + p++; + + if(!*p) + p = NULL; + else + *p = '\0'; + + if(!dap_dir_test(path)) { +#ifdef _WIN32 + int result = mkdir(path); +#else + int result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + if(result == -1) { + free(path); + errno = ENOTDIR; + return -1; + } + } + if(p) { + *p++ = DAP_DIR_SEPARATOR; + while(*p && DAP_IS_DIR_SEPARATOR(*p)) + p++; + } + } while(p); + + free(path); + return 0; +} + +/** + * dap_path_get_basename: + * @a_file_name: the name of the file + * + * Gets the last component of the filename. + * + * If @a_file_name ends with a directory separator it gets the component + * before the last slash. If @a_file_name consists only of directory + * separators (and on Windows, possibly a drive letter), a single + * separator is returned. If @a_file_name is empty, it gets ".". + * + * Returns: a newly allocated string containing the last + * component of the filename + */ +char* dap_path_get_basename(const char *a_file_name) +{ + ssize_t l_base; + ssize_t l_last_nonslash; + size_t l_len; + const char *l_retval; + + dap_return_val_if_fail(a_file_name != NULL, NULL); + + if(a_file_name[0] == '\0') + return dap_strdup("."); + + l_last_nonslash = strlen(a_file_name) - 1; + + while(l_last_nonslash >= 0 && DAP_IS_DIR_SEPARATOR(a_file_name[l_last_nonslash])) + l_last_nonslash--; + + if(l_last_nonslash == -1) + // string only containing slashes + return dap_strdup(DAP_DIR_SEPARATOR_S); + +#ifdef _WIN32 + if (l_last_nonslash == 1 && + dap_ascii_isalpha (a_file_name[0]) && + a_file_name[1] == ':') + // string only containing slashes and a drive + return dap_strdup (DAP_DIR_SEPARATOR_S); +#endif + l_base = l_last_nonslash; + + while(l_base >= 0 && !DAP_IS_DIR_SEPARATOR(a_file_name[l_base])) + l_base--; + +#ifdef _WIN32 + if (l_base == -1 && + dap_ascii_isalpha (a_file_name[0]) && + a_file_name[1] == ':') + l_base = 1; +#endif + + l_len = l_last_nonslash - l_base; + l_retval = a_file_name + l_base + 1; + + return dap_strdup(l_retval); +} + +/** + * dap_path_is_absolute: + * @a_file_name: a file name + * + * Returns true if the given @a_file_name is an absolute file name. + * Note that this is a somewhat vague concept on Windows. + * + * On POSIX systems, an absolute file name is well-defined. It always + * starts from the single root directory. For example "/usr/local". + * + * On Windows, the concepts of current drive and drive-specific + * current directory introduce vagueness. This function interprets as + * an absolute file name one that either begins with a directory + * separator such as "\Users\tml" or begins with the root on a drive, + * for example "C:\Windows". The first case also includes UNC paths + * such as "\\myserver\docs\foo". In all cases, either slashes or + * backslashes are accepted. + * + * Returns: true if @a_file_name is absolute + */ +bool dap_path_is_absolute(const char *a_file_name) +{ + dap_return_val_if_fail(a_file_name != NULL, false); + + if(DAP_IS_DIR_SEPARATOR(a_file_name[0])) + return true; + +#ifdef _WIN32 + /* Recognize drive letter on native Windows */ + if (dap_ascii_isalpha (a_file_name[0]) && + a_file_name[1] == ':' && DAP_IS_DIR_SEPARATOR (a_file_name[2])) + return true; +#endif + + return false; +} + +/** + * dap_path_get_dirname: + * @a_file_name: the name of the file + * + * Gets the directory components of a file name. + * + * If the file name has no directory components "." is returned. + * The returned string should be freed when no longer needed. + * + * Returns: the directory components of the file + */ +char* dap_path_get_dirname(const char *a_file_name) +{ + char *l_base; + size_t l_len; + + dap_return_val_if_fail(a_file_name != NULL, NULL); + + l_base = strrchr(a_file_name, DAP_DIR_SEPARATOR); + +#ifdef _WIN32 + { + char *l_q; + l_q = strrchr (a_file_name, '/'); + if (l_base == NULL || (l_q != NULL && l_q > l_base)) + l_base = l_q; + } +#endif + + if(!l_base) + { +#ifdef _WIN32 + if (dap_ascii_isalpha (a_file_name[0]) && a_file_name[1] == ':') + { + char l_drive_colon_dot[4]; + + l_drive_colon_dot[0] = a_file_name[0]; + l_drive_colon_dot[1] = ':'; + l_drive_colon_dot[2] = '.'; + l_drive_colon_dot[3] = '\0'; + + return dap_strdup (l_drive_colon_dot); + } +#endif + return dap_strdup("."); + } + + while(l_base > a_file_name && DAP_IS_DIR_SEPARATOR(*l_base)) + l_base--; + +#ifdef _WIN32 + /* base points to the char before the last slash. + * + * In case file_name is the root of a drive (X:\) or a child of the + * root of a drive (X:\foo), include the slash. + * + * In case file_name is the root share of an UNC path + * (\\server\share), add a slash, returning \\server\share\ . + * + * In case file_name is a direct child of a share in an UNC path + * (\\server\share\foo), include the slash after the share name, + * returning \\server\share\ . + */ + if (l_base == a_file_name + 1 && + dap_ascii_isalpha (a_file_name[0]) && + a_file_name[1] == ':') + l_base++; + else if (DAP_IS_DIR_SEPARATOR (a_file_name[0]) && + DAP_IS_DIR_SEPARATOR (a_file_name[1]) && + a_file_name[2] && + !DAP_IS_DIR_SEPARATOR (a_file_name[2]) && + l_base >= a_file_name + 2) + { + const char *l_p = a_file_name + 2; + while (*l_p && !DAP_IS_DIR_SEPARATOR (*l_p)) + l_p++; + if (l_p == l_base + 1) + { + l_len = (uint32_t) strlen (a_file_name) + 1; + l_base = DAP_NEW_SIZE (char, l_len + 1); + strcpy (l_base, a_file_name); + l_base[l_len-1] = DAP_DIR_SEPARATOR; + l_base[l_len] = 0; + return l_base; + } + if (DAP_IS_DIR_SEPARATOR (*l_p)) + { + l_p++; + while (*l_p && !DAP_IS_DIR_SEPARATOR (*l_p)) + l_p++; + if (l_p == l_base + 1) + l_base++; + } + } +#endif + + l_len = (uint32_t) 1 + l_base - a_file_name; + l_base = DAP_NEW_SIZE(char, l_len + 1); + memmove(l_base, a_file_name, l_len); + l_base[l_len] = 0; + + return l_base; +} diff --git a/core/file_utils.h b/core/dap_file_utils.h similarity index 59% rename from core/file_utils.h rename to core/dap_file_utils.h index d05ef8c64610db7892cda76e1b0cb06fc804782b..4576faab6bbfe5ada5c17ed8948f256324cce237 100644 --- a/core/file_utils.h +++ b/core/dap_file_utils.h @@ -3,7 +3,7 @@ * Aleksandr Lysikov <alexander.lysikov@demlabs.net> * DeM Labs Inc. https://demlabs.net * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 + * Copyright (c) 2017-2019 * All rights reserved. This file is part of DAP (Deus Applications Prototypes) the open source project @@ -25,7 +25,29 @@ #include <stdbool.h> #ifndef _FILE_UTILS_H_ -#define _FILE_UTILS_H_ +#define _DAP_FILE_UTILS_H_ + +#ifdef _WIN32 + +/* On Win32, the canonical directory separator is the backslash, and + * the search path separator is the semicolon. Note that also the + * (forward) slash works as directory separator. + */ +#define DAP_DIR_SEPARATOR '\\' +#define DAP_DIR_SEPARATOR_S "\\" +#define DAP_IS_DIR_SEPARATOR(c) ((c) == DAP_DIR_SEPARATOR || (c) == '/') +#define DAP_SEARCHPATH_SEPARATOR ';' +#define DAP_SEARCHPATH_SEPARATOR_S ";" + +#else + +#define DAP_DIR_SEPARATOR '/' +#define DAP_DIR_SEPARATOR_S "/" +#define DAP_IS_DIR_SEPARATOR(c) ((c) == DAP_DIR_SEPARATOR) +#define DAP_SEARCHPATH_SEPARATOR ':' +#define DAP_SEARCHPATH_SEPARATOR_S ":" + +#endif /** * Check the directory path for unsupported symbols @@ -33,7 +55,7 @@ * @dir_path directory pathname * @return true, if the directory path contains only ASCII symbols */ -bool valid_ascii_symbols(const char *dir_path); +bool dap_valid_ascii_symbols(const char *a_dir_path); /** * Check the directory for exists @@ -41,7 +63,7 @@ bool valid_ascii_symbols(const char *dir_path); * @dir_path directory pathname * @return true, if the file is a directory */ -bool dir_test(const char * dir_path); +bool dap_dir_test(const char * a_dir_path); /** * Create a new directory with intermediate sub-directories @@ -49,6 +71,11 @@ bool dir_test(const char * dir_path); * @dir_path new directory pathname * @return 0, if the directory was created or already exist, else -1 */ -int mkdir_with_parents(const char *dir_path); +int dap_mkdir_with_parents(const char *a_dir_path); + + +char* dap_path_get_basename(const char *a_file_name); +bool dap_path_is_absolute(const char *a_file_name); +char* dap_path_get_dirname(const char *a_file_name); #endif // _FILE_UTILS_H_ diff --git a/core/dap_strfuncs.h b/core/dap_strfuncs.h index 68abb1c20b17ba8d02cdd02e4b8a64b1b2fc2acd..eb2d8241b9859a0b9b4bcf8e63f527a2009649d0 100755 --- a/core/dap_strfuncs.h +++ b/core/dap_strfuncs.h @@ -15,7 +15,7 @@ #define POINTER_TO_UINT(p) ((unsigned int) (p)) #define INT_TO_POINTER(i) ((void*) (i)) -#define GUINT_TO_POINTER(u) ((void*) (u)) +#define UINT_TO_POINTER(u) ((void*) (u)) #undef max #define max(a, b) (((a) > (b)) ? (a) : (b)) diff --git a/core/dap_string.c b/core/dap_string.c index 831c4abdd864664bb10569d056c2f682c416172b..994a2f6b9d068965e3fe8f64d0eda0bdbf08479b 100755 --- a/core/dap_string.c +++ b/core/dap_string.c @@ -742,66 +742,6 @@ dap_string_t* dap_string_erase(dap_string_t *string, ssize_t pos, ssize_t len) return string; } -/** - * dap_string_ascii_down: - * @a_string: a dap_string_t - * - * Converts all uppercase ASCII letters to lowercase ASCII letters. - * - * Returns: (transfer none): passed-in @a_string pointer, with all the - * uppercase characters converted to lowercase in place, - * with semantics that exactly match dap_ascii_tolower(). - */ -dap_string_t* dap_string_ascii_down(dap_string_t *string) -{ - char *s; - int n; - - dap_return_val_if_fail(string != NULL, NULL); - - n = string->len; - s = string->str; - - while(n) - { - *s = tolower(*s); - s++; - n--; - } - - return string; -} - -/** - * dap_string_ascii_up: - * @a_string: a dap_string_t - * - * Converts all lowercase ASCII letters to uppercase ASCII letters. - * - * Returns: (transfer none): passed-in @a_string pointer, with all the - * lowercase characters converted to uppercase in place, - * with semantics that exactly match dap_ascii_toupper(). - */ -dap_string_t* dap_string_ascii_up(dap_string_t *string) -{ - char *s; - int n; - - dap_return_val_if_fail(string != NULL, NULL); - - n = string->len; - s = string->str; - - while(n) - { - *s = toupper(*s); - s++; - n--; - } - - return string; -} - /** * dap_string_down: * @a_string: a #dap_string_t diff --git a/core/dap_string.h b/core/dap_string.h index ae4c977aae4d33369fa8ba2a28c897fea48aed94..6519f6acd17d04f18d8a62590a7647d60760f706 100755 --- a/core/dap_string.h +++ b/core/dap_string.h @@ -60,10 +60,6 @@ dap_string_t* dap_string_overwrite_len(dap_string_t *string, size_t pos, const c dap_string_t* dap_string_erase(dap_string_t *string, ssize_t pos, ssize_t len); -dap_string_t* dap_string_ascii_down(dap_string_t *string); - -dap_string_t* dap_string_ascii_up(dap_string_t *string); - void dap_string_vprintf(dap_string_t *string, const char *format, va_list args); void dap_string_printf(dap_string_t *string, const char *format, ...); void dap_string_append_vprintf(dap_string_t *string, const char *format, va_list args); diff --git a/core/file_utils.c b/core/file_utils.c deleted file mode 100644 index 7d2358d2460dfa27c5d8bc20f0966c428f495860..0000000000000000000000000000000000000000 --- a/core/file_utils.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Authors: - * Aleksandr Lysikov <alexander.lysikov@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 - * All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <errno.h> -#if (OS_TARGET == OS_MACOS) - #include <stdio.h> -#else - #include <malloc.h> -#endif -#include <string.h> -#include <sys/stat.h> -#include "file_utils.h" - -#ifdef _WIN32 -#include <windows.h> -#include <io.h> -#define DIR_SEPARATOR '\\' -#else -#define DIR_SEPARATOR '/' -#endif -#define IS_DIR_SEPARATOR(c) ((c) == DIR_SEPARATOR || (c) == '/') - -/** - * Check the directory path for unsupported symbols - * - * @string - * @return true, if the directory path contains only ASCII symbols - */ -bool valid_ascii_symbols(const char *string) -{ - if(!string) - return true; - for(size_t i = 0; i < strlen(string); i++) { - if((uint8_t) string[i] > 0x7f) - return false; - } - return true; -} - -/** - * Check the directory for exists - * - * @dir_path directory pathname - * @return true, if the file is a directory - */ -bool dir_test(const char * dir_path) -{ - if(!dir_path) - return false; -#ifdef _WIN32 - int attr = GetFileAttributesA(dir_path); - if(attr != -1 && (attr & FILE_ATTRIBUTE_DIRECTORY)) - return true; -#else - struct stat st; - if (!stat(dir_path, &st)) { - if (S_ISDIR(st.st_mode)) - return true; - } -#endif - return false; -} - -/** - * Create a new directory with intermediate sub-directories - * - * @dir_path new directory pathname - * @return 0, if the directory was created or already exist, else -1 - */ -int mkdir_with_parents(const char *dir_path) -{ - - char *path, *p; - // validation of a pointer - if(dir_path == NULL || dir_path[0] == '\0') { - errno = EINVAL; - return -1; - } - path = strdup(dir_path); - // skip the root component if it is present, i.e. the "/" in Unix or "C:\" in Windows -#ifdef _WIN32 - if(((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) - && (path[1] == ':') && IS_DIR_SEPARATOR(path[2])) { - p = path + 3; - } -#else - if (IS_DIR_SEPARATOR(path[0])) { - p = path + 1; - } -#endif - else - p = path; - - do { - while(*p && !IS_DIR_SEPARATOR(*p)) - p++; - - if(!*p) - p = NULL; - else - *p = '\0'; - - if(!dir_test(path)) { -#ifdef _WIN32 - int result = mkdir(path); -#else - int result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); -#endif - if(result == -1) { - free(path); - errno = ENOTDIR; - return -1; - } - } - if(p) { - *p++ = DIR_SEPARATOR; - while(*p && IS_DIR_SEPARATOR(*p)) - p++; - } - } while(p); - - free(path); - return 0; -} - diff --git a/test/core/dap_strfuncs_test.c b/test/core/dap_strfuncs_test.c index d114d07892416bb3f9e52c23d4c81ee0b67d7494..f440b2e512007bdc1079d1eb1e064e378479fde9 100644 --- a/test/core/dap_strfuncs_test.c +++ b/test/core/dap_strfuncs_test.c @@ -1,5 +1,7 @@ #include "dap_common.h" #include "dap_strfuncs_test.h" +#include "dap_list.h" +#include "dap_string.h" void dap_str_dup_test(void) { @@ -76,6 +78,57 @@ void dap_str_array_test(void) DAP_DELETE(l_s_out); } +static void list_delete(void* a_pointer) +{ + DAP_DELETE(a_pointer); +} + +void dap_list_test(void) +{ + dap_list_t *l_list = NULL; + l_list = dap_list_append(l_list, "item 1"); + l_list = dap_list_append(l_list, "item 2"); + l_list = dap_list_append(l_list, "item 3"); + l_list = dap_list_prepend(l_list, "item 0"); + + dap_list_t *l_list_tmp = dap_list_find(l_list, "item 2"); + unsigned int l_count = dap_list_length(l_list); + dap_list_remove(l_list, "item 3"); + unsigned int l_count_after = dap_list_length(l_list); + + dap_assert_PIF(l_count == 4, "Test dap_list_length()"); + dap_assert_PIF(l_count_after == 3, "Test dap_list_remove()"); + dap_assert_PIF(!strcmp(l_list_tmp->data, "item 2"), "Test dap_list_find()"); + dap_list_free(l_list); + + // for test dap_list_free_full() + l_list = NULL; + l_list = dap_list_append(l_list, dap_strdup("item 1")); + l_list = dap_list_append(l_list, dap_strdup("item 2")); + + dap_assert(l_list, "Test dap_list_t"); + dap_list_free_full(l_list, list_delete); +} + +void dap_string_test(void) +{ + dap_string_t *l_str = dap_string_new(NULL); + dap_string_append(l_str, "str=string 1"); + dap_assert_PIF(!strcmp(l_str->str, "str=string 1"), "Test dap_string_append()"); + + dap_string_append_printf(l_str, " int=%d", 123); + dap_assert_PIF(!strcmp(l_str->str, "str=string 1 int=123"), "Test dap_string_append()"); + + dap_string_erase(l_str, 3, 9); + dap_assert_PIF(!strcmp(l_str->str, "str int=123"), "Test dap_string_erase()"); + + dap_string_append_len(l_str, " string2", strlen(" string2")); + dap_assert_PIF(!strcmp(l_str->str, "str int=123 string2"), "Test dap_string_append_len()"); + + dap_assert(l_str, "Test dap_list_t"); + dap_string_free(l_str, true); +} + void dap_strfuncs_tests_run(void) { dap_print_module_name("dap_strfuncs"); @@ -83,6 +136,8 @@ void dap_strfuncs_tests_run(void) dap_str_dup_test(); dap_str_modify_test(); dap_str_array_test(); + dap_list_test(); + dap_string_test(); dap_usleep(0.5 * DAP_USEC_PER_SEC); dap_assert(1, "Test dap_usleep(0.5 sec.)");