diff options
| author | ruki <[email protected]> | 2019-07-11 17:27:00 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2019-07-11 17:27:00 +0800 |
| commit | 5df725a007759b9821ac624e870b558ae0340853 (patch) | |
| tree | 4a2fba76a420dcc801c0c699bc9fe5f4eecbed05 /core/src | |
| parent | 4bc4a680ec5b6769955f655aa0bc0c0da56cbe80 (diff) | |
| parent | 45a4253be8540240758a69eb8c0c103a3edde057 (diff) | |
Merge branch 'utf8' into dev
Diffstat (limited to 'core/src')
29 files changed, 2290 insertions, 177 deletions
diff --git a/core/src/demo/xmake.c b/core/src/demo/xmake.c index 9c2d489d1..f7c8e6cc5 100644 --- a/core/src/demo/xmake.c +++ b/core/src/demo/xmake.c @@ -1,6 +1,6 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * includes - */ + */ #include "xmake/xmake.h" /* ////////////////////////////////////////////////////////////////////////////////////// @@ -12,7 +12,7 @@ tb_int_t main(tb_int_t argc, tb_char_t** argv) tb_int_t ok = -1; // init xmake - if (xm_init()) + if (xm_init()) { // init machine xm_machine_ref_t machine = xm_machine_init(); diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua index 4aceb3340..edd6adfdd 100644 --- a/core/src/demo/xmake.lua +++ b/core/src/demo/xmake.lua @@ -4,7 +4,7 @@ target("demo") -- add deps add_deps("xmake") - -- make as a binary + -- make as a binary set_kind("binary") -- set basename of target file @@ -28,8 +28,8 @@ target("demo") end -- add links - if is_plat("windows") then - add_links("ws2_32", "advapi32") + if is_plat("windows") then + add_links("ws2_32", "advapi32", "shell32") elseif is_plat("android") then add_links("m", "c") elseif is_plat("macosx") then diff --git a/core/src/tbox/inc/linux/tbox.config.h b/core/src/tbox/inc/linux/tbox.config.h index ccc0cabe0..1b2590f12 100755 --- a/core/src/tbox/inc/linux/tbox.config.h +++ b/core/src/tbox/inc/linux/tbox.config.h @@ -2,47 +2,84 @@ #define TB_CONFIG_H // version -#define TB_CONFIG_VERSION "1.6.2" +#define TB_CONFIG_VERSION "1.6.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 6 -#define TB_CONFIG_VERSION_ALTER 2 -#define TB_CONFIG_VERSION_BUILD 201705202359 +#define TB_CONFIG_VERSION_ALTER 3 +#define TB_CONFIG_VERSION_BUILD 201907051345 // defines #define TB_CONFIG_OS_LINUX 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 +/* #undef TB_CONFIG_MICRO_ENABLE */ +/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 +#define TB_CONFIG_FORCE_UTF8 1 + +// keywords +#define TB_CONFIG_KEYWORD_HAVE__thread 1 +#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 + +// modules +/* #undef TB_CONFIG_MODULE_HAVE_XML */ +/* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 +/* #undef TB_CONFIG_MODULE_HAVE_REGEX */ +/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ +#define TB_CONFIG_MODULE_HAVE_CHARSET 1 +/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ +/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ + +// packages +/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ +/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ +/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ +/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ +/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ + +// libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 #define TB_CONFIG_LIBC_HAVE_MEMCMP 1 +#define TB_CONFIG_LIBC_HAVE_MEMMEM 1 #define TB_CONFIG_LIBC_HAVE_STRCAT 1 #define TB_CONFIG_LIBC_HAVE_STRNCAT 1 #define TB_CONFIG_LIBC_HAVE_STRCPY 1 #define TB_CONFIG_LIBC_HAVE_STRNCPY 1 +/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 +#define TB_CONFIG_LIBC_HAVE_STRCHR 1 +#define TB_CONFIG_LIBC_HAVE_STRRCHR 1 +#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 + #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 #define TB_CONFIG_LIBC_HAVE_WCSNCPY 1 +/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 +/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 + #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 @@ -53,9 +90,19 @@ #define TB_CONFIG_LIBC_HAVE_KILL 1 #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 +#define TB_CONFIG_LIBC_HAVE_FPUTC 1 +#define TB_CONFIG_LIBC_HAVE_FGETC 1 +#define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 +#define TB_CONFIG_LIBC_HAVE_FGETS 1 +#define TB_CONFIG_LIBC_HAVE_FREAD 1 +#define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 + +// libm functions +#define TB_CONFIG_LIBM_HAVE_SINCOS 1 +#define TB_CONFIG_LIBM_HAVE_SINCOSF 1 #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 @@ -80,6 +127,8 @@ #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 + +// posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 @@ -88,28 +137,36 @@ #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 +#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP 1 #define TB_CONFIG_POSIX_HAVE_SOCKET 1 +#define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 +#define TB_CONFIG_POSIX_HAVE_STAT64 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1 #define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1 #define TB_CONFIG_POSIX_HAVE_SEM_INIT 1 #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 +#define TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY 1 #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 #define TB_CONFIG_POSIX_HAVE_PREADV 1 #define TB_CONFIG_POSIX_HAVE_PWRITEV 1 +#define TB_CONFIG_POSIX_HAVE_PREAD64 1 +#define TB_CONFIG_POSIX_HAVE_PWRITE64 1 #define TB_CONFIG_POSIX_HAVE_FDATASYNC 1 +/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */ #define TB_CONFIG_POSIX_HAVE_SENDFILE 1 #define TB_CONFIG_POSIX_HAVE_EPOLL_CREATE 1 #define TB_CONFIG_POSIX_HAVE_EPOLL_WAIT 1 #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 +#define TB_CONFIG_POSIX_HAVE_EXECVPE 1 #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 @@ -119,6 +176,12 @@ #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 + +// systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 +#define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1 + +// valgrind functions +/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif diff --git a/core/src/tbox/inc/macosx/tbox.config.h b/core/src/tbox/inc/macosx/tbox.config.h index 0fa89b373..5bfbea9cc 100755 --- a/core/src/tbox/inc/macosx/tbox.config.h +++ b/core/src/tbox/inc/macosx/tbox.config.h @@ -2,19 +2,47 @@ #define TB_CONFIG_H // version -#define TB_CONFIG_VERSION "1.6.2" +#define TB_CONFIG_VERSION "1.6.3" #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 6 -#define TB_CONFIG_VERSION_ALTER 2 -#define TB_CONFIG_VERSION_BUILD 201705202248 +#define TB_CONFIG_VERSION_ALTER 3 +#define TB_CONFIG_VERSION_BUILD 201907052137 // defines #define TB_CONFIG_OS_MACOSX 1 #define _GNU_SOURCE 1 #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 +/* #undef TB_CONFIG_MICRO_ENABLE */ +/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */ #define TB_CONFIG_TYPE_HAVE_FLOAT 1 +#define TB_CONFIG_FORCE_UTF8 1 + +// keywords +#define TB_CONFIG_KEYWORD_HAVE__thread 1 +#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1 + +// modules +/* #undef TB_CONFIG_MODULE_HAVE_XML */ +/* #undef TB_CONFIG_MODULE_HAVE_ZIP */ #define TB_CONFIG_MODULE_HAVE_HASH 1 +/* #undef TB_CONFIG_MODULE_HAVE_REGEX */ +/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */ +#define TB_CONFIG_MODULE_HAVE_CHARSET 1 +/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */ +/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */ + +// packages +/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */ +/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */ +/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */ +/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */ +/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */ +/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */ + +// libc functions #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 #define TB_CONFIG_LIBC_HAVE_MEMMOVE 1 @@ -28,11 +56,14 @@ #define TB_CONFIG_LIBC_HAVE_STRLEN 1 #define TB_CONFIG_LIBC_HAVE_STRNLEN 1 #define TB_CONFIG_LIBC_HAVE_STRSTR 1 +#define TB_CONFIG_LIBC_HAVE_STRCHR 1 +#define TB_CONFIG_LIBC_HAVE_STRRCHR 1 #define TB_CONFIG_LIBC_HAVE_STRCASESTR 1 #define TB_CONFIG_LIBC_HAVE_STRCMP 1 #define TB_CONFIG_LIBC_HAVE_STRCASECMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCMP 1 #define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1 + #define TB_CONFIG_LIBC_HAVE_WCSCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSNCAT 1 #define TB_CONFIG_LIBC_HAVE_WCSCPY 1 @@ -41,12 +72,14 @@ #define TB_CONFIG_LIBC_HAVE_WCSLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSNLEN 1 #define TB_CONFIG_LIBC_HAVE_WCSSTR 1 +/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */ #define TB_CONFIG_LIBC_HAVE_WCSCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCMP 1 #define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1 #define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1 #define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1 + #define TB_CONFIG_LIBC_HAVE_GMTIME 1 #define TB_CONFIG_LIBC_HAVE_MKTIME 1 #define TB_CONFIG_LIBC_HAVE_LOCALTIME 1 @@ -57,9 +90,19 @@ #define TB_CONFIG_LIBC_HAVE_KILL 1 #define TB_CONFIG_LIBC_HAVE_BACKTRACE 1 #define TB_CONFIG_LIBC_HAVE_SETLOCALE 1 +#define TB_CONFIG_LIBC_HAVE_FPUTC 1 +#define TB_CONFIG_LIBC_HAVE_FGETC 1 +#define TB_CONFIG_LIBC_HAVE_UNGETC 1 #define TB_CONFIG_LIBC_HAVE_FPUTS 1 +#define TB_CONFIG_LIBC_HAVE_FGETS 1 +#define TB_CONFIG_LIBC_HAVE_FREAD 1 +#define TB_CONFIG_LIBC_HAVE_FWRITE 1 #define TB_CONFIG_LIBC_HAVE_SRANDOM 1 #define TB_CONFIG_LIBC_HAVE_RANDOM 1 + +// libm functions +/* #undef TB_CONFIG_LIBM_HAVE_SINCOS */ +/* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */ #define TB_CONFIG_LIBM_HAVE_LOG2 1 #define TB_CONFIG_LIBM_HAVE_LOG2F 1 #define TB_CONFIG_LIBM_HAVE_SQRT 1 @@ -84,6 +127,8 @@ #define TB_CONFIG_LIBM_HAVE_SINF 1 #define TB_CONFIG_LIBM_HAVE_EXP 1 #define TB_CONFIG_LIBM_HAVE_EXPF 1 + +// posix functions #define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_SELECT 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1 @@ -92,7 +137,9 @@ #define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1 #define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1 +/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */ #define TB_CONFIG_POSIX_HAVE_SOCKET 1 +#define TB_CONFIG_POSIX_HAVE_POLL 1 #define TB_CONFIG_POSIX_HAVE_OPENDIR 1 #define TB_CONFIG_POSIX_HAVE_DLOPEN 1 #define TB_CONFIG_POSIX_HAVE_OPEN 1 @@ -103,13 +150,23 @@ #define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1 #define TB_CONFIG_POSIX_HAVE_SYSCONF 1 #define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1 +/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */ #define TB_CONFIG_POSIX_HAVE_REGCOMP 1 #define TB_CONFIG_POSIX_HAVE_REGEXEC 1 #define TB_CONFIG_POSIX_HAVE_READV 1 #define TB_CONFIG_POSIX_HAVE_WRITEV 1 +/* #undef TB_CONFIG_POSIX_HAVE_PREADV */ +/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */ +/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */ +/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */ +/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */ #define TB_CONFIG_POSIX_HAVE_COPYFILE 1 +/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */ +/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */ +/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */ #define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1 #define TB_CONFIG_POSIX_HAVE_EXECVP 1 +/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */ #define TB_CONFIG_POSIX_HAVE_FORK 1 #define TB_CONFIG_POSIX_HAVE_VFORK 1 #define TB_CONFIG_POSIX_HAVE_WAITPID 1 @@ -119,6 +176,12 @@ #define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1 #define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1 + +// systemv functions #define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1 +/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */ + +// valgrind functions +/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */ #endif diff --git a/core/src/tbox/inc/windows/tbox.config.h b/core/src/tbox/inc/windows/tbox.config.h deleted file mode 100755 index 4cc30f8d8..000000000 --- a/core/src/tbox/inc/windows/tbox.config.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TB_CONFIG_H
-#define TB_CONFIG_H
-
-// version
-#define TB_CONFIG_VERSION "1.6.2"
-#define TB_CONFIG_VERSION_MAJOR 1
-#define TB_CONFIG_VERSION_MINOR 6
-#define TB_CONFIG_VERSION_ALTER 2
-#define TB_CONFIG_VERSION_BUILD 201707201725
-
-// defines
-#define TB_CONFIG_OS_WINDOWS 1
-#define _GNU_SOURCE 1
-#define _REENTRANT 1
-#define TB_CONFIG_SMALL 1
-#define TB_CONFIG_TYPE_HAVE_FLOAT 1
-#define TB_CONFIG_MODULE_HAVE_HASH 1
-#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
-#define TB_CONFIG_LIBC_HAVE_MEMSET 1
-#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
-#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
-#define TB_CONFIG_LIBC_HAVE_STRCAT 1
-#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
-#define TB_CONFIG_LIBC_HAVE_STRCPY 1
-#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
-#define TB_CONFIG_LIBC_HAVE_STRLEN 1
-#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
-#define TB_CONFIG_LIBC_HAVE_STRSTR 1
-#define TB_CONFIG_LIBC_HAVE_STRCMP 1
-#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
-#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
-#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
-#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
-#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
-#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
-#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
-#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
-#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
-#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
-#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
-#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
-#define TB_CONFIG_LIBC_HAVE_GMTIME 1
-#define TB_CONFIG_LIBC_HAVE_MKTIME 1
-#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
-#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
-#define TB_CONFIG_LIBC_HAVE_SETJMP 1
-#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
-#define TB_CONFIG_LIBC_HAVE_FPUTS 1
-#define TB_CONFIG_LIBM_HAVE_SQRT 1
-#define TB_CONFIG_LIBM_HAVE_ACOS 1
-#define TB_CONFIG_LIBM_HAVE_ASIN 1
-#define TB_CONFIG_LIBM_HAVE_POW 1
-#define TB_CONFIG_LIBM_HAVE_FMOD 1
-#define TB_CONFIG_LIBM_HAVE_TAN 1
-#define TB_CONFIG_LIBM_HAVE_ATAN 1
-#define TB_CONFIG_LIBM_HAVE_ATAN2 1
-#define TB_CONFIG_LIBM_HAVE_COS 1
-#define TB_CONFIG_LIBM_HAVE_SIN 1
-#define TB_CONFIG_LIBM_HAVE_EXP 1
-
-#endif
diff --git a/core/src/tbox/makefile b/core/src/tbox/makefile index 11038c4e4..51dc1ae1c 100644 --- a/core/src/tbox/makefile +++ b/core/src/tbox/makefile @@ -47,6 +47,7 @@ tbox_C_FILES += \ tbox/src/tbox/libc/string/memset \ tbox/src/tbox/libc/string/strcat \ tbox/src/tbox/libc/string/strchr \ + tbox/src/tbox/libc/string/strnchr \ tbox/src/tbox/libc/string/strcmp \ tbox/src/tbox/libc/string/strcpy \ tbox/src/tbox/libc/string/strdup \ @@ -128,6 +129,7 @@ tbox_C_FILES += \ tbox/src/tbox/stream/filter \ tbox/src/tbox/stream/impl/filter/cache \ tbox/src/tbox/stream/impl/filter/chunked \ + tbox/src/tbox/stream/impl/filter/charset \ tbox/src/tbox/stream/impl/stream/data \ tbox/src/tbox/stream/impl/stream/file \ tbox/src/tbox/stream/impl/stream/filter \ @@ -199,6 +201,7 @@ tbox_C_FILES += \ tbox/src/tbox/container/stack \ tbox/src/tbox/container/vector \ tbox/src/tbox/libm/impl/libm \ + tbox/src/tbox/libm/exp \ tbox/src/tbox/libm/ilog2i \ tbox/src/tbox/libm/isqrti \ tbox/src/tbox/libm/idivi8 \ @@ -220,6 +223,7 @@ tbox_C_FILES += \ tbox/src/tbox/platform/path \ tbox/src/tbox/platform/poller \ tbox/src/tbox/platform/print \ + tbox/src/tbox/platform/stdfile \ tbox/src/tbox/platform/process \ tbox/src/tbox/platform/processor \ tbox/src/tbox/platform/sched \ @@ -230,6 +234,7 @@ tbox_C_FILES += \ tbox/src/tbox/platform/thread_local \ tbox/src/tbox/platform/time \ tbox/src/tbox/platform/timer \ + tbox/src/tbox/platform/impl/charset \ tbox/src/tbox/platform/impl/sockdata \ tbox/src/tbox/platform/impl/dns \ tbox/src/tbox/platform/impl/platform \ diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject ad025d12b7dfc9a993da2c7a75bd1e9cd70bd57 +Subproject 32e03f155426a393c3d5fce302366a9ec52d423 diff --git a/core/src/tbox/xmake.lua b/core/src/tbox/xmake.lua index 563fd12d5..3469900ec 100644 --- a/core/src/tbox/xmake.lua +++ b/core/src/tbox/xmake.lua @@ -1,7 +1,7 @@ includes("tbox") --- enable hash, charset modules -for _, name in ipairs({"hash", "charset"}) do +-- enable hash, charset, utf8 modules +for _, name in ipairs({ "hash", "charset", "force-utf8" }) do option(name) set_default(true) after_check(function (option) diff --git a/core/src/xmake/io/file.h b/core/src/xmake/io/file.h new file mode 100644 index 000000000..900ef00b6 --- /dev/null +++ b/core/src/xmake/io/file.h @@ -0,0 +1,146 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file.h + * + */ +#ifndef XM_IO_FILE_H +#define XM_IO_FILE_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ +#define xm_io_file_is_file(file) ((file)->type == XM_IO_FILE_TYPE_FILE) +#define xm_io_file_is_std(file) ((file)->type != XM_IO_FILE_TYPE_FILE) + +#define xm_io_file_is_closed_file(file) (xm_io_file_is_file(file) && !((file)->file_ref)) +#define xm_io_file_is_closed_std(file) (xm_io_file_is_std(file) && !((file)->std_ref)) + +#define xm_io_file_is_tty(file) (!!((file)->type & XM_IO_FILE_FLAG_TTY)) +#define xm_io_file_is_closed(file) (xm_io_file_is_closed_file(file) || xm_io_file_is_closed_std(file)) + +#define xm_io_file_udata "XM_IO_FILE*" + +#define xm_io_file_return_success() \ + do \ + { \ + return 1; \ + } while (0) + +#define xm_io_file_return_error(lua, file, reason) \ + do \ + { \ + lua_pushnil(lua); \ + lua_pushfstring(lua, "error: %s (%s)", reason, file->name); \ + return 2; \ + } while (0) + +#define xm_io_file_return_error_closed(lua) \ + do \ + { \ + lua_pushnil(lua); \ + lua_pushliteral(lua, "error: file has been closed"); \ + return 2; \ + } while (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ +typedef enum __xm_io_file_type_e +{ + XM_IO_FILE_TYPE_FILE = 0 //!< disk file + +, XM_IO_FILE_TYPE_STDIN = 1 +, XM_IO_FILE_TYPE_STDOUT = 2 +, XM_IO_FILE_TYPE_STDERR = 3 + +, XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream + +} xm_io_file_type_e; + +/* use negetive numbers for this enum, its a extension for tb_charset_type_e + * before adding new values, make sure they have not conflicts with values in tb_charset_type_e + */ +typedef enum __xm_io_file_encoding_e +{ + XM_IO_FILE_ENCODING_UNKNOWN = -1 +, XM_IO_FILE_ENCODING_BINARY = -2 + +} xm_io_file_encoding_e; + +typedef struct __xm_io_file +{ + union + { + /* the normal file for XM_IO_FILE_TYPE_FILE + * + * direct: file_ref -> stream -> file + * transcode: file_ref -> fstream -> stream -> file + */ + tb_stream_ref_t file_ref; + + // the standard io file + tb_stdfile_ref_t std_ref; + }; + + tb_stream_ref_t stream; // the file stream for XM_IO_FILE_TYPE_FILE + tb_stream_ref_t fstream; // the file charset stream filter + tb_size_t mode; // tb_file_mode_t + tb_size_t type; // xm_io_file_type_e + tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e + tb_char_t name[64]; + tb_char_t const* path; + tb_buffer_t rcache; // the read line cache buffer + tb_buffer_t wcache; // the write line cache buffer +} xm_io_file; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ +static __tb_inline__ xm_io_file* xm_io_newfile(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, tb_null); + + // new file + xm_io_file* file = (xm_io_file*)lua_newuserdata(lua, sizeof(xm_io_file)); + tb_assert_and_check_return_val(file, tb_null); + + // init file + luaL_getmetatable(lua, xm_io_file_udata); + lua_setmetatable(lua, -2); + tb_memset(file, 0, sizeof(xm_io_file)); + return file; +} + +static __tb_inline__ xm_io_file* xm_io_getfile(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, tb_null); + + // get file + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + tb_assert(file); + return file; +} + +#endif diff --git a/core/src/xmake/io/file___len.c b/core/src/xmake/io/file___len.c new file mode 100644 index 000000000..449df7d3c --- /dev/null +++ b/core/src/xmake/io/file___len.c @@ -0,0 +1,56 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file___len.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file___len" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* get file length, #file + */ +tb_int_t xm_io_file___len(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = xm_io_getfile(lua); + if (xm_io_file_is_closed(file)) + xm_io_file_return_error_closed(lua); + else if (xm_io_file_is_file(file)) + { + // get size from raw file stream, because we cannot get size from fstream + tb_assert(file->stream); + lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream)); + xm_io_file_return_success(); + } + else xm_io_file_return_error(lua, file, "getting file size for this file is invalid"); +} diff --git a/core/src/xmake/io/isatty.c b/core/src/xmake/io/file___tostring.c index d4dd7b57d..8290d358a 100644 --- a/core/src/xmake/io/isatty.c +++ b/core/src/xmake/io/file___tostring.c @@ -11,57 +11,41 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * + * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author ruki - * @file isatty.c + * @author OpportunityLiu + * @file file___tostring.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ -#define TB_TRACE_MODULE_NAME "isatty" -#define TB_TRACE_MODULE_DEBUG (0) +#define TB_TRACE_MODULE_NAME "file___tostring" +#define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ +#include "file.h" #include "prefix.h" -#ifdef TB_CONFIG_OS_WINDOWS -# include <io.h> -#else -# include <unistd.h> -#endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -/* stdout: io.isatty() - * stderr: io.isatty(io.stderr) - * stdin: io.isatty(io.stdin) +/* + * tostring(file) */ -tb_int_t xm_io_isatty(lua_State* lua) +tb_int_t xm_io_file___tostring(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - // get file pointer - FILE** fp = (FILE**)luaL_checkudata(lua, 1, LUA_FILEHANDLE); - - // no arguments? default: stdout - tb_int_t answer = 1; -#ifdef TB_CONFIG_OS_WINDOWS - if (fp) answer = _isatty(_fileno(*fp)); -#else - if (fp) answer = isatty(fileno(*fp)); -#endif - - // return answer - lua_pushboolean(lua, answer); - - // ok + // get file name as string + xm_io_file* file = xm_io_getfile(lua); + lua_pushstring(lua, file->name); return 1; } + diff --git a/core/src/xmake/io/file_close___gc.c b/core/src/xmake/io/file_close___gc.c new file mode 100644 index 000000000..3ff136f6a --- /dev/null +++ b/core/src/xmake/io/file_close___gc.c @@ -0,0 +1,123 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_close___gc.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_close___gc" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +static tb_int_t xm_io_file_close_impl(lua_State* lua, tb_bool_t allow_closed_file) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = xm_io_getfile(lua); + if (xm_io_file_is_closed(file)) + { + if (allow_closed_file) + { + lua_pushboolean(lua, tb_true); + xm_io_file_return_success(); + } + else xm_io_file_return_error_closed(lua); + } + if (xm_io_file_is_file(file)) + { + // check + tb_assert(file->file_ref); + +#ifdef TB_CONFIG_OS_WINDOWS + // write cached data first + tb_byte_t const* odata = tb_buffer_data(&file->wcache); + tb_size_t osize = tb_buffer_size(&file->wcache); + if (odata && osize) + { + if (!tb_stream_bwrit(file->file_ref, odata, osize)) return tb_false; + tb_buffer_clear(&file->wcache); + } +#endif + + // close file + if (!tb_stream_clos(file->file_ref)) + xm_io_file_return_error(lua, file, "failed to close file"); + file->file_ref = tb_null; + + // exit fstream + if (file->fstream) tb_stream_exit(file->fstream); + file->fstream = tb_null; + + // exit stream + if (file->stream) tb_stream_exit(file->stream); + file->stream = tb_null; + + // exit the line cache buffer + tb_buffer_exit(&file->rcache); + tb_buffer_exit(&file->wcache); + + // free file path + if (file->path) + { + tb_free(file->path); + file->path = tb_null; + } + + // mark this file as closed + tb_strlcpy(file->name, "file: (closed file)", tb_arrayn(file->name)); + lua_pushboolean(lua, tb_true); + xm_io_file_return_success(); + } + else + { + lua_pushboolean(lua, tb_true); + xm_io_file_return_success(); + } +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +/* + * file:close() + */ +tb_int_t xm_io_file_close(lua_State* lua) +{ + return xm_io_file_close_impl(lua, tb_false); +} + +/* + * file:close() + */ +tb_int_t xm_io_file___gc(lua_State* lua) +{ + return xm_io_file_close_impl(lua, tb_true); +} diff --git a/core/src/xmake/io/file_flush.c b/core/src/xmake/io/file_flush.c new file mode 100644 index 000000000..ccab16310 --- /dev/null +++ b/core/src/xmake/io/file_flush.c @@ -0,0 +1,86 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_flush.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_flush" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_bool_t xm_io_std_flush_impl(xm_io_file* file) +{ + tb_assert_and_check_return_val(xm_io_file_is_std(file) && !xm_io_file_is_closed(file), tb_false); + return (file->std_ref != tb_stdfile_input())? tb_stdfile_flush(file->std_ref) : tb_false; +} + +static tb_bool_t xm_io_file_flush_impl(xm_io_file* file) +{ + // check + tb_assert_and_check_return_val(xm_io_file_is_file(file) && !xm_io_file_is_closed(file), tb_false); + +#ifdef TB_CONFIG_OS_WINDOWS + // write cached data first + tb_byte_t const* odata = tb_buffer_data(&file->wcache); + tb_size_t osize = tb_buffer_size(&file->wcache); + if (odata && osize) + { + if (!tb_stream_bwrit(file->file_ref, odata, osize)) return tb_false; + tb_buffer_clear(&file->wcache); + } +#endif + return tb_stream_sync(file->file_ref, tb_false); +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +/* + * file:flush() + */ +tb_int_t xm_io_file_flush(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // file has been closed? + xm_io_file* file = xm_io_getfile(lua); + if (xm_io_file_is_closed(file)) + xm_io_file_return_error_closed(lua); + + // flush file + tb_bool_t ok = xm_io_file_is_file(file) ? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file); + if (ok) + { + lua_pushboolean(lua, tb_true); + xm_io_file_return_success(); + } + else xm_io_file_return_error(lua, file, "failed to flush file"); +} diff --git a/core/src/xmake/io/file_isatty.c b/core/src/xmake/io/file_isatty.c new file mode 100644 index 000000000..e09ea9b13 --- /dev/null +++ b/core/src/xmake/io/file_isatty.c @@ -0,0 +1,49 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_isatty.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_isatty" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* file:isatty() + */ +tb_int_t xm_io_file_isatty(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is tty? + xm_io_file* file = xm_io_getfile(lua); + lua_pushboolean(lua, xm_io_file_is_tty(file)); + return 1; +} diff --git a/core/src/xmake/io/file_path.c b/core/src/xmake/io/file_path.c new file mode 100644 index 000000000..92ecfa3c5 --- /dev/null +++ b/core/src/xmake/io/file_path.c @@ -0,0 +1,55 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_path.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_path" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* file:path() + */ +tb_int_t xm_io_file_path(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // this file has been closed? + xm_io_file* file = xm_io_getfile(lua); + if (xm_io_file_is_closed(file)) + xm_io_file_return_error_closed(lua); + else + { + // return file path + lua_pushstring(lua, file->path); + return 1; + } +} diff --git a/core/src/xmake/io/file_read.c b/core/src/xmake/io/file_read.c new file mode 100644 index 000000000..7cfae3a93 --- /dev/null +++ b/core/src/xmake/io/file_read.c @@ -0,0 +1,554 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_read.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_read" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" +#include "file.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ +typedef enum __xm_pushline_state_e +{ + PL_EOF, + PL_FIN, + PL_CONL, + PL_FAIL, + +} xm_pushline_state_e; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_ref_t line) +{ + // check + tb_assert_and_check_return_val(stream && line, -1); + + // read line and reserve crlf + tb_bool_t eof = tb_false; + tb_hize_t offset = 0; + tb_byte_t* data = tb_null; + tb_hong_t size = tb_stream_size(stream); + while (size < 0 || (offset = tb_stream_offset(stream)) < size) + { + tb_long_t real = tb_stream_peek(stream, &data, TB_STREAM_BLOCK_MAXN); + if (real > 0) + { + tb_char_t const* e = tb_strnchr((tb_char_t const*)data, real, '\n'); + if (e) + { + tb_size_t n = (tb_byte_t const*)e + 1 - data; + if (!tb_stream_skip(stream, n)) return -1; + tb_buffer_memncat(line, data, n); + break; + } + else + { + if (!tb_stream_skip(stream, real)) return -1; + tb_buffer_memncat(line, data, real); + } + } + else if (!real) + { + real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); + if (real <= 0) + { + eof = tb_true; + break; + } + } + else + { + eof = tb_true; + break; + } + } + + // ok? + tb_size_t linesize = tb_buffer_size(line); + if (linesize) return linesize; + else return (eof || tb_stream_beof(stream))? -1 : 0; +} +static tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + // check + tb_assert(buf && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // is binary? + tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; + if (is_binary) + { + continuation = ""; + keep_crlf = tb_true; + } + + // clear line buffer + tb_buffer_clear(&file->rcache); + + // read line data + tb_long_t size = xm_io_file_buffer_readline(file->file_ref, &file->rcache); + + // translate line data + tb_int_t result = PL_FAIL; + tb_char_t* data = tb_null; + tb_size_t conlen = tb_strlen(continuation); + do + { + // eof? + if (size < 0) + { + result = PL_EOF; + break; + } + + // patch two '\0' + tb_buffer_memncat(&file->rcache, (tb_byte_t const*)"\0\0", 2); + + // get line data + data = (tb_char_t*)tb_buffer_data(&file->rcache); + tb_assert_and_check_break(data); + + // no lf found + if (size > 0 && data[size - 1] != '\n') + result = PL_FIN; + else if (size > 1) + { + // crlf? => lf + if (!is_binary && data[size - 2] == '\r') + { + data[size - 2] = '\n'; + size--; + } + + // has continuation? + tb_bool_t has_conline = conlen && size >= conlen + 1 && tb_strncmp(continuation, (tb_char_t const*)(data + size - conlen - 1), conlen) == 0; + + // do not keep crlf, strip the last lf + if (!keep_crlf && !has_conline) size--; + + // strip it if has continuation? + if (has_conline) size -= conlen + 1; + data[size] = '\0'; + + result = has_conline ? PL_CONL : PL_FIN; + } + else + { + // a single '\n' + if (!keep_crlf) size = 0; + result = PL_FIN; + } + + } while (0); + + // push line data + if (data && size > 0 && (result == PL_FIN || result == PL_CONL)) + tb_buffer_memncat(buf, (tb_byte_t const*)data, size); + + // return result + return result; +} +static tb_int_t xm_io_file_read_all_directly(lua_State* lua, xm_io_file* file) +{ + // check + tb_assert(lua && file && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // init buffer + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) + xm_io_file_return_error(lua, file, "init buffer failed!"); + + // read all + tb_byte_t data[TB_STREAM_BLOCK_MAXN]; + tb_stream_ref_t stream = file->file_ref; + while (!tb_stream_beof(stream)) + { + tb_long_t real = tb_stream_read(stream, data, sizeof(data)); + if (real > 0) + tb_buffer_memncat(&buf, data, real); + else if (!real) + { + real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); + tb_check_break(real > 0); + } + else break; + } + + if (tb_buffer_size(&buf)) + lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + else lua_pushliteral(lua, ""); + tb_buffer_exit(&buf); + return 1; +} +static tb_int_t xm_io_file_read_all(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // is binary? read all directly + tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; + if (is_binary) + return xm_io_file_read_all_directly(lua, file); + + // init buffer + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) + xm_io_file_return_error(lua, file, "init buffer failed!"); + + // read all + tb_bool_t has_content = tb_false; + while (1) + { + switch (xm_io_file_buffer_pushline(&buf, file, continuation, tb_true)) + { + case PL_EOF: + if (!has_content) lua_pushliteral(lua, ""); + else lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_FIN: + case PL_CONL: + has_content = tb_true; + continue; + case PL_FAIL: + default: + tb_buffer_exit(&buf); + xm_io_file_return_error(lua, file, "failed to read all"); + break; + } + } +} + +static tb_int_t xm_io_file_read_line(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // init buffer + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) + xm_io_file_return_error(lua, file, "init buffer failed!"); + + // read line + tb_bool_t has_content = tb_false; + while (1) + { + switch (xm_io_file_buffer_pushline(&buf, file, continuation, keep_crlf)) + { + case PL_EOF: + if (!has_content) lua_pushnil(lua); + else lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_FIN: + lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_CONL: + has_content = tb_true; + continue; + case PL_FAIL: + default: + tb_buffer_exit(&buf); + xm_io_file_return_error(lua, file, "failed to readline"); + break; + } + } +} + +static tb_int_t xm_io_file_read_n(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_long_t n) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // check continuation + if (*continuation != '\0') + xm_io_file_return_error(lua, file, "continuation is not supported for read number of bytes"); + + // check encoding + if (file->encoding != XM_IO_FILE_ENCODING_BINARY) + xm_io_file_return_error(lua, file, "read number of bytes only allows binary file, reopen with 'rb' and try again"); + + tb_bool_t ok = tb_false; + if (n == 0) + { + tb_byte_t* data = tb_null; + if (tb_stream_need(file->file_ref, &data, 1)) + { + lua_pushliteral(lua, ""); + ok = tb_true; + } + } + else + { + tb_byte_t* bufptr = tb_buffer_resize(&file->rcache, n + 1); + if (bufptr) + { + if (tb_stream_bread(file->file_ref, bufptr, n)) + { + lua_pushlstring(lua, (tb_char_t const*)bufptr, n); + ok = tb_true; + } + } + } + if (!ok) lua_pushnil(lua); + return 1; +} + +static tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + // check + tb_assert(buf && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // get input buffer + tb_char_t strbuf[8192]; + tb_size_t buflen = 0; + tb_size_t result = PL_FAIL; + if (tb_stdfile_gets(file->std_ref, strbuf, tb_arrayn(strbuf) - 1)) + buflen = tb_strlen(strbuf); + else return PL_EOF; + + tb_size_t conlen = tb_strlen(continuation); + if (buflen > 0 && strbuf[buflen - 1] != '\n') + { + // end of file, no lf found + result = PL_FIN; + } + else if (buflen > 1) + { + // crlf? => lf + if (strbuf[buflen - 2] == '\r') + { + strbuf[buflen - 2] = '\n'; + buflen--; + } + + // has continuation? + tb_bool_t has_conline = conlen && buflen >= conlen + 1 && tb_strncmp(continuation, (strbuf + buflen - conlen - 1), conlen) == 0; + + // do not keep crlf, strip the last lf + if (!keep_crlf && !has_conline) buflen--; + + // strip it if has continuation? + if (has_conline) buflen -= conlen + 1; + strbuf[buflen] = '\0'; + + result = has_conline? PL_CONL : PL_FIN; + } + else + { + // a single '\n' + if (!keep_crlf) buflen = 0; + result = PL_FIN; + } + + if (result == PL_FIN || result == PL_CONL) + tb_buffer_memncat(buf, (tb_byte_t const*)strbuf, buflen); + return result; +} + +static tb_int_t xm_io_file_std_read_line(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // init buffer + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) + xm_io_file_return_error(lua, file, "init buffer failed!"); + + // read line + tb_bool_t has_content = tb_false; + while (1) + { + switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, keep_crlf)) + { + case PL_EOF: + if (!has_content) lua_pushnil(lua); + else lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_FIN: + lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_CONL: + has_content = tb_true; + continue; + case PL_FAIL: + default: + tb_buffer_exit(&buf); + xm_io_file_return_error(lua, file, "failed to readline"); + break; + } + } +} + +static tb_int_t xm_io_file_std_read_all(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // init buffer + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) + xm_io_file_return_error(lua, file, "init buffer failed!"); + + // read all + tb_bool_t has_content = tb_false; + while (1) + { + switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, tb_true)) + { + case PL_EOF: + if (!has_content) lua_pushliteral(lua, ""); + else lua_pushlstring(lua, (tb_char_t const*)tb_buffer_data(&buf), tb_buffer_size(&buf)); + tb_buffer_exit(&buf); + return 1; + case PL_FIN: + case PL_CONL: + has_content = tb_true; + continue; + case PL_FAIL: + default: + tb_buffer_exit(&buf); + xm_io_file_return_error(lua, file, "failed to readline"); + break; + } + } +} + +static tb_int_t xm_io_file_std_read_n(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_long_t n) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // check continuation + if (*continuation != '\0') + xm_io_file_return_error(lua, file, "continuation is not supported for std streams"); + + // io.read(0) + if (n == 0) + { + tb_char_t ch; + if (!tb_stdfile_peek(file->std_ref, &ch)) + lua_pushnil(lua); + else + lua_pushliteral(lua, ""); + return 1; + } + + // get line buffer + tb_byte_t* buf_ptr = tb_buffer_resize(&file->rcache, (tb_size_t)n); + tb_assert(buf_ptr); + + // io.read(n) + if (tb_stdfile_read(file->std_ref, buf_ptr, (tb_size_t)n)) + lua_pushlstring(lua, (tb_char_t const*)buf_ptr, (size_t)n); + else lua_pushnil(lua); + return 1; +} + +static tb_int_t xm_io_file_std_read_num(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + // check + tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // check continuation + if (*continuation != '\0') + xm_io_file_return_error(lua, file, "continuation is not supported for std streams"); + + // read number + tb_char_t strbuf[512]; + if (tb_stdfile_gets(file->std_ref, strbuf, tb_arrayn(strbuf))) + lua_pushnumber(lua, tb_s10tod(strbuf)); // TODO check invalid float number string and push nil + else lua_pushnil(lua); + return 1; +} + +/* + * file:read([mode, [continuation]]) + * file:read("all", "\\") + * file:read("L") + * file:read(10) + */ +tb_int_t xm_io_file_read(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get file and arguments + xm_io_file* file = xm_io_getfile(lua); + tb_char_t const* mode = luaL_optstring(lua, 2, "l"); + tb_char_t const* continuation = luaL_optstring(lua, 3, ""); + tb_assert_and_check_return_val(mode && continuation, 0); + + tb_long_t count = -1; + if (lua_isnumber(lua, 2)) + { + count = (tb_long_t)lua_tointeger(lua, 2); + if (count < 0) xm_io_file_return_error(lua, file, "invalid read size, must be positive nubmber or 0"); + } + else if (*mode == '*') + mode++; + + if (xm_io_file_is_file(file)) + { + // this file has been closed? + if (xm_io_file_is_closed_file(file)) + xm_io_file_return_error_closed(lua); + + if (count >= 0) return xm_io_file_read_n(lua, file, continuation, count); + switch (*mode) + { + case 'a': return xm_io_file_read_all(lua, file, continuation); + case 'L': return xm_io_file_read_line(lua, file, continuation, tb_true); + case 'n': xm_io_file_return_error(lua, file, "read number is not implemented"); + case 'l': return xm_io_file_read_line(lua, file, continuation, tb_false); + default: + xm_io_file_return_error(lua, file, "unknonwn read mode"); + return 0; + } + } + else + { + if (count >= 0) return xm_io_file_std_read_n(lua, file, continuation, count); + switch (*mode) + { + case 'a': return xm_io_file_std_read_all(lua, file, continuation); + case 'L': return xm_io_file_std_read_line(lua, file, continuation, tb_true); + case 'n': return xm_io_file_std_read_num(lua, file, continuation); + case 'l': return xm_io_file_std_read_line(lua, file, continuation, tb_false); + default: + xm_io_file_return_error(lua, file, "unknonwn read mode"); + return 0; + } + } +} diff --git a/core/src/xmake/io/file_seek.c b/core/src/xmake/io/file_seek.c new file mode 100644 index 000000000..37588fe4f --- /dev/null +++ b/core/src/xmake/io/file_seek.c @@ -0,0 +1,81 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_seek.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_seek" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * file:seek([whence [, offset]]) + */ +tb_int_t xm_io_file_seek(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = xm_io_getfile(lua); + tb_char_t const* whence = luaL_optstring(lua, 2, "cur"); + tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0); + tb_assert_and_check_return_val(file && whence, 0); + + if (xm_io_file_is_file(file)) + { + if (xm_io_file_is_closed_file(file)) + xm_io_file_return_error_closed(lua); + + switch (*whence) + { + case 's': // "set" + break; + case 'e': // "end" + { + tb_hong_t size = tb_stream_size(file->file_ref); + if (size > 0 && size + offset <= size) + offset = size + offset; + else xm_io_file_return_error(lua, file, "seek failed, invalid offset!"); + } + break; + default: // "cur" + offset = tb_stream_offset(file->file_ref) + offset; + break; + } + + if (tb_stream_seek(file->file_ref, offset)) + { + lua_pushnumber(lua, (lua_Number)offset); + xm_io_file_return_success(); + } + else xm_io_file_return_error(lua, file, "seek failed!"); + } + else xm_io_file_return_error(lua, file, "seek is not supported on this file"); +} diff --git a/core/src/xmake/io/file_write.c b/core/src/xmake/io/file_write.c new file mode 100644 index 000000000..553b91996 --- /dev/null +++ b/core/src/xmake/io/file_write.c @@ -0,0 +1,147 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file file_write.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_write" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" +#include "file.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_void_t xm_io_file_write_file_directly(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + // check + tb_assert(file && data && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + + // write data to file + tb_stream_bwrit(file->file_ref, (tb_byte_t const*)data, size); +} +static tb_void_t xm_io_file_write_file_transcrlf(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + // check + tb_assert(file && data && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + +#ifdef TB_CONFIG_OS_WINDOWS + + // write cached data first + tb_byte_t const* odata = tb_buffer_data(&file->wcache); + tb_size_t osize = tb_buffer_size(&file->wcache); + if (odata && osize) + { + if (!tb_stream_bwrit(file->file_ref, odata, osize)) return ; + tb_buffer_clear(&file->wcache); + } + + // write data by lines + tb_char_t const* p = (tb_char_t const*)data; + tb_char_t const* e = p + size; + tb_char_t const* lf = tb_null; + while (p < e) + { + lf = tb_strnchr(p, e - p, '\n'); + if (lf) + { + if (lf > p && lf[-1] == '\r') + { + if (!tb_stream_bwrit(file->file_ref, (tb_byte_t const*)p, lf + 1 - p)) break; + } + else + { + if (lf > p && !tb_stream_bwrit(file->file_ref, (tb_byte_t const*)p, lf - p)) break; + if (!tb_stream_bwrit(file->file_ref, (tb_byte_t const*)"\r\n", 2)) break; + } + + // next line + p = lf + 1; + } + else + { + // cache the left data + tb_buffer_memncat(&file->wcache, (tb_byte_t const*)p, e - p); + p = e; + break; + } + } +#else + return xm_io_file_write_file_directly(file, data, size); +#endif +} +static tb_void_t xm_io_file_write_std(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + // check + tb_assert(file && data && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + + // check type + tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY); + tb_check_return(type != XM_IO_FILE_TYPE_STDIN); + + // write data to stdout/stderr + tb_stdfile_writ(file->std_ref, (tb_byte_t const*)data, size); +} + +/* + * file:write(...) + */ +tb_int_t xm_io_file_write(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get file + xm_io_file* file = xm_io_getfile(lua); + tb_int_t narg = lua_gettop(lua); + + // this file has been closed? + if (xm_io_file_is_closed(file)) + xm_io_file_return_error_closed(lua); + + if (narg > 1) + { + tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; + for (tb_int_t i = 2; i <= narg; i++) + { + // get data + size_t datasize = 0; + tb_char_t const* data = luaL_checklstring(lua, i, &datasize); + tb_check_continue(datasize); + tb_assert_and_check_break(data); + + // write data to std or file + if (xm_io_file_is_std(file)) + xm_io_file_write_std(file, data, (tb_size_t)datasize); + else if (is_binary) + xm_io_file_write_file_directly(file, data, (tb_size_t)datasize); + else + xm_io_file_write_file_transcrlf(file, data, (tb_size_t)datasize); + } + } + + lua_settop(lua, 1); + xm_io_file_return_success(); +} diff --git a/core/src/xmake/io/open.c b/core/src/xmake/io/open.c new file mode 100644 index 000000000..1507e9235 --- /dev/null +++ b/core/src/xmake/io/open.c @@ -0,0 +1,320 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file open.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "open" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// num of bytes read to guess encoding +#define CHECK_SIZE (1024) + +// is utf-8 tail character +#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_size_t xm_io_file_detect_charset(tb_byte_t const** data_ptr, tb_long_t size) +{ + // check + tb_assert(data_ptr && *data_ptr); + + tb_byte_t const* data = *data_ptr; + tb_size_t charset = XM_IO_FILE_ENCODING_BINARY; + do + { + if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) // utf-8 with bom + { + charset = TB_CHARSET_TYPE_UTF8; + data += 3; // skip bom + break; + } + if (size >= 2) + { + if (data[0] == 254 && data[1] == 255) // utf16be + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + data += 2; // skip bom + break; + } + else if (data[0] == 255 && data[1] == 254) // utf16le + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + data += 2; // skip bom + break; + } + } + + tb_sint16_t utf16be_conf = 0; + tb_sint16_t utf16le_conf = 0; + tb_sint16_t utf8_conf = 0; + tb_sint16_t ascii_conf = 0; + tb_sint16_t zero_count = 0; + for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) + { + if (data[i] == 0) zero_count++; + + if (data[i] < 0x80) + ascii_conf++; + else + ascii_conf = TB_MINS16; + + if (i % 2 == 0) + { + if (data[i] == 0) utf16be_conf++; + if (data[i + 1] == 0) utf16le_conf++; + } + + if (IS_UTF8_TAIL(data[i])) + ; + else if (data[i] < 0x80) + utf8_conf++; + else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) + utf8_conf++; + else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) + utf8_conf++; + else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) && IS_UTF8_TAIL(data[i + 3])) + utf8_conf++; + else + utf8_conf = TB_MINS16; + } + + if (ascii_conf > 0 && zero_count <= 1) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + if (utf8_conf > 0 && zero_count <= 1) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + break; + } + if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + break; + } + if (utf8_conf > 0) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + +#ifdef TB_CONFIG_OS_WINDOWS + charset = TB_CHARSET_TYPE_ANSI; +#endif + + } while (0); + + *data_ptr = data; + return charset; +} +static tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t* pbomoff) +{ + // check + tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY); + + // detect encoding + tb_byte_t* data = tb_null; + tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY; + tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE); + if (size > 0) + { + tb_byte_t const* p = data; + encoding = xm_io_file_detect_charset(&p, size); + *pbomoff = p - data; + } + return encoding; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * io.open(path, modestr) + */ +tb_int_t xm_io_open(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get file path and mode + tb_char_t const* path = luaL_checkstring(lua, 1); + tb_char_t const* modestr = luaL_optstring(lua, 2, "r"); + tb_assert_and_check_return_val(path && modestr, 0); + + // get file mode value + tb_size_t mode = TB_FILE_MODE_RW; + switch (modestr[0]) + { + case 'w': mode |= TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC; break; + case 'a': mode |= TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT; break; + default: break; + } + + // get file encoding + tb_long_t bomoff = 0; + tb_stream_ref_t stream = tb_null; + tb_bool_t update = !!tb_strchr(modestr, '+'); + tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN; + if (modestr[1] == 'b' || (update && modestr[2] == 'b')) + encoding = XM_IO_FILE_ENCODING_BINARY; + else if (tb_strstr(modestr, "utf8") || tb_strstr(modestr, "utf-8")) + encoding = TB_CHARSET_TYPE_UTF8; + else if (tb_strstr(modestr, "utf16le") || tb_strstr(modestr, "utf-16le")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + else if (tb_strstr(modestr, "utf16be") || tb_strstr(modestr, "utf-16be")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + else if (tb_strstr(modestr, "utf16") || tb_strstr(modestr, "utf-16")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE; + else if (modestr[0] == 'w' || modestr[0] == 'a') // set to utf-8 if not specified for the writing mode + encoding = TB_CHARSET_TYPE_UTF8; + else if (modestr[0] == 'r') // detect encoding if not specified for the reading mode + { + stream = tb_stream_init_from_file(path, mode); + if (stream && tb_stream_open(stream)) + encoding = xm_io_file_detect_encoding(stream, &bomoff); + else + { + if (stream) tb_stream_exit(stream); + lua_pushnil(lua); + lua_pushliteral(lua, "file not found!"); + return 2; + } + } + else + { + lua_pushnil(lua); + lua_pushliteral(lua, "invalid open mode!"); + return 2; + } + tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0); + + // open file + tb_bool_t open_ok = tb_false; + tb_stream_ref_t file_ref = tb_null; + tb_stream_ref_t fstream = tb_null; + do + { + // init stream from file + stream = stream? stream : tb_stream_init_from_file(path, mode); + tb_assert_and_check_break(stream); + + // is transcode? + tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY; + if (is_transcode) + { + if (modestr[0] == 'r') + fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8); + else + fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding); + tb_assert_and_check_break(fstream); + + // use fstream as file + file_ref = fstream; + } + else file_ref = stream; + + // open file stream + if (!tb_stream_open(file_ref)) break; + + // skip bom characters if exists + if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) break; + + // ok + open_ok = tb_true; + + } while (0); + + // open failed? + if (!open_ok) + { + // exit stream + if (stream) tb_stream_exit(stream); + stream = tb_null; + + // exit charset stream filter + if (fstream) tb_stream_exit(fstream); + fstream = tb_null; + + // return errors + lua_pushnil(lua); + lua_pushliteral(lua, "failed to open file."); + return 2; + } + + // get absolute file path + tb_char_t full[TB_PATH_MAXN] = {0}; + path = tb_path_absolute(path, full, TB_PATH_MAXN); + tb_assert_and_check_return_val(path, 0); + + // new file + xm_io_file* xm_file = xm_io_newfile(lua); + xm_file->file_ref = file_ref; + xm_file->stream = stream; + xm_file->fstream = fstream; + xm_file->mode = mode; + xm_file->type = XM_IO_FILE_TYPE_FILE; + xm_file->encoding = encoding; + + // init the read/write line cache buffer + tb_buffer_init(&xm_file->rcache); + tb_buffer_init(&xm_file->wcache); + + // save file path + tb_size_t pathlen = tb_strlen(path); + xm_file->path = tb_malloc_cstr(pathlen + 1); + if (xm_file->path) + { + tb_strncpy((tb_char_t*)xm_file->path, path, pathlen); + ((tb_char_t*)xm_file->path)[pathlen] = '\0'; + } + + // save file name + tb_size_t name_maxn = tb_arrayn(xm_file->name); + tb_strlcpy(xm_file->name, "file: ", name_maxn); + if (pathlen < name_maxn - tb_arrayn("file: ")) + tb_strcat(xm_file->name, path); + else + { + tb_strcat(xm_file->name, "..."); + tb_strcat(xm_file->name, path + (pathlen - name_maxn + tb_arrayn("file: ") + tb_arrayn("..."))); + } + return 1; +} diff --git a/core/src/xmake/io/std.c b/core/src/xmake/io/std.c new file mode 100644 index 000000000..4ee446d85 --- /dev/null +++ b/core/src/xmake/io/std.c @@ -0,0 +1,138 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file std.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "io_std" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" +#include <stdio.h> +#ifdef TB_CONFIG_OS_WINDOWS +# include <io.h> +#else +# include <unistd.h> +#endif + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +static tb_size_t xm_io_std_isatty(tb_size_t type) +{ + tb_bool_t answer = tb_false; +#ifdef TB_CONFIG_OS_WINDOWS + DWORD mode; + HANDLE console_handle; + switch (type) + { + case XM_IO_FILE_TYPE_STDIN: console_handle = GetStdHandle(STD_INPUT_HANDLE); break; + case XM_IO_FILE_TYPE_STDOUT: console_handle = GetStdHandle(STD_OUTPUT_HANDLE); break; + case XM_IO_FILE_TYPE_STDERR: console_handle = GetStdHandle(STD_ERROR_HANDLE); break; + } + answer = GetConsoleMode(console_handle, &mode); +#else + switch (type) + { + case XM_IO_FILE_TYPE_STDIN: answer = isatty(fileno(stdin)); break; + case XM_IO_FILE_TYPE_STDOUT: answer = isatty(fileno(stdout)); break; + case XM_IO_FILE_TYPE_STDERR: answer = isatty(fileno(stderr)); break; + } +#endif + + if (answer) type |= XM_IO_FILE_FLAG_TTY; + return type; +} + +static tb_void_t xm_io_std_init(lua_State* lua, tb_size_t type) +{ + // check + tb_assert_and_check_return(lua); + + tb_char_t const* name = tb_null; + tb_char_t const* path = tb_null; + tb_stdfile_ref_t fp = tb_null; + switch (type) + { + case XM_IO_FILE_TYPE_STDIN: + name = "stdin"; + fp = tb_stdfile_input(); + break; + case XM_IO_FILE_TYPE_STDOUT: + name = "stdout"; + fp = tb_stdfile_output(); + break; + case XM_IO_FILE_TYPE_STDERR: + name = "stderr"; + fp = tb_stdfile_error(); + break; + } +#ifdef TB_CONFIG_OS_WINDOWS + path = "CON"; // console device +#else + switch (type) + { + case XM_IO_FILE_TYPE_STDIN: path = "/dev/stdin"; break; + case XM_IO_FILE_TYPE_STDOUT: path = "/dev/stdout"; break; + case XM_IO_FILE_TYPE_STDERR: path = "/dev/stderr"; break; + } +#endif + tb_assert_and_check_return(name && path && fp); + + // new file + xm_io_file* file = xm_io_newfile(lua); + tb_assert_and_check_return(file); + lua_setfield(lua, -2, name); + + // init file + file->encoding = TB_CHARSET_TYPE_UTF8; + file->type = xm_io_std_isatty(type); + file->path = path; + file->std_ref = fp; + file->stream = tb_null; + file->fstream = tb_null; + + // init name + tb_char_t const* info = xm_io_file_is_tty(file) ? "" : " redirected"; + tb_snprintf(file->name, tb_arrayn(file->name), "file: (%s%s)", name, info); + + // init the line cache buffer + tb_buffer_init(&file->rcache); + tb_buffer_init(&file->wcache); +} + +tb_int_t xm_io_std(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // init io.stdin, io.stdout and io.stderr + lua_getglobal(lua, "io"); + xm_io_std_init(lua, XM_IO_FILE_TYPE_STDIN); + xm_io_std_init(lua, XM_IO_FILE_TYPE_STDOUT); + xm_io_std_init(lua, XM_IO_FILE_TYPE_STDERR); + lua_pop(lua, 1); + return 0; +} diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index 2ca2227c5..77661a445 100644 --- a/core/src/xmake/machine.c +++ b/core/src/xmake/machine.c @@ -31,6 +31,8 @@ #include "xmake.h" #if defined(TB_CONFIG_OS_WINDOWS) # include <windows.h> +# include <io.h> +# include <fcntl.h> #elif defined(TB_CONFIG_OS_MACOSX) # include <mach-o/dyld.h> #elif defined(TB_CONFIG_OS_LINUX) @@ -53,6 +55,8 @@ typedef struct __xm_machine_t * declaration */ +// the global functions + // the os functions tb_int_t xm_os_argv(lua_State* lua); tb_int_t xm_os_find(lua_State* lua); @@ -88,7 +92,20 @@ tb_int_t xm_os_getown(lua_State* lua); #endif // the io functions -tb_int_t xm_io_isatty(lua_State* lua); +tb_int_t xm_io_std(lua_State* lua); +tb_int_t xm_io_open(lua_State* lua); + +// the file functions +tb_int_t xm_io_file_read(lua_State* lua); +tb_int_t xm_io_file_seek(lua_State* lua); +tb_int_t xm_io_file_write(lua_State* lua); +tb_int_t xm_io_file_flush(lua_State* lua); +tb_int_t xm_io_file_close(lua_State* lua); +tb_int_t xm_io_file_isatty(lua_State* lua); +tb_int_t xm_io_file_path(lua_State* lua); +tb_int_t xm_io_file___len(lua_State* lua); +tb_int_t xm_io_file___tostring(lua_State* lua); +tb_int_t xm_io_file___gc(lua_State* lua); // the path functions tb_int_t xm_path_relative(lua_State* lua); @@ -102,6 +119,11 @@ tb_int_t xm_hash_sha256(lua_State* lua); // the windows functions #ifdef TB_CONFIG_OS_WINDOWS +tb_int_t xm_winos_cp_info(lua_State* lua); +tb_int_t xm_winos_console_cp(lua_State* lua); +tb_int_t xm_winos_console_output_cp(lua_State* lua); +tb_int_t xm_winos_ansi_cp(lua_State* lua); +tb_int_t xm_winos_oem_cp(lua_State* lua); tb_int_t xm_winos_logical_drives(lua_State* lua); tb_int_t xm_winos_registry_query(lua_State* lua); #endif @@ -186,19 +208,40 @@ static luaL_Reg const g_os_functions[] = #ifdef TB_CONFIG_OS_WINDOWS static luaL_Reg const g_winos_functions[] = { - { "logical_drives", xm_winos_logical_drives } -, { "registry_query", xm_winos_registry_query } -, { tb_null, tb_null } + { "cp_info", xm_winos_cp_info } +, { "console_cp", xm_winos_console_cp } +, { "console_output_cp", xm_winos_console_output_cp } +, { "oem_cp", xm_winos_oem_cp } +, { "ansi_cp", xm_winos_ansi_cp } +, { "logical_drives", xm_winos_logical_drives } +, { "registry_query", xm_winos_registry_query } +, { tb_null, tb_null } }; #endif // the io functions static luaL_Reg const g_io_functions[] = { - { "isatty", xm_io_isatty } + { "open", xm_io_open } , { tb_null, tb_null } }; +// the file functions +static luaL_Reg const g_io_file_functions[] = +{ + { "read", xm_io_file_read } +, { "seek", xm_io_file_seek } +, { "write", xm_io_file_write } +, { "flush", xm_io_file_flush } +, { "isatty", xm_io_file_isatty } +, { "path", xm_io_file_path } +, { "close", xm_io_file_close } +, { "__gc", xm_io_file___gc } +, { "__len", xm_io_file___len } +, { "__tostring", xm_io_file___tostring } +, { tb_null, tb_null } +}; + // the path functions static luaL_Reg const g_path_functions[] = { @@ -274,15 +317,25 @@ static tb_bool_t xm_machine_save_arguments(xm_machine_t* machine, tb_int_t argc, // check tb_assert_and_check_return_val(machine && machine->lua && argc >= 1 && argv, tb_false); +#ifdef TB_CONFIG_OS_WINDOWS + tb_wchar_t **argvw = CommandLineToArgvW(GetCommandLineW(), &argc); +#endif + // put a new table into the stack - lua_newtable(machine->lua); + lua_createtable(machine->lua, argc, 0); // save all arguments to the new table tb_int_t i = 0; for (i = 1; i < argc; i++) { +#ifdef TB_CONFIG_OS_WINDOWS + tb_char_t argvbuf[4096] = {0}; + tb_wcstombs(argvbuf, argvw[i], tb_arrayn(argvbuf)); // table_new[table.getn(table_new) + 1] = argv[i] + lua_pushstring(machine->lua, argvbuf); +#else lua_pushstring(machine->lua, argv[i]); +#endif lua_rawseti(machine->lua, -2, (int)lua_objlen(machine->lua, -2) + 1); } @@ -303,10 +356,13 @@ static tb_size_t xm_machine_get_program_file(xm_machine_t* machine, tb_char_t* p { #if defined(TB_CONFIG_OS_WINDOWS) // get the executale file path as program directory - tb_size_t size = (tb_size_t)GetModuleFileName(tb_null, path, (DWORD)maxn); - tb_assert_and_check_break(size < maxn); - + tb_wchar_t buf[TB_PATH_MAXN] = {0}; + tb_size_t size = (tb_size_t)GetModuleFileNameW(tb_null, buf, (DWORD)TB_PATH_MAXN); + tb_assert_and_check_break(size < TB_PATH_MAXN); // end + buf[size] = L'\0'; + size = tb_wcstombs(path, buf, maxn); + tb_assert_and_check_break(size < maxn); path[size] = '\0'; // ok @@ -520,6 +576,26 @@ xm_machine_ref_t xm_machine_init() // bind io functions luaL_register(machine->lua, "io", g_io_functions); + // bind file functions + // stack: {metatable} + luaL_newmetatable(machine->lua, "XM_IO_FILE*"); + // stack: {metatable}, {metatable} + lua_pushvalue(machine->lua, -1); + // stack: {metatable, __index = {metatable}} + lua_setfield(machine->lua, -2, "__index"); + // stack: {metatable}, {io} + lua_getglobal(machine->lua, "io"); + // stack: {metatable}, {io}, {metatable} + lua_pushvalue(machine->lua, -2); + // stack: {metatable}, {io, file = {metatable}} + lua_setfield(machine->lua, -2, "file"); + // stack: {metatable} + lua_pop(machine->lua, 1); + // stack: + luaL_register(machine->lua, NULL, g_io_file_functions); + // add stdin,stdout,stderr to io + xm_io_std(machine->lua); + // bind path functions luaL_register(machine->lua, "path", g_path_functions); @@ -643,6 +719,10 @@ tb_int_t xm_machine_main(xm_machine_ref_t self, tb_int_t argc, tb_char_t** argv) xm_machine_t* machine = (xm_machine_t*)self; tb_assert_and_check_return_val(machine && machine->lua, -1); +#ifdef TB_CONFIG_OS_WINDOWS + if (_isatty(_fileno(stdin))) _setmode(_fileno(stdin), _O_U16TEXT); +#endif + // save main arguments to the global variable: _ARGV if (!xm_machine_save_arguments(machine, argc, argv)) return -1; diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index b51504cee..f35becda6 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -44,7 +44,17 @@ xmake_C_FILES += \ os/uid \ os/gid \ os/getown \ - io/isatty \ + io/file___len \ + io/file___tostring \ + io/file_close___gc \ + io/file_flush \ + io/file_isatty \ + io/file_path \ + io/file_read \ + io/file_seek \ + io/file_write \ + io/open \ + io/std \ path/relative \ path/absolute \ path/translate \ diff --git a/core/src/xmake/os/find.c b/core/src/xmake/os/find.c index 198e0a5bf..3a1271048 100644 --- a/core/src/xmake/os/find.c +++ b/core/src/xmake/os/find.c @@ -90,7 +90,7 @@ static tb_bool_t xm_os_find_walk(tb_char_t const* path, tb_file_info_t const* in tb_assert_and_check_return_val(rootdir && rootlen, tb_false); // check - tb_assert(!tb_strcmp(path, rootdir)); + tb_assert(!tb_strncmp(path, rootdir, rootlen)); tb_assert(rootlen + 1 <= tb_strlen(path)); // skip the rootdir if not "." diff --git a/core/src/xmake/sandbox/interactive.c b/core/src/xmake/sandbox/interactive.c index 6fc643520..95d01a19c 100644 --- a/core/src/xmake/sandbox/interactive.c +++ b/core/src/xmake/sandbox/interactive.c @@ -29,17 +29,19 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ -#define TB_TRACE_MODULE_NAME "sandbox.interactive" -#define TB_TRACE_MODULE_DEBUG (0) +#define TB_TRACE_MODULE_NAME "sandbox.interactive" +#define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" +#include "../winos/ansi.h" #ifdef XM_CONFIG_API_HAVE_READLINE -# include <stdio.h> // on some OS (like centos) required -# include <readline/readline.h> # include <readline/history.h> +# include <readline/readline.h> +# include <stdlib.h> +# include <stdio.h> // on some OS (like centos) required #endif /* ////////////////////////////////////////////////////////////////////////////////////// @@ -47,10 +49,13 @@ */ // interactive prompt -#define LUA_PROMPT "> " +#define LUA_PROMPT "> " // continuation prompt -#define LUA_PROMPT2 ">> " +#define LUA_PROMPT2 ">> " + +// buffer size for prompt +#define LUA_PROMPT_BUFSIZE 4096 /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation @@ -59,7 +64,7 @@ // report results static tb_void_t xm_sandbox_report(lua_State *lua) { - if (!lua_isnil(lua, -1)) + if (!lua_isnil(lua, -1)) { // get message tb_char_t const* msg = lua_tostring(lua, -1); @@ -77,14 +82,14 @@ static tb_void_t xm_sandbox_report(lua_State *lua) // the traceback function static tb_int_t xm_sandbox_traceback(lua_State *lua) { - if (!lua_isstring(lua, 1)) + if (!lua_isstring(lua, 1)) { // non-string error object? try metamethod. if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, "__tostring") || !lua_isstring(lua, -1)) - return 1; // return non-string error object. - + return 1; // return non-string error object. + // replace object by result of __tostring metamethod. - lua_remove(lua, 1); + lua_remove(lua, 1); } // return backtrace @@ -92,8 +97,8 @@ static tb_int_t xm_sandbox_traceback(lua_State *lua) return 1; } -// execute codes -static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) +// execute codes +static tb_int_t xm_sandbox_docall(lua_State* lua, tb_int_t narg, tb_int_t clear) { /* get error function index * @@ -105,19 +110,19 @@ static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) lua_pushcfunction(lua, xm_sandbox_traceback); // put it under chunk and args - lua_insert(lua, errfunc); + lua_insert(lua, errfunc); /* execute it * - * stack: errfunc arg1 scriptfunc -> ... - * after: errfunc arg1 [results] -> ... + * stack: errfunc arg1 scriptfunc -> ... + * after: errfunc arg1 [results] -> ... */ - tb_int_t status = lua_pcall(lua, narg, (clear? 0 : LUA_MULTRET), errfunc); + tb_int_t status = lua_pcall(lua, narg, (clear ? 0 : LUA_MULTRET), errfunc); // remove traceback function - lua_remove(lua, errfunc); + lua_remove(lua, errfunc); - // force a complete garbage collection in case of errors + // force a complete garbage collection in case of errors if (status != 0) lua_gc(lua, LUA_GCCOLLECT, 0); // ok? @@ -128,12 +133,12 @@ static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) static tb_int_t xm_sandbox_incomplete(lua_State *lua, tb_int_t status) { // syntax error? - if (status == LUA_ERRSYNTAX) + if (status == LUA_ERRSYNTAX) { - size_t lmsg; + size_t lmsg; tb_char_t const* msg = lua_tolstring(lua, -1, &lmsg); - tb_char_t const* tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); - if (tb_strstr(msg, LUA_QL("<eof>")) == tp) + tb_char_t const* tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); + if (tb_strstr(msg, LUA_QL("<eof>")) == tp) { lua_pop(lua, 1); return 1; @@ -156,35 +161,34 @@ static tb_size_t xm_sandbox_readline(tb_char_t* data, tb_size_t maxn, tb_char_t tb_size_t size = tb_strlcpy(data, line, maxn); // free line - tb_free(line); + free((void*)line); // truncated? - if (size >= maxn) - return 0; + if (size >= maxn) return 0; // ok return size; } #else - + // print prompt tb_printf(prompt); tb_print_sync(); // get input buffer - if (fgets(data, (tb_int_t)maxn, stdin)) + if (tb_stdfile_gets(tb_stdfile_input(), data, maxn)) return tb_strlen(data); #endif - + // no more input return 0; } // read and push input line -static tb_int_t xm_sandbox_pushline(lua_State *lua) +static tb_int_t xm_sandbox_pushline(lua_State* lua) { // read line - tb_char_t data[1024]; + tb_char_t data[LUA_PROMPT_BUFSIZE]; tb_size_t size = xm_sandbox_readline(data, sizeof(data), LUA_PROMPT2); if (size) { @@ -204,14 +208,14 @@ static tb_int_t xm_sandbox_pushline(lua_State *lua) } // load code line -static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) +static tb_int_t xm_sandbox_loadline(lua_State* lua, tb_int_t top) { - // clear stack + // clear stack lua_settop(lua, top); // read first line tb_int_t status; - tb_char_t data[1024]; + tb_char_t data[LUA_PROMPT_BUFSIZE]; tb_size_t size = xm_sandbox_readline(data + 7, sizeof(data) - 7, LUA_PROMPT); if (size) { @@ -221,13 +225,13 @@ static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) // patch "return " tb_memcpy(data, "return ", 7); - + // attempt to load "return ..." status = luaL_loadbuffer(lua, data, size + 7, "=stdin"); // ok? if (status != LUA_ERRSYNTAX) return status; - + // pop error msg lua_pop(lua, 1); @@ -238,7 +242,7 @@ static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) // load input line while (1) - { + { /* repeat until gets a complete line * * stack: arg1(sandbox_scope) scriptbuffer(top) -> ... @@ -250,15 +254,14 @@ static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) if (!xm_sandbox_incomplete(lua, status)) break; // get more input - if (!xm_sandbox_pushline(lua)) - return -1; + if (!xm_sandbox_pushline(lua)) return -1; // cancel multi-line input? if (!tb_strcmp(lua_tostring(lua, -1), "q")) { lua_pop(lua, 2); lua_pushstring(lua, "return "); - continue ; + continue; } /* add a new line @@ -268,7 +271,7 @@ static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) lua_pushliteral(lua, "\n"); // between the two lines - lua_insert(lua, -2); + lua_insert(lua, -2); /* join them * @@ -279,7 +282,7 @@ static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) } // remove redundant scriptbuffer - lua_remove(lua, -2); + lua_remove(lua, -2); return status; } @@ -299,9 +302,9 @@ tb_int_t xm_sandbox_interactive(lua_State* lua) */ tb_int_t top = lua_gettop(lua); - // enter interactive + // enter interactive tb_int_t status; - while ((status = xm_sandbox_loadline(lua, top)) != -1) + while ((status = xm_sandbox_loadline(lua, top)) != -1) { // execute codes if (status == 0) @@ -321,12 +324,13 @@ tb_int_t xm_sandbox_interactive(lua_State* lua) } // report errors - if (status) xm_sandbox_report(lua); + if (status) + xm_sandbox_report(lua); // print any results - if (status == 0 && lua_gettop(lua) > top) + if (status == 0 && lua_gettop(lua) > top) { - // get results count + // get results count tb_int_t count = lua_gettop(lua) - top; /* dump results @@ -341,7 +345,7 @@ tb_int_t xm_sandbox_interactive(lua_State* lua) } } - // clear stack + // clear stack lua_settop(lua, top); tb_printl(""); tb_print_sync(); diff --git a/core/src/xmake/string/convert.c b/core/src/xmake/string/convert.c index 32e5088ed..a6edd5692 100644 --- a/core/src/xmake/string/convert.c +++ b/core/src/xmake/string/convert.c @@ -48,15 +48,20 @@ typedef struct __xm_charset_entry_t // the charsets, @note: type & name is sorted static xm_charset_entry_t g_charsets[] = { - {TB_CHARSET_TYPE_ASCII, "ascii" } -, {TB_CHARSET_TYPE_GB2312, "gb2312" } -, {TB_CHARSET_TYPE_GBK, "gbk" } -, {TB_CHARSET_TYPE_ISO8859, "iso8859" } -, {TB_CHARSET_TYPE_UCS2, "ucs3" } -, {TB_CHARSET_TYPE_UCS4, "ucs4" } -, {TB_CHARSET_TYPE_UTF16, "utf16" } -, {TB_CHARSET_TYPE_UTF32, "utf32" } -, {TB_CHARSET_TYPE_UTF8, "utf8" } + {TB_CHARSET_TYPE_ANSI, "ansi" } +, {TB_CHARSET_TYPE_ASCII, "ascii" } +, {TB_CHARSET_TYPE_GB2312, "gb2312" } +, {TB_CHARSET_TYPE_GBK, "gbk" } +, {TB_CHARSET_TYPE_ISO8859, "iso8859" } +, {TB_CHARSET_TYPE_UCS2, "ucs2" } +, {TB_CHARSET_TYPE_UCS4, "ucs4" } +, {TB_CHARSET_TYPE_UTF16, "utf16" } +, {TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE, "utf16be" } +, {TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, "utf16le" } +, {TB_CHARSET_TYPE_UTF32, "utf32" } +, {TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_BE, "utf32be" } +, {TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_LE, "utf32le" } +, {TB_CHARSET_TYPE_UTF8, "utf8" } }; /* ////////////////////////////////////////////////////////////////////////////////////// @@ -122,10 +127,10 @@ tb_int_t xm_string_convert(lua_State* lua) tb_byte_t* dst_data = tb_malloc_bytes(dst_maxn); if (dst_data && dst_maxn && (dst_size = tb_charset_conv_data(fcharset->type, tcharset->type, (tb_byte_t const*)src_cstr, (tb_size_t)src_size, dst_data, dst_maxn)) >= 0 && dst_size < dst_maxn) { - dst_data[dst_size] = '\0'; - lua_pushstring(lua, (tb_char_t const*)dst_data); + lua_pushlstring(lua, (tb_char_t const *)dst_data, dst_size); } else lua_pushnil(lua); + tb_free(dst_data); } // ok diff --git a/core/src/xmake/winos/ansi.c b/core/src/xmake/winos/ansi.c new file mode 100644 index 000000000..2d56d77a9 --- /dev/null +++ b/core/src/xmake/winos/ansi.c @@ -0,0 +1,169 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file ansi.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "ansi" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "ansi.h" +#include <Windows.h> + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +static tb_int_t xm_expand_cp(tb_int_t cp) +{ + // check + tb_assert_and_check_return_val(cp >= 0 && cp <= 65535, 0); + + if (cp == CP_OEMCP) return GetOEMCP(); + if (cp == CP_ACP) return GetACP(); + return cp; +} + +tb_int_t xm_winos_console_cp(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_int_t n = lua_gettop(lua); + if (n >= 1) + { + lua_Integer cp = luaL_checkinteger(lua, 1); + luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); + cp = xm_expand_cp((tb_uint_t)cp); + luaL_argcheck(lua, SetConsoleCP((tb_uint_t)cp), 1, "failed to set code page"); + lua_pushinteger(lua, cp); + return 1; + } + else + { + tb_uint_t cp = GetConsoleCP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; + } +} + +tb_int_t xm_winos_console_output_cp(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_int_t n = lua_gettop(lua); + if (n >= 1) + { + lua_Integer cp = luaL_checkinteger(lua, 1); + luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); + cp = xm_expand_cp((tb_uint_t)cp); + luaL_argcheck(lua, SetConsoleOutputCP((tb_uint_t)cp), 1, "failed to set code page"); + lua_pushinteger(lua, cp); + return 1; + } + else + { + tb_uint_t cp = GetConsoleOutputCP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; + } +} + +tb_int_t xm_winos_cp_info(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_int_t n = lua_gettop(lua); + lua_Integer cp = luaL_checkinteger(lua, 1); + luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); + CPINFOEX cp_info; + luaL_argcheck(lua, GetCPInfoEx((tb_uint_t)cp, 0, &cp_info), 1, "invalid code page"); + + lua_newtable(lua); + + lua_pushliteral(lua, "name"); + tb_char_t* namebuf = tb_malloc_cstr(sizeof(cp_info.CodePageName) * 2); + tb_assert_and_check_return_val(namebuf, 0); + tb_size_t namelen = tb_wtoa(namebuf, cp_info.CodePageName, sizeof(cp_info.CodePageName) * 2); + tb_assert_and_check_return_val(namelen < sizeof(cp_info.CodePageName) * 2, 0); + lua_pushlstring(lua, namebuf, namelen); + tb_free(namebuf); + lua_settable(lua, -3); + + lua_pushliteral(lua, "max_char_size"); + lua_pushinteger(lua, (lua_Integer)cp_info.MaxCharSize); + lua_settable(lua, -3); + + lua_pushliteral(lua, "id"); + lua_pushinteger(lua, (lua_Integer)cp_info.CodePage); + lua_settable(lua, -3); + + lua_pushliteral(lua, "default_char"); + lua_pushstring(lua, (tb_char_t const*)cp_info.DefaultChar); + lua_settable(lua, -3); + + lua_pushliteral(lua, "lead_byte"); + lua_createtable(lua, MAX_LEADBYTES / 2, 0); + for (tb_size_t i = 0; i < MAX_LEADBYTES && cp_info.LeadByte[i] != 0 && cp_info.LeadByte[i + 1] != 0; i += 2) + { + lua_pushinteger(lua, (i / 2) + 1); + lua_createtable(lua, 0, 2); + + lua_pushliteral(lua, "from"); + lua_pushinteger(lua, cp_info.LeadByte[i]); + lua_settable(lua, -3); + + lua_pushliteral(lua, "to"); + lua_pushinteger(lua, cp_info.LeadByte[i + 1]); + lua_settable(lua, -3); + + lua_settable(lua, -3); + } + lua_settable(lua, -3); + + return 1; +} + +tb_int_t xm_winos_ansi_cp(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_uint_t cp = GetACP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; +} + +tb_int_t xm_winos_oem_cp(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_uint_t cp = GetOEMCP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; +} + diff --git a/core/src/xmake/winos/ansi.h b/core/src/xmake/winos/ansi.h new file mode 100644 index 000000000..fe07d15ba --- /dev/null +++ b/core/src/xmake/winos/ansi.h @@ -0,0 +1,29 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2019, TBOOX Open Source Group. + * + * @author OpportunityLiu + * @file ansi.h + * + */ +#ifndef XM_WINOS_ANSI_H +#define XM_WINOS_ANSI_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +#endif diff --git a/core/src/xmake/winos/registry_query.c b/core/src/xmake/winos/registry_query.c index afee6192e..7f759278b 100644 --- a/core/src/xmake/winos/registry_query.c +++ b/core/src/xmake/winos/registry_query.c @@ -161,7 +161,7 @@ tb_int_t xm_winos_registry_query(lua_State* lua) // get registry value size DWORD valuesize = 0; - if (RegQueryValueEx(keynew, valuename, tb_null, tb_null, tb_null, &valuesize) != ERROR_SUCCESS) + if (RegQueryValueExA(keynew, valuename, tb_null, tb_null, tb_null, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value size failed: %s", path); @@ -174,7 +174,7 @@ tb_int_t xm_winos_registry_query(lua_State* lua) // get value result type = 0; - if (RegQueryValueEx(keynew, valuename, tb_null, &type, (LPBYTE)value, &valuesize) != ERROR_SUCCESS) + if (RegQueryValueExA(keynew, valuename, tb_null, &type, (LPBYTE)value, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value failed: %s", path); diff --git a/core/src/xmake/xmake.lua b/core/src/xmake/xmake.lua index d1bd77107..c3df93473 100644 --- a/core/src/xmake/xmake.lua +++ b/core/src/xmake/xmake.lua @@ -9,6 +9,9 @@ target("xmake") -- add defines add_defines("__tb_prefix__=\"xmake\"") + if is_mode("debug") then + add_defines("__tb_debug__", {public = true}) + end -- set the auto-generated config.h set_configdir("$(buildir)/$(plat)/$(arch)/$(mode)") @@ -23,11 +26,15 @@ target("xmake") if is_plat("windows") then add_files("winos/*.c") end - + -- add readline - add_options("readline") + add_options("readline") + if is_plat("windows") or has_config("curses") then add_defines("XM_CONFIG_API_HAVE_CURSES") end + if is_plat("windows") then + add_defines("UNICODE", "_UNICODE") + end |
