From 236988050bfe9f51ebe6b72c6e3d760bb2e349ef Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 18 Aug 2019 23:29:31 +0800 Subject: rewrite io --- core/src/xmake/io/file.h | 147 ----------------- core/src/xmake/io/file___len.c | 56 ------- core/src/xmake/io/file___tostring.c | 51 ------ core/src/xmake/io/file_close.c | 92 +++++++++++ core/src/xmake/io/file_close___gc.c | 124 -------------- core/src/xmake/io/file_flush.c | 28 ++-- core/src/xmake/io/file_isatty.c | 13 +- core/src/xmake/io/file_open.c | 298 +++++++++++++++++++++++++++++++++ core/src/xmake/io/file_path.c | 55 ------- core/src/xmake/io/file_read.c | 81 ++++----- core/src/xmake/io/file_seek.c | 32 ++-- core/src/xmake/io/file_size.c | 60 +++++++ core/src/xmake/io/file_write.c | 35 ++-- core/src/xmake/io/open.c | 320 ------------------------------------ core/src/xmake/io/prefix.h | 66 ++++++++ core/src/xmake/io/std.c | 87 ++++------ core/src/xmake/machine.c | 43 ++--- core/src/xmake/makefile | 10 +- 18 files changed, 661 insertions(+), 937 deletions(-) delete mode 100644 core/src/xmake/io/file.h delete mode 100644 core/src/xmake/io/file___len.c delete mode 100644 core/src/xmake/io/file___tostring.c create mode 100644 core/src/xmake/io/file_close.c delete mode 100644 core/src/xmake/io/file_close___gc.c create mode 100644 core/src/xmake/io/file_open.c delete mode 100644 core/src/xmake/io/file_path.c create mode 100644 core/src/xmake/io/file_size.c delete mode 100644 core/src/xmake/io/open.c (limited to 'core/src') diff --git a/core/src/xmake/io/file.h b/core/src/xmake/io/file.h deleted file mode 100644 index 69555b393..000000000 --- a/core/src/xmake/io/file.h +++ /dev/null @@ -1,147 +0,0 @@ -/*!A cross-platform build utility based on Lua - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2019, TBOOX Open Source Group. - * - * @author OpportunityLiu - * @file file.h - * - */ -#ifndef XM_IO_FILE_H -#define XM_IO_FILE_H - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * macros - */ -#define xm_io_file_is_file(file) ((file)->type == XM_IO_FILE_TYPE_FILE) -#define xm_io_file_is_std(file) ((file)->type != XM_IO_FILE_TYPE_FILE) - -#define xm_io_file_is_closed_file(file) (xm_io_file_is_file(file) && !((file)->file_ref)) -#define xm_io_file_is_closed_std(file) (xm_io_file_is_std(file) && !((file)->std_ref)) - -#define xm_io_file_is_tty(file) (!!((file)->type & XM_IO_FILE_FLAG_TTY)) -#define xm_io_file_is_closed(file) (xm_io_file_is_closed_file(file) || xm_io_file_is_closed_std(file)) - -// the file udata type -#define xm_io_file_udata "io._file*" - -// return file success -#define xm_io_file_return_success() do { return 1; } while (0) - -// return file error with reason -#define xm_io_file_return_error(lua, file, reason) \ - do \ - { \ - lua_pushnil(lua); \ - lua_pushfstring(lua, "error: %s (%s)", reason, file->name); \ - return 2; \ - } while (0) - -// return file closed error -#define xm_io_file_return_error_closed(lua) \ - do \ - { \ - lua_pushnil(lua); \ - lua_pushliteral(lua, "error: file has been closed"); \ - return 2; \ - } while (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * types - */ -typedef enum __xm_io_file_type_e -{ - XM_IO_FILE_TYPE_FILE = 0 //!< disk file - -, XM_IO_FILE_TYPE_STDIN = 1 -, XM_IO_FILE_TYPE_STDOUT = 2 -, XM_IO_FILE_TYPE_STDERR = 3 - -, XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream - -} xm_io_file_type_e; - -/* use negetive numbers for this enum, its a extension for tb_charset_type_e - * before adding new values, make sure they have not conflicts with values in tb_charset_type_e - */ -typedef enum __xm_io_file_encoding_e -{ - XM_IO_FILE_ENCODING_UNKNOWN = -1 -, XM_IO_FILE_ENCODING_BINARY = -2 - -} xm_io_file_encoding_e; - -// the file type -typedef struct __xm_io_file_t -{ - union - { - /* the normal file for XM_IO_FILE_TYPE_FILE - * - * direct: file_ref -> stream -> file - * transcode: file_ref -> fstream -> stream -> file - */ - tb_stream_ref_t file_ref; - - // the standard io file - tb_stdfile_ref_t std_ref; - }; - - tb_stream_ref_t stream; // the file stream for XM_IO_FILE_TYPE_FILE - tb_stream_ref_t fstream; // the file charset stream filter - tb_size_t mode; // tb_file_mode_t - tb_size_t type; // xm_io_file_type_e - tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e - tb_char_t name[64]; - tb_char_t const* path; - tb_buffer_t rcache; // the read line cache buffer - tb_buffer_t wcache; // the write line cache buffer -} xm_io_file_t; - -/* ////////////////////////////////////////////////////////////////////////////////////// - * interfaces - */ -static __tb_inline__ xm_io_file_t* xm_io_newfile(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, tb_null); - - // new file - xm_io_file_t* file = (xm_io_file_t*)lua_newuserdata(lua, sizeof(xm_io_file_t)); - tb_assert_and_check_return_val(file, tb_null); - - // init file - luaL_getmetatable(lua, xm_io_file_udata); - lua_setmetatable(lua, -2); - tb_memset(file, 0, sizeof(xm_io_file_t)); - return file; -} - -static __tb_inline__ xm_io_file_t* xm_io_getfile(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, tb_null); - - // get file - xm_io_file_t* file = (xm_io_file_t*)luaL_checkudata(lua, 1, xm_io_file_udata); - tb_assert(file); - return file; -} - -#endif diff --git a/core/src/xmake/io/file___len.c b/core/src/xmake/io/file___len.c deleted file mode 100644 index d244edfd4..000000000 --- a/core/src/xmake/io/file___len.c +++ /dev/null @@ -1,56 +0,0 @@ -/*!A cross-platform build utility based on Lua - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2019, TBOOX Open Source Group. - * - * @author OpportunityLiu - * @file file___len.c - * - */ - -/* ////////////////////////////////////////////////////////////////////////////////////// - * trace - */ -#define TB_TRACE_MODULE_NAME "file___len" -#define TB_TRACE_MODULE_DEBUG (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "file.h" -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * implementation - */ - -/* get file length, #file - */ -tb_int_t xm_io_file___len(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - xm_io_file_t* file = xm_io_getfile(lua); - if (xm_io_file_is_closed(file)) - xm_io_file_return_error_closed(lua); - else if (xm_io_file_is_file(file)) - { - // get size from raw file stream, because we cannot get size from fstream - tb_assert(file->stream); - lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream)); - xm_io_file_return_success(); - } - else xm_io_file_return_error(lua, file, "getting file size for this file is invalid"); -} diff --git a/core/src/xmake/io/file___tostring.c b/core/src/xmake/io/file___tostring.c deleted file mode 100644 index 55a5e9167..000000000 --- a/core/src/xmake/io/file___tostring.c +++ /dev/null @@ -1,51 +0,0 @@ -/*!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); - - // get file name as string - xm_io_file_t* file = xm_io_getfile(lua); - 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..b808d3e44 --- /dev/null +++ b/core/src/xmake/io/file_close.c @@ -0,0 +1,92 @@ +/*!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, ruki + * @file file_close.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_close" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +// io.file_close(file) +tb_int_t xm_io_file_close(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + + // close file + if (xm_io_file_is_file(file)) + { + // check + tb_assert(file->file_ref); + +#ifdef TB_CONFIG_OS_WINDOWS + // write cached data first + tb_byte_t const* odata = tb_buffer_data(&file->wcache); + tb_size_t osize = tb_buffer_size(&file->wcache); + if (odata && osize) + { + if (!tb_stream_bwrit(file->file_ref, odata, osize)) return tb_false; + tb_buffer_clear(&file->wcache); + } +#endif + + // close file + if (!tb_stream_clos(file->file_ref)) + xm_io_file_return_error(lua, "failed to close file"); + file->file_ref = tb_null; + + // exit fstream + if (file->fstream) tb_stream_exit(file->fstream); + file->fstream = tb_null; + + // exit stream + if (file->stream) tb_stream_exit(file->stream); + file->stream = tb_null; + + // exit the line cache buffer + tb_buffer_exit(&file->rcache); + tb_buffer_exit(&file->wcache); + + // exit file + tb_free(file); + } + + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/io/file_close___gc.c b/core/src/xmake/io/file_close___gc.c deleted file mode 100644 index 1c59ff3ea..000000000 --- a/core/src/xmake/io/file_close___gc.c +++ /dev/null @@ -1,124 +0,0 @@ -/*!A cross-platform build utility based on Lua - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2019, TBOOX Open Source Group. - * - * @author OpportunityLiu - * @file file_close___gc.c - * - */ - -/* ////////////////////////////////////////////////////////////////////////////////////// - * trace - */ -#define TB_TRACE_MODULE_NAME "file_close___gc" -#define TB_TRACE_MODULE_DEBUG (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "file.h" -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * implementation - */ - -static tb_int_t xm_io_file_close_impl(lua_State* lua, tb_bool_t allow_closed_file) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - // close file - xm_io_file_t* file = xm_io_getfile(lua); - if (xm_io_file_is_closed(file)) - { - if (allow_closed_file) - { - lua_pushboolean(lua, tb_true); - xm_io_file_return_success(); - } - else xm_io_file_return_error_closed(lua); - } - if (xm_io_file_is_file(file)) - { - // check - tb_assert(file->file_ref); - -#ifdef TB_CONFIG_OS_WINDOWS - // write cached data first - tb_byte_t const* odata = tb_buffer_data(&file->wcache); - tb_size_t osize = tb_buffer_size(&file->wcache); - if (odata && osize) - { - if (!tb_stream_bwrit(file->file_ref, odata, osize)) return tb_false; - tb_buffer_clear(&file->wcache); - } -#endif - - // close file - if (!tb_stream_clos(file->file_ref)) - xm_io_file_return_error(lua, file, "failed to close file"); - file->file_ref = tb_null; - - // exit fstream - if (file->fstream) tb_stream_exit(file->fstream); - file->fstream = tb_null; - - // exit stream - if (file->stream) tb_stream_exit(file->stream); - file->stream = tb_null; - - // exit the line cache buffer - tb_buffer_exit(&file->rcache); - tb_buffer_exit(&file->wcache); - - // free file path - if (file->path) - { - tb_free(file->path); - file->path = tb_null; - } - - // mark this file as closed - tb_strlcpy(file->name, "file: (closed file)", tb_arrayn(file->name)); - lua_pushboolean(lua, tb_true); - xm_io_file_return_success(); - } - else - { - lua_pushboolean(lua, tb_true); - xm_io_file_return_success(); - } -} - -/* ////////////////////////////////////////////////////////////////////////////////////// - * interfaces - */ - -/* - * file:close() - */ -tb_int_t xm_io_file_close(lua_State* lua) -{ - return xm_io_file_close_impl(lua, tb_false); -} - -/* - * file:close() - */ -tb_int_t xm_io_file___gc(lua_State* lua) -{ - return xm_io_file_close_impl(lua, tb_true); -} diff --git a/core/src/xmake/io/file_flush.c b/core/src/xmake/io/file_flush.c index e63a0952a..1c1939db1 100644 --- a/core/src/xmake/io/file_flush.c +++ b/core/src/xmake/io/file_flush.c @@ -14,7 +14,7 @@ * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author OpportunityLiu + * @author OpportunityLiu, ruki * @file file_flush.c * */ @@ -28,7 +28,6 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ -#include "file.h" #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// @@ -36,14 +35,14 @@ */ static tb_bool_t xm_io_std_flush_impl(xm_io_file_t* file) { - tb_assert_and_check_return_val(xm_io_file_is_std(file) && !xm_io_file_is_closed(file), tb_false); + tb_assert_and_check_return_val(xm_io_file_is_std(file), tb_false); return (file->std_ref != tb_stdfile_input())? tb_stdfile_flush(file->std_ref) : tb_false; } static tb_bool_t xm_io_file_flush_impl(xm_io_file_t* file) { // check - tb_assert_and_check_return_val(xm_io_file_is_file(file) && !xm_io_file_is_closed(file), tb_false); + tb_assert_and_check_return_val(xm_io_file_is_file(file), tb_false); #ifdef TB_CONFIG_OS_WINDOWS // write cached data first @@ -62,25 +61,26 @@ static tb_bool_t xm_io_file_flush_impl(xm_io_file_t* file) * interfaces */ -/* - * file:flush() - */ +// io.file_flush(file) tb_int_t xm_io_file_flush(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - // file has been closed? - xm_io_file_t* file = xm_io_getfile(lua); - if (xm_io_file_is_closed(file)) - xm_io_file_return_error_closed(lua); + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); // flush file - tb_bool_t ok = xm_io_file_is_file(file) ? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file); + tb_bool_t ok = xm_io_file_is_file(file)? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file); if (ok) { lua_pushboolean(lua, tb_true); - xm_io_file_return_success(); + return 1; } - else xm_io_file_return_error(lua, file, "failed to flush file"); + else xm_io_file_return_error(lua, "failed to flush file"); } diff --git a/core/src/xmake/io/file_isatty.c b/core/src/xmake/io/file_isatty.c index ca44ce0a0..548fc8b2b 100644 --- a/core/src/xmake/io/file_isatty.c +++ b/core/src/xmake/io/file_isatty.c @@ -28,22 +28,27 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ -#include "file.h" #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -/* file:isatty() - */ +// io.file_isatty(file) tb_int_t xm_io_file_isatty(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + // is tty? - xm_io_file_t* file = xm_io_getfile(lua); lua_pushboolean(lua, xm_io_file_is_tty(file)); return 1; } diff --git a/core/src/xmake/io/file_open.c b/core/src/xmake/io/file_open.c new file mode 100644 index 000000000..3f1f0e9e2 --- /dev/null +++ b/core/src/xmake/io/file_open.c @@ -0,0 +1,298 @@ +/*!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, ruki + * @file file_open.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_open" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// num of bytes read to guess encoding +#define CHECK_SIZE (1024) + +// is utf-8 tail character +#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_size_t xm_io_file_detect_charset(tb_byte_t const** data_ptr, tb_long_t size) +{ + // check + tb_assert(data_ptr && *data_ptr); + + tb_byte_t const* data = *data_ptr; + tb_size_t charset = XM_IO_FILE_ENCODING_BINARY; + do + { + if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) // utf-8 with bom + { + charset = TB_CHARSET_TYPE_UTF8; + data += 3; // skip bom + break; + } + if (size >= 2) + { + if (data[0] == 254 && data[1] == 255) // utf16be + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + data += 2; // skip bom + break; + } + else if (data[0] == 255 && data[1] == 254) // utf16le + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + data += 2; // skip bom + break; + } + } + + tb_sint16_t utf16be_conf = 0; + tb_sint16_t utf16le_conf = 0; + tb_sint16_t utf8_conf = 0; + tb_sint16_t ascii_conf = 0; + tb_sint16_t zero_count = 0; + for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) + { + if (data[i] == 0) zero_count++; + + if (data[i] < 0x80) + ascii_conf++; + else + ascii_conf = TB_MINS16; + + if (i % 2 == 0) + { + if (data[i] == 0) utf16be_conf++; + if (data[i + 1] == 0) utf16le_conf++; + } + + if (IS_UTF8_TAIL(data[i])) + ; + else if (data[i] < 0x80) + utf8_conf++; + else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) + utf8_conf++; + else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) + utf8_conf++; + else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) && IS_UTF8_TAIL(data[i + 3])) + utf8_conf++; + else + utf8_conf = TB_MINS16; + } + + if (ascii_conf > 0 && zero_count <= 1) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + if (utf8_conf > 0 && zero_count <= 1) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + break; + } + if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) + { + charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + break; + } + if (utf8_conf > 0) + { + charset = TB_CHARSET_TYPE_UTF8; + break; + } + +#ifdef TB_CONFIG_OS_WINDOWS + charset = TB_CHARSET_TYPE_ANSI; +#endif + + } while (0); + + *data_ptr = data; + return charset; +} +static tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t* pbomoff) +{ + // check + tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY); + + // detect encoding + tb_byte_t* data = tb_null; + tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY; + tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE); + if (size > 0) + { + tb_byte_t const* p = data; + encoding = xm_io_file_detect_charset(&p, size); + *pbomoff = p - data; + } + return encoding; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// io.file_open(path, modestr) +tb_int_t xm_io_file_open(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get file path and mode + tb_char_t const* path = luaL_checkstring(lua, 1); + tb_char_t const* modestr = luaL_optstring(lua, 2, "r"); + tb_assert_and_check_return_val(path && modestr, 0); + + // get file mode value + tb_size_t mode; + switch (modestr[0]) + { + case 'w': mode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC; break; + case 'a': mode = TB_FILE_MODE_RW | TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT; break; + case 'r': default: mode = TB_FILE_MODE_RO; break; + } + + // get file encoding + tb_long_t bomoff = 0; + tb_stream_ref_t stream = tb_null; + tb_bool_t update = !!tb_strchr(modestr, '+'); + tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN; + if (modestr[1] == 'b' || (update && modestr[2] == 'b')) + encoding = XM_IO_FILE_ENCODING_BINARY; + else if (tb_strstr(modestr, "utf8") || tb_strstr(modestr, "utf-8")) + encoding = TB_CHARSET_TYPE_UTF8; + else if (tb_strstr(modestr, "utf16le") || tb_strstr(modestr, "utf-16le")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; + else if (tb_strstr(modestr, "utf16be") || tb_strstr(modestr, "utf-16be")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; + else if (tb_strstr(modestr, "utf16") || tb_strstr(modestr, "utf-16")) + encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE; + else if (modestr[0] == 'w' || modestr[0] == 'a') // set to utf-8 if not specified for the writing mode + encoding = TB_CHARSET_TYPE_UTF8; + else if (modestr[0] == 'r') // detect encoding if not specified for the reading mode + { + stream = tb_stream_init_from_file(path, mode); + if (stream && tb_stream_open(stream)) + encoding = xm_io_file_detect_encoding(stream, &bomoff); + else + { + if (stream) tb_stream_exit(stream); + lua_pushnil(lua); + lua_pushliteral(lua, "file not found!"); + return 2; + } + } + else + { + lua_pushnil(lua); + lua_pushliteral(lua, "invalid open mode!"); + return 2; + } + tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0); + + // open file + tb_bool_t open_ok = tb_false; + tb_stream_ref_t file_ref = tb_null; + tb_stream_ref_t fstream = tb_null; + do + { + // init stream from file + stream = stream? stream : tb_stream_init_from_file(path, mode); + tb_assert_and_check_break(stream); + + // is transcode? + tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY; + if (is_transcode) + { + if (modestr[0] == 'r') + fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8); + else + fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding); + tb_assert_and_check_break(fstream); + + // use fstream as file + file_ref = fstream; + } + else file_ref = stream; + + // open file stream + if (!tb_stream_open(file_ref)) break; + + // skip bom characters if exists + if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) break; + + // ok + open_ok = tb_true; + + } while (0); + + // open failed? + if (!open_ok) + { + // exit stream + if (stream) tb_stream_exit(stream); + stream = tb_null; + + // exit charset stream filter + if (fstream) tb_stream_exit(fstream); + fstream = tb_null; + + // return errors + lua_pushnil(lua); + lua_pushliteral(lua, "failed to open file."); + return 2; + } + + // make file + xm_io_file_t* file = tb_malloc0_type(xm_io_file_t); + tb_assert_and_check_return_val(file, 0); + + // init file + file->file_ref = file_ref; + file->stream = stream; + file->fstream = fstream; + file->mode = mode; + file->type = XM_IO_FILE_TYPE_FILE; + file->encoding = encoding; + + // init the read/write line cache buffer + tb_buffer_init(&file->rcache); + tb_buffer_init(&file->wcache); + + // ok + lua_pushlightuserdata(lua, (tb_pointer_t)file); + return 1; +} diff --git a/core/src/xmake/io/file_path.c b/core/src/xmake/io/file_path.c deleted file mode 100644 index fab2b156b..000000000 --- a/core/src/xmake/io/file_path.c +++ /dev/null @@ -1,55 +0,0 @@ -/*!A cross-platform build utility based on Lua - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2019, TBOOX Open Source Group. - * - * @author OpportunityLiu - * @file file_path.c - * - */ - -/* ////////////////////////////////////////////////////////////////////////////////////// - * trace - */ -#define TB_TRACE_MODULE_NAME "file_path" -#define TB_TRACE_MODULE_DEBUG (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "file.h" -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * implementation - */ - -/* file:path() - */ -tb_int_t xm_io_file_path(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - // this file has been closed? - xm_io_file_t* file = xm_io_getfile(lua); - if (xm_io_file_is_closed(file)) - xm_io_file_return_error_closed(lua); - else - { - // return file path - lua_pushstring(lua, file->path); - xm_io_file_return_success(); - } -} diff --git a/core/src/xmake/io/file_read.c b/core/src/xmake/io/file_read.c index 4e264d87a..d183c0011 100644 --- a/core/src/xmake/io/file_read.c +++ b/core/src/xmake/io/file_read.c @@ -14,7 +14,7 @@ * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author OpportunityLiu + * @author OpportunityLiu, ruki * @file file_read.c * */ @@ -29,7 +29,6 @@ * includes */ #include "prefix.h" -#include "file.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types @@ -99,7 +98,7 @@ static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_re static tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_t* file, tb_char_t const* continuation, tb_bool_t keep_crlf) { // check - tb_assert(buf && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(buf && file && continuation && xm_io_file_is_file(file) && file->file_ref); // is binary? tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; @@ -178,12 +177,12 @@ static tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_t* fi static tb_int_t xm_io_file_read_all_directly(lua_State* lua, xm_io_file_t* file) { // check - tb_assert(lua && file && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && xm_io_file_is_file(file) && file->file_ref); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) - xm_io_file_return_error(lua, file, "init buffer failed!"); + xm_io_file_return_error(lua, "init buffer failed!"); // read all tb_byte_t data[TB_STREAM_BLOCK_MAXN]; @@ -210,7 +209,7 @@ static tb_int_t xm_io_file_read_all_directly(lua_State* lua, xm_io_file_t* file) static tb_int_t xm_io_file_read_all(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation) { // check - tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->file_ref); // is binary? read all directly tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; @@ -220,7 +219,7 @@ static tb_int_t xm_io_file_read_all(lua_State* lua, xm_io_file_t* file, tb_char_ // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) - xm_io_file_return_error(lua, file, "init buffer failed!"); + xm_io_file_return_error(lua, "init buffer failed!"); // read all tb_bool_t has_content = tb_false; @@ -240,7 +239,7 @@ static tb_int_t xm_io_file_read_all(lua_State* lua, xm_io_file_t* file, tb_char_ case PL_FAIL: default: tb_buffer_exit(&buf); - xm_io_file_return_error(lua, file, "failed to read all"); + xm_io_file_return_error(lua, "failed to read all"); break; } } @@ -249,12 +248,12 @@ static tb_int_t xm_io_file_read_all(lua_State* lua, xm_io_file_t* file, tb_char_ static tb_int_t xm_io_file_read_line(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation, tb_bool_t keep_crlf) { // check - tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->file_ref); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) - xm_io_file_return_error(lua, file, "init buffer failed!"); + xm_io_file_return_error(lua, "init buffer failed!"); // read line tb_bool_t has_content = tb_false; @@ -277,7 +276,7 @@ static tb_int_t xm_io_file_read_line(lua_State* lua, xm_io_file_t* file, tb_char case PL_FAIL: default: tb_buffer_exit(&buf); - xm_io_file_return_error(lua, file, "failed to readline"); + xm_io_file_return_error(lua, "failed to readline"); break; } } @@ -286,15 +285,15 @@ static tb_int_t xm_io_file_read_line(lua_State* lua, xm_io_file_t* file, tb_char static tb_int_t xm_io_file_read_n(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation, tb_long_t n) { // check - tb_assert(lua && file && continuation && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->file_ref); // check continuation if (*continuation != '\0') - xm_io_file_return_error(lua, file, "continuation is not supported for read number of bytes"); + xm_io_file_return_error(lua, "continuation is not supported for read number of bytes"); // check encoding if (file->encoding != XM_IO_FILE_ENCODING_BINARY) - xm_io_file_return_error(lua, file, "read number of bytes only allows binary file, reopen with 'rb' and try again"); + xm_io_file_return_error(lua, "read number of bytes only allows binary file, reopen with 'rb' and try again"); tb_bool_t ok = tb_false; if (n == 0) @@ -325,7 +324,7 @@ static tb_int_t xm_io_file_read_n(lua_State* lua, xm_io_file_t* file, tb_char_t static tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_t* file, tb_char_t const* continuation, tb_bool_t keep_crlf) { // check - tb_assert(buf && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(buf && file && continuation && xm_io_file_is_std(file)); // get input buffer tb_char_t strbuf[8192]; @@ -377,12 +376,12 @@ static tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf, xm_io_file_ static tb_int_t xm_io_file_std_read_line(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation, tb_bool_t keep_crlf) { // check - tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) - xm_io_file_return_error(lua, file, "init buffer failed!"); + xm_io_file_return_error(lua, "init buffer failed!"); // read line tb_bool_t has_content = tb_false; @@ -405,7 +404,7 @@ static tb_int_t xm_io_file_std_read_line(lua_State* lua, xm_io_file_t* file, tb_ case PL_FAIL: default: tb_buffer_exit(&buf); - xm_io_file_return_error(lua, file, "failed to readline"); + xm_io_file_return_error(lua, "failed to readline"); break; } } @@ -414,12 +413,12 @@ static tb_int_t xm_io_file_std_read_line(lua_State* lua, xm_io_file_t* file, tb_ static tb_int_t xm_io_file_std_read_all(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation) { // check - tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // init buffer tb_buffer_t buf; if (!tb_buffer_init(&buf)) - xm_io_file_return_error(lua, file, "init buffer failed!"); + xm_io_file_return_error(lua, "init buffer failed!"); // read all tb_bool_t has_content = tb_false; @@ -439,7 +438,7 @@ static tb_int_t xm_io_file_std_read_all(lua_State* lua, xm_io_file_t* file, tb_c case PL_FAIL: default: tb_buffer_exit(&buf); - xm_io_file_return_error(lua, file, "failed to readline"); + xm_io_file_return_error(lua, "failed to readline"); break; } } @@ -448,11 +447,11 @@ static tb_int_t xm_io_file_std_read_all(lua_State* lua, xm_io_file_t* file, tb_c static tb_int_t xm_io_file_std_read_n(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation, tb_long_t n) { // check - tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // check continuation if (*continuation != '\0') - xm_io_file_return_error(lua, file, "continuation is not supported for std streams"); + xm_io_file_return_error(lua, "continuation is not supported for std streams"); // io.read(0) if (n == 0) @@ -479,11 +478,11 @@ static tb_int_t xm_io_file_std_read_n(lua_State* lua, xm_io_file_t* file, tb_cha static tb_int_t xm_io_file_std_read_num(lua_State* lua, xm_io_file_t* file, tb_char_t const* continuation) { // check - tb_assert(lua && file && continuation && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(lua && file && continuation && xm_io_file_is_std(file)); // check continuation if (*continuation != '\0') - xm_io_file_return_error(lua, file, "continuation is not supported for std streams"); + xm_io_file_return_error(lua, "continuation is not supported for std streams"); // read number tb_char_t strbuf[512]; @@ -493,19 +492,25 @@ static tb_int_t xm_io_file_std_read_num(lua_State* lua, xm_io_file_t* file, tb_c return 1; } -/* - * file:read([mode, [continuation]]) - * file:read("all", "\\") - * file:read("L") - * file:read(10) +/* io.file_read(file, [mode, [continuation]]) + * io.file_read(file, "all", "\\") + * io.file_read(file, "L") + * io.file_read(file, 10) */ tb_int_t xm_io_file_read(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - // get file and arguments - xm_io_file_t* file = xm_io_getfile(lua); + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + + // get arguments tb_char_t const* mode = luaL_optstring(lua, 2, "l"); tb_char_t const* continuation = luaL_optstring(lua, 3, ""); tb_assert_and_check_return_val(mode && continuation, 0); @@ -514,26 +519,22 @@ tb_int_t xm_io_file_read(lua_State* lua) if (lua_isnumber(lua, 2)) { count = (tb_long_t)lua_tointeger(lua, 2); - if (count < 0) xm_io_file_return_error(lua, file, "invalid read size, must be positive nubmber or 0"); + if (count < 0) xm_io_file_return_error(lua, "invalid read size, must be positive nubmber or 0"); } else if (*mode == '*') mode++; if (xm_io_file_is_file(file)) { - // this file has been closed? - if (xm_io_file_is_closed_file(file)) - xm_io_file_return_error_closed(lua); - if (count >= 0) return xm_io_file_read_n(lua, file, continuation, count); switch (*mode) { case 'a': return xm_io_file_read_all(lua, file, continuation); case 'L': return xm_io_file_read_line(lua, file, continuation, tb_true); - case 'n': xm_io_file_return_error(lua, file, "read number is not implemented"); + case 'n': xm_io_file_return_error(lua, "read number is not implemented"); case 'l': return xm_io_file_read_line(lua, file, continuation, tb_false); default: - xm_io_file_return_error(lua, file, "unknonwn read mode"); + xm_io_file_return_error(lua, "unknonwn read mode"); return 0; } } @@ -547,7 +548,7 @@ tb_int_t xm_io_file_read(lua_State* lua) case 'n': return xm_io_file_std_read_num(lua, file, continuation); case 'l': return xm_io_file_std_read_line(lua, file, continuation, tb_false); default: - xm_io_file_return_error(lua, file, "unknonwn read mode"); + xm_io_file_return_error(lua, "unknonwn read mode"); return 0; } } diff --git a/core/src/xmake/io/file_seek.c b/core/src/xmake/io/file_seek.c index 54e0d4026..8387a6083 100644 --- a/core/src/xmake/io/file_seek.c +++ b/core/src/xmake/io/file_seek.c @@ -14,7 +14,7 @@ * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author OpportunityLiu + * @author OpportunityLiu, ruki * @file file_seek.c * */ @@ -28,31 +28,35 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ -#include "file.h" #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -/* - * file:seek([whence [, offset]]) - */ +// io.file_seek(file, [whence [, offset]]) tb_int_t xm_io_file_seek(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - xm_io_file_t* file = xm_io_getfile(lua); + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + + // get whence and offset tb_char_t const* whence = luaL_optstring(lua, 2, "cur"); tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0); - tb_assert_and_check_return_val(file && whence, 0); + tb_assert_and_check_return_val(whence, 0); + // seek file if (xm_io_file_is_file(file)) { - if (xm_io_file_is_closed_file(file)) - xm_io_file_return_error_closed(lua); - + tb_assert(file->file_ref); switch (*whence) { case 's': // "set" @@ -62,7 +66,7 @@ tb_int_t xm_io_file_seek(lua_State* lua) tb_hong_t size = tb_stream_size(file->file_ref); if (size > 0 && size + offset <= size) offset = size + offset; - else xm_io_file_return_error(lua, file, "seek failed, invalid offset!"); + else xm_io_file_return_error(lua, "seek failed, invalid offset!"); } break; default: // "cur" @@ -73,9 +77,9 @@ tb_int_t xm_io_file_seek(lua_State* lua) if (tb_stream_seek(file->file_ref, offset)) { lua_pushnumber(lua, (lua_Number)offset); - xm_io_file_return_success(); + return 1; } - else xm_io_file_return_error(lua, file, "seek failed!"); + else xm_io_file_return_error(lua, "seek failed!"); } - else xm_io_file_return_error(lua, file, "seek is not supported on this file"); + else xm_io_file_return_error(lua, "seek is not supported on this file"); } diff --git a/core/src/xmake/io/file_size.c b/core/src/xmake/io/file_size.c new file mode 100644 index 000000000..ca0343e8a --- /dev/null +++ b/core/src/xmake/io/file_size.c @@ -0,0 +1,60 @@ +/*!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, ruki + * @file file_size.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "file_size" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// io.file_size(file) +tb_int_t xm_io_file_size(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; + + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + + // get file length + if (xm_io_file_is_file(file)) + { + // get size from raw file stream, because we cannot get size from fstream + tb_assert(file->stream); + lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream)); + return 1; + } + else xm_io_file_return_error(lua, "getting file size for this file is invalid"); +} diff --git a/core/src/xmake/io/file_write.c b/core/src/xmake/io/file_write.c index d0c371516..7dc38cdce 100644 --- a/core/src/xmake/io/file_write.c +++ b/core/src/xmake/io/file_write.c @@ -14,7 +14,7 @@ * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author OpportunityLiu + * @author OpportunityLiu, ruki * @file file_write.c * */ @@ -29,7 +29,6 @@ * includes */ #include "prefix.h" -#include "file.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation @@ -37,7 +36,7 @@ static tb_void_t xm_io_file_write_file_directly(xm_io_file_t* file, tb_char_t const* data, tb_size_t size) { // check - tb_assert(file && data && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(file && data && xm_io_file_is_file(file) && file->file_ref); // write data to file tb_stream_bwrit(file->file_ref, (tb_byte_t const*)data, size); @@ -45,7 +44,7 @@ static tb_void_t xm_io_file_write_file_directly(xm_io_file_t* file, tb_char_t co static tb_void_t xm_io_file_write_file_transcrlf(xm_io_file_t* file, tb_char_t const* data, tb_size_t size) { // check - tb_assert(file && data && xm_io_file_is_file(file) && !xm_io_file_is_closed(file)); + tb_assert(file && data && xm_io_file_is_file(file) && file->file_ref); #ifdef TB_CONFIG_OS_WINDOWS @@ -95,7 +94,7 @@ static tb_void_t xm_io_file_write_file_transcrlf(xm_io_file_t* file, tb_char_t c static tb_void_t xm_io_file_write_std(xm_io_file_t* file, tb_char_t const* data, tb_size_t size) { // check - tb_assert(file && data && xm_io_file_is_std(file) && !xm_io_file_is_closed(file)); + tb_assert(file && data && xm_io_file_is_std(file)); // check type tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY); @@ -105,22 +104,26 @@ static tb_void_t xm_io_file_write_std(xm_io_file_t* file, tb_char_t const* data, tb_stdfile_writ(file->std_ref, (tb_byte_t const*)data, size); } -/* - * file:write(...) +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation */ + +// io.file_write(file, ...) tb_int_t xm_io_file_write(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - // get file - xm_io_file_t* file = xm_io_getfile(lua); - tb_int_t narg = lua_gettop(lua); + // is user data? + if (!lua_isuserdata(lua, 1)) + return 0; - // this file has been closed? - if (xm_io_file_is_closed(file)) - xm_io_file_return_error_closed(lua); + // get file + xm_io_file_t* file = (xm_io_file_t*)lua_touserdata(lua, 1); + tb_check_return_val(file, 0); + // write file data + tb_int_t narg = lua_gettop(lua); if (narg > 1) { tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY; @@ -141,7 +144,7 @@ tb_int_t xm_io_file_write(lua_State* lua) xm_io_file_write_file_transcrlf(file, data, (tb_size_t)datasize); } } - - lua_settop(lua, 1); - xm_io_file_return_success(); + lua_settop(lua, 1); + lua_pushboolean(lua, tb_true); + return 1; } diff --git a/core/src/xmake/io/open.c b/core/src/xmake/io/open.c deleted file mode 100644 index b71daf7df..000000000 --- a/core/src/xmake/io/open.c +++ /dev/null @@ -1,320 +0,0 @@ -/*!A cross-platform build utility based on Lua - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2019, TBOOX Open Source Group. - * - * @author OpportunityLiu - * @file open.c - * - */ - -/* ////////////////////////////////////////////////////////////////////////////////////// - * trace - */ -#define TB_TRACE_MODULE_NAME "open" -#define TB_TRACE_MODULE_DEBUG (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "file.h" -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * macros - */ - -// num of bytes read to guess encoding -#define CHECK_SIZE (1024) - -// is utf-8 tail character -#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * private implementation - */ -static tb_size_t xm_io_file_detect_charset(tb_byte_t const** data_ptr, tb_long_t size) -{ - // check - tb_assert(data_ptr && *data_ptr); - - tb_byte_t const* data = *data_ptr; - tb_size_t charset = XM_IO_FILE_ENCODING_BINARY; - do - { - if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) // utf-8 with bom - { - charset = TB_CHARSET_TYPE_UTF8; - data += 3; // skip bom - break; - } - if (size >= 2) - { - if (data[0] == 254 && data[1] == 255) // utf16be - { - charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; - data += 2; // skip bom - break; - } - else if (data[0] == 255 && data[1] == 254) // utf16le - { - charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; - data += 2; // skip bom - break; - } - } - - tb_sint16_t utf16be_conf = 0; - tb_sint16_t utf16le_conf = 0; - tb_sint16_t utf8_conf = 0; - tb_sint16_t ascii_conf = 0; - tb_sint16_t zero_count = 0; - for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) - { - if (data[i] == 0) zero_count++; - - if (data[i] < 0x80) - ascii_conf++; - else - ascii_conf = TB_MINS16; - - if (i % 2 == 0) - { - if (data[i] == 0) utf16be_conf++; - if (data[i + 1] == 0) utf16le_conf++; - } - - if (IS_UTF8_TAIL(data[i])) - ; - else if (data[i] < 0x80) - utf8_conf++; - else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) - utf8_conf++; - else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) - utf8_conf++; - else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) && IS_UTF8_TAIL(data[i + 3])) - utf8_conf++; - else - utf8_conf = TB_MINS16; - } - - if (ascii_conf > 0 && zero_count <= 1) - { - charset = TB_CHARSET_TYPE_UTF8; - break; - } - if (utf8_conf > 0 && zero_count <= 1) - { - charset = TB_CHARSET_TYPE_UTF8; - break; - } - if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) - { - charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; - break; - } - if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) - { - charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; - break; - } - if (utf8_conf > 0) - { - charset = TB_CHARSET_TYPE_UTF8; - break; - } - -#ifdef TB_CONFIG_OS_WINDOWS - charset = TB_CHARSET_TYPE_ANSI; -#endif - - } while (0); - - *data_ptr = data; - return charset; -} -static tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t* pbomoff) -{ - // check - tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY); - - // detect encoding - tb_byte_t* data = tb_null; - tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY; - tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE); - if (size > 0) - { - tb_byte_t const* p = data; - encoding = xm_io_file_detect_charset(&p, size); - *pbomoff = p - data; - } - return encoding; -} - -/* ////////////////////////////////////////////////////////////////////////////////////// - * implementation - */ - -/* - * io.open(path, modestr) - */ -tb_int_t xm_io_open(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - // get file path and mode - tb_char_t const* path = luaL_checkstring(lua, 1); - tb_char_t const* modestr = luaL_optstring(lua, 2, "r"); - tb_assert_and_check_return_val(path && modestr, 0); - - // get file mode value - tb_size_t mode; - switch (modestr[0]) - { - case 'w': mode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC; break; - case 'a': mode = TB_FILE_MODE_RW | TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT; break; - case 'r': default: mode = TB_FILE_MODE_RO; break; - } - - // get file encoding - tb_long_t bomoff = 0; - tb_stream_ref_t stream = tb_null; - tb_bool_t update = !!tb_strchr(modestr, '+'); - tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN; - if (modestr[1] == 'b' || (update && modestr[2] == 'b')) - encoding = XM_IO_FILE_ENCODING_BINARY; - else if (tb_strstr(modestr, "utf8") || tb_strstr(modestr, "utf-8")) - encoding = TB_CHARSET_TYPE_UTF8; - else if (tb_strstr(modestr, "utf16le") || tb_strstr(modestr, "utf-16le")) - encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE; - else if (tb_strstr(modestr, "utf16be") || tb_strstr(modestr, "utf-16be")) - encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE; - else if (tb_strstr(modestr, "utf16") || tb_strstr(modestr, "utf-16")) - encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE; - else if (modestr[0] == 'w' || modestr[0] == 'a') // set to utf-8 if not specified for the writing mode - encoding = TB_CHARSET_TYPE_UTF8; - else if (modestr[0] == 'r') // detect encoding if not specified for the reading mode - { - stream = tb_stream_init_from_file(path, mode); - if (stream && tb_stream_open(stream)) - encoding = xm_io_file_detect_encoding(stream, &bomoff); - else - { - if (stream) tb_stream_exit(stream); - lua_pushnil(lua); - lua_pushliteral(lua, "file not found!"); - return 2; - } - } - else - { - lua_pushnil(lua); - lua_pushliteral(lua, "invalid open mode!"); - return 2; - } - tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0); - - // open file - tb_bool_t open_ok = tb_false; - tb_stream_ref_t file_ref = tb_null; - tb_stream_ref_t fstream = tb_null; - do - { - // init stream from file - stream = stream? stream : tb_stream_init_from_file(path, mode); - tb_assert_and_check_break(stream); - - // is transcode? - tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY; - if (is_transcode) - { - if (modestr[0] == 'r') - fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8); - else - fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding); - tb_assert_and_check_break(fstream); - - // use fstream as file - file_ref = fstream; - } - else file_ref = stream; - - // open file stream - if (!tb_stream_open(file_ref)) break; - - // skip bom characters if exists - if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) break; - - // ok - open_ok = tb_true; - - } while (0); - - // open failed? - if (!open_ok) - { - // exit stream - if (stream) tb_stream_exit(stream); - stream = tb_null; - - // exit charset stream filter - if (fstream) tb_stream_exit(fstream); - fstream = tb_null; - - // return errors - lua_pushnil(lua); - lua_pushliteral(lua, "failed to open file."); - return 2; - } - - // get absolute file path - tb_char_t full[TB_PATH_MAXN] = {0}; - path = tb_path_absolute(path, full, TB_PATH_MAXN); - tb_assert_and_check_return_val(path, 0); - - // new file - xm_io_file_t* xm_file = xm_io_newfile(lua); - xm_file->file_ref = file_ref; - xm_file->stream = stream; - xm_file->fstream = fstream; - xm_file->mode = mode; - xm_file->type = XM_IO_FILE_TYPE_FILE; - xm_file->encoding = encoding; - - // init the read/write line cache buffer - tb_buffer_init(&xm_file->rcache); - tb_buffer_init(&xm_file->wcache); - - // save file path - tb_size_t pathlen = tb_strlen(path); - xm_file->path = tb_malloc_cstr(pathlen + 1); - if (xm_file->path) - { - tb_strncpy((tb_char_t*)xm_file->path, path, pathlen); - ((tb_char_t*)xm_file->path)[pathlen] = '\0'; - } - - // save file name - tb_size_t name_maxn = tb_arrayn(xm_file->name); - tb_strlcpy(xm_file->name, "file: ", name_maxn); - if (pathlen < name_maxn - tb_arrayn("file: ")) - tb_strcat(xm_file->name, path); - else - { - tb_strcat(xm_file->name, "..."); - tb_strcat(xm_file->name, path + (pathlen - name_maxn + tb_arrayn("file: ") + tb_arrayn("..."))); - } - return 1; -} diff --git a/core/src/xmake/io/prefix.h b/core/src/xmake/io/prefix.h index fc61e8829..761d4cdf8 100644 --- a/core/src/xmake/io/prefix.h +++ b/core/src/xmake/io/prefix.h @@ -26,6 +26,72 @@ */ #include "../prefix.h" +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ +#define xm_io_file_is_file(file) ((file)->type == XM_IO_FILE_TYPE_FILE) +#define xm_io_file_is_std(file) ((file)->type != XM_IO_FILE_TYPE_FILE) +#define xm_io_file_is_tty(file) (!!((file)->type & XM_IO_FILE_FLAG_TTY)) + +// return file error +#define xm_io_file_return_error(lua, error) \ + do \ + { \ + lua_pushnil(lua); \ + lua_pushstring(lua, error); \ + return 2; \ + } while (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ +typedef enum __xm_io_file_type_e +{ + XM_IO_FILE_TYPE_FILE = 0 //!< disk file + +, XM_IO_FILE_TYPE_STDIN = 1 +, XM_IO_FILE_TYPE_STDOUT = 2 +, XM_IO_FILE_TYPE_STDERR = 3 + +, XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream + +} xm_io_file_type_e; + +/* use negetive numbers for this enum, its a extension for tb_charset_type_e + * before adding new values, make sure they have not conflicts with values in tb_charset_type_e + */ +typedef enum __xm_io_file_encoding_e +{ + XM_IO_FILE_ENCODING_UNKNOWN = -1 +, XM_IO_FILE_ENCODING_BINARY = -2 + +} xm_io_file_encoding_e; + +// the file type +typedef struct __xm_io_file_t +{ + union + { + /* the normal file for XM_IO_FILE_TYPE_FILE + * + * direct: file_ref -> stream -> file + * transcode: file_ref -> fstream -> stream -> file + */ + tb_stream_ref_t file_ref; + + // the standard io file + tb_stdfile_ref_t std_ref; + }; + + tb_stream_ref_t stream; // the file stream for XM_IO_FILE_TYPE_FILE + tb_stream_ref_t fstream; // the file charset stream filter + tb_size_t mode; // tb_file_mode_t + tb_size_t type; // xm_io_file_type_e + tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e + tb_buffer_t rcache; // the read line cache buffer + tb_buffer_t wcache; // the write line cache buffer + +} xm_io_file_t; #endif diff --git a/core/src/xmake/io/std.c b/core/src/xmake/io/std.c index 2ed46a341..b549f3da7 100644 --- a/core/src/xmake/io/std.c +++ b/core/src/xmake/io/std.c @@ -14,31 +14,24 @@ * * Copyright (C) 2015 - 2019, TBOOX Open Source Group. * - * @author OpportunityLiu - * @file std.c + * @author OpportunityLiu, ruki + * @file file_std.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ -#define TB_TRACE_MODULE_NAME "io_std" +#define TB_TRACE_MODULE_NAME "std" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ -#include "file.h" #include "prefix.h" -#include -#ifdef TB_CONFIG_OS_WINDOWS -# include -#else -# include -#endif /* ////////////////////////////////////////////////////////////////////////////////////// - * implementation + * private implementation */ static tb_size_t xm_io_std_isatty(tb_size_t type) { @@ -66,73 +59,49 @@ static tb_size_t xm_io_std_isatty(tb_size_t type) return type; } -static tb_void_t xm_io_std_init(lua_State* lua, tb_size_t type) +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +// io.std(stdin: 1, stdout: 2, stderr: 3) +tb_int_t xm_io_std(lua_State* lua) { // check - tb_assert_and_check_return(lua); + tb_assert_and_check_return_val(lua, 0); - tb_char_t const* name = tb_null; - tb_char_t const* path = tb_null; - tb_stdfile_ref_t fp = tb_null; + // get std type + tB_int_t type = lua_tointeger(lua, 1); + tb_stdfile_ref_t fp = tb_null; switch (type) { case XM_IO_FILE_TYPE_STDIN: - name = "stdin"; fp = tb_stdfile_input(); break; case XM_IO_FILE_TYPE_STDOUT: - name = "stdout"; fp = tb_stdfile_output(); break; case XM_IO_FILE_TYPE_STDERR: - name = "stderr"; fp = tb_stdfile_error(); break; } -#ifdef TB_CONFIG_OS_WINDOWS - path = "CON"; // console device -#else - switch (type) - { - case XM_IO_FILE_TYPE_STDIN: path = "/dev/stdin"; break; - case XM_IO_FILE_TYPE_STDOUT: path = "/dev/stdout"; break; - case XM_IO_FILE_TYPE_STDERR: path = "/dev/stderr"; break; - } -#endif - tb_assert_and_check_return(name && path && fp); - // new file - xm_io_file_t* file = xm_io_newfile(lua); - tb_assert_and_check_return(file); - lua_setfield(lua, -2, name); + // make file + xm_io_file_t* file = tb_malloc0_type(xm_io_file_t); + tb_assert_and_check_return_val(file, 0); // init file - file->encoding = TB_CHARSET_TYPE_UTF8; - file->type = xm_io_std_isatty(type); - file->path = path; - file->std_ref = fp; - file->stream = tb_null; - file->fstream = tb_null; + file->std_ref = fp; + file->stream = tb_null; + file->fstream = tb_null; + file->type = xm_io_std_isatty(type); + file->encoding = TB_CHARSET_TYPE_UTF8; - // init name - tb_char_t const* info = xm_io_file_is_tty(file) ? "" : " redirected"; - tb_snprintf(file->name, tb_arrayn(file->name), "file: (%s%s)", name, info); + // init the read/write line cache buffer + tb_buffer_init(&file->rcache); + tb_buffer_init(&file->wcache); - // init the line cache buffer - tb_buffer_init(&file->rcache); - tb_buffer_init(&file->wcache); + // ok + lua_pushlightuserdata(lua, (tb_pointer_t)file); + return 1; } -tb_int_t xm_io_std(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - // init io.stdin, io.stdout and io.stderr - lua_getglobal(lua, "io"); - xm_io_std_init(lua, XM_IO_FILE_TYPE_STDIN); - xm_io_std_init(lua, XM_IO_FILE_TYPE_STDOUT); - xm_io_std_init(lua, XM_IO_FILE_TYPE_STDERR); - lua_pop(lua, 1); - return 0; -} diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index 53f781031..83b218760 100644 --- a/core/src/xmake/machine.c +++ b/core/src/xmake/machine.c @@ -89,21 +89,16 @@ tb_int_t xm_os_gid(lua_State* lua); tb_int_t xm_os_getown(lua_State* lua); #endif -// the io functions -tb_int_t xm_io_std(lua_State* lua); -tb_int_t xm_io_open(lua_State* lua); - // the io/file functions +tb_int_t xm_io_std(lua_State* lua); +tb_int_t xm_io_file_open(lua_State* lua); 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_size(lua_State* lua); tb_int_t xm_io_file_write(lua_State* lua); tb_int_t xm_io_file_flush(lua_State* lua); tb_int_t xm_io_file_close(lua_State* lua); tb_int_t xm_io_file_isatty(lua_State* lua); -tb_int_t xm_io_file_path(lua_State* lua); -tb_int_t xm_io_file___len(lua_State* lua); -tb_int_t xm_io_file___tostring(lua_State* lua); -tb_int_t xm_io_file___gc(lua_State* lua); // the io/filelock functions tb_int_t xm_io_filelock_open(lua_State* lua); @@ -228,7 +223,15 @@ static luaL_Reg const g_winos_functions[] = // the io functions static luaL_Reg const g_io_functions[] = { - { "open", xm_io_open } + { "std", xm_io_std } +, { "file_open", xm_io_file_open } +, { "file_read", xm_io_file_read } +, { "file_seek", xm_io_file_seek } +, { "file_size", xm_io_file_size } +, { "file_write", xm_io_file_write } +, { "file_flush", xm_io_file_flush } +, { "file_isatty", xm_io_file_isatty } +, { "file_close", xm_io_file_close } , { "filelock_open", xm_io_filelock_open } , { "filelock_lock", xm_io_filelock_lock } , { "filelock_trylock", xm_io_filelock_trylock } @@ -237,22 +240,6 @@ static luaL_Reg const g_io_functions[] = , { tb_null, tb_null } }; -// the io/file functions -static luaL_Reg const g_io_file_functions[] = -{ - { "read", xm_io_file_read } -, { "seek", xm_io_file_seek } -, { "write", xm_io_file_write } -, { "flush", xm_io_file_flush } -, { "isatty", xm_io_file_isatty } -, { "path", xm_io_file_path } -, { "close", xm_io_file_close } -, { "__gc", xm_io_file___gc } -, { "__len", xm_io_file___len } -, { "__tostring", xm_io_file___tostring } -, { tb_null, tb_null } -}; - // the path functions static luaL_Reg const g_path_functions[] = { @@ -614,12 +601,6 @@ xm_machine_ref_t xm_machine_init() // bind io functions luaL_register(machine->lua, "io", g_io_functions); - // bind io._file (metatable) functions - xm_machine_register_metatable(machine, "io", "_file", "io._file*", 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); diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index 1568a8b45..9385211cb 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -44,12 +44,12 @@ xmake_C_FILES += \ os/uid \ os/gid \ os/getown \ - io/file___len \ - io/file___tostring \ - io/file_close___gc \ + io/std \ + io/file_size \ + io/file_close \ io/file_flush \ io/file_isatty \ - io/file_path \ + io/file_open \ io/file_read \ io/file_seek \ io/file_write \ @@ -58,8 +58,6 @@ xmake_C_FILES += \ io/filelock_unlock \ io/filelock_trylock \ io/filelock_close \ - io/open \ - io/std \ path/relative \ path/absolute \ path/translate \ -- cgit v1.3.1