提交 dce677a7 编写于 作者: wafwerar's avatar wafwerar

fix(os): fix window compilation errors.

上级 56200d6c
......@@ -14,9 +14,24 @@ if(${BUILD_PTHREAD})
cat("${TD_SUPPORT_DIR}/pthread_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
endif()
# gnu regex
if(${BUILD_GNUREGEX})
cat("${TD_SUPPORT_DIR}/gnuregex_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
# iconv
if(${BUILD_WITH_ICONV})
cat("${TD_SUPPORT_DIR}/iconv_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
endif()
# msvc regex
if(${BUILD_MSVCREGEX})
cat("${TD_SUPPORT_DIR}/msvcregex_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
endif()
# wcwidth
if(${BUILD_WCWIDTH})
cat("${TD_SUPPORT_DIR}/wcwidth_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
endif()
# wingetopt
if(${BUILD_WINGETOPT})
cat("${TD_SUPPORT_DIR}/wingetopt_CMakeLists.txt.in" ${CONTRIB_TMP_FILE})
endif()
# googletest
......@@ -99,8 +114,27 @@ if(${BUILD_TEST})
target_include_directories(
gtest
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp-stub/src>
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp-stub/src_linux>
)
if(${TD_WINDOWS})
target_include_directories(
gtest
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp-stub/src_win>
)
endif(${TD_WINDOWS})
if(${TD_LINUX})
target_include_directories(
gtest
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp-stub/src_linux>
)
endif(${TD_LINUX})
if(${TD_DARWIN})
target_include_directories(
gtest
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp-stub/src_darwin>
)
endif(${TD_DARWIN})
endif(${BUILD_TEST})
# cJson
......@@ -182,6 +216,53 @@ if(${BUILD_WITH_NURAFT})
add_subdirectory(nuraft)
endif(${BUILD_WITH_NURAFT})
# pthread
if(${BUILD_PTHREAD})
set(CMAKE_BUILD_TYPE release)
add_definitions(-DPTW32_STATIC_LIB)
add_subdirectory(pthread)
set_target_properties(libpthreadVC3 PROPERTIES OUTPUT_NAME pthread)
add_library(pthread STATIC IMPORTED GLOBAL)
SET_PROPERTY(TARGET pthread PROPERTY IMPORTED_LOCATION ${LIBRARY_OUTPUT_PATH}/pthread.lib)
endif()
# iconv
if(${BUILD_WITH_ICONV})
add_subdirectory(iconv)
endif(${BUILD_WITH_ICONV})
# wingetopt
if(${BUILD_WINGETOPT})
add_subdirectory(wingetopt)
endif(${BUILD_WINGETOPT})
# msvcregex
if(${BUILD_MSVCREGEX})
add_library(msvcregex STATIC "")
target_sources(msvcregex
PRIVATE "msvcregex/regex.c"
)
target_include_directories(msvcregex
PRIVATE "msvcregex"
)
target_link_libraries(msvcregex
INTERFACE Shell32
)
SET_TARGET_PROPERTIES(msvcregex PROPERTIES OUTPUT_NAME msvcregex)
endif(${BUILD_MSVCREGEX})
# msvcregex
if(${BUILD_WCWIDTH})
add_library(wcwidth STATIC "")
target_sources(wcwidth
PRIVATE "wcwidth/wcwidth.c"
)
target_include_directories(wcwidth
PRIVATE "wcwidth"
)
SET_TARGET_PROPERTIES(wcwidth PROPERTIES OUTPUT_NAME wcwidth)
endif(${BUILD_WCWIDTH})
# CRAFT
if(${BUILD_WITH_CRAFT})
add_library(craft STATIC IMPORTED GLOBAL)
......@@ -238,8 +319,12 @@ if(${BUILD_WITH_SQLITE})
target_link_libraries(sqlite
INTERFACE m
INTERFACE pthread
INTERFACE dl
)
if(NOT TD_WINDOWS)
target_link_libraries(sqlite
INTERFACE dl
)
endif(NOT TD_WINDOWS)
endif(${BUILD_WITH_SQLITE})
# pthread
......
add_executable(simulate_vnode "simulate_vnode.c")
target_link_libraries(simulate_vnode PUBLIC craft lz4 uv_a)
\ No newline at end of file
target_link_libraries(simulate_vnode PUBLIC craft lz4 uv_a)
if(${BUILD_WINGETOPT})
target_link_libraries(simulate_vnode PUBLIC wingetopt)
target_include_directories(
simulate_vnode
PUBLIC "${TD_SOURCE_DIR}/contrib/wingetopt/src"
)
endif()
\ No newline at end of file
......@@ -6,43 +6,39 @@
#define POINTER_SHIFT(ptr, s) ((void *)(((char *)ptr) + (s)))
#define POINTER_DISTANCE(pa, pb) ((char *)(pb) - (char *)(pa))
#define tPutA(buf, val) \
({ \
memcpy(buf, &val, sizeof(val)); \
POINTER_SHIFT(buf, sizeof(val)); \
})
static inline void tPutA(void **buf, uint64_t val) {
memcpy(buf, &val, sizeof(val));
*buf = POINTER_SHIFT(buf, sizeof(val));
}
#define tPutB(buf, val) \
({ \
((uint8_t *)buf)[7] = ((val) >> 56) & 0xff; \
((uint8_t *)buf)[6] = ((val) >> 48) & 0xff; \
((uint8_t *)buf)[5] = ((val) >> 40) & 0xff; \
((uint8_t *)buf)[4] = ((val) >> 32) & 0xff; \
((uint8_t *)buf)[3] = ((val) >> 24) & 0xff; \
((uint8_t *)buf)[2] = ((val) >> 16) & 0xff; \
((uint8_t *)buf)[1] = ((val) >> 8) & 0xff; \
((uint8_t *)buf)[0] = (val)&0xff; \
POINTER_SHIFT(buf, sizeof(val)); \
})
static inline void tPutB(void **buf, uint64_t val) {
((uint8_t *)buf)[7] = ((val) >> 56) & 0xff;
((uint8_t *)buf)[6] = ((val) >> 48) & 0xff;
((uint8_t *)buf)[5] = ((val) >> 40) & 0xff;
((uint8_t *)buf)[4] = ((val) >> 32) & 0xff;
((uint8_t *)buf)[3] = ((val) >> 24) & 0xff;
((uint8_t *)buf)[2] = ((val) >> 16) & 0xff;
((uint8_t *)buf)[1] = ((val) >> 8) & 0xff;
((uint8_t *)buf)[0] = (val)&0xff;
*buf = POINTER_SHIFT(buf, sizeof(val));
}
#define tPutC(buf, val) \
({ \
if (buf) { \
((uint64_t *)buf)[0] = (val); \
POINTER_SHIFT(buf, sizeof(val)); \
} \
NULL; \
})
static inline void tPutC(void **buf, uint64_t val) {
if (buf) {
((uint64_t *)buf)[0] = (val);
POINTER_SHIFT(buf, sizeof(val));
}
*buf = NULL;
}
#define tPutD(buf, val) \
({ \
uint64_t tmp = val; \
for (size_t i = 0; i < sizeof(val); i++) { \
((uint8_t *)buf)[i] = tmp & 0xff; \
tmp >>= 8; \
} \
POINTER_SHIFT(buf, sizeof(val)); \
})
static inline void tPutD(void **buf, uint64_t val) {
uint64_t tmp = val;
for (size_t i = 0; i < sizeof(val); i++) {
((uint8_t *)buf)[i] = tmp & 0xff;
tmp >>= 8;
}
*buf = POINTER_SHIFT(buf, sizeof(val));
}
static inline void tPutE(void **buf, uint64_t val) {
if (buf) {
......@@ -61,7 +57,7 @@ static void func(T t) {
switch (t) {
case A:
for (size_t i = 0; i < 10 * 1024l * 1024l * 1024l; i++) {
pBuf = tPutA(pBuf, val);
tPutA(pBuf, val);
if (POINTER_DISTANCE(buf, pBuf) == 1024) {
pBuf = buf;
}
......@@ -69,7 +65,7 @@ static void func(T t) {
break;
case B:
for (size_t i = 0; i < 10 * 1024l * 1024l * 1024l; i++) {
pBuf = tPutB(pBuf, val);
tPutB(pBuf, val);
if (POINTER_DISTANCE(buf, pBuf) == 1024) {
pBuf = buf;
}
......@@ -77,7 +73,7 @@ static void func(T t) {
break;
case C:
for (size_t i = 0; i < 10 * 1024l * 1024l * 1024l; i++) {
pBuf = tPutC(pBuf, val);
tPutC(pBuf, val);
if (POINTER_DISTANCE(buf, pBuf) == 1024) {
pBuf = buf;
}
......@@ -85,7 +81,7 @@ static void func(T t) {
break;
case D:
for (size_t i = 0; i < 10 * 1024l * 1024l * 1024l; i++) {
pBuf = tPutD(pBuf, val);
tPutD(pBuf, val);
if (POINTER_DISTANCE(buf, pBuf) == 1024) {
pBuf = buf;
}
......
......@@ -30,6 +30,7 @@ target_link_libraries(demoapi
)
target_include_directories(tmq
PUBLIC "${TD_SOURCE_DIR}/include/os"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
)
......
......@@ -17,8 +17,8 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "taos.h"
#include "osSleep.h"
static int running = 1;
static void msg_process(TAOS_RES* msg) {
......@@ -48,7 +48,7 @@ int32_t init_env() {
return -1;
}
taos_free_result(pRes);
sleep(1);
taosSsleep(1);
pRes = taos_query(pConn, "use abc1");
if (taos_errno(pRes) != 0) {
......
......@@ -88,7 +88,11 @@ typedef struct taosField {
int32_t bytes;
} TAOS_FIELD;
#define DLL_EXPORT
#ifdef WINDOWS
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
typedef void (*__taos_async_fn_t)(void *param, TAOS_RES *, int code);
......
aux_source_directory(src CLIENT_SRC)
add_library(taos SHARED ${CLIENT_SRC})
if(TD_WINDOWS)
add_library(taos SHARED ${CLIENT_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/src/taos.rc.in)
else()
add_library(taos SHARED ${CLIENT_SRC})
endif ()
target_include_directories(
taos
PUBLIC "${TD_SOURCE_DIR}/include/client"
......@@ -10,6 +14,13 @@ target_link_libraries(
INTERFACE api
PRIVATE os util common transport nodes parser command planner catalog scheduler function qcom
)
if(TD_WINDOWS)
set_target_properties(taos
PROPERTIES
LINK_FLAGS
/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/taos.def
)
endif ()
set_target_properties(
taos
......
taos_cleanup
taos_options
taos_set_config
taos_connect
taos_connect_l
taos_connect_auth
taos_close
taos_data_type
taos_stmt_init
taos_stmt_prepare
taos_stmt_set_tbname_tags
taos_stmt_set_tbname
taos_stmt_set_sub_tbname
taos_stmt_is_insert
taos_stmt_num_params
taos_stmt_get_param
taos_stmt_bind_param
taos_stmt_bind_param_batch
taos_stmt_bind_single_param_batch
taos_stmt_add_batch
taos_stmt_execute
taos_stmt_use_result
taos_stmt_close
taos_stmt_errstr
taos_stmt_affected_rows
taos_stmt_affected_rows_once
taos_query
taos_query_l
taos_fetch_row
taos_result_precision
taos_free_result
taos_field_count
taos_num_fields
taos_affected_rows
taos_fetch_fields
taos_select_db
taos_print_row
taos_stop_query
taos_is_null
taos_is_update_query
taos_fetch_block
taos_fetch_block_s
taos_fetch_raw_block
taos_get_column_data_offset
taos_validate_sql
taos_reset_current_db
taos_fetch_lengths
taos_result_block
taos_get_server_info
taos_get_client_info
taos_errstr
taos_errno
taos_query_a
taos_fetch_rows_a
taos_subscribe
taos_consume
taos_unsubscribe
taos_load_table_info
taos_schemaless_insert
tmq_list_new
tmq_list_append
tmq_list_destroy
tmq_list_get_size
tmq_list_to_c_array
tmq_consumer_new
tmq_err2str
tmq_subscribe
tmq_unsubscribe
tmq_subscription
tmq_consumer_poll
tmq_consumer_close
tmq_commit
tmq_conf_new
tmq_conf_set
tmq_conf_destroy
tmq_conf_set_offset_commit_cb
tmq_get_topic_name
tmq_get_vgroup_id
tmq_create_stream
taos_check_server_status
\ No newline at end of file
1 VERSIONINFO
FILEVERSION ${TD_VER_NUMBER}
PRODUCTVERSION ${TD_VER_NUMBER}
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x0L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Native C Driver for TDengine"
VALUE "FileVersion", "${TD_VER_NUMBER}"
VALUE "InternalName", "taos.dll(${TD_VER_CPUTYPE})"
VALUE "LegalCopyright", "Copyright (C) 2020 TAOS Data"
VALUE "OriginalFilename", ""
VALUE "ProductName", "taos.dll(${TD_VER_CPUTYPE})"
VALUE "ProductVersion", "${TD_VER_NUMBER}"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
\ No newline at end of file
......@@ -221,7 +221,7 @@ void initGroupedResultInfo(SGroupResInfo* pGroupResInfo, SHashObj* pHashmap, boo
p->groupId = *(uint64_t*) key;
p->pos = *(SResultRowPosition*) pData;
memcpy(p->key, key + sizeof(uint64_t), keyLen - sizeof(uint64_t));
memcpy(p->key, (char*)key + sizeof(uint64_t), keyLen - sizeof(uint64_t));
taosArrayPush(pGroupResInfo->pRows, &p);
}
......
......@@ -979,7 +979,8 @@ void transCloseServer(void* arg) {
transSrvInst--;
if (transSrvInst == 0) {
transModuleInit = PTHREAD_ONCE_INIT;
TdThreadOnce tmpInit = PTHREAD_ONCE_INIT;
memcpy(&transModuleInit, &tmpInit, sizeof(TdThreadOnce));
uvCloseExHandleMgt();
}
}
......
......@@ -145,6 +145,12 @@ static int32_t cfgCheckAndSetDir(SConfigItem *pItem, const char *inputDir) {
return -1;
}
if (taosRealPath(fullDir, NULL, PATH_MAX) != 0) {
terrno = TAOS_SYSTEM_ERROR(errno);
uError("failed to get realpath of dir:%s since %s", inputDir, terrstr());
return -1;
}
taosMemoryFreeClear(pItem->str);
pItem->str = strdup(fullDir);
if (pItem->str == NULL) {
......@@ -823,7 +829,7 @@ int32_t cfgLoadFromApollUrl(SConfig *pConfig, const char *url) {
}
p++;
if (bcmp(url, "jsonFile", 8) == 0) {
if (memcmp(url, "jsonFile", 8) == 0) {
char *filepath = p;
if (!taosCheckExistFile(filepath)) {
uError("fial to load json file: %s", filepath);
......@@ -893,8 +899,8 @@ int32_t cfgLoadFromApollUrl(SConfig *pConfig, const char *url) {
}
tjsonDelete(pJson);
// } else if (bcmp(url, "jsonUrl", 7) == 0) {
// } else if (bcmp(url, "etcdUrl", 7) == 0) {
// } else if (memcmp(url, "jsonUrl", 7) == 0) {
// } else if (memcmp(url, "etcdUrl", 7) == 0) {
} else {
uError("Unsupported url: %s", url);
return -1;
......@@ -908,7 +914,7 @@ int32_t cfgGetApollUrl(const char **envCmd, const char *envFile, char* apolloUrl
int32_t index = 0;
if (envCmd == NULL) return 0;
while (envCmd[index]!=NULL) {
if (bcmp(envCmd[index], "TAOS_APOLLO_URL", 14) == 0) {
if (memcmp(envCmd[index], "TAOS_APOLLO_URL", 14) == 0) {
char *p = strchr(envCmd[index], '=');
if (p != NULL) {
p++;
......@@ -934,7 +940,7 @@ int32_t cfgGetApollUrl(const char **envCmd, const char *envFile, char* apolloUrl
break;
}
if(line[_bytes - 1] == '\n') line[_bytes - 1] = 0;
if (bcmp(line, "TAOS_APOLLO_URL", 14) == 0) {
if (memcmp(line, "TAOS_APOLLO_URL", 14) == 0) {
char *p = strchr(line, '=');
if (p != NULL) {
p++;
......@@ -975,7 +981,7 @@ int32_t cfgGetApollUrl(const char **envCmd, const char *envFile, char* apolloUrl
break;
}
if(line[_bytes - 1] == '\n') line[_bytes - 1] = 0;
if (bcmp(line, "TAOS_APOLLO_URL", 14) == 0) {
if (memcmp(line, "TAOS_APOLLO_URL", 14) == 0) {
char *p = strchr(line, '=');
if (p != NULL) {
p++;
......
......@@ -14,14 +14,12 @@
*/
#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "taos.h"
#include "taoserror.h"
......@@ -103,8 +101,8 @@ void initLogFile() {
TdFilePtr pFile = taosOpenFile(file, TD_FILE_TEXT | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM);
if (NULL == pFile) {
fprintf(stderr, "Failed to open %s for save result\n", "./tmqlog.txt");
exit -1;
};
exit(-1);
}
g_fp = pFile;
}
......
......@@ -61,6 +61,35 @@ void shellPrintHelp() {
printf("\n\nReport bugs to %s.\n", SHELL_EMAIL);
}
#ifdef LINUX
#include <argp.h>
#include <termio.h>
const char *argp_program_version = version;
const char *argp_program_bug_address = SHELL_EMAIL;
static struct argp_option shellOptions[] = {
{"host", 'h', "HOST", 0, SHELL_HOST},
{"port", 'P', "PORT", 0, SHELL_PORT},
{"user", 'u', "USER", 0, SHELL_USER},
{0, 'p', 0, 0, SHELL_PASSWORD},
{"auth", 'a', "AUTH", 0, SHELL_AUTH},
{"generate-auth", 'A', 0, 0, SHELL_GEN_AUTH},
{"config-dir", 'c', "DIR", 0, SHELL_CFG_DIR},
{"dump-config", 'C', 0, 0, SHELL_DMP_CFG},
{"commands", 's', "COMMANDS", 0, SHELL_CMD},
{"raw-time", 'r', 0, 0, SHELL_RAW_TIME},
{"file", 'f', "FILE", 0, SHELL_FILE},
{"database", 'd', "DATABASE", 0, SHELL_DB},
{"check", 'k', 0, 0, SHELL_CHECK},
{"startup", 't', 0, 0, SHELL_STARTUP},
{"display-width", 'w', "WIDTH", 0, SHELL_WIDTH},
{"netrole", 'n', "NETROLE", 0, SHELL_NET_ROLE},
{"pktlen", 'l', "PKTLEN", 0, SHELL_PKG_LEN},
{"pktnum", 'N', "PKTNUM", 0, SHELL_PKT_NUM},
{0},
};
static int32_t shellParseSingleOpt(int32_t key, char *arg) {
SShellArgs *pArgs = &shell.args;
......@@ -178,35 +207,6 @@ int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) {
return 0;
}
#ifdef LINUX
#include <argp.h>
#include <termio.h>
const char *argp_program_version = version;
const char *argp_program_bug_address = SHELL_EMAIL;
static struct argp_option shellOptions[] = {
{"host", 'h', "HOST", 0, SHELL_HOST},
{"port", 'P', "PORT", 0, SHELL_PORT},
{"user", 'u', "USER", 0, SHELL_USER},
{0, 'p', 0, 0, SHELL_PASSWORD},
{"auth", 'a', "AUTH", 0, SHELL_AUTH},
{"generate-auth", 'A', 0, 0, SHELL_GEN_AUTH},
{"config-dir", 'c', "DIR", 0, SHELL_CFG_DIR},
{"dump-config", 'C', 0, 0, SHELL_DMP_CFG},
{"commands", 's', "COMMANDS", 0, SHELL_CMD},
{"raw-time", 'r', 0, 0, SHELL_RAW_TIME},
{"file", 'f', "FILE", 0, SHELL_FILE},
{"database", 'd', "DATABASE", 0, SHELL_DB},
{"check", 'k', 0, 0, SHELL_CHECK},
{"startup", 't', 0, 0, SHELL_STARTUP},
{"display-width", 'w', "WIDTH", 0, SHELL_WIDTH},
{"netrole", 'n', "NETROLE", 0, SHELL_NET_ROLE},
{"pktlen", 'l', "PKTLEN", 0, SHELL_PKG_LEN},
{"pktnum", 'N', "PKTNUM", 0, SHELL_PKT_NUM},
{0},
};
static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) { return shellParseSingleOpt(key, arg); }
static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""};
......@@ -335,7 +335,7 @@ int32_t shellParseArgs(int32_t argc, char *argv[]) {
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
shell.info.osname = "Windows";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "C:/TDengine/%s", SHELL_HISTORY_FILE);
if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
// if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
#elif defined(_TD_DARWIN_64)
shell.info.osname = "Darwin";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getpwuid(getuid())->pw_dir, SHELL_HISTORY_FILE);
......
......@@ -54,8 +54,8 @@ static void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
static void shellShowOnScreen(SShellCmd *cmd);
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
static void shellPrintContinuePrompt() { printf("%s", shell.args.promptContinue); }
static void shellPrintPrompt() { printf("%s", shell.args.promptHeader); }
// static void shellPrintContinuePrompt() { printf("%s", shell.args.promptContinue); }
// static void shellPrintPrompt() { printf("%s", shell.args.promptHeader); }
void shellUpdateBuffer(SShellCmd *cmd) {
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
......@@ -112,7 +112,7 @@ int32_t shellReadCommand(char command[]) {
cmd.command = NULL;
return 0;
} else {
shellPrintContinuePrompt();
// shellPrintContinuePrompt();
shellUpdateBuffer(&cmd);
}
break;
......
......@@ -42,8 +42,6 @@ int main(int argc, char *argv[]) {
return 0;
}
taos_init();
if (shell.args.is_dump_config) {
shellDumpConfig();
taos_cleanup();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册