summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpportunityLiu <[email protected]>2019-07-01 14:19:05 +0800
committerOpportunityLiu <[email protected]>2019-07-01 14:19:05 +0800
commitf40152174188626df4b70ca1b9044a721fd3c6e8 (patch)
tree388f5b8e3acdcf1bc9253556fe762dc8b09a5d2a
parent19cbd06f95dddacd1247d1dffab9fa29d719d02b (diff)
utf8 support
-rw-r--r--.appveyor.yml5
-rw-r--r--core/.clang-format115
-rw-r--r--core/src/demo/xmake.c4
-rw-r--r--core/src/demo/xmake.lua6
-rwxr-xr-xcore/src/tbox/inc/linux/tbox.config.h1
-rwxr-xr-xcore/src/tbox/inc/macosx/tbox.config.h1
-rwxr-xr-xcore/src/tbox/inc/windows/tbox.config.h1
m---------core/src/tbox/tbox0
-rw-r--r--core/src/tbox/xmake.lua4
-rw-r--r--core/src/xmake/global/prefix.h32
-rw-r--r--core/src/xmake/io/file.h93
-rw-r--r--core/src/xmake/io/file___len.c56
-rw-r--r--core/src/xmake/io/file___tostring.c50
-rw-r--r--core/src/xmake/io/file_close.c73
-rw-r--r--core/src/xmake/io/file_flush.c58
-rw-r--r--core/src/xmake/io/file_isatty.c (renamed from core/src/xmake/io/isatty.c)41
-rw-r--r--core/src/xmake/io/file_path.c61
-rw-r--r--core/src/xmake/io/file_read.c643
-rw-r--r--core/src/xmake/io/file_seek.c70
-rw-r--r--core/src/xmake/io/file_write.c141
-rw-r--r--core/src/xmake/io/open.c106
-rw-r--r--core/src/xmake/io/std.c117
-rw-r--r--core/src/xmake/machine.c110
-rw-r--r--core/src/xmake/makefile12
-rw-r--r--core/src/xmake/sandbox/interactive.c108
-rw-r--r--core/src/xmake/string/convert.c6
-rw-r--r--core/src/xmake/winos/ansi.c231
-rw-r--r--core/src/xmake/winos/ansi.h36
-rw-r--r--core/src/xmake/winos/registry_query.c4
-rw-r--r--core/src/xmake/xmake.lua8
-rw-r--r--core/xmake.lua3
-rw-r--r--tests/modules/io/files/.gitattributes1
-rw-r--r--tests/modules/io/files/utf16be-lf-eleofbin0 -> 28 bytes
-rw-r--r--tests/modules/io/files/utf16le-crlf-neleofbin0 -> 30 bytes
-rw-r--r--tests/modules/io/files/utf8-crlf-neleof3
-rw-r--r--tests/modules/io/files/utf8-longline-eleof1
-rw-r--r--tests/modules/io/files/utf8-longline-neleof1
-rw-r--r--tests/modules/io/files/utf8bom-lf-eleof3
-rw-r--r--tests/modules/io/test.lua80
-rw-r--r--tests/projects/c/Unicode 测试/test.luabin0 -> 144 bytes
-rw-r--r--tests/projects/c/Unicode 测试/xmake.luabin0 -> 782 bytes
-rw-r--r--tests/projects/c/Unicode 测试/头文件✨/标头🎟.h3
-rw-r--r--tests/projects/c/Unicode 测试/源文件🎆/中文.c7
-rw-r--r--tests/projects/c/Unicode 测试/源文件🎆/😘.c8
-rw-r--r--tests/run.lua15
-rw-r--r--tests/test_utils/print_error.lua28
-rw-r--r--xmake/core/_xmake_main.lua20
-rw-r--r--xmake/core/base/dump.lua45
-rw-r--r--xmake/core/base/emoji.lua5
-rw-r--r--xmake/core/base/interpreter.lua2
-rw-r--r--xmake/core/base/io.lua205
-rw-r--r--xmake/core/base/option.lua46
-rw-r--r--xmake/core/base/os.lua21
-rw-r--r--xmake/core/base/path.lua1
-rw-r--r--xmake/core/base/table.lua25
-rw-r--r--xmake/core/base/task.lua2
-rw-r--r--xmake/core/base/utils.lua1
-rw-r--r--xmake/core/base/winos.lua18
-rw-r--r--xmake/core/main.lua2
-rw-r--r--xmake/core/sandbox/modules/debug.lua22
-rw-r--r--xmake/core/sandbox/modules/io.lua150
-rw-r--r--xmake/core/sandbox/modules/winos.lua11
-rw-r--r--xmake/core/tool/builder.lua2
-rw-r--r--xmake/modules/core/tools/cl.lua6
-rw-r--r--xmake/modules/core/tools/gcc.lua5
-rw-r--r--xmake/modules/core/tools/nvcc.lua5
-rw-r--r--xmake/modules/private/tools/gcc/parse_deps.lua6
-rw-r--r--xmake/plugins/lua/xmake.lua6
-rw-r--r--xmake/themes/dark/xmake.lua4
-rw-r--r--xmake/themes/default/xmake.lua4
-rw-r--r--xmake/themes/emoji/xmake.lua4
-rw-r--r--xmake/themes/plain/xmake.lua4
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
new file mode 100644
index 000000000..139bddb28
--- /dev/null
+++ b/tests/modules/io/files/utf16be-lf-eleof
Binary files differ
diff --git a/tests/modules/io/files/utf16le-crlf-neleof b/tests/modules/io/files/utf16le-crlf-neleof
new file mode 100644
index 000000000..4089f2b19
--- /dev/null
+++ b/tests/modules/io/files/utf16le-crlf-neleof
Binary files differ
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
new file mode 100644
index 000000000..53d97c80b
--- /dev/null
+++ b/tests/projects/c/Unicode 测试/test.lua
Binary files differ
diff --git a/tests/projects/c/Unicode 测试/xmake.lua b/tests/projects/c/Unicode 测试/xmake.lua
new file mode 100644
index 000000000..5e244687e
--- /dev/null
+++ b/tests/projects/c/Unicode 测试/xmake.lua
Binary files differ
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", "")