diff options
| author | OpportunityLiu <[email protected]> | 2019-07-01 14:19:05 +0800 |
|---|---|---|
| committer | OpportunityLiu <[email protected]> | 2019-07-01 14:19:05 +0800 |
| commit | f40152174188626df4b70ca1b9044a721fd3c6e8 (patch) | |
| tree | 388f5b8e3acdcf1bc9253556fe762dc8b09a5d2a | |
| parent | 19cbd06f95dddacd1247d1dffab9fa29d719d02b (diff) | |
utf8 support
72 files changed, 2638 insertions, 330 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 29a95f9b1..648605b89 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -109,11 +109,10 @@ test_script: $filename = $_.filename Update-AppveyorTest -Name $testname -Framework "xmake-test" -FileName $filename -Outcome Running $time = Measure-Command { - $results = xmake lua --verbose --diagnosis runner.lua $_.fullname + xmake lua --verbose --diagnosis runner.lua $_.fullname >stdout_file 2>stderr_file $outcome = if ($?) { "Passed" } else { $all_success = $false; "Failed" } - $stdout = [string]::Join("`n", $results) } - Update-AppveyorTest -Name $testname -Framework "xmake-test" -FileName $filename -Outcome $outcome -Duration $time.TotalMilliseconds -StdOut $stdout + Update-AppveyorTest -Name $testname -Framework "xmake-test" -FileName $filename -Outcome $outcome -Duration $time.TotalMilliseconds -StdOut (Get-Content -Raw stdout_file) -StdErr (Get-Content -Raw stderr_file) } - ps: Pop-Location - ps: if ($all_success) { Write-Host "All tests passed!" } else { Write-Error "Some tests failed!" } diff --git a/core/.clang-format b/core/.clang-format new file mode 100644 index 000000000..70b14e93c --- /dev/null +++ b/core/.clang-format @@ -0,0 +1,115 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: AfterHash +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +RawStringFormats: + - Delimiter: pb + Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + 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..10f5f0996 100755 --- a/core/src/tbox/inc/linux/tbox.config.h +++ b/core/src/tbox/inc/linux/tbox.config.h @@ -14,6 +14,7 @@ #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 #define TB_CONFIG_TYPE_HAVE_FLOAT 1 +#define TB_CONFIG_FORCE_UTF8 1 #define TB_CONFIG_MODULE_HAVE_HASH 1 #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 diff --git a/core/src/tbox/inc/macosx/tbox.config.h b/core/src/tbox/inc/macosx/tbox.config.h index 0fa89b373..7bbbbb464 100755 --- a/core/src/tbox/inc/macosx/tbox.config.h +++ b/core/src/tbox/inc/macosx/tbox.config.h @@ -14,6 +14,7 @@ #define _REENTRANT 1 #define TB_CONFIG_SMALL 1 #define TB_CONFIG_TYPE_HAVE_FLOAT 1 +#define TB_CONFIG_FORCE_UTF8 1 #define TB_CONFIG_MODULE_HAVE_HASH 1 #define TB_CONFIG_LIBC_HAVE_MEMCPY 1 #define TB_CONFIG_LIBC_HAVE_MEMSET 1 diff --git a/core/src/tbox/inc/windows/tbox.config.h b/core/src/tbox/inc/windows/tbox.config.h index 4cc30f8d8..a4eaf50b8 100755 --- a/core/src/tbox/inc/windows/tbox.config.h +++ b/core/src/tbox/inc/windows/tbox.config.h @@ -14,6 +14,7 @@ #define _REENTRANT 1
#define TB_CONFIG_SMALL 1
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
+#define TB_CONFIG_FORCE_UTF8 1
#define TB_CONFIG_MODULE_HAVE_HASH 1
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject ad025d12b7dfc9a993da2c7a75bd1e9cd70bd57 +Subproject 3cbefcb387542a9b3e0bb42f4e601fc937379a5 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/global/prefix.h b/core/src/xmake/global/prefix.h new file mode 100644 index 000000000..e8e7c8d5a --- /dev/null +++ b/core/src/xmake/global/prefix.h @@ -0,0 +1,32 @@ +/*!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 ruki + * @file prefix.h + * + */ +#ifndef XM_G_PREFIX_H +#define XM_G_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + + +#endif + + diff --git a/core/src/xmake/io/file.h b/core/src/xmake/io/file.h new file mode 100644 index 000000000..b14e13ad0 --- /dev/null +++ b/core/src/xmake/io/file.h @@ -0,0 +1,93 @@ +/*!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" + +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; + +typedef enum __xm_io_file_encoding_e +{ + XM_IO_FILE_ENCODING_BINARY = -1, + XM_IO_FILE_ENCODING_UNKNOWN = -2, +#ifdef TB_CONFIG_OS_WINDOWS + XM_IO_FILE_ENCODING_ANSI = -3, +#endif +} xm_io_file_encoding_e; + +typedef struct __xm_io_file +{ + union { + tb_file_ref_t file_ref; + FILE* std_ref; + }; + + tb_size_t mode; + tb_size_t type; + 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; +} xm_io_file; + +#define xm_io_file_is_file(fileref) (fileref->type == XM_IO_FILE_TYPE_FILE) +#define xm_io_file_is_closed_file(fileref) (fileref->type == XM_IO_FILE_TYPE_FILE && fileref->file_ref == tb_null) +#define xm_io_file_is_tty(fileref) (!!(fileref->type & XM_IO_FILE_FLAG_TTY)) + +#define xm_io_file_udata "XM_IO_FILE*" + +#define xm_io_file_success() \ + do \ + { \ + return 1; \ + } while (0) +#define xm_io_file_error(lua, reason) \ + do \ + { \ + lua_pushnil(lua); \ + lua_pushliteral(lua, reason); \ + return 2; \ + } while (0) + +#define xm_io_file_error_closed(lua) xm_io_file_error(lua, "file has been closed") + +static inline xm_io_file* xm_io_newfile(lua_State* lua) +{ + xm_io_file* file = (xm_io_file*)lua_newuserdata(lua, sizeof(xm_io_file)); + luaL_getmetatable(lua, xm_io_file_udata); + lua_setmetatable(lua, -2); + tb_memset(file, 0, sizeof(xm_io_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..31557b6d4 --- /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 "prefix.h" +#include "file.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * #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_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + if(xm_io_file_is_closed_file(file)) + xm_io_file_error_closed(lua); + else if (xm_io_file_is_file(file)) + { + lua_pushnumber(lua, (lua_Number)tb_file_size(file->file_ref)); + xm_io_file_success(); + } + else + xm_io_file_error(lua, "getting file size for this file is invalid"); +} diff --git a/core/src/xmake/io/file___tostring.c b/core/src/xmake/io/file___tostring.c new file mode 100644 index 000000000..e92b3c61d --- /dev/null +++ b/core/src/xmake/io/file___tostring.c @@ -0,0 +1,50 @@ +/*!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___tostring.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file___tostring" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * tostring(file) + */ +tb_int_t xm_io_file___tostring(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + lua_pushstring(lua, file->name); + return 1; +} + diff --git a/core/src/xmake/io/file_close.c b/core/src/xmake/io/file_close.c new file mode 100644 index 000000000..f384f4c11 --- /dev/null +++ b/core/src/xmake/io/file_close.c @@ -0,0 +1,73 @@ +/*!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.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_close" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "file.h" +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * file:close() + */ +tb_int_t xm_io_file_close(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + if (xm_io_file_is_closed_file(file) || (!xm_io_file_is_file(file) && file->std_ref == tb_null)) + { + lua_pushboolean(lua, tb_true); + xm_io_file_success(); + } + if (xm_io_file_is_file(file)) + { + if (!tb_file_exit(file->file_ref)) xm_io_file_error(lua, "failed to close file"); + file->file_ref = tb_null; + tb_free(file->path); + file->path = tb_null; + tb_strcpy(file->name, "file: (closed file)"); + lua_pushboolean(lua, tb_true); + xm_io_file_success(); + } + else + { + // should we support close std files? + + // if (fclose(file->std_ref)) xm_io_file_error(lua, "failed to close file"); + // file->std_ref = tb_null; + // file->path = tb_null; + // tb_strcpy(file->name, "file: (closed file)"); + lua_pushboolean(lua, tb_true); + xm_io_file_success(); + } +} diff --git a/core/src/xmake/io/file_flush.c b/core/src/xmake/io/file_flush.c new file mode 100644 index 000000000..3e40f527f --- /dev/null +++ b/core/src/xmake/io/file_flush.c @@ -0,0 +1,58 @@ +/*!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" +#include <stdio.h> + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +static tb_bool_t std_flush(xm_io_file* file) { return !fflush(file->std_ref); } + +/* + * file:flush() + */ +tb_int_t xm_io_file_flush(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + + if (xm_io_file_is_closed_file(file)) xm_io_file_error_closed(lua); + tb_bool_t succeed = xm_io_file_is_file(file) ? tb_file_sync(file->file_ref) : std_flush(file); + if (succeed) + { + lua_pushboolean(lua, tb_true); + xm_io_file_success(); + } + xm_io_file_error(lua, "failed to flush file"); +} diff --git a/core/src/xmake/io/isatty.c b/core/src/xmake/io/file_isatty.c index d4dd7b57d..0f29f98bc 100644 --- a/core/src/xmake/io/isatty.c +++ b/core/src/xmake/io/file_isatty.c @@ -11,56 +11,49 @@ * 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_isatty.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ -#define TB_TRACE_MODULE_NAME "isatty" -#define TB_TRACE_MODULE_DEBUG (0) +#define TB_TRACE_MODULE_NAME "file_isatty" +#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) +/* file:isatty() */ -tb_int_t xm_io_isatty(lua_State* lua) +tb_int_t xm_io_file_isatty(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 + xm_io_file* fp = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + if (xm_io_file_is_file(fp)) + { + lua_pushboolean(lua, tb_false); + // ok + return 1; + } + tb_bool_t istty = xm_io_file_is_tty(fp); // return answer - lua_pushboolean(lua, answer); + lua_pushboolean(lua, istty); // ok 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..37191ab93 --- /dev/null +++ b/core/src/xmake/io/file_path.c @@ -0,0 +1,61 @@ +/*!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); + + // get file pointer + xm_io_file* fp = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + + if (xm_io_file_is_file(fp)) + { + if (xm_io_file_is_closed_file(fp)) xm_io_file_error_closed(lua); + lua_pushstring(lua, fp->path); + // ok + return 1; + } + else + { + lua_pushstring(lua, fp->path); + // ok + 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..56d8ba5cb --- /dev/null +++ b/core/src/xmake/io/file_read.c @@ -0,0 +1,643 @@ +/*!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" +#ifdef TB_CONFIG_OS_WINDOWS +# include "../winos/ansi.h" +# include <io.h> +#else +# include <unistd.h> +#endif +#include "file.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// num of bytes read to guess encoding +#define CHECK_SIZE (1024) + +#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +static tb_size_t detect_charset(tb_byte_t const** data_ptr, tb_long_t size) +{ + tb_byte_t const* data = *data_ptr; + tb_size_t charset = TB_CHARSET_TYPE_NONE; + + 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 = XM_IO_FILE_ENCODING_ANSI; +#else + charset = XM_IO_FILE_ENCODING_BINARY; +#endif + } while (0); + + *data_ptr = data; + return charset; +} + +static tb_byte_t const* find_lf(tb_byte_t const* buf, tb_size_t buflen, tb_size_t encoding) +{ + tb_byte_t const* bufend = buf + buflen; + tb_bool_t success = tb_false; + switch (encoding) + { + case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE: + case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE: + { + buflen &= ~1; + tb_uint16_t const* wbuf = (tb_uint16_t const*)buf; + tb_uint16_t const* wbufend = (tb_uint16_t const*)(buf + buflen); + tb_uint16_t lf = (encoding == (TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE)) ? '\n' << 8 : '\n'; + while (wbuf != wbufend) + { + if (*wbuf == lf) + { + wbuf++; + success = tb_true; + break; + } + else + wbuf++; + } + buf = (tb_byte_t const*)wbuf; + break; + } + default: + { + while (buf != bufend) + { + if (*buf == '\n') + { + buf++; + success = tb_true; + break; + } + else + buf++; + } + } + break; + } + return success ? buf : tb_null; +} + +typedef enum __pushline_state_e +{ + PL_EOF, + PL_FIN, + PL_CONL, + PL_FAIL, +} pushline_state_e; + +static tb_int_t buffer_pushline(luaL_Buffer* buf, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + tb_size_t charset = file->encoding; + tb_bool_t binary = charset == XM_IO_FILE_ENCODING_BINARY || charset == XM_IO_FILE_ENCODING_UNKNOWN; + if (binary) + { + continuation = ""; + keep_crlf = tb_true; + } + tb_int_t result = 0; + tb_byte_t readbuf[512]; + tb_size_t conlen = tb_strlen(continuation); + + tb_buffer_t readdata; + tb_buffer_init(&readdata); + tb_buffer_t transdata; + tb_buffer_init(&transdata); + // transcode is redundant, write to transdata directly + tb_bool_t notrans = charset == TB_CHARSET_TYPE_UTF8 || binary; + while (1) + { + tb_long_t readsize = tb_file_read(file->file_ref, readbuf, tb_arrayn(readbuf)); + if (readsize <= 0) break; + tb_byte_t const* lf_ptr = find_lf(readbuf, readsize, charset); + if (lf_ptr) + { + tb_size_t validlen = (tb_size_t)(lf_ptr - readbuf); + // set pos to after lf + tb_file_seek(file->file_ref, (tb_hong_t)validlen - readsize, TB_FILE_SEEK_CUR); + if (notrans) + tb_buffer_memncpyp(&transdata, tb_buffer_size(&transdata), readbuf, validlen); + else + tb_buffer_memncpyp(&readdata, tb_buffer_size(&readdata), readbuf, validlen); + break; + } + // not line ending? copy to heap and continue + if (notrans) + tb_buffer_memncpyp(&transdata, tb_buffer_size(&transdata), readbuf, readsize); + else + tb_buffer_memncpyp(&readdata, tb_buffer_size(&readdata), readbuf, readsize); + } + + tb_size_t len = 0; + do + { + if (tb_buffer_size(notrans ? &transdata : &readdata) == 0) + { + result = PL_EOF; + break; + } + + if (notrans) + { + len = tb_buffer_size(&transdata); + tb_buffer_memncpyp(&transdata, len, (tb_byte_t const*)"\0\0", 2); + } + else + { + len = tb_buffer_size(&readdata); + tb_buffer_memncpyp(&readdata, len, (tb_byte_t const*)"\0\0", 2); + } + + if (notrans) + { + } +#ifdef TB_CONFIG_OS_WINDOWS + else if (charset == XM_IO_FILE_ENCODING_ANSI) + { + tb_long_t dst_size = 0; + tb_size_t dst_maxn = len * 3; + tb_char_t* dst_data = (tb_char_t*)tb_buffer_resize(&transdata, dst_maxn + 1); + if (dst_data && dst_maxn && + (dst_size = xm_mbstoutf8(dst_data, (tb_char_t const*)tb_buffer_data(&readdata), dst_maxn, GetACP())) >= + 0 && + dst_size < dst_maxn) + { + len = dst_size; + } + else + { + result = PL_FAIL; + break; + } + } +#endif + else + { + // convert string + tb_long_t dst_size = 0; + tb_size_t dst_maxn = len * 3; + tb_byte_t* dst_data = tb_buffer_resize(&transdata, dst_maxn + 1); + if (dst_data && dst_maxn && + (dst_size = tb_charset_conv_data(charset, TB_CHARSET_TYPE_UTF8, tb_buffer_data(&readdata), len, + dst_data, dst_maxn)) >= 0 && + dst_size < dst_maxn) + { + len = dst_size; + } + else + { + result = PL_FAIL; + break; + } + } + tb_byte_t* buf = tb_buffer_data(&transdata); + if (buf[len - 1] != '\n') + { + // end of file, no lf found + result = PL_FIN; + } + else if (len > 1) + { + if (!binary && buf[len - 2] == '\r') + { + buf[len - 2] = '\n'; + len--; + } + tb_bool_t con_line = conlen && len >= conlen + 1 && + tb_strncmp(continuation, (tb_char_t const*)(buf + len - conlen - 1), conlen) == 0; + if (!keep_crlf && !con_line) len--; + if (con_line) len -= conlen + 1; + buf[len] = '\0'; + result = con_line ? PL_CONL : PL_FIN; + } + else + { + // a single '\n' + if (!keep_crlf) len = 0; + result = PL_FIN; + } + } while (0); + + if (result == PL_FIN || result == PL_CONL) luaL_addlstring(buf, (tb_char_t const*)tb_buffer_data(&transdata), len); + + tb_buffer_exit(&readdata); + tb_buffer_exit(&transdata); + return result; +} + +static tb_int_t read_all(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + luaL_Buffer sbuf, *buf = &sbuf; + luaL_buffinit(lua, buf); + tb_bool_t has_content = tb_false; + while (1) + { + switch (buffer_pushline(buf, file, continuation, tb_true)) + { + case PL_EOF: + luaL_pushresult(buf); + if (!has_content) lua_pushliteral(lua, ""); + return 1; + case PL_FIN: + case PL_CONL: has_content = tb_true; continue; + case PL_FAIL: + default: luaL_pushresult(buf); xm_io_file_error(lua, "failed to readline"); + } + } +} + +static tb_int_t read_line(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + luaL_Buffer sbuf, *buf = &sbuf; + luaL_buffinit(lua, buf); + tb_bool_t has_content = tb_false; + while (1) + { + switch (buffer_pushline(buf, file, continuation, keep_crlf)) + { + case PL_EOF: + luaL_pushresult(buf); + if (!has_content) lua_pushnil(lua); + return 1; + case PL_FIN: luaL_pushresult(buf); return 1; + case PL_CONL: has_content = tb_true; continue; + case PL_FAIL: + default: luaL_pushresult(buf); xm_io_file_error(lua, "failed to readline"); + } + } +} + +static tb_int_t read_n(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_long_t n) +{ + if (*continuation != '\0') xm_io_file_error(lua, "continuation is not supported for read number of bytes"); + tb_size_t charset = file->encoding; + tb_bool_t binary = charset == XM_IO_FILE_ENCODING_BINARY || charset == XM_IO_FILE_ENCODING_UNKNOWN; + if (!binary) xm_io_file_error(lua, "read number of bytes only allows binary file, reopen with 'rb' and try again"); + if (n == 0) + { + tb_byte_t buf[1]; + tb_long_t readsize = tb_file_read(file->file_ref, buf, 1); + if (readsize > 0) + { + lua_pushliteral(lua, ""); + tb_file_seek(file->file_ref, -readsize, TB_FILE_SEEK_CUR); + lua_pushlstring(lua, (tb_char_t const*)buf, readsize); + } + else + lua_pushnil(lua); + return 1; + } + else + { + tb_buffer_t buf; + tb_buffer_init(&buf); + tb_byte_t* bufptr = tb_buffer_resize(&buf, n + 1); + tb_long_t readsize = tb_file_read(file->file_ref, bufptr, n); + if (readsize > 0) + lua_pushlstring(lua, (tb_char_t const*)bufptr, readsize); + else + lua_pushnil(lua); + tb_buffer_exit(&buf); + return 1; + } +} + +static tb_size_t std_buffer_pushline(luaL_Buffer* buf, xm_io_file* file, tb_char_t const* continuation, + tb_bool_t keep_crlf) +{ + tb_char_t strbuf[8192]; + tb_size_t buflen = 0; + tb_size_t result = PL_FAIL; +#ifdef TB_CONFIG_OS_WINDOWS + tb_wchar_t readbuf[2730]; + // get input buffer + if (fgetws(readbuf, (tb_int_t)tb_arrayn(readbuf) - 1, file->std_ref)) + { + buflen = xm_wcstoutf8(strbuf, readbuf, tb_arrayn(strbuf) - 1); + } +#else + if (fgets(strbuf, (tb_int_t)tb_arrayn(strbuf) - 1, file->std_ref)) + { + buflen = tb_strlen(strbuf); + } +#endif + 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 > conlen) + { + tb_bool_t con_line = + conlen && buflen >= conlen + 1 && tb_strncmp(continuation, (strbuf + buflen - conlen - 1), conlen) == 0; + if (!keep_crlf && !con_line) buflen--; + if (con_line) buflen -= conlen + 1; + result = con_line ? PL_CONL : PL_FIN; + } + else + { + // a single '\n' + if (!keep_crlf) buflen = 0; + result = PL_FIN; + } + + if (result == PL_FIN || result == PL_CONL) luaL_addlstring(buf, strbuf, buflen); + return result; +} + +static tb_int_t std_read_line(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_bool_t keep_crlf) +{ + luaL_Buffer sbuf, *buf = &sbuf; + luaL_buffinit(lua, buf); + tb_bool_t has_content = tb_false; + while (1) + { + switch (std_buffer_pushline(buf, file, continuation, keep_crlf)) + { + case PL_EOF: + luaL_pushresult(buf); + if (!has_content) lua_pushnil(lua); + return 1; + case PL_FIN: luaL_pushresult(buf); return 1; + case PL_CONL: has_content = tb_true; continue; + case PL_FAIL: + default: luaL_pushresult(buf); xm_io_file_error(lua, "failed to readline"); + } + } +} + +static tb_int_t std_read_all(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + luaL_Buffer sbuf, *buf = &sbuf; + luaL_buffinit(lua, buf); + tb_bool_t has_content = tb_false; + while (1) + { + switch (std_buffer_pushline(buf, file, continuation, tb_true)) + { + case PL_EOF: + luaL_pushresult(buf); + if (!has_content) lua_pushliteral(lua, ""); + return 1; + case PL_FIN: + case PL_CONL: has_content = tb_true; continue; + case PL_FAIL: + default: luaL_pushresult(buf); xm_io_file_error(lua, "failed to readline"); + } + } +} + +static tb_int_t std_read_n(lua_State* lua, xm_io_file* file, tb_char_t const* continuation, tb_long_t n) +{ + if (*continuation != '\0') xm_io_file_error(lua, "continuation is not supported for std streams"); + if (n == 0) + { +#ifdef TB_CONFIG_OS_WINDOWS + wint_t c = getwc(file->std_ref); + ungetwc(c, file->std_ref); + if (c == WEOF) +#else + int c = getc(file->std_ref); + ungetc(c, file->std_ref); + if (c == EOF) +#endif + lua_pushnil(lua); + else + lua_pushliteral(lua, ""); + return 1; + } +#ifdef TB_CONFIG_OS_WINDOWS + tb_buffer_t readbuf, transbuf; + tb_buffer_init(&readbuf); + tb_wchar_t* readbuf_ptr = (tb_wchar_t*)tb_buffer_resize(&readbuf, (tb_size_t)((n + 1) * sizeof(tb_wchar_t))); + tb_size_t readcount = fread(readbuf_ptr, sizeof(tb_wchar_t), n, file->std_ref); + readbuf_ptr[readcount] = L'\0'; // add null termination for tb_wcstombs + tb_buffer_init(&transbuf); + tb_char_t* transbuf_ptr = (tb_char_t*)tb_buffer_resize(&transbuf, (tb_size_t)(n * 3)); + tb_size_t transcount = tb_wcstombs(transbuf_ptr, readbuf_ptr, (tb_size_t)(n * 3)); + tb_buffer_exit(&readbuf); + lua_pushlstring(lua, transbuf_ptr, transcount); + tb_buffer_exit(&transbuf); +#else + tb_buffer_t buf; + tb_buffer_init(&buf); + tb_char_t* buf_ptr = (tb_char_t*)tb_buffer_resize(&buf, (tb_size_t)n); + tb_size_t readcount = fread(buf_ptr, sizeof(tb_byte_t), (tb_size_t)n, file->std_ref); + lua_pushlstring(lua, buf_ptr, readcount); + tb_buffer_exit(&buf); +#endif + return 1; +} + +static tb_int_t std_read_num(lua_State* lua, xm_io_file* file, tb_char_t const* continuation) +{ + if (*continuation != '\0') xm_io_file_error(lua, "continuation is not supported for std streams"); + tb_double_t d; +#ifdef TB_CONFIG_OS_WINDOWS + if (fwscanf(file->std_ref, L"%lf", &d) == 1) + { + lua_pushnumber(lua, d); + return 1; + } +#else + if (fscanf(file->std_ref, "%lf", &d) == 1) + { + lua_pushnumber(lua, d); + return 1; + } +#endif + else + { + lua_pushnil(lua); + return 0; + } +} + +/* + * 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); + + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + tb_char_t const* mode = luaL_optstring(lua, 2, "l"); + tb_char_t const* continuation = luaL_optstring(lua, 3, ""); + + tb_long_t count = -1; + if (lua_isnumber(lua, 2)) + count = (tb_long_t)lua_tointeger(lua, 2); + else if (*mode == '*') + mode++; + + if (xm_io_file_is_file(file)) + { + if (xm_io_file_is_closed_file(file)) xm_io_file_error_closed(lua); + if (file->encoding == XM_IO_FILE_ENCODING_UNKNOWN) + { + // detect encoding + tb_byte_t buffer[1024]; + tb_byte_t const* buffer_ptr = buffer; + // save offset + tb_hong_t offset = tb_file_offset(file->file_ref); + tb_file_seek(file->file_ref, 0, TB_FILE_SEEK_BEG); + tb_long_t size = tb_file_read(file->file_ref, buffer, 1024); + if (size <= 0) + file->encoding = XM_IO_FILE_ENCODING_BINARY; + else + { + file->encoding = detect_charset(&buffer_ptr, size); + if (offset == 0) offset += buffer_ptr - buffer; // skip bom if we are at the begining + } + // restore offset + tb_file_seek(file->file_ref, offset, TB_FILE_SEEK_BEG); + } + if (count >= 0) return read_n(lua, file, continuation, count); + switch (*mode) + { + case 'a': return read_all(lua, file, continuation); + case 'L': return read_line(lua, file, continuation, tb_true); + case 'n': xm_io_file_error(lua, "read number is not implemented"); + case 'l': + default: return read_line(lua, file, continuation, tb_false); + } + } + if (count >= 0) return std_read_n(lua, file, continuation, count); + switch (*mode) + { + case 'a': return std_read_all(lua, file, continuation); + case 'L': return std_read_line(lua, file, continuation, tb_true); + case 'n': return std_read_num(lua, file, continuation); + case 'l': + default: return std_read_line(lua, file, continuation, tb_false); + } +} diff --git a/core/src/xmake/io/file_seek.c b/core/src/xmake/io/file_seek.c new file mode 100644 index 000000000..cc0e65594 --- /dev/null +++ b/core/src/xmake/io/file_seek.c @@ -0,0 +1,70 @@ +/*!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_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + tb_char_t const* whence = luaL_optstring(lua, 2, "cur"); + tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0); + if (xm_io_file_is_file(file)) + { + if (xm_io_file_is_closed_file(file)) xm_io_file_error_closed(lua); + tb_size_t mode = TB_FILE_SEEK_CUR; + switch (*whence) + { + case 's': // "set" + mode = TB_FILE_SEEK_BEG; + break; + case 'e': // "end" + mode = TB_FILE_SEEK_END; + break; + } + offset = tb_file_seek(file->file_ref, offset, mode); + lua_pushnumber(lua, (lua_Number)offset); + xm_io_file_success(); + } + else + { + xm_io_file_error(lua, "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..81b6fe74e --- /dev/null +++ b/core/src/xmake/io/file_write.c @@ -0,0 +1,141 @@ +/*!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" +#ifdef TB_CONFIG_OS_WINDOWS +# include "../winos/ansi.h" +# include <io.h> +#else +# include <unistd.h> +#endif +#include "file.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +static tb_void_t direct_write(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + tb_file_writ(file->file_ref, (tb_byte_t const*)data, size); +} +static tb_void_t transcode_write(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + tb_buffer_t buf; + tb_buffer_init(&buf); + tb_byte_t* buf_ptr = tb_buffer_resize(&buf, (size + 1) * 2); + tb_long_t buf_size = tb_charset_conv_cstr(TB_CHARSET_TYPE_UTF8, file->encoding, data, buf_ptr, size * 2); + if (buf_size > 0) tb_file_writ(file->file_ref, buf_ptr, (tb_size_t)buf_size); + tb_buffer_exit(&buf); + return; +} + +static tb_void_t std_write(xm_io_file* file, tb_char_t const* data, tb_size_t size) +{ + tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY); + tb_check_return(type != XM_IO_FILE_TYPE_STDIN); + +#ifdef TB_CONFIG_OS_WINDOWS + HANDLE handle = INVALID_HANDLE_VALUE; + switch (type) + { + case XM_IO_FILE_TYPE_STDOUT: handle = GetStdHandle(STD_OUTPUT_HANDLE); break; + case XM_IO_FILE_TYPE_STDERR: handle = GetStdHandle(STD_ERROR_HANDLE); break; + } + tb_check_return(handle != INVALID_HANDLE_VALUE); + + // write string to stdout + tb_size_t writ = 0; + + // write to the stdout + DWORD real = 0; + tb_buffer_t wbuf; + tb_buffer_init(&wbuf); + if (xm_io_file_is_tty(file)) + { + // write to console + tb_wchar_t* wdata = (tb_wchar_t*)tb_buffer_resize(&wbuf, (size + 1) * 2); + tb_size_t wsize = tb_mbstowcs(wdata, data, size); + while (writ < wsize) + { + if (!WriteConsoleW(handle, wdata + writ, (DWORD)(wsize - writ), &real, tb_null)) break; + // update writted size + writ += (tb_size_t)real; + } + } + else + { + // write to redirected file + tb_char_t* wdata = (tb_char_t*)tb_buffer_resize(&wbuf, (size + 1) * 4); + tb_size_t wsize = xm_utf8tombs(wdata, data, size * 4, GetConsoleOutputCP()); + while (writ < wsize) + { + if (!WriteFile(handle, wdata + writ, (DWORD)(wsize - writ), &real, tb_null)) break; + // update writted size + writ += (tb_size_t)real; + } + } + tb_buffer_exit(&wbuf); +#else + fwrite(data, sizeof(tb_char_t), size, file->std_ref); +#endif +} + +/* + * file:write(...) + */ +tb_int_t xm_io_file_write(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + xm_io_file* file = (xm_io_file*)luaL_checkudata(lua, 1, xm_io_file_udata); + tb_int_t narg = lua_gettop(lua); + + // set to utf-8 if not specified + if (file->encoding == XM_IO_FILE_ENCODING_UNKNOWN) file->encoding = TB_CHARSET_TYPE_UTF8; + tb_bool_t direct = file->encoding == TB_CHARSET_TYPE_UTF8 || file->encoding == XM_IO_FILE_ENCODING_BINARY; + if (xm_io_file_is_closed_file(file)) xm_io_file_error_closed(lua); + + for (tb_int_t i = 2; i <= narg; i++) + { + size_t datasize; + tb_char_t const* data = luaL_checklstring(lua, i, &datasize); + + if (!xm_io_file_is_file(file)) + std_write(file, data, (tb_size_t)datasize); + else if (direct) + direct_write(file, data, (tb_size_t)datasize); + else + transcode_write(file, data, (tb_size_t)datasize); + } + + lua_settop(lua, 1); + xm_io_file_success(); +} diff --git a/core/src/xmake/io/open.c b/core/src/xmake/io/open.c new file mode 100644 index 000000000..fae03781f --- /dev/null +++ b/core/src/xmake/io/open.c @@ -0,0 +1,106 @@ +/*!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" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* + * io.open(path, mode) + */ +tb_int_t xm_io_open(lua_State* lua) +{ + tb_char_t const* path = luaL_checkstring(lua, 1); + tb_char_t const* mode = luaL_optstring(lua, 2, "r"); + tb_size_t tb_mode = TB_FILE_MODE_RW; + switch (mode[0]) + { + case 'w': tb_mode |= TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC; break; + case 'a': tb_mode |= TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT; break; + default: break; + } + tb_bool_t update = !!tb_strchr(mode, '+'); + tb_char_t full[TB_PATH_MAXN] = {0}; + path = tb_path_absolute(path, full, TB_PATH_MAXN); + tb_file_ref_t file = tb_file_init(path, tb_mode); + tb_size_t pathlen = tb_strlen(path); + tb_char_t* savedfull = tb_malloc_cstr(pathlen + 1); + tb_strcpy(savedfull, path); + + if (file) + { + tb_bool_t is_binary = mode[1] == 'b' || (update && mode[2] == 'b'); + tb_bool_t is_utf8 = tb_strstr(mode, "utf8") || tb_strstr(mode, "utf-8"); + tb_bool_t is_u16le = tb_strstr(mode, "utf16le") || tb_strstr(mode, "utf-16le"); + tb_bool_t is_u16be = tb_strstr(mode, "utf16be") || tb_strstr(mode, "utf-16be"); + tb_bool_t is_u16 = tb_strstr(mode, "utf16") || tb_strstr(mode, "utf-16"); + + tb_size_t enc = XM_IO_FILE_ENCODING_UNKNOWN; + if (is_binary) + enc = XM_IO_FILE_ENCODING_BINARY; + else if (is_utf8) + enc = TB_CHARSET_TYPE_UTF8; + else if (is_u16le) + enc = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + else if (is_u16be) + enc = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + else if (is_u16) + enc = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE; + + xm_io_file* xm_file = xm_io_newfile(lua); + xm_file->file_ref = file; + xm_file->mode = tb_mode; + xm_file->type = XM_IO_FILE_TYPE_FILE; + xm_file->encoding = enc; + xm_file->path = savedfull; + tb_strcpy(xm_file->name, "file: "); + if (pathlen < tb_arrayn(xm_file->name) - tb_arrayn("file: ")) + { + tb_strcat(xm_file->name, full); + } + else + { + tb_strcat(xm_file->name, "..."); + tb_strcat(xm_file->name, + full + (pathlen - tb_arrayn(xm_file->name) + tb_arrayn("file: ") + tb_arrayn("..."))); + } + return 1; + } + else + { + tb_free(savedfull); + lua_pushnil(lua); + lua_pushliteral(lua, "failed to open file."); + return 2; + } +}
\ No newline at end of file diff --git a/core/src/xmake/io/std.c b/core/src/xmake/io/std.c new file mode 100644 index 000000000..4a79f5397 --- /dev/null +++ b/core/src/xmake/io/std.c @@ -0,0 +1,117 @@ +/*!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_isatty(tb_size_t type) +{ + tb_bool_t answer; +#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 + + // return answer + if (answer) type |= XM_IO_FILE_FLAG_TTY; + return type; +} + +static void xm_init(lua_State* lua, tb_size_t type) +{ + tb_char_t const *name, *path; + FILE* fp; + switch (type) + { + case XM_IO_FILE_TYPE_STDIN: + name = "stdin"; + fp = stdin; + break; + case XM_IO_FILE_TYPE_STDOUT: + name = "stdout"; + fp = stdout; + break; + case XM_IO_FILE_TYPE_STDERR: + name = "stderr"; + fp = stderr; + 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 + xm_io_file* file = xm_io_newfile(lua); + lua_setfield(lua, -2, name); + file->encoding = TB_CHARSET_TYPE_UTF8; + file->type = xm_isatty(type); + file->path = path; + file->std_ref = fp; + tb_char_t const* info = xm_io_file_is_tty(file) ? "" : " redirected"; + tb_sprintf(file->name, "file: (%s%s)", name, info); +} + +tb_int_t xm_io_std(lua_State* lua) +{ + lua_getglobal(lua, "io"); + xm_init(lua, XM_IO_FILE_TYPE_STDIN); + xm_init(lua, XM_IO_FILE_TYPE_STDOUT); + xm_init(lua, XM_IO_FILE_TYPE_STDERR); + lua_pop(lua, 1); + return 0; +}
\ No newline at end of file diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index 2ca2227c5..26734acfd 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,19 @@ 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); // the path functions tb_int_t xm_path_relative(lua_State* lua); @@ -102,6 +118,12 @@ tb_int_t xm_hash_sha256(lua_State* lua); // the windows functions #ifdef TB_CONFIG_OS_WINDOWS +tb_int_t xm_winos_mbstoutf8(lua_State* lua); +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 @@ -144,6 +166,12 @@ tb_int_t xm_curses_register(lua_State* lua); * globals */ +// the global functions +static luaL_Reg const g_functions[] = +{ + { tb_null, tb_null } +}; + // the os functions static luaL_Reg const g_os_functions[] = { @@ -186,19 +214,41 @@ 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 } + { "mbstoutf8", xm_winos_mbstoutf8 } +, { "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_close } +, { "__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,13 +324,23 @@ 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], 4096); + argv[i] = argvbuf; +#endif + // table_new[table.getn(table_new) + 1] = argv[i] lua_pushstring(machine->lua, argv[i]); lua_rawseti(machine->lua, -2, (int)lua_objlen(machine->lua, -2) + 1); @@ -303,10 +363,14 @@ 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); + path[size] = '\0'; // ok @@ -520,6 +584,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); @@ -554,6 +638,12 @@ xm_machine_ref_t xm_machine_init() lua_setglobal(machine->lua, "curses"); #endif + // bind global functions + for (tb_size_t i = 0; g_functions[i].name != tb_null && g_functions[i].func != tb_null; i++) + { + lua_register(machine->lua, g_functions[i].name, g_functions[i].func); + } + // init host #if defined(TB_CONFIG_OS_WINDOWS) lua_pushstring(machine->lua, "windows"); @@ -643,6 +733,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..b528d00ba 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 \ + 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/sandbox/interactive.c b/core/src/xmake/sandbox/interactive.c index 6fc643520..c5536acb1 100644 --- a/core/src/xmake/sandbox/interactive.c +++ b/core/src/xmake/sandbox/interactive.c @@ -29,17 +29,18 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * 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 <stdio.h> // on some OS (like centos) required #endif /* ////////////////////////////////////////////////////////////////////////////////////// @@ -47,10 +48,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 +63,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 +81,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 +96,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 +109,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 +132,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; @@ -159,32 +163,42 @@ static tb_size_t xm_sandbox_readline(tb_char_t* data, tb_size_t maxn, tb_char_t tb_free(line); // truncated? - if (size >= maxn) - return 0; + if (size >= maxn) return 0; // ok return size; } #else - + // print prompt tb_printf(prompt); tb_print_sync(); +# ifdef TB_CONFIG_OS_WINDOWS + tb_wchar_t buf[LUA_PROMPT_BUFSIZE]; // get input buffer - if (fgets(data, (tb_int_t)maxn, stdin)) + if (fgetws(buf, (tb_int_t)(maxn / 3), stdin)) + { + xm_wcstoutf8(data, buf, maxn); + return tb_strlen(data); + } +# else + if (fgets(data, (tb_int_t)maxn, stdin)) + { return tb_strlen(data); + } +# endif #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 +218,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 +235,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 +252,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 +264,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 +281,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 +292,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 +312,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 +334,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 +355,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..693a605ee 100644 --- a/core/src/xmake/string/convert.c +++ b/core/src/xmake/string/convert.c @@ -52,7 +52,7 @@ static xm_charset_entry_t g_charsets[] = , {TB_CHARSET_TYPE_GB2312, "gb2312" } , {TB_CHARSET_TYPE_GBK, "gbk" } , {TB_CHARSET_TYPE_ISO8859, "iso8859" } -, {TB_CHARSET_TYPE_UCS2, "ucs3" } +, {TB_CHARSET_TYPE_UCS2, "ucs2" } , {TB_CHARSET_TYPE_UCS4, "ucs4" } , {TB_CHARSET_TYPE_UTF16, "utf16" } , {TB_CHARSET_TYPE_UTF32, "utf32" } @@ -122,10 +122,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..1973fdc82 --- /dev/null +++ b/core/src/xmake/winos/ansi.c @@ -0,0 +1,231 @@ +/*!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); + +tb_int_t xm_winos_console_cp(lua_State* lua) +{ + 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) +{ + 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) +{ + 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); + xm_wcstoutf8(namebuf, cp_info.CodePageName, sizeof(cp_info.CodePageName) * 2); + lua_pushstring(lua, namebuf); + 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) +{ + tb_uint_t cp = GetACP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; +} + +tb_int_t xm_winos_oem_cp(lua_State* lua) +{ + tb_uint_t cp = GetOEMCP(); + lua_pushinteger(lua, (lua_Integer)cp); + return 1; +} + +tb_int_t xm_winos_mbstoutf8(lua_State* lua) +{ + tb_int_t n = lua_gettop(lua); + if (n == 0) + { + return 0; + } + tb_int_t cp = 0; + tb_int_t r_len = 0; + lua_Integer lcp = luaL_optinteger(lua, 1, CP_ACP); + luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page"); + cp = (tb_int_t)lcp; + for (tb_int_t i = 2; i <= n; i++) + { + tb_char_t const* mbs = lua_tostring(lua, i); + tb_size_t utf8size = tb_strlen(mbs) * 4; + tb_char_t* utf8 = tb_malloc_cstr(utf8size); + utf8size = xm_mbstoutf8(utf8, mbs, utf8size, cp); + lua_pushlstring(lua, utf8, utf8size); + tb_free(utf8); + r_len++; + } + return r_len; +} + +tb_size_t xm_wcstoutf8(tb_char_t* s1, tb_wchar_t const* s2, tb_size_t n) +{ + if (*s2 == 0) + { + if (n > 0) *s1 = 0; + return 0; + } + tb_size_t size = (tb_size_t)WideCharToMultiByte(CP_UTF8, 0, s2, -1, s1, (tb_int_t)n, NULL, NULL); + if (size > 0 && s1[size - 1] == 0) size--; + return size; +} + +tb_size_t xm_utf8towcs(tb_wchar_t* s1, tb_char_t const* s2, tb_size_t n) +{ + if (*s2 == 0) + { + if (n > 0) *s1 = 0; + return 0; + } + tb_size_t size = (tb_size_t)MultiByteToWideChar(CP_UTF8, 0, s2, -1, s1, (tb_int_t)n); + if (size > 0 && s1[size - 1] == 0) size--; + return size; +} + +tb_size_t xm_mbstoutf8(tb_char_t* s1, tb_char_t const* s2, tb_size_t n, tb_int_t mbs_cp) +{ + if (*s2 == 0) + { + if (n > 0) *s1 = 0; + return 0; + } + tb_int_t u16buflen = MultiByteToWideChar(mbs_cp, 0, s2, -1, NULL, 0); + tb_wchar_t* u16buf = tb_nalloc_type(u16buflen, tb_wchar_t); + u16buflen = MultiByteToWideChar(mbs_cp, 0, s2, -1, u16buf, u16buflen); + tb_size_t size = (tb_size_t)WideCharToMultiByte(CP_UTF8, 0, u16buf, u16buflen, s1, (tb_int_t)n, NULL, NULL); + tb_free(u16buf); + if (size > 0 && s1[size - 1] == 0) size--; + return size; +} + +tb_size_t xm_utf8tombs(tb_char_t* s1, tb_char_t const* s2, tb_size_t n, tb_int_t mbs_cp) +{ + if (*s2 == 0) + { + if (n > 0) *s1 = 0; + return 0; + } + tb_int_t u16buflen = MultiByteToWideChar(CP_UTF8, 0, s2, -1, NULL, 0); + tb_wchar_t* u16buf = tb_nalloc_type(u16buflen, tb_wchar_t); + u16buflen = MultiByteToWideChar(CP_UTF8, 0, s2, -1, u16buf, u16buflen); + tb_size_t size = (tb_size_t)WideCharToMultiByte(mbs_cp, 0, u16buf, u16buflen, s1, (tb_int_t)n, NULL, NULL); + tb_free(u16buf); + if (size > 0 && s1[size - 1] == 0) size--; + return size; +} + +static tb_int_t xm_expand_cp(tb_int_t cp) +{ + if (cp == CP_OEMCP) return GetOEMCP(); + if (cp == CP_ACP) return GetACP(); + return cp; +} diff --git a/core/src/xmake/winos/ansi.h b/core/src/xmake/winos/ansi.h new file mode 100644 index 000000000..cb68c0710 --- /dev/null +++ b/core/src/xmake/winos/ansi.h @@ -0,0 +1,36 @@ +/*!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" + +#ifdef TB_CONFIG_OS_WINDOWS +tb_size_t xm_wcstoutf8(tb_char_t *s1, tb_wchar_t const *s2, tb_size_t n); +tb_size_t xm_utf8towcs(tb_wchar_t *s1, tb_char_t const *s2, tb_size_t n); +tb_size_t xm_mbstoutf8(tb_char_t *s1, tb_char_t const *s2, tb_size_t n, tb_int_t mbs_cp); +tb_size_t xm_utf8tombs(tb_char_t *s1, tb_char_t const *s2, tb_size_t n, tb_int_t mbs_cp); +#endif + +#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..8806d1ca5 100644 --- a/core/src/xmake/xmake.lua +++ b/core/src/xmake/xmake.lua @@ -23,11 +23,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 diff --git a/core/xmake.lua b/core/xmake.lua index 68f13470f..4a73121ca 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -61,10 +61,11 @@ option_end() -- suppress warnings if is_plat("windows") then add_defines("_CRT_SECURE_NO_WARNINGS") + add_cxflags("/utf-8") end -- add projects -includes("src/lcurses", "src/sv","src/luajit", "src/tbox", "src/xmake", "src/demo") +includes("src/lcurses", "src/sv","src/luajit", "src/tbox", "src/xmake", "src/demo") if is_plat("windows") then includes("src/pdcurses") end diff --git a/tests/modules/io/files/.gitattributes b/tests/modules/io/files/.gitattributes new file mode 100644 index 000000000..741c0a207 --- /dev/null +++ b/tests/modules/io/files/.gitattributes @@ -0,0 +1 @@ +* binary
\ No newline at end of file diff --git a/tests/modules/io/files/utf16be-lf-eleof b/tests/modules/io/files/utf16be-lf-eleof Binary files differnew file mode 100644 index 000000000..139bddb28 --- /dev/null +++ b/tests/modules/io/files/utf16be-lf-eleof diff --git a/tests/modules/io/files/utf16le-crlf-neleof b/tests/modules/io/files/utf16le-crlf-neleof Binary files differnew file mode 100644 index 000000000..4089f2b19 --- /dev/null +++ b/tests/modules/io/files/utf16le-crlf-neleof diff --git a/tests/modules/io/files/utf8-crlf-neleof b/tests/modules/io/files/utf8-crlf-neleof new file mode 100644 index 000000000..daeda335b --- /dev/null +++ b/tests/modules/io/files/utf8-crlf-neleof @@ -0,0 +1,3 @@ +123\
+456
+789
\ No newline at end of file diff --git a/tests/modules/io/files/utf8-longline-eleof b/tests/modules/io/files/utf8-longline-eleof new file mode 100644 index 000000000..22a5d40c9 --- /dev/null +++ b/tests/modules/io/files/utf8-longline-eleof @@ -0,0 +1 @@ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 diff --git a/tests/modules/io/files/utf8-longline-neleof b/tests/modules/io/files/utf8-longline-neleof new file mode 100644 index 000000000..22d650d63 --- /dev/null +++ b/tests/modules/io/files/utf8-longline-neleof @@ -0,0 +1 @@ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
\ No newline at end of file diff --git a/tests/modules/io/files/utf8bom-lf-eleof b/tests/modules/io/files/utf8bom-lf-eleof new file mode 100644 index 000000000..8845bbb9f --- /dev/null +++ b/tests/modules/io/files/utf8bom-lf-eleof @@ -0,0 +1,3 @@ +123\ +456 +789 diff --git a/tests/modules/io/test.lua b/tests/modules/io/test.lua new file mode 100644 index 000000000..cbdb94923 --- /dev/null +++ b/tests/modules/io/test.lua @@ -0,0 +1,80 @@ +function test_read(t) + t:are_equal(io.readfile("files/utf8bom-lf-eleof"), "123\\\n456\n789\n") + t:are_equal(io.readfile("files/utf8-crlf-neleof"), "123\\\n456\n789") + t:are_equal(io.readfile("files/utf8-crlf-neleof", {encoding = "binary"}), "123\\\r\n456\r\n789") + t:are_equal(io.readfile("files/utf8-crlf-neleof", {continuation = "\\"}), "123456\n789") + t:are_equal(io.readfile("files/utf16be-lf-eleof"), "123\\\n456\n789\n") + t:are_equal(io.readfile("files/utf16le-crlf-neleof"), "123\\\n456\n789") + + local data1 = io.readfile("files/utf8-longline-neleof") + t:are_equal(#data1, 10000) + t:require(data1:endswith("1234567890")) + + local data2 = io.readfile("files/utf8-longline-eleof") + t:are_equal(#data2, 10001) + t:require(data2:endswith("1234567890\n")) +end + +function test_lines(t) + t:are_equal(table.to_array(io.lines("files/utf8bom-lf-eleof")), {"123\\", "456", "789"}) + t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof")), {"123\\", "456", "789"}) + t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof", {encoding = "binary"})), {"123\\\r\n", "456\r\n", "789"}) + t:are_equal(table.to_array(io.lines("files/utf8-crlf-neleof", {continuation = "\\"})), {"123456", "789"}) + t:are_equal(table.to_array(io.lines("files/utf16be-lf-eleof")), {"123\\", "456", "789"}) + t:are_equal(table.to_array(io.lines("files/utf16le-crlf-neleof")), {"123\\", "456", "789"}) +end + +function test_readlines(t) + + function get_all(file, opt) + local fp = io.open(file, "r", opt) + local r = {} + while true do + local l = fp:read("L", opt) + if l == nil then break end + table.insert(r, l) + end + t:require(fp:close()) + + return r + end + + t:are_equal(get_all("files/utf8bom-lf-eleof"), {"123\\\n", "456\n", "789\n"}) + t:are_equal(get_all("files/utf8-crlf-neleof"), {"123\\\n", "456\n", "789"}) + t:are_equal(get_all("files/utf8-crlf-neleof", {encoding = "binary"}), {"123\\\r\n", "456\r\n", "789"}) + t:are_equal(get_all("files/utf8-crlf-neleof", {continuation = "\\"}), {"123456\n", "789"}) + t:are_equal(get_all("files/utf16be-lf-eleof"), {"123\\\n", "456\n", "789\n"}) + t:are_equal(get_all("files/utf16le-crlf-neleof"), {"123\\\n", "456\n", "789"}) +end + +function test_prop(t) + t:are_equal(io.open("files/utf8bom-lf-eleof"):size(), 16) + t:are_equal(io.open("files/utf8-crlf-neleof"):size(), 14) + t:are_equal(io.open("files/utf16be-lf-eleof"):size(), 28) + t:are_equal(io.open("files/utf16le-crlf-neleof"):size(), 30) + + t:are_equal(io.open("files/utf8bom-lf-eleof"):path(), path.absolute("files/utf8bom-lf-eleof")) + t:are_equal(io.open("files/utf8-crlf-neleof"):path(), path.absolute("files/utf8-crlf-neleof")) + t:are_equal(io.open("files/utf16be-lf-eleof"):path(), path.absolute("files/utf16be-lf-eleof")) + t:are_equal(io.open("files/utf16le-crlf-neleof"):path(), path.absolute("files/utf16le-crlf-neleof")) +end + +function test_write(t) + + function write(fname, opt) + local f = io.open(fname, "w", opt) + f:write(123, "abc", 456, "def", "\n") + f:close() + + -- give encoding info + t:are_equal(io.readfile(fname, opt), "123abc456def\n") + -- auto detect encoding + t:are_equal(io.readfile(fname), "123abc456def\n") + end + write("temp/path/not/exist/utf8", {encoding = "utf8"}) + write("temp/path/not/exist/utf16", {encoding = "utf16"}) + write("temp/path/not/exist/utf16le", {encoding = "utf16le"}) + write("temp/path/not/exist/utf16be", {encoding = "utf16be"}) + + os.tryrm("temp") +end
\ No newline at end of file diff --git a/tests/projects/c/Unicode 测试/test.lua b/tests/projects/c/Unicode 测试/test.lua Binary files differnew file mode 100644 index 000000000..53d97c80b --- /dev/null +++ b/tests/projects/c/Unicode 测试/test.lua diff --git a/tests/projects/c/Unicode 测试/xmake.lua b/tests/projects/c/Unicode 测试/xmake.lua Binary files differnew file mode 100644 index 000000000..5e244687e --- /dev/null +++ b/tests/projects/c/Unicode 测试/xmake.lua diff --git a/tests/projects/c/Unicode 测试/头文件✨/标头🎟.h b/tests/projects/c/Unicode 测试/头文件✨/标头🎟.h new file mode 100644 index 000000000..5d6e3d81e --- /dev/null +++ b/tests/projects/c/Unicode 测试/头文件✨/标头🎟.h @@ -0,0 +1,3 @@ +#pragma once + +void hello();
\ No newline at end of file diff --git a/tests/projects/c/Unicode 测试/源文件🎆/中文.c b/tests/projects/c/Unicode 测试/源文件🎆/中文.c new file mode 100644 index 000000000..22d8f910e --- /dev/null +++ b/tests/projects/c/Unicode 测试/源文件🎆/中文.c @@ -0,0 +1,7 @@ +#include <标头🎟.h> + +int main(int argc, char** argv) +{ + hello(); + return 0; +} diff --git a/tests/projects/c/Unicode 测试/源文件🎆/😘.c b/tests/projects/c/Unicode 测试/源文件🎆/😘.c new file mode 100644 index 000000000..ec043495b --- /dev/null +++ b/tests/projects/c/Unicode 测试/源文件🎆/😘.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <wchar.h> +#include <标头🎟.h> + +void hello() +{ + printf("你好\n"); +} diff --git a/tests/run.lua b/tests/run.lua index 3658e4d22..c2554397c 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -13,28 +13,25 @@ function _run_test(script) assert(script:endswith("test.lua")) - local old_dir = os.cd(os.scriptdir()) - os.execv("xmake", table.join("lua", params, "./runner.lua", script)) - os.cd(old_dir) - + os.execv("xmake", table.join("lua", params, path.join(os.scriptdir(), "runner.lua"), script)) end -- run test with the given name function _run_test_filter(name) local tests = {} - + local root = path.absolute(os.scriptdir()) -- find the test script - for _, script in ipairs(os.files(path.join(os.scriptdir(), "**", name, "**", "test.lua"))) do + for _, script in ipairs(os.files(path.join(root, "**", name, "**", "test.lua"))) do table.insert(tests, path.absolute(script)) end - for _, script in ipairs(os.files(path.join(os.scriptdir(), name, "**", "test.lua"))) do + for _, script in ipairs(os.files(path.join(root, name, "**", "test.lua"))) do table.insert(tests, path.absolute(script)) end - for _, script in ipairs(os.files(path.join(os.scriptdir(), "**", name, "test.lua"))) do + for _, script in ipairs(os.files(path.join(root, "**", name, "test.lua"))) do table.insert(tests, path.absolute(script)) end - for _, script in ipairs(os.files(path.join(os.scriptdir(), name, "test.lua"))) do + for _, script in ipairs(os.files(path.join(root, name, "test.lua"))) do table.insert(tests, path.absolute(script)) end diff --git a/tests/test_utils/print_error.lua b/tests/test_utils/print_error.lua index dcf1e82bb..814389c5b 100644 --- a/tests/test_utils/print_error.lua +++ b/tests/test_utils/print_error.lua @@ -1,31 +1,47 @@ -function main(t, message, funcs_or_filename, abort_reason) +function _getinfo(v) + local info = debug.getinfo(v) + if info == nil then return end + if info and info.source:startswith("@") then + info.fullpath = path.absolute(vformat(info.source:sub(2)), os.workingdir()) + info.path = path.relative(info.fullpath, os.workingdir()) + end + return info +end + +function _getfuncs(funcs_or_filename) local funcs = nil if type(funcs_or_filename) == "function" then - funcs = { debug.getinfo(funcs_or_filename) } + funcs = { _getinfo(funcs_or_filename) } elseif type(funcs_or_filename) == "table" then funcs = {} for _, v in ipairs(funcs_or_filename) do - table.insert(funcs, debug.getinfo(v)) + table.join2(funcs, _getfuncs(v)) end else assert(type(funcs_or_filename) == "string") + funcs_or_filename = path.absolute(funcs_or_filename) funcs = {} local uplevel = 2 local func = nil repeat - func = debug.getinfo(uplevel) - if (func and func.source:endswith(funcs_or_filename)) then + func = _getinfo(uplevel) + if func and func.fullpath == funcs_or_filename then table.insert(funcs, func) end uplevel = uplevel + 1 until func == nil end + return funcs +end + +function main(t, message, funcs_or_filename, abort_reason) + local funcs = _getfuncs(funcs_or_filename) cprint(">> ${red}test failed:${reset} %s", message) for _, func in ipairs(funcs) do local line = (func.currentline >= 0) and func.currentline or func.linedefined local name = (func.func == t.func) and t.funcname or func.name or "(anonymous)" - cprint(">> function %s ${underline}%s${reset}:${bright}%d${reset}", name, func.source, line) + cprint(">> function %s ${underline}%s${reset}:${bright}%d${reset}", name, func.path, line) end raise("aborting because of ${red}%s${reset} ...", abort_reason or "failed assertion") end
\ No newline at end of file diff --git a/xmake/core/_xmake_main.lua b/xmake/core/_xmake_main.lua index 3246b1b57..809c58715 100644 --- a/xmake/core/_xmake_main.lua +++ b/xmake/core/_xmake_main.lua @@ -48,8 +48,24 @@ function loadfile(filepath) end end - -- load script from file - local script, errors = _loadfile(filepath) + -- load script data from file + local data, rerrors = io.readfile(filepath) + if not data then + return nil, rerrors + end + + -- init displaypath + local displaypath = filepath + if filepath:startswith(xmake._WORKING_DIR) then + displaypath = path.join(".", path.relative(filepath, xmake._WORKING_DIR)) + elseif filepath:startswith(xmake._PROGRAM_DIR) then + displaypath = path.join("$(programdir)", path.relative(filepath, xmake._PROGRAM_DIR)) + elseif filepath:startswith(xmake._PROJECT_DIR) then + displaypath = path.join("$(projectdir)", path.relative(filepath, xmake._PROJECT_DIR)) + end + + -- load script from string + local script, errors = load(data, "@" .. displaypath) if script then _loadcache[filepath] = {script = script, mtime = mtime or os.mtime(filepath)} end diff --git a/xmake/core/base/dump.lua b/xmake/core/base/dump.lua index 463c05a96..d117cf112 100644 --- a/xmake/core/base/dump.lua +++ b/xmake/core/base/dump.lua @@ -25,6 +25,12 @@ local dump = dump or {} local colors = require("base/colors") local table = require("base/table") +function dump._format(fmtkey, fmtdefault, ...) + local theme = colors.theme() + local fmt = theme and theme:get(fmtkey) or fmtdefault + return string.format(fmt, ...) +end + -- print string function dump._print_string(str, as_key) local quote = (not as_key) or (not str:match("^[a-zA-Z_][a-zA-Z0-9_]*$")) @@ -67,8 +73,7 @@ end -- print value with default format function dump._print_default(value) io.write(colors.translate("${color.dump.default}", { patch_reset = false })) - local fmt = colors.theme():get("text.dump.default_format") or "%s" - io.write(string.format(fmt, value)) + io.write(dump._format("text.dump.default_format", "%s", value)) io.write(colors.translate("${reset}", { patch_reset = false })) end @@ -89,15 +94,39 @@ function dump._print_scalar(value, as_key) end end +-- print anchor +function dump._print_anchor(value) + io.write(colors.translate("${color.dump.anchor}", { patch_reset = false })) + io.write(dump._format("text.dump.anchor", "&%s", value)) + io.write(colors.translate("${reset}", { patch_reset = false })) +end +-- print reference +function dump._print_reference(value) + io.write(colors.translate("${color.dump.reference}", { patch_reset = false })) + io.write(dump._format("text.dump.reference", "*%s", value)) + io.write(colors.translate("${reset}", { patch_reset = false })) +end + -- print table -function dump._print_table(value, first_indent, remain_indent) - io.write(first_indent .. colors.translate("${dim}{")) +function dump._print_table(value, first_indent, remain_indent, printed_set) + + io.write(first_indent) + local __tostring = rawget(getmetatable(value) or {}, "__tostring") + if __tostring then + return dump._print_default(__tostring(value, value)) + end + printed_set = printed_set or { len = 0 } + io.write(colors.translate("${dim}{")) local inner_indent = remain_indent .. " " local is_arr = table.is_array(value) local first_value = true for k, v in pairs(value) do if first_value then + printed_set.len = printed_set.len + 1 + io.write(" ") + dump._print_anchor(printed_set.len) io.write("\n") + printed_set[value] = printed_set.len first_value = false else io.write(",\n") @@ -108,7 +137,11 @@ function dump._print_table(value, first_indent, remain_indent) io.write(colors.translate("${dim} = ")) end if type(v) == "table" then - dump._print_table(v, "", inner_indent) + if printed_set[v] then + dump._print_reference(printed_set[v]) + else + dump._print_table(v, "", inner_indent, printed_set) + end else dump._print_scalar(v) end @@ -124,7 +157,7 @@ end function dump._print(value, indent) indent = indent or "" if type(value) == "table" then - dump._print_table(value, indent, indent:gsub(".", " ")) + dump._print_table(value, indent, indent:gsub(".", " "), nil) else io.write(indent) dump._print_scalar(value) diff --git a/xmake/core/base/emoji.lua b/xmake/core/base/emoji.lua index 0839f0694..e70b026ea 100644 --- a/xmake/core/base/emoji.lua +++ b/xmake/core/base/emoji.lua @@ -37,11 +37,6 @@ function emoji.translate(str) -- translate it local chars = emoji.keys[str] - -- check supported? - if chars and xmake._HOST ~= "macosx" then - return "" - end - -- ok? return chars end diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua index 01d76973e..9377c976f 100644 --- a/xmake/core/base/interpreter.lua +++ b/xmake/core/base/interpreter.lua @@ -704,7 +704,7 @@ function interpreter:load(file) -- clear first self:_clear() - -- init the current file + -- init the current file self._PRIVATE._CURFILE = file -- init the root directory diff --git a/xmake/core/base/io.lua b/xmake/core/base/io.lua index d129cacf6..e3f6b153d 100644 --- a/xmake/core/base/io.lua +++ b/xmake/core/base/io.lua @@ -11,7 +11,7 @@ -- 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 @@ -20,51 +20,43 @@ -- define module local io = io or {} -local _file = _file or {} +local _file = _file or io.file or {} -- load modules local path = require("base/path") local table = require("base/table") -local utils = require("base/utils") local string = require("base/string") -- save original apis -io._open = io._open or io.open -io._isatty = io._isatty or io.isatty +io._open = io._open or io.open --- seek file -function _file:seek(...) - return self._FILE:seek(...) -end +_file._read = _file._read or _file.read --- read file -function _file:read(...) - return self._FILE:read(...) +function _file:read(fmt, opt) + opt = opt or {} + return self:_read(fmt, opt.continuation) end --- write file -function _file:write(...) - return self._FILE:write(...) +function _file:lines(opt) + + opt = opt or {} + return function() + local l = self:read("l", opt) + if not l and opt.close_on_finished then + self:close() + end + return l + end end -- print file function _file:print(...) - return self._FILE:write(string.format(...) .. "\n") + return self:write(string.format(...), "\n") end -- printf file function _file:printf(...) - return self._FILE:write(string.format(...)) -end - --- get lines -function _file:lines() - return self._FILE:lines() -end - --- close file -function _file:close() - return self._FILE:close() + return self:write(string.format(...)) end -- save object @@ -84,31 +76,73 @@ function _file:load() end end --- read all data from file -function io.readfile(filepath) +-- read all data from file +function io.lines(filepath, opt) + + opt = opt or {} + + if opt.close_on_finished == nil then + opt.close_on_finished = true + end + + -- open file + local file = io.open(filepath, "r", opt) + if not file then + -- error + return function() return nil end + end + + return file:lines(opt) +end + +function io.readfile(filepath, opt) + + opt = opt or {} -- open file - local file = io.open(filepath, "r") + local file = io.open(filepath, "r", opt) if not file then -- error return nil, string.format("open %s failed!", filepath) end -- read all - local data = file:read("*all") + local data, err = file:read("*all", opt) -- exit file file:close() -- ok? - return data + return data, err +end + +function io.read(fmt, opt) + return io.stdin:read(fmt, opt) +end + +function io.write(...) + io.stdout:write(...) +end + +function io.print(...) + return io.stdout:print(...) end --- write data to file -function io.writefile(filepath, data) +function io.printf(...) + return io.stdout:printf(...) +end + +function io.flush() + return io.stdout:flush() +end + +-- write data to file +function io.writefile(filepath, data, opt) + + opt = opt or {} -- open file - local file = io.open(filepath, "w") + local file = io.open(filepath, "w", opt) if not file then return false, string.format("open %s failed!", filepath) end @@ -123,62 +157,52 @@ function io.writefile(filepath, data) return true end --- replace the original isatty interface +-- isatty function io.isatty(fd) - if io._ISATTY == nil then - io._ISATTY = io._isatty(fd or io.stdout) - end - return io._ISATTY + fd = fd or io.stdout + return fd:isatty() end -- replace the original open interface -function io.open(filepath, mode) +function io.open(filepath, mode, opt) -- check assert(filepath) - -- write file? - if mode == "w" then - - -- get the file directory - local dir = path.directory(filepath) - - -- ensure the file directory - if not os.isdir(dir) then - os.mkdir(dir) - end - end - - -- init file instance - local file = table.inherit(_file) + mode = mode or "r" + opt = opt or {} -- open it - local handle, errors = io._open(path.translate(filepath), mode) + local handle = io._open(path.translate(filepath), mode .. (opt.encoding or "")) if not handle then - return nil, errors + return nil, string.format("failed to open %s", filepath) end - -- save file handle - file._FILE = handle - -- ok? - return file, errors + return handle +end + +-- close file +function io.close(file) + return (file or io.stdout):close() end -- save object the the given filepath -function io.save(filepath, object) +function io.save(filepath, object, opt) - -- check + -- check assert(filepath and object) + opt = opt or {} + -- ensure directory local dir = path.directory(filepath) if not os.isdir(dir) then os.mkdir(dir) end - + -- open the file - local file = io.open(filepath, "w") + local file = io.open(filepath, "w", opt) if not file then -- error return false, string.format("open %s failed!", filepath) @@ -187,26 +211,28 @@ function io.save(filepath, object) -- save object to file local ok, errors = file:save(object) if not ok then - -- error + -- error file:close() return false, string.format("save %s failed, %s!", filepath, errors) end -- close file file:close() - + -- ok return true end -- load object from the given file -function io.load(filepath) +function io.load(filepath, opt) -- check assert(filepath) + opt = opt or {} + -- open the file - local file = io.open(filepath, "r") + local file = io.open(filepath, "r", opt) if not file then -- error return nil, string.format("open %s failed!", filepath) @@ -223,10 +249,12 @@ function io.load(filepath) end -- gsub the given file and return replaced data -function io.gsub(filepath, pattern, replace) +function io.gsub(filepath, pattern, replace, opt) + + opt = opt or {} -- read all data from file - local data, errors = io.readfile(filepath) + local data, errors = io.readfile(filepath, opt) if not data then return nil, 0, errors end -- replace it @@ -240,7 +268,7 @@ function io.gsub(filepath, pattern, replace) -- replace ok? if count ~= 0 then -- write all data to file - local ok, errors = io.writefile(filepath, data) + local ok, errors = io.writefile(filepath, data, opt) if not ok then return nil, 0, errors end end @@ -248,19 +276,21 @@ function io.gsub(filepath, pattern, replace) return data, count end --- cat the given file -function io.cat(filepath, linecount) +-- cat the given file +function io.cat(filepath, linecount, opt) + + opt = opt or {} -- open file - local file = io.open(filepath, "r") + local file = io.open(filepath, "r", opt) if file then -- show file local count = 1 - for line in file:lines() do + for line in file:lines(opt) do -- show line - print(line) + io.print(line) -- end? if linecount and count >= linecount then @@ -269,28 +299,30 @@ function io.cat(filepath, linecount) -- update the line count count = count + 1 - end + end -- exit file - file:close() + file:close() end end --- tail the given file -function io.tail(filepath, linecount) +-- tail the given file +function io.tail(filepath, linecount, opt) + + opt = opt or {} -- all? if linecount < 0 then - return io.cat(filepath) + return io.cat(filepath, opt) end -- open file - local file = io.open(filepath, "r") + local file = io.open(filepath, "r", opt) if file then -- read lines local lines = {} - for line in file:lines() do + for line in file:lines(opt) do table.insert(lines, line) end @@ -318,15 +350,16 @@ function io.tail(filepath, linecount) for index = #tails, 1, -1 do -- show tail - print(tails[index]) + io.print(tails[index]) end end -- exit file - file:close() + file:close() end end + -- return module return io diff --git a/xmake/core/base/option.lua b/xmake/core/base/option.lua index b748d29f6..feec19a11 100644 --- a/xmake/core/base/option.lua +++ b/xmake/core/base/option.lua @@ -832,7 +832,7 @@ function option.show_logo() end -- show logo - print(colors.translate(logo)) + io.print(colors.translate(logo)) -- define footer local footer = [[ @@ -841,7 +841,7 @@ function option.show_logo() ]] -- show footer - print(colors.translate(footer)) + io.print(colors.translate(footer)) end -- show the menu @@ -863,12 +863,12 @@ function option.show_menu(task) -- print title if menu.title then - print(colors.translate(menu.title)) + io.print(colors.translate(menu.title)) end -- print copyright if menu.copyright then - print(colors.translate(menu.copyright)) + io.print(colors.translate(menu.copyright)) end -- show logo @@ -876,14 +876,14 @@ function option.show_menu(task) -- print usage if taskmenu.usage then - print("") - print(colors.translate("${bright}Usage: $${default cyan}" .. taskmenu.usage)) + io.print("") + io.print(colors.translate("${bright}Usage: $${default cyan}" .. taskmenu.usage)) end -- print description if taskmenu.description then - print("") - print(taskmenu.description) + io.print("") + io.print(taskmenu.description) end -- print options @@ -905,12 +905,12 @@ function option.show_main() -- print title if menu.title then - print(colors.translate(menu.title)) + io.print(colors.translate(menu.title)) end -- print copyright if menu.copyright then - print(colors.translate(menu.copyright)) + io.print(colors.translate(menu.copyright)) end -- show logo @@ -918,14 +918,14 @@ function option.show_main() -- print usage if main.usage then - print("") - print(colors.translate("${bright}Usage: $${default cyan}" .. main.usage)) + io.print("") + io.print(colors.translate("${bright}Usage: $${default cyan}" .. main.usage)) end -- print description if main.description then - print("") - print(main.description) + io.print("") + io.print(main.description) end -- print tasks @@ -968,8 +968,8 @@ function option.show_main() assert(categoryname and categorytask) -- print category name - print("") - print(colors.translate(string.format("${bright}%s%ss: ", string.sub(categoryname, 1, 1):upper(), string.sub(categoryname, 2)))) + io.print("") + io.print(colors.translate(string.format("${bright}%s%ss: ", string.sub(categoryname, 1, 1):upper(), string.sub(categoryname, 2)))) -- the padding spaces local padding = 42 @@ -1005,7 +1005,7 @@ function option.show_main() end -- print task line - print(colors.translate(taskline)) + io.print(colors.translate(taskline)) end end end @@ -1023,8 +1023,8 @@ function option.show_options(options) assert(options) -- print header - print("") - print(colors.translate("${bright}Options: ")) + io.print("") + io.print(colors.translate("${bright}Options: ")) -- the padding spaces local padding = 42 @@ -1111,7 +1111,7 @@ function option.show_options(options) end -- print option info - print(colors.translate(option_info)) + io.print(colors.translate(option_info)) -- print more description if exists for i = 6, 64 do @@ -1135,7 +1135,7 @@ function option.show_options(options) end -- print this description - print(option._inwidth_append(spaces, description, padding + 1, console_width)) + io.print(option._inwidth_append(spaces, description, padding + 1, console_width)) -- the description is table? elseif type(description) == "table" then @@ -1150,7 +1150,7 @@ function option.show_options(options) end -- print this description - print(option._inwidth_append(spaces, v, padding + 1, console_width)) + io.print(option._inwidth_append(spaces, v, padding + 1, console_width)) end end end @@ -1171,7 +1171,7 @@ function option.show_options(options) end -- print this value - print(option._inwidth_append(spaces, " - " .. tostring(value), padding + 1, console_width)) + io.print(option._inwidth_append(spaces, " - " .. tostring(value), padding + 1, console_width)) end end end diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index 631276fca..ae04bf49f 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -531,11 +531,13 @@ end -- run command with arguments list function os.runv(program, argv, opt) + opt = opt or {} + -- make temporary log file local log = os.tmpfile() -- execute it - local ok = os.execv(program, argv, table.join(opt or {}, {stdout = log, stderr = log})) + local ok = os.execv(program, argv, table.join(opt, {stdout = log, stderr = log})) if ok ~= 0 then -- make errors @@ -679,12 +681,14 @@ end -- run command with arguments and return output and error data function os.iorunv(program, argv, opt) + opt = opt or {} + -- make temporary output and error file local outfile = os.tmpfile() local errfile = os.tmpfile() -- run command - local ok = os.execv(program, argv, table.join(opt or {}, {stdout = outfile, stderr = errfile})) + local ok = os.execv(program, argv, table.join(opt, {stdout = outfile, stderr = errfile})) -- get output and error data local outdata = io.readfile(outfile) @@ -707,7 +711,7 @@ function os.raise(msg, ...) -- flush log log:flush() - -- flush io buffer + -- flush io buffer io.flush() -- raise it @@ -785,13 +789,16 @@ function os.is_arch(...) end end --- get the system null device +-- get the system null device function os.nuldev(input) if os.host() == "windows" then + -- not every program supports windows NUL device + -- we use a disk file to simulate it + -- init the output nuldev if xmake._NULDEV_OUTPUT == nil then - xmake._NULDEV_OUTPUT = os.tmpfile() + xmake._NULDEV_OUTPUT = path.join(path.directory(os.tmpdir()), "null") else os.rm(xmake._NULDEV_OUTPUT) end @@ -803,7 +810,7 @@ function os.nuldev(input) -- $ gcc -fopenmp -S -o nul -xc nul -- gcc: fatal error:input file ‘nul’ is the same as output file -- - local inputfile = os.tmpfile() + local inputfile = path.join(path.directory(os.tmpdir()), "nullin") io.writefile(inputfile, "") xmake._NULDEV_INPUT = inputfile end @@ -829,7 +836,7 @@ function os.user_agent() -- init user agent if os._USER_AGENT == nil then - + -- init systems local systems = {macosx = "Macintosh", linux = "Linux", windows = "Windows"} diff --git a/xmake/core/base/path.lua b/xmake/core/base/path.lua index c5ba7423b..c1222ffc6 100644 --- a/xmake/core/base/path.lua +++ b/xmake/core/base/path.lua @@ -22,7 +22,6 @@ local path = path or {} -- load modules -local utils = require("base/utils") local string = require("base/string") -- get the directory of the path diff --git a/xmake/core/base/table.lua b/xmake/core/base/table.lua index 43e8b6db9..9af47b5a8 100644 --- a/xmake/core/base/table.lua +++ b/xmake/core/base/table.lua @@ -186,6 +186,31 @@ function table.is_dictionary(dict) return type(dict) == "table" and dict[1] == nil end +-- read data from iterator, push them to an array +-- usage: table.to_array(ipairs("a", "b")) -> {{1,"a",n=2},{2,"b",n=2}},2 +-- usage: table.to_array(io.lines("file")) -> {"line 1","line 2", ... , "line n"},n +function table.to_array(iterator, state, var) + + assert(iterator) + + local result = {} + local count = 0 + while true do + local data = table.pack(iterator(state, var)) + if data[1] == nil then break end + var = data[1] + + if data.n == 1 then + table.insert(result, var) + else + table.insert(result, data) + end + count = count + 1 + end + + return result, count +end + -- unwrap object if be only one function table.unwrap(object) if type(object) == "table" then diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index 072219fc9..d83983c8b 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -315,7 +315,7 @@ function task._load(filepath) -- get interpreter local interp = task._interpreter() - assert(interp) + assert(interp) -- load script local ok, errors = interp:load(filepath) diff --git a/xmake/core/base/utils.lua b/xmake/core/base/utils.lua index caa633c7c..ec7c63bcc 100644 --- a/xmake/core/base/utils.lua +++ b/xmake/core/base/utils.lua @@ -26,6 +26,7 @@ local option = require("base/option") local colors = require("base/colors") local string = require("base/string") local log = require("base/log") +local io = require("base/io") local dump = require("base/dump") -- dump value diff --git a/xmake/core/base/winos.lua b/xmake/core/base/winos.lua index b444b2ed2..56d769b58 100644 --- a/xmake/core/base/winos.lua +++ b/xmake/core/base/winos.lua @@ -25,6 +25,24 @@ local winos = winos or {} local os = require("base/os") local semver = require("base/semver") + +winos._ansi_cp = winos._ansi_cp or winos.ansi_cp +winos._oem_cp = winos._oem_cp or winos.oem_cp + +function winos.ansi_cp() + if not winos._ANSI_CP then + winos._ANSI_CP = winos._ansi_cp() + end + return winos._ANSI_CP +end + +function winos.oem_cp() + if not winos._OEM_CP then + winos._OEM_CP = winos._oem_cp() + end + return winos._OEM_CP +end + -- get windows version from name function winos._version_from_name(name) diff --git a/xmake/core/main.lua b/xmake/core/main.lua index 6d147ff94..0452e7aa8 100644 --- a/xmake/core/main.lua +++ b/xmake/core/main.lua @@ -171,7 +171,7 @@ function main.entry() main._init() -- init option - local ok, errors = option.init(menu) + local ok, errors = option.init(menu) if not ok then utils.error(errors) return -1 diff --git a/xmake/core/sandbox/modules/debug.lua b/xmake/core/sandbox/modules/debug.lua index 318d056d2..f428a802d 100644 --- a/xmake/core/sandbox/modules/debug.lua +++ b/xmake/core/sandbox/modules/debug.lua @@ -18,6 +18,24 @@ -- @file debug.lua -- --- load module -return debug +-- load modules +local table = require("base/table") +-- define module +local sandbox_debug = sandbox_debug or table.join(debug) + +sandbox_debug.rawget = rawget +sandbox_debug.rawset = rawset +sandbox_debug.rawequal = rawequal +sandbox_debug.rawlen = rawlen +sandbox_debug.require = require +function sandbox_debug.global(key) + if key == nil then + return _G + end + return _G[key] +end + + +-- return module +return sandbox_debug diff --git a/xmake/core/sandbox/modules/io.lua b/xmake/core/sandbox/modules/io.lua index 53d8399f4..2f467dd9b 100644 --- a/xmake/core/sandbox/modules/io.lua +++ b/xmake/core/sandbox/modules/io.lua @@ -26,41 +26,62 @@ local raise = require("sandbox/modules/raise") local vformat = require("sandbox/modules/vformat") -- define module -local sandbox_io = sandbox_io or {} +local sandbox_io = sandbox_io or {} +local sandbox_io_file = sandbox_io_file or {} -- inherit some builtin interfaces -sandbox_io.flush = io.flush -sandbox_io.seek = io.seek +sandbox_io.lines = io.lines sandbox_io.read = io.read -sandbox_io.write = io.write -sandbox_io.stdin = io.stdin -sandbox_io.stderr = io.stderr -sandbox_io.stdout = io.stdout sandbox_io.isatty = io.isatty +-- inherit matatable of file +sandbox_io_file.__index = sandbox_io_file +for k, v in pairs(io.file) do + if type(v) == "function" then + sandbox_io_file[k] = function(s, ...) + local result, err = v(s._FILE, ...) + if result == nil and err ~= nil then + raise(err) + end + -- wrap to sandbox_file again + if result == s._FILE then + result = s + end + return result + end + end +end + +-- get file size +function sandbox_io_file:size() + -- __len on tables is scheduled to be supported in 5.2. + return sandbox_io_file.__len(self) +end + -- print file -function sandbox_io._print(self, ...) +function sandbox_io_file:print(...) - -- check - assert(self._FILE) - -- print it - return self._FILE:write(vformat(...) .. "\n") + return self:write(vformat(...), "\n") end -- printf file -function sandbox_io._printf(self, ...) +function sandbox_io_file:printf(...) - -- check - assert(self._FILE) - -- printf it - return self._FILE:write(vformat(...)) + return self:write(vformat(...)) +end + +-- writef file +function sandbox_io_file:writef(...) + + -- writef it + return self:write(string.format(...)) end -- gsub the given file and return replaced data -function sandbox_io.gsub(filepath, pattern, replace) - +function sandbox_io.gsub(filepath, pattern, replace, opt) + -- check assert(filepath) @@ -68,7 +89,7 @@ function sandbox_io.gsub(filepath, pattern, replace) filepath = vformat(filepath) -- replace all - local data, count, errors = io.gsub(filepath, pattern, replace) + local data, count, errors = io.gsub(filepath, pattern, replace, opt) if not data then raise(errors) end @@ -78,8 +99,8 @@ function sandbox_io.gsub(filepath, pattern, replace) end -- open file -function sandbox_io.open(filepath, mode) - +function sandbox_io.open(filepath, mode, opt) + -- check assert(filepath) @@ -87,24 +108,21 @@ function sandbox_io.open(filepath, mode) filepath = vformat(filepath) -- open it - local file, errors = io.open(filepath, mode) + local file, errors = io.open(filepath, mode, opt) if not file then raise(errors) end + file = { _FILE = file } -- replace print with vformat - file.print = sandbox_io._print - file.printf = sandbox_io._printf - - -- add writef with format - file.writef = sandbox_io._writef + setmetatable(file, sandbox_io_file); -- ok? return file end -- load object from the given file -function sandbox_io.load(filepath) +function sandbox_io.load(filepath, opt) -- check assert(filepath) @@ -113,7 +131,7 @@ function sandbox_io.load(filepath) filepath = vformat(filepath) -- done - local result, errors = io.load(filepath) + local result, errors = io.load(filepath, opt) if not result then raise(errors) end @@ -123,8 +141,8 @@ function sandbox_io.load(filepath) end -- save object the the given filepath -function sandbox_io.save(filepath, object) - +function sandbox_io.save(filepath, object, opt) + -- check assert(filepath) @@ -132,14 +150,14 @@ function sandbox_io.save(filepath, object) filepath = vformat(filepath) -- done - local ok, errors = io.save(filepath, object) + local ok, errors = io.save(filepath, object, opt) if not ok then raise(errors) end end -- read all data from file -function sandbox_io.readfile(filepath) +function sandbox_io.readfile(filepath, opt) -- check assert(filepath) @@ -148,7 +166,7 @@ function sandbox_io.readfile(filepath) filepath = vformat(filepath) -- done - local result, errors = io.readfile(filepath) + local result, errors = io.readfile(filepath, opt) if not result then raise(errors) end @@ -157,9 +175,19 @@ function sandbox_io.readfile(filepath) return result end --- write all data to file -function sandbox_io.writefile(filepath, data) - +--- direct write to stdout +function sandbox_io.write(...) + sandbox_io.stdout:write(...) +end + +--- flush file +function sandbox_io.flush(file) + return (file or sandbox_io.stdout):flush() +end + +-- write all data to file +function sandbox_io.writefile(filepath, data, opt) + -- check assert(filepath) @@ -167,7 +195,7 @@ function sandbox_io.writefile(filepath, data) filepath = vformat(filepath) -- done - local ok, errors = io.writefile(filepath, data) + local ok, errors = io.writefile(filepath, data, opt) if not ok then raise(errors) end @@ -178,34 +206,14 @@ function sandbox_io.print(filepath, ...) sandbox_io.writefile(filepath, vformat(...) .. "\n") end --- print data to file -function sandbox_io.printf(filepath, ...) +-- print string to file +function sandbox_io.print(filepath, ...) sandbox_io.writefile(filepath, vformat(...)) end --- printf file -function sandbox_io._printf(self, ...) - - -- check - assert(self._FILE) - - -- printf it - return self._FILE:write(vformat(...)) -end - --- writef file -function sandbox_io._writef(self, ...) - - -- check - assert(self._FILE) - - -- printf it - return self._FILE:write(string.format(...)) -end - -- cat the given file -function sandbox_io.cat(filepath, linecount) - +function sandbox_io.cat(filepath, linecount, opt) + -- check assert(filepath) @@ -213,12 +221,12 @@ function sandbox_io.cat(filepath, linecount) filepath = vformat(filepath) -- cat it - io.cat(filepath, linecount) + io.cat(filepath, linecount, opt) end -- tail the given file -function sandbox_io.tail(filepath, linecount) - +function sandbox_io.tail(filepath, linecount, opt) + -- check assert(filepath) @@ -226,9 +234,17 @@ function sandbox_io.tail(filepath, linecount) filepath = vformat(filepath) -- tail it - io.tail(filepath, linecount) + io.tail(filepath, linecount, opt) end +-- wrap std files +sandbox_io.stdin = { _FILE = io.stdin } +sandbox_io.stderr = { _FILE = io.stderr } +sandbox_io.stdout = { _FILE = io.stdout } +setmetatable(sandbox_io.stdin, sandbox_io_file); +setmetatable(sandbox_io.stderr, sandbox_io_file); +setmetatable(sandbox_io.stdout, sandbox_io_file); + -- return module return sandbox_io diff --git a/xmake/core/sandbox/modules/winos.lua b/xmake/core/sandbox/modules/winos.lua index 18b971064..0f495d4a9 100644 --- a/xmake/core/sandbox/modules/winos.lua +++ b/xmake/core/sandbox/modules/winos.lua @@ -26,8 +26,15 @@ local raise = require("sandbox/modules/raise") local sandbox_winos = sandbox_winos or {} -- inherit some builtin interfaces -sandbox_winos.registry_query = winos.registry_query -sandbox_winos.logical_drives = winos.logical_drives +sandbox_winos.ansi_cp = winos.ansi_cp +sandbox_winos.mbstoutf8 = winos.mbstoutf8 +sandbox_winos.cp_info = winos.cp_info +sandbox_winos.oem_cp = winos.oem_cp +sandbox_winos.console_cp = winos.console_cp +sandbox_winos.console_cp = winos.console_cp +sandbox_winos.console_output_cp = winos.console_output_cp +sandbox_winos.registry_query = winos.registry_query +sandbox_winos.logical_drives = winos.logical_drives -- get windows system version function sandbox_winos.version() diff --git a/xmake/core/tool/builder.lua b/xmake/core/tool/builder.lua index a59dc26c5..472d5be76 100644 --- a/xmake/core/tool/builder.lua +++ b/xmake/core/tool/builder.lua @@ -280,7 +280,7 @@ end -- add flags from the option function builder:_add_flags_from_option(flags, opt) for _, flagkind in ipairs(self:_flagkinds()) do - self:_add_flags_from_flagkind(targetflags, opt, flagkind) + self:_add_flags_from_flagkind(flags, opt, flagkind) end end diff --git a/xmake/modules/core/tools/cl.lua b/xmake/modules/core/tools/cl.lua index 480d32a03..7709165d1 100644 --- a/xmake/modules/core/tools/cl.lua +++ b/xmake/modules/core/tools/cl.lua @@ -285,7 +285,7 @@ function _include_note(self, line) _g.notes = _g.notes or { "Note: including file: " - , "\215\162\210\226: \176\252\186\172\206\196\188\254: " -- zh-cn: "注意: 包含文件: " + , "注意: 包含文件: " } -- contain notes? @@ -321,10 +321,12 @@ function _include_deps(self, outdata) -- get the relative includefile = path.relative(includefile, project.directory()) + includefile = path.absolute(includefile) -- save it if belong to the project - if path.absolute(includefile):startswith(os.projectdir()) then + if includefile:startswith(os.projectdir()) then + includefile = path.relative(includefile, project.directory()) -- insert it and filter repeat if not uniques[includefile] then table.insert(results, includefile) diff --git a/xmake/modules/core/tools/gcc.lua b/xmake/modules/core/tools/gcc.lua index ad4104cd9..1e4267be1 100644 --- a/xmake/modules/core/tools/gcc.lua +++ b/xmake/modules/core/tools/gcc.lua @@ -461,10 +461,9 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags) -- generate the dependent includes if depfile and os.isfile(depfile) then - local depdata = io.readfile(depfile) - if dependinfo and self:kind() ~= "as" and depdata then + if dependinfo and self:kind() ~= "as" then local files = dependinfo.files or {} - table.join2(files, parse_deps(depdata)) + table.join2(files, parse_deps(depfile)) dependinfo.files = table.unique(files) end diff --git a/xmake/modules/core/tools/nvcc.lua b/xmake/modules/core/tools/nvcc.lua index e72857a93..73b18950c 100644 --- a/xmake/modules/core/tools/nvcc.lua +++ b/xmake/modules/core/tools/nvcc.lua @@ -342,10 +342,9 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags) -- generate the dependent includes if depfile and os.isfile(depfile) then - local depdata = io.readfile(depfile) - if dependinfo and self:kind() ~= "as" and depdata then + if dependinfo and self:kind() ~= "as" then local files = dependinfo.files or {} - table.join2(files, parse_deps(depdata)) + table.join2(files, parse_deps(depfile)) dependinfo.files = table.unique(files) end diff --git a/xmake/modules/private/tools/gcc/parse_deps.lua b/xmake/modules/private/tools/gcc/parse_deps.lua index 4d38aede9..eb90ee1b7 100644 --- a/xmake/modules/private/tools/gcc/parse_deps.lua +++ b/xmake/modules/private/tools/gcc/parse_deps.lua @@ -54,8 +54,9 @@ end -- src/tbox/libc/string/../../prefix/../config.h \ -- build/iphoneos/x86_64/release/tbox.config.h \ -- -function main(depsdata) +function main(depsfile) + local depsdata = io.readfile(depsfile, { continuation = "\\"}) -- check if not depsdata or #depsdata == 0 then return {} @@ -63,8 +64,7 @@ function main(depsdata) -- parse results local results = {} - local data = depsdata:gsub("\\\n", "") - for _, line in ipairs(data:split("\n", {plain = true})) do + for _, line in ipairs(depsdata:split("\n", {plain = true})) do local p = line:find(':', 1, true) if p then line = line:sub(p + 1) diff --git a/xmake/plugins/lua/xmake.lua b/xmake/plugins/lua/xmake.lua index 32c929001..b6d66a670 100644 --- a/xmake/plugins/lua/xmake.lua +++ b/xmake/plugins/lua/xmake.lua @@ -54,14 +54,16 @@ task("lua") if script then -- import and run script - if os.isfile(script) then + if path.extension(script) == ".lua" and os.isfile(script) then -- run the given lua script file (xmake lua /tmp/script.lua) + vprint("runing given lua script file: %s", path.relative(script)) import(path.basename(script), {rootdir = path.directory(script), anonymous = true})(unpack(option.get("arguments") or {})) elseif os.isfile(path.join(os.scriptdir(), "scripts", script .. ".lua")) then -- run builtin lua script (xmake lua echo "hello xmake") + vprint("runing builtin lua script: %s", script) import("scripts." .. script, {anonymous = true})(unpack(option.get("arguments") or {})) else @@ -76,9 +78,11 @@ task("lua") local result = nil if object then -- run builtin modules (xmake lua core.xxx.xxx) + vprint("runing builtin module: %s", script) result = object(unpack(option.get("arguments") or {})) else -- run imported modules (xmake lua core.xxx.xxx) + vprint("runing imported module: %s", script) result = import(script, {anonymous = true})(unpack(option.get("arguments") or {})) end if result ~= nil then utils.dump(result) end diff --git a/xmake/themes/dark/xmake.lua b/xmake/themes/dark/xmake.lua index e31c32b0a..ad1152e97 100644 --- a/xmake/themes/dark/xmake.lua +++ b/xmake/themes/dark/xmake.lua @@ -53,6 +53,10 @@ theme("dark") -- color dump set_text("dump.default_format", "<%s>") + set_text("dump.anchor", "&%s") + set_text("dump.reference", "*%s") + set_color("dump.anchor", "yellow") + set_color("dump.reference", "yellow") set_color("dump.default", "bright") set_color("dump.string", "magenta bright") set_color("dump.string_quote", "magenta") diff --git a/xmake/themes/default/xmake.lua b/xmake/themes/default/xmake.lua index 69cef1fd5..f099196db 100644 --- a/xmake/themes/default/xmake.lua +++ b/xmake/themes/default/xmake.lua @@ -53,6 +53,10 @@ theme("default") -- color dump set_text("dump.default_format", "<%s>") + set_text("dump.anchor", "&%s") + set_text("dump.reference", "*%s") + set_color("dump.anchor", "yellow") + set_color("dump.reference", "yellow") set_color("dump.default", "bright") set_color("dump.string", "magenta bright") set_color("dump.string_quote", "magenta") diff --git a/xmake/themes/emoji/xmake.lua b/xmake/themes/emoji/xmake.lua index 0148891f7..663271719 100644 --- a/xmake/themes/emoji/xmake.lua +++ b/xmake/themes/emoji/xmake.lua @@ -53,6 +53,10 @@ theme("emoji") -- color dump set_text("dump.default_format", "<%s>") + set_text("dump.anchor", "⚓ %s") + set_text("dump.reference", "⛵ %s") + set_color("dump.anchor", "yellow") + set_color("dump.reference", "yellow") set_color("dump.default", "bright") set_color("dump.string", "magenta bright") set_color("dump.string_quote", "magenta") diff --git a/xmake/themes/plain/xmake.lua b/xmake/themes/plain/xmake.lua index 0771a857d..69760dca2 100644 --- a/xmake/themes/plain/xmake.lua +++ b/xmake/themes/plain/xmake.lua @@ -53,6 +53,10 @@ theme("plain") -- color dump set_text("dump.default_format", "<%s>") + set_text("dump.anchor", "&%s") + set_text("dump.reference", "*%s") + set_color("dump.anchor", "") + set_color("dump.reference", "") set_color("dump.default", "") set_color("dump.string", "") set_color("dump.string_quote", "") |
