refactor(tools): refact shell codes
This commit is contained in:
parent
2d94f8a875
commit
d2d5196186
|
@ -31,19 +31,19 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct TdCmd *TdCmdPtr;
|
typedef struct TdCmd *TdCmdPtr;
|
||||||
|
|
||||||
TdCmdPtr taosOpenCmd(const char *cmd);
|
TdCmdPtr taosOpenCmd(const char* cmd);
|
||||||
int64_t taosGetLineCmd(TdCmdPtr pCmd, char ** __restrict ptrBuf);
|
int64_t taosGetLineCmd(TdCmdPtr pCmd, char** __restrict ptrBuf);
|
||||||
int32_t taosEOFCmd(TdCmdPtr pCmd);
|
int32_t taosEOFCmd(TdCmdPtr pCmd);
|
||||||
int64_t taosCloseCmd(TdCmdPtr *ppCmd);
|
int64_t taosCloseCmd(TdCmdPtr* ppCmd);
|
||||||
|
|
||||||
void* taosLoadDll(const char* filename);
|
void* taosLoadDll(const char* filename);
|
||||||
void* taosLoadSym(void* handle, char* name);
|
void* taosLoadSym(void* handle, char* name);
|
||||||
void taosCloseDll(void* handle);
|
void taosCloseDll(void* handle);
|
||||||
|
|
||||||
int32_t taosSetConsoleEcho(bool on);
|
int32_t taosSetConsoleEcho(bool on);
|
||||||
void setTerminalMode();
|
void taosSetTerminalMode();
|
||||||
int32_t getOldTerminalMode();
|
int32_t taosGetOldTerminalMode();
|
||||||
void resetTerminalMode();
|
void taosResetTerminalMode();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,6 @@ extern const int32_t TYPE_BYTES[15];
|
||||||
#define TSDB_DEFAULT_PASS "taosdata"
|
#define TSDB_DEFAULT_PASS "taosdata"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SHELL_MAX_PASSWORD_LEN 20
|
|
||||||
|
|
||||||
#define TSDB_TRUE 1
|
#define TSDB_TRUE 1
|
||||||
#define TSDB_FALSE 0
|
#define TSDB_FALSE 0
|
||||||
#define TSDB_OK 0
|
#define TSDB_OK 0
|
||||||
|
|
|
@ -119,7 +119,7 @@ int taosSetConsoleEcho(bool on) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTerminalMode() {
|
void taosSetTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -152,7 +152,7 @@ void setTerminalMode() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t getOldTerminalMode() {
|
int32_t taosGetOldTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -170,7 +170,7 @@ int32_t getOldTerminalMode() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetTerminalMode() {
|
void taosResetTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _TD_SHELL_COMMAND_H_
|
|
||||||
#define _TD_SHELL_COMMAND_H_
|
|
||||||
|
|
||||||
#include "shellInt.h"
|
|
||||||
|
|
||||||
#define LEFT 1
|
|
||||||
#define RIGHT 2
|
|
||||||
#define UP 3
|
|
||||||
#define DOWN 4
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *buffer;
|
|
||||||
char *command;
|
|
||||||
unsigned commandSize;
|
|
||||||
unsigned bufferSize;
|
|
||||||
unsigned cursorOffset;
|
|
||||||
unsigned screenOffset;
|
|
||||||
unsigned endOffset;
|
|
||||||
} Command;
|
|
||||||
|
|
||||||
extern void backspaceChar(Command *cmd);
|
|
||||||
extern void clearLineBefore(Command *cmd);
|
|
||||||
extern void clearLineAfter(Command *cmd);
|
|
||||||
extern void deleteChar(Command *cmd);
|
|
||||||
extern void moveCursorLeft(Command *cmd);
|
|
||||||
extern void moveCursorRight(Command *cmd);
|
|
||||||
extern void positionCursorHome(Command *cmd);
|
|
||||||
extern void positionCursorEnd(Command *cmd);
|
|
||||||
extern void showOnScreen(Command *cmd);
|
|
||||||
extern void updateBuffer(Command *cmd);
|
|
||||||
extern int isReadyGo(Command *cmd);
|
|
||||||
extern void resetCommand(Command *cmd, const char s[]);
|
|
||||||
|
|
||||||
int countPrefixOnes(unsigned char c);
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos);
|
|
||||||
void printChar(char c, int times);
|
|
||||||
void positionCursor(int step, int direction);
|
|
||||||
|
|
||||||
#endif /*_TD_SHELL_COMMAND_H_*/
|
|
|
@ -19,34 +19,37 @@
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "taos.h"
|
#include "taos.h"
|
||||||
#include "taosdef.h"
|
#include "taosdef.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
#include "tconfig.h"
|
||||||
|
#include "tglobal.h"
|
||||||
|
#include "ttypes.h"
|
||||||
|
#include "tutil.h"
|
||||||
|
|
||||||
#include <regex.h>
|
#define SHELL_MAX_HISTORY_SIZE 1000
|
||||||
#include <wordexp.h>
|
#define SHELL_MAX_COMMAND_SIZE 1048586
|
||||||
|
#define SHELL_HISTORY_FILE ".taos_history"
|
||||||
#define MAX_HISTORY_SIZE 1000
|
#define SHELL_DEFAULT_RES_SHOW_NUM 100
|
||||||
#define MAX_COMMAND_SIZE 1048586
|
#define SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30
|
||||||
#define HISTORY_FILE ".taos_history"
|
|
||||||
#define DEFAULT_RES_SHOW_NUM 100
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* hist[MAX_HISTORY_SIZE];
|
char* hist[SHELL_MAX_HISTORY_SIZE];
|
||||||
|
char file[TSDB_FILENAME_LEN];
|
||||||
int32_t hstart;
|
int32_t hstart;
|
||||||
int32_t hend;
|
int32_t hend;
|
||||||
} SShellHistory;
|
} SShellHistory;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* host;
|
const char* host;
|
||||||
const char* password;
|
|
||||||
const char* user;
|
const char* user;
|
||||||
const char* auth;
|
const char* auth;
|
||||||
const char* database;
|
const char* database;
|
||||||
const char* file;
|
const char* file;
|
||||||
const char* cfgdir;
|
const char* cfgdir;
|
||||||
const char* commands;
|
const char* commands;
|
||||||
|
const char* netrole;
|
||||||
|
char password[TSDB_USET_PASSWORD_LEN];
|
||||||
bool is_gen_auth;
|
bool is_gen_auth;
|
||||||
bool is_raw_time;
|
bool is_raw_time;
|
||||||
bool is_client;
|
|
||||||
bool is_server;
|
|
||||||
bool is_version;
|
bool is_version;
|
||||||
bool is_dump_config;
|
bool is_dump_config;
|
||||||
bool is_check;
|
bool is_check;
|
||||||
|
@ -55,38 +58,51 @@ typedef struct {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
int32_t pktLen;
|
int32_t pktLen;
|
||||||
int32_t pktNum;
|
int32_t pktNum;
|
||||||
|
int32_t displayWidth;
|
||||||
int32_t abort;
|
int32_t abort;
|
||||||
} SShellArgs;
|
} SShellArgs;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SShellArgs args;
|
const char* clientVersion;
|
||||||
SShellHistory history;
|
const char* promptHeader;
|
||||||
TAOS* conn;
|
const char* promptContinue;
|
||||||
int64_t result;
|
const char* osname;
|
||||||
|
int32_t promptSize;
|
||||||
|
char programVersion[32];
|
||||||
|
} SShellOsDetails;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SShellArgs args;
|
||||||
|
SShellHistory history;
|
||||||
|
SShellOsDetails info;
|
||||||
|
TAOS* conn;
|
||||||
|
TdThread pid;
|
||||||
|
tsem_t cancelSem;
|
||||||
|
int64_t result;
|
||||||
} SShellObj;
|
} SShellObj;
|
||||||
|
|
||||||
|
// shellArguments.c
|
||||||
int32_t shellParseArgs(int32_t argc, char* argv[]);
|
int32_t shellParseArgs(int32_t argc, char* argv[]);
|
||||||
int32_t shellInit();
|
|
||||||
void shellCleanup(void* arg);
|
|
||||||
void shellExit();
|
|
||||||
|
|
||||||
void* shellThreadLoop(void* arg);
|
// shellCommand.c
|
||||||
void shellPrintError(TAOS_RES* tres, int64_t st);
|
int32_t shellReadCommand(char* command);
|
||||||
int32_t shellRegexMatch(const char* s, const char* reg, int32_t cflags);
|
|
||||||
void shellGetGrantInfo();
|
|
||||||
void shellReadHistory();
|
|
||||||
void shellWriteHistory();
|
|
||||||
void shellHistoryPath(char* history);
|
|
||||||
|
|
||||||
int32_t shellReadCommand(char command[]);
|
// shellEngine.c
|
||||||
int32_t shellRunCommand(char* command);
|
int32_t shellExecute();
|
||||||
void shellRunCommandImp(char command[]);
|
|
||||||
void shellSourceFile(TAOS* con, char* fptr);
|
|
||||||
int32_t shellDumpResult(TAOS_RES* con, char* fname, int32_t* error_no, bool printMode);
|
|
||||||
|
|
||||||
extern char PROMPT_HEADER[];
|
// shellUtil.c
|
||||||
extern char CONTINUE_PROMPT[];
|
int32_t shellCheckIntSize();
|
||||||
extern int32_t prompt_size;
|
void shellPrintVersion();
|
||||||
|
void shellGenerateAuth();
|
||||||
|
void shellDumpConfig();
|
||||||
|
void shellCheckServerStatus();
|
||||||
|
bool shellRegexMatch(const char* s, const char* reg, int32_t cflags);
|
||||||
|
|
||||||
|
// shellNettest.c
|
||||||
|
void shellTestNetWork();
|
||||||
|
|
||||||
|
// shellMain.c
|
||||||
extern SShellObj shell;
|
extern SShellObj shell;
|
||||||
|
extern void taos_init();
|
||||||
|
|
||||||
#endif /*_TD_SHELL_INT_H_*/
|
#endif /*_TD_SHELL_INT_H_*/
|
||||||
|
|
|
@ -1,498 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __USE_XOPEN
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#include "shellInt.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
#include "tbase64.h"
|
|
||||||
|
|
||||||
#include "tscLog.h"
|
|
||||||
|
|
||||||
#define OPT_ABORT 1 /* <20>Cabort */
|
|
||||||
|
|
||||||
int indicator = 1;
|
|
||||||
struct termios oldtio;
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size);
|
|
||||||
|
|
||||||
|
|
||||||
void printHelp() {
|
|
||||||
char indent[10] = " ";
|
|
||||||
printf("taos shell is used to test the TDengine database\n");
|
|
||||||
|
|
||||||
printf("%s%s\n", indent, "-h");
|
|
||||||
printf("%s%s%s\n", indent, indent, "TDengine server IP address to connect. The default host is localhost.");
|
|
||||||
printf("%s%s\n", indent, "-p");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-P");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
|
|
||||||
printf("%s%s\n", indent, "-u");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-c");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Configuration directory.");
|
|
||||||
printf("%s%s\n", indent, "-s");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-r");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
|
|
||||||
printf("%s%s\n", indent, "-f");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-d");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-t");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
|
|
||||||
printf("%s%s\n", indent, "-D");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Use multi-thread to import all SQL files in the directory separately.");
|
|
||||||
printf("%s%s\n", indent, "-T");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Number of threads when using multi-thread to import data.");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
char DARWINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
void shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
|
|
||||||
wordexp_t full_path;
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
// for host
|
|
||||||
if (strcmp(argv[i], "-h") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->host = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -h requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for password
|
|
||||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
strcpy(tsOsName, "Darwin");
|
|
||||||
printf(DARWINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password read error\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
getchar();
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
strcpy(argv[i], "");
|
|
||||||
argc -= 1;
|
|
||||||
}
|
|
||||||
// for management port
|
|
||||||
else if (strcmp(argv[i], "-P") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->port = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -P requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for user
|
|
||||||
else if (strcmp(argv[i], "-u") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->user = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -u requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-c") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
if (strlen(argv[++i]) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", argv[i], TSDB_FILENAME_LEN - 1);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(configDir, argv[i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Option -c requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->commands = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -s requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-r") == 0) {
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
}
|
|
||||||
// For temperory batch commands to run TODO
|
|
||||||
else if (strcmp(argv[i], "-f") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
strcpy(arguments->file, argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -f requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for default database
|
|
||||||
else if (strcmp(argv[i], "-d") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->database = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -d requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-t") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->timezone = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -t requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For import directory
|
|
||||||
else if (strcmp(argv[i], "-D") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
if (wordexp(argv[++i], &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", argv[i]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(arguments->dir, full_path.we_wordv[0]);
|
|
||||||
wordfree(&full_path);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -D requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-T") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->threadNum = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -T requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For temperory command TODO
|
|
||||||
else if (strcmp(argv[i], "--help") == 0) {
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "wrong options\n");
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char *command) {
|
|
||||||
unsigned hist_counter = history.hend;
|
|
||||||
char utf8_array[10] = "\0";
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = getchar();
|
|
||||||
|
|
||||||
if (c < 0) { // For UTF-8
|
|
||||||
int count = countPrefixOnes(c);
|
|
||||||
utf8_array[0] = c;
|
|
||||||
for (int k = 1; k < count; k++) {
|
|
||||||
c = getchar();
|
|
||||||
utf8_array[k] = c;
|
|
||||||
}
|
|
||||||
insertChar(&cmd, utf8_array, count);
|
|
||||||
} else if (c < '\033') {
|
|
||||||
// Ctrl keys. TODO: Implement ctrl combinations
|
|
||||||
switch (c) {
|
|
||||||
case 1: // ctrl A
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
printf("\n");
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
kill(0, SIGINT);
|
|
||||||
break;
|
|
||||||
case 4: // EOF or Ctrl+D
|
|
||||||
printf("\n");
|
|
||||||
taos_close(con);
|
|
||||||
// write the history
|
|
||||||
shellWriteHistory();
|
|
||||||
shellExit();
|
|
||||||
break;
|
|
||||||
case 5: // ctrl E
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
printf("\n");
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFreeClear(cmd.buffer);
|
|
||||||
taosMemoryFreeClear(cmd.command);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 11: // Ctrl + K;
|
|
||||||
clearLineAfter(&cmd);
|
|
||||||
break;
|
|
||||||
case 12: // Ctrl + L;
|
|
||||||
system("clear");
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
break;
|
|
||||||
case 21: // Ctrl + U
|
|
||||||
clearLineBefore(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == '\033') {
|
|
||||||
c = getchar();
|
|
||||||
switch (c) {
|
|
||||||
case '[':
|
|
||||||
c = getchar();
|
|
||||||
switch (c) {
|
|
||||||
case 'A': // Up arrow
|
|
||||||
if (hist_counter != history.hstart) {
|
|
||||||
hist_counter = (hist_counter + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE;
|
|
||||||
resetCommand(&cmd, (history.hist[hist_counter] == NULL) ? "" : history.hist[hist_counter]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B': // Down arrow
|
|
||||||
if (hist_counter != history.hend) {
|
|
||||||
int next_hist = (hist_counter + 1) % MAX_HISTORY_SIZE;
|
|
||||||
|
|
||||||
if (next_hist != history.hend) {
|
|
||||||
resetCommand(&cmd, (history.hist[next_hist] == NULL) ? "" : history.hist[next_hist]);
|
|
||||||
} else {
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
}
|
|
||||||
hist_counter = next_hist;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C': // Right arrow
|
|
||||||
moveCursorRight(&cmd);
|
|
||||||
break;
|
|
||||||
case 'D': // Left arrow
|
|
||||||
moveCursorLeft(&cmd);
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Insert key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Delete key
|
|
||||||
deleteChar(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Page up key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Page down key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 72:
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 70:
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == 0x7f) {
|
|
||||||
// press delete key
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
} else {
|
|
||||||
insertChar(&cmd, &c, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellThreadLoop(void *arg) {
|
|
||||||
if (indicator) {
|
|
||||||
getOldTerminalMode();
|
|
||||||
indicator = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
|
|
||||||
setThreadName("shellThreadLoop");
|
|
||||||
|
|
||||||
taosThreadCleanupPush(shellCleanup, NULL);
|
|
||||||
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL){
|
|
||||||
tscError("failed to malloc command");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Read command from shell.
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
setTerminalMode();
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
resetTerminalMode();
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
taosMemoryFreeClear(command);
|
|
||||||
shellExit();
|
|
||||||
|
|
||||||
taosThreadCleanupPop(1);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellHistoryPath(char *history) { sprintf(history, "%s/%s", getpwuid(getuid())->pw_dir, HISTORY_FILE); }
|
|
||||||
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
//fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
positionCursor(cursor_y, LEFT);
|
|
||||||
positionCursor(command_x - cursor_x, DOWN);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
for (int i = 0; i < command_x; i++) {
|
|
||||||
positionCursor(1, UP);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showOnScreen(Command *cmd) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
//fprintf(stderr, "No stream device\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
// Print out the command.
|
|
||||||
char *total_string = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total_string, '\0', MAX_COMMAND_SIZE);
|
|
||||||
if (strcmp(cmd->buffer, "") == 0) {
|
|
||||||
sprintf(total_string, "%s%s", PROMPT_HEADER, cmd->command);
|
|
||||||
} else {
|
|
||||||
sprintf(total_string, "%s%s", CONTINUE_PROMPT, cmd->command);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remain_column = w.ws_col;
|
|
||||||
/* size = cmd->commandSize + prompt_size; */
|
|
||||||
for (char *str = total_string; size < cmd->commandSize + prompt_size;) {
|
|
||||||
int ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
|
||||||
if (ret < 0) break;
|
|
||||||
size += ret;
|
|
||||||
/* assert(size >= 0); */
|
|
||||||
int width = taosWcharWidth(wc);
|
|
||||||
if (remain_column > width) {
|
|
||||||
printf("%lc", wc);
|
|
||||||
remain_column -= width;
|
|
||||||
} else {
|
|
||||||
if (remain_column == width) {
|
|
||||||
printf("%lc\n\r", wc);
|
|
||||||
remain_column = w.ws_col;
|
|
||||||
} else {
|
|
||||||
printf("\n\r%lc", wc);
|
|
||||||
remain_column = w.ws_col - width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = total_string + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total_string);
|
|
||||||
/* for (int i = 0; i < size; i++){ */
|
|
||||||
/* char c = total_string[i]; */
|
|
||||||
/* if (k % w.ws_col == 0) { */
|
|
||||||
/* printf("%c\n\r", c); */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* printf("%c", c); */
|
|
||||||
/* } */
|
|
||||||
/* k += 1; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
// Position the cursor
|
|
||||||
int cursor_pos = cmd->screenOffset + prompt_size;
|
|
||||||
int ecmd_pos = cmd->endOffset + prompt_size;
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
// int cursor_y = cursor % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
int command_y = ecmd_pos % w.ws_col;
|
|
||||||
// int command_y = (command.size() + prompt_size) % w.ws_col;
|
|
||||||
positionCursor(command_y, LEFT);
|
|
||||||
positionCursor(command_x, UP);
|
|
||||||
positionCursor(cursor_x, DOWN);
|
|
||||||
positionCursor(cursor_y, RIGHT);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellCleanup(void *arg) { resetTerminalMode(); }
|
|
||||||
|
|
||||||
void shellExit() {
|
|
||||||
resetTerminalMode();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
|
@ -1,325 +0,0 @@
|
||||||
/*******************************************************************
|
|
||||||
* Copyright (c) 2017 by TAOS Technologies, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This file is proprietary and confidential to TAOS Technologies.
|
|
||||||
* No part of this file may be reproduced, stored, transmitted,
|
|
||||||
* disclosed or used in any form or by any means other than as
|
|
||||||
* expressly provided by the written permission from Jianhui Tao
|
|
||||||
*
|
|
||||||
* ****************************************************************/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../../../../include/client/taos.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "shellInt.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
|
|
||||||
extern char configDir[];
|
|
||||||
|
|
||||||
char WINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
|
|
||||||
void printVersion() {
|
|
||||||
printf("version: %s\n", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printHelp() {
|
|
||||||
char indent[10] = " ";
|
|
||||||
printf("taos shell is used to test the TDengine database\n");
|
|
||||||
|
|
||||||
printf("%s%s\n", indent, "-h");
|
|
||||||
printf("%s%s%s\n", indent, indent, "TDengine server FQDN to connect. The default host is localhost.");
|
|
||||||
printf("%s%s\n", indent, "-p");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-P");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
|
|
||||||
printf("%s%s\n", indent, "-u");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-A");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user auth to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-c");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Configuration directory.");
|
|
||||||
printf("%s%s\n", indent, "-C");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Dump configuration.");
|
|
||||||
printf("%s%s\n", indent, "-s");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-r");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
|
|
||||||
printf("%s%s\n", indent, "-f");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-d");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-t");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
|
|
||||||
printf("%s%s\n", indent, "-n");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn.");
|
|
||||||
printf("%s%s\n", indent, "-l");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet length used for net test, default is 1000 bytes.");
|
|
||||||
printf("%s%s\n", indent, "-N");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet numbers used for net test, default is 100.");
|
|
||||||
printf("%s%s\n", indent, "-S");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet type used for net test, default is TCP.");
|
|
||||||
printf("%s%s\n", indent, "-V");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Print program version.");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
void shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
// for host
|
|
||||||
if (strcmp(argv[i], "-h") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->host = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -h requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for password
|
|
||||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
strcpy(tsOsName, "Windows");
|
|
||||||
printf(WINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password read error!\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
getchar();
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
strcpy(argv[i], "");
|
|
||||||
argc -= 1;
|
|
||||||
}
|
|
||||||
// for management port
|
|
||||||
else if (strcmp(argv[i], "-P") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->port = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -P requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for user
|
|
||||||
else if (strcmp(argv[i], "-u") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->user = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -u requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-A") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->auth = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -A requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-c") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
char *tmp = argv[++i];
|
|
||||||
if (strlen(tmp) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", tmp, TSDB_FILENAME_LEN - 1);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(configDir, tmp);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Option -c requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-C") == 0) {
|
|
||||||
arguments->dump_config = true;
|
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->commands = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -s requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-r") == 0) {
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
}
|
|
||||||
// For temperory batch commands to run TODO
|
|
||||||
else if (strcmp(argv[i], "-f") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
strcpy(arguments->file, argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -f requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for default database
|
|
||||||
else if (strcmp(argv[i], "-d") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->database = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -d requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-t") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->timezone = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -t requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-n") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->netTestRole = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -n requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-l") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktLen = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -l requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-N") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktNum = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -N requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-S") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktType = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -S requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-V") == 0) {
|
|
||||||
printVersion();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
// For temperory command TODO
|
|
||||||
else if (strcmp(argv[i], "--help") == 0) {
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "wrong options\n");
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellPrintContinuePrompt() { printf("%s", CONTINUE_PROMPT); }
|
|
||||||
|
|
||||||
void shellPrintPrompt() { printf("%s", PROMPT_HEADER); }
|
|
||||||
|
|
||||||
void updateBuffer(Command *cmd) {
|
|
||||||
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
|
||||||
strcat(cmd->buffer, cmd->command);
|
|
||||||
|
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
|
||||||
cmd->cursorOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int isReadyGo(Command *cmd) {
|
|
||||||
char *total = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total, 0, MAX_COMMAND_SIZE);
|
|
||||||
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
|
||||||
|
|
||||||
char *reg_str =
|
|
||||||
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
|
||||||
"\\s*clear\\s*$)";
|
|
||||||
if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
|
||||||
taosMemoryFree(total);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char c) {
|
|
||||||
// TODO: Check if the length enough.
|
|
||||||
if (cmd->cursorOffset >= MAX_COMMAND_SIZE) {
|
|
||||||
fprintf(stdout, "sql is larger than %d bytes", MAX_COMMAND_SIZE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->command[cmd->cursorOffset++] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char command[]) {
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = getchar();
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFree(cmd.buffer);
|
|
||||||
cmd.buffer = NULL;
|
|
||||||
taosMemoryFree(cmd.command);
|
|
||||||
cmd.command = NULL;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
shellPrintContinuePrompt();
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
insertChar(&cmd, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellThreadLoop(void *arg) {
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL) return NULL;
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
shellPrintPrompt();
|
|
||||||
|
|
||||||
// Read command from shell.
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellHistoryPath(char *history) { sprintf(history, "C:/TDengine/%s", HISTORY_FILE); }
|
|
||||||
|
|
||||||
void shellExit() { exit(EXIT_SUCCESS); }
|
|
|
@ -0,0 +1,348 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32) || defined(_TD_DARWIN_64)
|
||||||
|
void shellPrintHelp() {
|
||||||
|
char indent[10] = " ";
|
||||||
|
printf("taos shell is used to test the TDengine database\n");
|
||||||
|
printf("%s%s\n", indent, "-h");
|
||||||
|
printf("%s%s%s\n", indent, indent, "TDengine server FQDN to connect. The default host is localhost.");
|
||||||
|
printf("%s%s\n", indent, "-P");
|
||||||
|
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
|
||||||
|
printf("%s%s\n", indent, "-u");
|
||||||
|
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
|
||||||
|
printf("%s%s\n", indent, "-p");
|
||||||
|
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
|
||||||
|
printf("%s%s\n", indent, "-a");
|
||||||
|
printf("%s%s%s\n", indent, indent, "The user auth to use when connecting to the server.");
|
||||||
|
printf("%s%s\n", indent, "-A");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Generate auth string from password.");
|
||||||
|
printf("%s%s\n", indent, "-c");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Configuration directory.");
|
||||||
|
printf("%s%s\n", indent, "-C");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Dump configuration.");
|
||||||
|
printf("%s%s\n", indent, "-s");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
|
||||||
|
printf("%s%s\n", indent, "-r");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
|
||||||
|
printf("%s%s\n", indent, "-f");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
|
||||||
|
printf("%s%s\n", indent, "-d");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
|
||||||
|
printf("%s%s\n", indent, "-k");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Check the service status.");
|
||||||
|
printf("%s%s\n", indent, "-t");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Check the details of the service status.");
|
||||||
|
printf("%s%s\n", indent, "-w");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Set the default binary display width.");
|
||||||
|
printf("%s%s\n", indent, "-n");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, options: client|server.");
|
||||||
|
printf("%s%s\n", indent, "-l");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Packet length used for net test, default is 1000 bytes.");
|
||||||
|
printf("%s%s\n", indent, "-N");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Packet numbers used for net test, default is 100.");
|
||||||
|
printf("%s%s\n", indent, "-V");
|
||||||
|
printf("%s%s%s\n", indent, indent, "Print program version.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellParseArgsInWindows(int argc, char *argv[]) {
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-h") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->host = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -h requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-P") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->port = atoi(argv[++i]);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -P requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-u") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->user = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -u requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
|
||||||
|
continue;
|
||||||
|
} else if (strcmp(argv[i], "-a") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->auth = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -a requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-A") == 0) {
|
||||||
|
arguments->is_gen_auth = true;
|
||||||
|
} else if (strcmp(argv[i], "-c") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->cfgdir = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Option -c requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-C") == 0) {
|
||||||
|
arguments->is_dump_config = true;
|
||||||
|
} else if (strcmp(argv[i], "-s") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->commands = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -s requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-r") == 0) {
|
||||||
|
arguments->is_raw_time = true;
|
||||||
|
} else if (strcmp(argv[i], "-f") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
strcpy(arguments->file, argv[++i]);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -f requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-d") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->database = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -d requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-k") == 0) {
|
||||||
|
arguments->is_check = true;
|
||||||
|
} else if (strcmp(argv[i], "-t") == 0) {
|
||||||
|
arguments->is_startup = true;
|
||||||
|
} else if (strcmp(argv[i], "-w") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->displayWidth = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -w requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-n") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->netTestRole = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -n requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-l") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->pktLen = atoi(argv[++i]);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -l requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-N") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->pktNum = atoi(argv[++i]);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -N requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-S") == 0) {
|
||||||
|
if (i < argc - 1) {
|
||||||
|
arguments->pktType = argv[++i];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option -S requires an argument\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "-V") == 0) {
|
||||||
|
arguments->is_version = true;
|
||||||
|
} else if (strcmp(argv[i], "--help") == 0) {
|
||||||
|
arguments->is_help = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "wrong options\n");
|
||||||
|
arguments->is_help = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <argp.h>
|
||||||
|
#include <termio.h>
|
||||||
|
const char *argp_program_version = version;
|
||||||
|
const char *argp_program_bug_address = "<support@taosdata.com>";
|
||||||
|
|
||||||
|
static struct argp_option shellOptions[] = {
|
||||||
|
{"host", 'h', "HOST", 0, "TDengine server FQDN to connect. The default host is localhost."},
|
||||||
|
{"port", 'P', "PORT", 0, "The TCP/IP port number to use for the connection."},
|
||||||
|
{"user", 'u', "USER", 0, "The user name to use when connecting to the server."},
|
||||||
|
{"password", 'p', "PASSWORD", 0, "The password to use when connecting to the server."},
|
||||||
|
{"auth", 'a', "AUTH", 0, "The auth string to use when connecting to the server."},
|
||||||
|
{"generate-auth", 'A', 0, 0, "Generate auth string from password."},
|
||||||
|
{"config-dir", 'c', "CONFIG_DIR", 0, "Configuration directory."},
|
||||||
|
{"dump-config", 'C', 0, 0, "Dump configuration."},
|
||||||
|
{"commands", 's', "COMMANDS", 0, "Commands to run without enter the shell."},
|
||||||
|
{"raw-time", 'r', 0, 0, "Output time as uint64_t."},
|
||||||
|
{"file", 'f', "FILE", 0, "Script to run without enter the shell."},
|
||||||
|
{"database", 'd', "DATABASE", 0, "Database to use when connecting to the server."},
|
||||||
|
{"check", 'k', 0, 0, "Check the service status."},
|
||||||
|
{"startup", 't', 0, 0, "Check the details of the service status."},
|
||||||
|
{"display-width", 'w', 0, 0, "Set the default binary display width."},
|
||||||
|
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, options: client|server."},
|
||||||
|
{"pktlen", 'l', "PKTLEN", 0, "Packet length used for net test, default is 1000 bytes."},
|
||||||
|
{"pktnum", 'N', "PKTNUM", 0, "Packet numbers used for net test, default is 100."},
|
||||||
|
{"version", 'V', 0, 0, "Print client version number."},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) {
|
||||||
|
SShellArgs *arguments = &shell.args;
|
||||||
|
wordexp_t full_path = {0};
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'h':
|
||||||
|
arguments->host = arg;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
arguments->port = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
arguments->user = arg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
arguments->auth = arg;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
arguments->is_gen_auth = true;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
arguments->cfgdir = arg;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
arguments->is_dump_config = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
arguments->commands = arg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
arguments->is_raw_time = true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
arguments->file = arg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
arguments->database = arg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
arguments->is_check = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
arguments->is_startup = true;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
arguments->displayWidth = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
arguments->netrole = arg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
arguments->pktLen = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
arguments->pktNum = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
arguments->is_version = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
arguments->abort = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""};
|
||||||
|
|
||||||
|
static void shellParseArgsInLinux(int argc, char *argv[]) {
|
||||||
|
argp_program_version = shell.info.programVersion;
|
||||||
|
argp_parse(&shellArgp, argc, argv, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void shellInitArgs(int argc, char *argv[]) {
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
|
||||||
|
printf(shell.info.clientVersion, tsOsName, taos_get_client_info());
|
||||||
|
if ((strlen(argv[i]) == 2) || (strncmp(argv[i], "--password", 10) == 0)) {
|
||||||
|
printf("Enter password: ");
|
||||||
|
taosSetConsoleEcho(false);
|
||||||
|
if (scanf("%20s", shell.args.password) > 1) {
|
||||||
|
fprintf(stderr, "password reading error\n");
|
||||||
|
}
|
||||||
|
taosSetConsoleEcho(true);
|
||||||
|
if (EOF == getchar()) {
|
||||||
|
fprintf(stderr, "getchar() return EOF\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tstrncpy(shell.args.password, (char *)(argv[i] + 2), sizeof(shell.args.password));
|
||||||
|
strcpy(argv[i], "-p");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(shell.args.password) == 0) {
|
||||||
|
tstrncpy(shell.args.password, TSDB_DEFAULT_PASS, sizeof(shell.args.password));
|
||||||
|
}
|
||||||
|
|
||||||
|
shell.args.pktLen = 1024;
|
||||||
|
shell.args.pktNum = 100;
|
||||||
|
shell.args.displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
|
||||||
|
shell.args.user = TSDB_DEFAULT_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t shellCheckArgs() { return 0; }
|
||||||
|
|
||||||
|
int32_t shellParseArgs(int32_t argc, char *argv[]) {
|
||||||
|
shellInitArgs(argc, argv);
|
||||||
|
shell.info.clientVersion =
|
||||||
|
"Welcome to the TDengine shell from %s, Client Version:%s\n"
|
||||||
|
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
||||||
|
shell.info.promptHeader = "taos> ";
|
||||||
|
shell.info.promptContinue = " -> ";
|
||||||
|
shell.info.promptSize = 6;
|
||||||
|
snprintf(shell.info.programVersion, sizeof(shell.info.programVersion), "version: %s\n", version);
|
||||||
|
|
||||||
|
#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);
|
||||||
|
shellParseArgsInLinuxAndDarwin();
|
||||||
|
#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);
|
||||||
|
shellParseArgsInLinuxAndDarwin();
|
||||||
|
#else
|
||||||
|
shell.info.osname = "Linux";
|
||||||
|
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), SHELL_HISTORY_FILE);
|
||||||
|
shellParseArgsInLinux(argc, argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (shell.args.abort) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shellCheckArgs();
|
||||||
|
}
|
|
@ -14,222 +14,60 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __USE_XOPEN
|
#define __USE_XOPEN
|
||||||
|
|
||||||
#include "shellCommand.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "shellInt.h"
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
#define LEFT 1
|
||||||
|
#define RIGHT 2
|
||||||
|
#define UP 3
|
||||||
|
#define DOWN 4
|
||||||
|
#define PSIZE shell.info.promptSize
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char widthInString;
|
char *buffer;
|
||||||
char widthOnScreen;
|
char *command;
|
||||||
} UTFCodeInfo;
|
uint32_t commandSize;
|
||||||
|
uint32_t bufferSize;
|
||||||
|
uint32_t cursorOffset;
|
||||||
|
uint32_t screenOffset;
|
||||||
|
uint32_t endOffset;
|
||||||
|
} SShellCmd;
|
||||||
|
|
||||||
int countPrefixOnes(unsigned char c) {
|
static int32_t shellCountPrefixOnes(uint8_t c);
|
||||||
unsigned char mask = 127;
|
static void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
|
||||||
mask = ~mask;
|
static void shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
|
||||||
int ret = 0;
|
static void shellInsertChar(SShellCmd *cmd, char *c, int size);
|
||||||
while ((c & mask) != 0) {
|
static void shellBackspaceChar(SShellCmd *cmd);
|
||||||
ret++;
|
static void shellClearLineBefore(SShellCmd *cmd);
|
||||||
c <<= 1;
|
static void shellClearLineAfter(SShellCmd *cmd);
|
||||||
}
|
static void shellDeleteChar(SShellCmd *cmd);
|
||||||
|
static void shellMoveCursorLeft(SShellCmd *cmd);
|
||||||
|
static void shellMoveCursorRight(SShellCmd *cmd);
|
||||||
|
static void shellPositionCursorHome(SShellCmd *cmd);
|
||||||
|
static void shellPositionCursorEnd(SShellCmd *cmd);
|
||||||
|
static void shellPrintChar(char c, int32_t times);
|
||||||
|
static void shellPositionCursor(int32_t step, int32_t direction);
|
||||||
|
static void shellUpdateBuffer(SShellCmd *cmd);
|
||||||
|
static int32_t shellIsReadyGo(SShellCmd *cmd);
|
||||||
|
static void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width);
|
||||||
|
static void shellResetCommand(SShellCmd *cmd, const char s[]);
|
||||||
|
static void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
|
||||||
|
static void shellShowOnScreen(SShellCmd *cmd);
|
||||||
|
|
||||||
return ret;
|
#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); }
|
||||||
void getPrevCharSize(const char *str, int pos, int *size, int *width) {
|
|
||||||
assert(pos > 0);
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
*size = 0;
|
|
||||||
*width = 0;
|
|
||||||
|
|
||||||
while (--pos >= 0) {
|
|
||||||
*size += 1;
|
|
||||||
|
|
||||||
if (str[pos] > 0 || countPrefixOnes((unsigned char)str[pos]) > 1) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
|
||||||
assert(rc == *size);
|
|
||||||
|
|
||||||
*width = taosWcharWidth(wc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getNextCharSize(const char *str, int pos, int *size, int *width) {
|
|
||||||
assert(pos >= 0);
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
*size = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
|
||||||
*width = taosWcharWidth(wc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
if (taosMbToWchar(&wc, c, size) < 0) return;
|
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
/* update the buffer */
|
|
||||||
memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
|
|
||||||
cmd->commandSize - cmd->cursorOffset);
|
|
||||||
memcpy(cmd->command + cmd->cursorOffset, c, size);
|
|
||||||
/* update the values */
|
|
||||||
cmd->commandSize += size;
|
|
||||||
cmd->cursorOffset += size;
|
|
||||||
cmd->screenOffset += taosWcharWidth(wc);
|
|
||||||
cmd->endOffset += taosWcharWidth(wc);
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void backspaceChar(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
int size = 0;
|
|
||||||
int width = 0;
|
|
||||||
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
|
||||||
memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
|
|
||||||
cmd->commandSize - cmd->cursorOffset);
|
|
||||||
cmd->commandSize -= size;
|
|
||||||
cmd->cursorOffset -= size;
|
|
||||||
cmd->screenOffset -= width;
|
|
||||||
cmd->endOffset -= width;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearLineBefore(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
memmove(cmd->command, cmd->command + cmd->cursorOffset, cmd->commandSize - cmd->cursorOffset);
|
|
||||||
cmd->commandSize -= cmd->cursorOffset;
|
|
||||||
cmd->cursorOffset = 0;
|
|
||||||
cmd->screenOffset = 0;
|
|
||||||
cmd->endOffset = cmd->commandSize;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearLineAfter(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
|
|
||||||
cmd->endOffset = cmd->cursorOffset;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteChar(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
int size = 0;
|
|
||||||
int width = 0;
|
|
||||||
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
|
||||||
memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
|
|
||||||
cmd->commandSize - cmd->cursorOffset - size);
|
|
||||||
cmd->commandSize -= size;
|
|
||||||
cmd->endOffset -= width;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveCursorLeft(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
int size = 0;
|
|
||||||
int width = 0;
|
|
||||||
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
|
||||||
cmd->cursorOffset -= size;
|
|
||||||
cmd->screenOffset -= width;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveCursorRight(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
int size = 0;
|
|
||||||
int width = 0;
|
|
||||||
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
|
||||||
cmd->cursorOffset += size;
|
|
||||||
cmd->screenOffset += width;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void positionCursorHome(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
cmd->cursorOffset = 0;
|
|
||||||
cmd->screenOffset = 0;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void positionCursorEnd(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
|
||||||
cmd->cursorOffset = cmd->commandSize;
|
|
||||||
cmd->screenOffset = cmd->endOffset;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printChar(char c, int times) {
|
|
||||||
for (int i = 0; i < times; i++) {
|
|
||||||
fprintf(stdout, "%c", c);
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void positionCursor(int step, int direction) {
|
|
||||||
if (step > 0) {
|
|
||||||
if (direction == LEFT) {
|
|
||||||
fprintf(stdout, "\033[%dD", step);
|
|
||||||
} else if (direction == RIGHT) {
|
|
||||||
fprintf(stdout, "\033[%dC", step);
|
|
||||||
} else if (direction == UP) {
|
|
||||||
fprintf(stdout, "\033[%dA", step);
|
|
||||||
} else if (direction == DOWN) {
|
|
||||||
fprintf(stdout, "\033[%dB", step);
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateBuffer(Command *cmd) {
|
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
|
||||||
|
|
||||||
|
void shellUpdateBuffer(SShellCmd *cmd) {
|
||||||
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
||||||
strcat(cmd->buffer, cmd->command);
|
strcat(cmd->buffer, cmd->command);
|
||||||
cmd->bufferSize += cmd->commandSize;
|
|
||||||
|
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
cmd->cursorOffset = 0;
|
cmd->cursorOffset = 0;
|
||||||
cmd->screenOffset = 0;
|
|
||||||
cmd->commandSize = 0;
|
|
||||||
cmd->endOffset = 0;
|
|
||||||
showOnScreen(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int isReadyGo(Command *cmd) {
|
int shellIsReadyGo(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
char *total = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
|
||||||
|
memset(total, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
char *total = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
memset(cmd->command + cmd->commandSize, 0, MAX_COMMAND_SIZE - cmd->commandSize);
|
|
||||||
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
||||||
|
|
||||||
char *reg_str =
|
char *reg_str =
|
||||||
|
@ -244,28 +82,531 @@ int isReadyGo(Command *cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getMbSizeInfo(const char *str, int *size, int *width) {
|
void shellInsertChar(SShellCmd *cmd, char c) {
|
||||||
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), MAX_COMMAND_SIZE);
|
if (cmd->cursorOffset >= SHELL_MAX_COMMAND_SIZE) {
|
||||||
|
fprintf(stdout, "sql is larger than %d bytes", SHELL_MAX_COMMAND_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmd->command[cmd->cursorOffset++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellReadCommand(char command[]) {
|
||||||
|
SShellCmd cmd;
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.buffer = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd.command = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
|
||||||
|
// Read input.
|
||||||
|
char c;
|
||||||
|
while (1) {
|
||||||
|
c = getchar();
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
if (shellIsReadyGo(&cmd)) {
|
||||||
|
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
||||||
|
taosMemoryFree(cmd.buffer);
|
||||||
|
cmd.buffer = NULL;
|
||||||
|
taosMemoryFree(cmd.command);
|
||||||
|
cmd.command = NULL;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
shellPrintContinuePrompt();
|
||||||
|
shellUpdateBuffer(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shellInsertChar(&cmd, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int32_t shellCountPrefixOnes(uint8_t c) {
|
||||||
|
uint8_t mask = 127;
|
||||||
|
mask = ~mask;
|
||||||
|
int32_t ret = 0;
|
||||||
|
while ((c & mask) != 0) {
|
||||||
|
ret++;
|
||||||
|
c <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
|
||||||
|
assert(pos > 0);
|
||||||
|
|
||||||
|
TdWchar wc;
|
||||||
|
*size = 0;
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
while (--pos >= 0) {
|
||||||
|
*size += 1;
|
||||||
|
|
||||||
|
if (str[pos] > 0 || shellCountPrefixOnes((uint8_t)str[pos]) > 1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t rc = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
||||||
|
assert(rc == *size);
|
||||||
|
|
||||||
|
*width = taosWcharWidth(wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
|
||||||
|
assert(pos >= 0);
|
||||||
|
|
||||||
|
TdWchar wc;
|
||||||
|
*size = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
||||||
|
*width = taosWcharWidth(wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellInsertChar(SShellCmd *cmd, char *c, int32_t size) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
TdWchar wc;
|
||||||
|
if (taosMbToWchar(&wc, c, size) < 0) return;
|
||||||
|
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
/* update the buffer */
|
||||||
|
memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
|
||||||
|
cmd->commandSize - cmd->cursorOffset);
|
||||||
|
memcpy(cmd->command + cmd->cursorOffset, c, size);
|
||||||
|
/* update the values */
|
||||||
|
cmd->commandSize += size;
|
||||||
|
cmd->cursorOffset += size;
|
||||||
|
cmd->screenOffset += taosWcharWidth(wc);
|
||||||
|
cmd->endOffset += taosWcharWidth(wc);
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellBackspaceChar(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset > 0) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
int32_t size = 0;
|
||||||
|
int32_t width = 0;
|
||||||
|
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
|
memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
|
||||||
|
cmd->commandSize - cmd->cursorOffset);
|
||||||
|
cmd->commandSize -= size;
|
||||||
|
cmd->cursorOffset -= size;
|
||||||
|
cmd->screenOffset -= width;
|
||||||
|
cmd->endOffset -= width;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellClearLineBefore(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
memmove(cmd->command, cmd->command + cmd->cursorOffset, cmd->commandSize - cmd->cursorOffset);
|
||||||
|
cmd->commandSize -= cmd->cursorOffset;
|
||||||
|
cmd->cursorOffset = 0;
|
||||||
|
cmd->screenOffset = 0;
|
||||||
|
cmd->endOffset = cmd->commandSize;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellClearLineAfter(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
|
||||||
|
cmd->endOffset = cmd->cursorOffset;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellDeleteChar(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
int32_t size = 0;
|
||||||
|
int32_t width = 0;
|
||||||
|
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
|
memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
|
||||||
|
cmd->commandSize - cmd->cursorOffset - size);
|
||||||
|
cmd->commandSize -= size;
|
||||||
|
cmd->endOffset -= width;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellMoveCursorLeft(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset > 0) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
int32_t size = 0;
|
||||||
|
int32_t width = 0;
|
||||||
|
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
|
cmd->cursorOffset -= size;
|
||||||
|
cmd->screenOffset -= width;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellMoveCursorRight(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
int32_t size = 0;
|
||||||
|
int32_t width = 0;
|
||||||
|
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
|
cmd->cursorOffset += size;
|
||||||
|
cmd->screenOffset += width;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPositionCursorHome(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset > 0) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
cmd->cursorOffset = 0;
|
||||||
|
cmd->screenOffset = 0;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPositionCursorEnd(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
|
cmd->cursorOffset = cmd->commandSize;
|
||||||
|
cmd->screenOffset = cmd->endOffset;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPrintChar(char c, int32_t times) {
|
||||||
|
for (int32_t i = 0; i < times; i++) {
|
||||||
|
fprintf(stdout, "%c", c);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPositionCursor(int32_t step, int32_t direction) {
|
||||||
|
if (step > 0) {
|
||||||
|
if (direction == LEFT) {
|
||||||
|
fprintf(stdout, "\033[%dD", step);
|
||||||
|
} else if (direction == RIGHT) {
|
||||||
|
fprintf(stdout, "\033[%dC", step);
|
||||||
|
} else if (direction == UP) {
|
||||||
|
fprintf(stdout, "\033[%dA", step);
|
||||||
|
} else if (direction == DOWN) {
|
||||||
|
fprintf(stdout, "\033[%dB", step);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellUpdateBuffer(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
||||||
|
strcat(cmd->buffer, cmd->command);
|
||||||
|
cmd->bufferSize += cmd->commandSize;
|
||||||
|
|
||||||
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd->cursorOffset = 0;
|
||||||
|
cmd->screenOffset = 0;
|
||||||
|
cmd->commandSize = 0;
|
||||||
|
cmd->endOffset = 0;
|
||||||
|
shellShowOnScreen(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellIsReadyGo(SShellCmd *cmd) {
|
||||||
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
|
char *total = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
memset(cmd->command + cmd->commandSize, 0, SHELL_MAX_COMMAND_SIZE - cmd->commandSize);
|
||||||
|
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
||||||
|
|
||||||
|
char *reg_str =
|
||||||
|
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
||||||
|
"\\s*clear\\s*$)";
|
||||||
|
if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
||||||
|
taosMemoryFree(total);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMemoryFree(total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width) {
|
||||||
|
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), SHELL_MAX_COMMAND_SIZE);
|
||||||
*size = strlen(str);
|
*size = strlen(str);
|
||||||
taosMbsToWchars(wc, str, MAX_COMMAND_SIZE);
|
taosMbsToWchars(wc, str, SHELL_MAX_COMMAND_SIZE);
|
||||||
*width = taosWcharsWidth(wc, MAX_COMMAND_SIZE);
|
*width = taosWcharsWidth(wc, SHELL_MAX_COMMAND_SIZE);
|
||||||
taosMemoryFree(wc);
|
taosMemoryFree(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCommand(Command *cmd, const char s[]) {
|
void shellResetCommand(SShellCmd *cmd, const char s[]) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
memset(cmd->buffer, 0, MAX_COMMAND_SIZE);
|
memset(cmd->buffer, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
strncpy(cmd->command, s, MAX_COMMAND_SIZE);
|
strncpy(cmd->command, s, SHELL_MAX_COMMAND_SIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getMbSizeInfo(s, &size, &width);
|
shellGetMbSizeInfo(s, &size, &width);
|
||||||
cmd->bufferSize = 0;
|
cmd->bufferSize = 0;
|
||||||
cmd->commandSize = size;
|
cmd->commandSize = size;
|
||||||
cmd->cursorOffset = size;
|
cmd->cursorOffset = size;
|
||||||
cmd->screenOffset = width;
|
cmd->screenOffset = width;
|
||||||
cmd->endOffset = width;
|
cmd->endOffset = width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos) {
|
||||||
|
struct winsize w;
|
||||||
|
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
||||||
|
// fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
||||||
|
w.ws_col = 120;
|
||||||
|
w.ws_row = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t cursor_x = cursor_pos / w.ws_col;
|
||||||
|
int32_t cursor_y = cursor_pos % w.ws_col;
|
||||||
|
int32_t command_x = ecmd_pos / w.ws_col;
|
||||||
|
shellPositionCursor(cursor_y, LEFT);
|
||||||
|
shellPositionCursor(command_x - cursor_x, DOWN);
|
||||||
|
fprintf(stdout, "\033[2K");
|
||||||
|
for (int32_t i = 0; i < command_x; i++) {
|
||||||
|
shellPositionCursor(1, UP);
|
||||||
|
fprintf(stdout, "\033[2K");
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellShowOnScreen(SShellCmd *cmd) {
|
||||||
|
struct winsize w;
|
||||||
|
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
||||||
|
fprintf(stderr, "No stream device\n");
|
||||||
|
w.ws_col = 120;
|
||||||
|
w.ws_row = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
TdWchar wc;
|
||||||
|
int32_t size = 0;
|
||||||
|
|
||||||
|
// Print out the command.
|
||||||
|
char *total_string = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
|
||||||
|
memset(total_string, '\0', SHELL_MAX_COMMAND_SIZE);
|
||||||
|
if (strcmp(cmd->buffer, "") == 0) {
|
||||||
|
sprintf(total_string, "%s%s", shell.info.promptHeader, cmd->command);
|
||||||
|
} else {
|
||||||
|
sprintf(total_string, "%s%s", shell.info.promptContinue, cmd->command);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t remain_column = w.ws_col;
|
||||||
|
for (char *str = total_string; size < cmd->commandSize + PSIZE;) {
|
||||||
|
int32_t ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
||||||
|
if (ret < 0) break;
|
||||||
|
size += ret;
|
||||||
|
/* assert(size >= 0); */
|
||||||
|
int32_t width = taosWcharWidth(wc);
|
||||||
|
if (remain_column > width) {
|
||||||
|
printf("%lc", wc);
|
||||||
|
remain_column -= width;
|
||||||
|
} else {
|
||||||
|
if (remain_column == width) {
|
||||||
|
printf("%lc\n\r", wc);
|
||||||
|
remain_column = w.ws_col;
|
||||||
|
} else {
|
||||||
|
printf("\n\r%lc", wc);
|
||||||
|
remain_column = w.ws_col - width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = total_string + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMemoryFree(total_string);
|
||||||
|
|
||||||
|
// Position the cursor
|
||||||
|
int32_t cursor_pos = cmd->screenOffset + PSIZE;
|
||||||
|
int32_t ecmd_pos = cmd->endOffset + PSIZE;
|
||||||
|
|
||||||
|
int32_t cursor_x = cursor_pos / w.ws_col;
|
||||||
|
int32_t cursor_y = cursor_pos % w.ws_col;
|
||||||
|
// int32_t cursor_y = cursor % w.ws_col;
|
||||||
|
int32_t command_x = ecmd_pos / w.ws_col;
|
||||||
|
int32_t command_y = ecmd_pos % w.ws_col;
|
||||||
|
// int32_t command_y = (command.size() + PSIZE) % w.ws_col;
|
||||||
|
shellPositionCursor(command_y, LEFT);
|
||||||
|
shellPositionCursor(command_x, UP);
|
||||||
|
shellPositionCursor(cursor_x, DOWN);
|
||||||
|
shellPositionCursor(cursor_y, RIGHT);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellReadCommand(char *command) {
|
||||||
|
SShellHistory *pHistory = &shell.history;
|
||||||
|
SShellCmd cmd = {0};
|
||||||
|
uint32_t hist_counter = pHistory->hend;
|
||||||
|
char utf8_array[10] = "\0";
|
||||||
|
|
||||||
|
cmd.buffer = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd.command = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
shellShowOnScreen(&cmd);
|
||||||
|
|
||||||
|
// Read input.
|
||||||
|
char c;
|
||||||
|
while (1) {
|
||||||
|
c = (char)getchar(); // getchar() return an 'int32_t' value
|
||||||
|
|
||||||
|
if (c == EOF) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) { // For UTF-8
|
||||||
|
int32_t count = shellCountPrefixOnes(c);
|
||||||
|
utf8_array[0] = c;
|
||||||
|
for (int32_t k = 1; k < count; k++) {
|
||||||
|
c = (char)getchar();
|
||||||
|
utf8_array[k] = c;
|
||||||
|
}
|
||||||
|
shellInsertChar(&cmd, utf8_array, count);
|
||||||
|
} else if (c < '\033') {
|
||||||
|
// Ctrl keys. TODO: Implement ctrl combinations
|
||||||
|
switch (c) {
|
||||||
|
case 1: // ctrl A
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("\n");
|
||||||
|
shellResetCommand(&cmd, "");
|
||||||
|
kill(0, SIGINT);
|
||||||
|
break;
|
||||||
|
case 4: // EOF or Ctrl+D
|
||||||
|
printf("\n");
|
||||||
|
return -1;
|
||||||
|
case 5: // ctrl E
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
shellBackspaceChar(&cmd);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
printf("\n");
|
||||||
|
if (shellIsReadyGo(&cmd)) {
|
||||||
|
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
||||||
|
taosMemoryFreeClear(cmd.buffer);
|
||||||
|
taosMemoryFreeClear(cmd.command);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
shellUpdateBuffer(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11: // Ctrl + K;
|
||||||
|
shellClearLineAfter(&cmd);
|
||||||
|
break;
|
||||||
|
case 12: // Ctrl + L;
|
||||||
|
system("clear");
|
||||||
|
shellShowOnScreen(&cmd);
|
||||||
|
break;
|
||||||
|
case 21: // Ctrl + U;
|
||||||
|
shellClearLineBefore(&cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (c == '\033') {
|
||||||
|
c = (char)getchar();
|
||||||
|
switch (c) {
|
||||||
|
case '[':
|
||||||
|
c = (char)getchar();
|
||||||
|
switch (c) {
|
||||||
|
case 'A': // Up arrow
|
||||||
|
if (hist_counter != pHistory->hstart) {
|
||||||
|
hist_counter = (hist_counter + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE;
|
||||||
|
shellResetCommand(&cmd, (pHistory->hist[hist_counter] == NULL) ? "" : pHistory->hist[hist_counter]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'B': // Down arrow
|
||||||
|
if (hist_counter != pHistory->hend) {
|
||||||
|
int32_t next_hist = (hist_counter + 1) % SHELL_MAX_HISTORY_SIZE;
|
||||||
|
|
||||||
|
if (next_hist != pHistory->hend) {
|
||||||
|
shellResetCommand(&cmd, (pHistory->hist[next_hist] == NULL) ? "" : pHistory->hist[next_hist]);
|
||||||
|
} else {
|
||||||
|
shellResetCommand(&cmd, "");
|
||||||
|
}
|
||||||
|
hist_counter = next_hist;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'C': // Right arrow
|
||||||
|
shellMoveCursorRight(&cmd);
|
||||||
|
break;
|
||||||
|
case 'D': // Left arrow
|
||||||
|
shellMoveCursorLeft(&cmd);
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Home key
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Insert key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Delete key
|
||||||
|
shellDeleteChar(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// End key
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Page up key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Page down key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 72:
|
||||||
|
// Home key
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
break;
|
||||||
|
case 70:
|
||||||
|
// End key
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (c == 0x7f) {
|
||||||
|
// press delete key
|
||||||
|
shellBackspaceChar(&cmd);
|
||||||
|
} else {
|
||||||
|
shellInsertChar(&cmd, &c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -14,682 +14,52 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __USE_XOPEN
|
#define __USE_XOPEN
|
||||||
#include "shellCommand.h"
|
#include "shellInt.h"
|
||||||
#include "tglobal.h"
|
|
||||||
|
|
||||||
#include <argp.h>
|
SShellObj shell = {0};
|
||||||
#include <termio.h>
|
|
||||||
#include <wordexp.h>
|
|
||||||
|
|
||||||
#define OPT_ABORT 1 /* abort */
|
|
||||||
|
|
||||||
int indicator = 1;
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size);
|
|
||||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t pkgNum, char *pkgType);
|
|
||||||
const char *argp_program_version = version;
|
|
||||||
const char *argp_program_bug_address = "<support@taosdata.com>";
|
|
||||||
static char doc[] = "";
|
|
||||||
static char args_doc[] = "";
|
|
||||||
|
|
||||||
TdThread pid;
|
|
||||||
static tsem_t cancelSem;
|
|
||||||
extern void taos_init();
|
|
||||||
|
|
||||||
static struct argp_option options[] = {
|
|
||||||
{"host", 'h', "HOST", 0, "TDengine server FQDN to connect. The default host is localhost."},
|
|
||||||
{"password", 'p', NULL, 0, "The password to use when connecting to the server."},
|
|
||||||
{"port", 'P', "PORT", 0, "The TCP/IP port number to use for the connection."},
|
|
||||||
{"user", 'u', "USER", 0, "The user name to use when connecting to the server."},
|
|
||||||
{"auth", 'A', "Auth", 0, "The auth string to use when connecting to the server."},
|
|
||||||
{"config-dir", 'c', "CONFIG_DIR", 0, "Configuration directory."},
|
|
||||||
{"dump-config",'C', NULL, 0, "Dump configuration."},
|
|
||||||
{"commands", 's', "COMMANDS", 0, "Commands to run without enter the shell."},
|
|
||||||
{"raw-time", 'r', NULL, 0, "Output time as uint64_t."},
|
|
||||||
{"file", 'f', "FILE", 0, "Script to run without enter the shell."},
|
|
||||||
{"directory", 'D', "DIRECTORY", 0, "Use multi-thread to import all SQL files in the directory separately."},
|
|
||||||
{"thread", 'T', "THREADNUM", 0, "Number of threads when using multi-thread to import data."},
|
|
||||||
{"check", 'k', "CHECK", 0, "Check tables."},
|
|
||||||
{"database", 'd', "DATABASE", 0, "Database to use when connecting to the server."},
|
|
||||||
{"timezone", 'z', "TIMEZONE", 0, "Time zone of the shell, default is local."},
|
|
||||||
{"status", 't', NULL, 0, "Check the service status."},
|
|
||||||
{"verbose", 'v', NULL, 0, "Check the details of the service status."},
|
|
||||||
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn."},
|
|
||||||
{"pktlen", 'l', "PKTLEN", 0, "Packet length used for net test, default is 1000 bytes."},
|
|
||||||
{"pktnum", 'N', "PKTNUM", 0, "Packet numbers used for net test, default is 100."},
|
|
||||||
// Shuduo: 3.0 does not support UDP any more
|
|
||||||
// {"pkttype", 'S', "PKTTYPE", 0, "Packet type used for net test, default is TCP."},
|
|
||||||
{0}};
|
|
||||||
|
|
||||||
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|
||||||
/* Get the input argument from argp_parse, which we
|
|
||||||
know is a pointer to our arguments structure. */
|
|
||||||
SShellArgs *arguments = state->input;
|
|
||||||
wordexp_t full_path;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case 'h':
|
|
||||||
arguments->host = arg;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
if (arg) {
|
|
||||||
arguments->port = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid port\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
arguments->timezone = arg;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
arguments->user = arg;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
arguments->auth = arg;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
if (wordexp(arg, &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (strlen(full_path.we_wordv[0]) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", full_path.we_wordv[0], TSDB_FILENAME_LEN - 1);
|
|
||||||
wordfree(&full_path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(configDir, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
arguments->dump_config = true;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
arguments->commands = arg;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
if ((0 == strlen(arg)) || (wordexp(arg, &full_path, 0) != 0)) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(arguments->file, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
if (wordexp(arg, &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(arguments->dir, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
if (arg) {
|
|
||||||
arguments->threadNum = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid number of threads\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
arguments->check = atoi(arg);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
arguments->status = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
arguments->verbose = true;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
arguments->database = arg;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
arguments->netTestRole = arg;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if (arg) {
|
|
||||||
arguments->pktLen = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid packet length\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'N':
|
|
||||||
if (arg) {
|
|
||||||
arguments->pktNum = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid packet number\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
arguments->pktType = arg;
|
|
||||||
break;
|
|
||||||
case OPT_ABORT:
|
|
||||||
arguments->abort = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ARGP_ERR_UNKNOWN;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Our argp parser. */
|
|
||||||
static struct argp argp = {options, parse_opt, args_doc, doc};
|
|
||||||
|
|
||||||
char LINUXCLIENT_VERSION[] =
|
|
||||||
"Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
static void parse_args(int argc, char *argv[], SShellArgs *arguments) {
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf(LINUXCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2) || (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%20s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password reading error\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
if (EOF == getchar()) {
|
|
||||||
fprintf(stderr, "getchar() return EOF\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
strcpy(argv[i], "-p");
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
|
|
||||||
static char verType[32] = {0};
|
|
||||||
sprintf(verType, "version: %s\n", version);
|
|
||||||
|
|
||||||
argp_program_version = verType;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
parse_args(argc, argv, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
argp_parse(&argp, argc, argv, 0, 0, arguments);
|
|
||||||
if (arguments->abort) {
|
|
||||||
#ifndef _ALPINE
|
|
||||||
#if 0
|
|
||||||
error(10, 0, "ABORTED");
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
abort();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char *command) {
|
|
||||||
unsigned hist_counter = history.hend;
|
|
||||||
char utf8_array[10] = "\0";
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = (char)getchar(); // getchar() return an 'int' value
|
|
||||||
|
|
||||||
if (c == EOF) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c < 0) { // For UTF-8
|
|
||||||
int count = countPrefixOnes(c);
|
|
||||||
utf8_array[0] = c;
|
|
||||||
for (int k = 1; k < count; k++) {
|
|
||||||
c = (char)getchar();
|
|
||||||
utf8_array[k] = c;
|
|
||||||
}
|
|
||||||
insertChar(&cmd, utf8_array, count);
|
|
||||||
} else if (c < '\033') {
|
|
||||||
// Ctrl keys. TODO: Implement ctrl combinations
|
|
||||||
switch (c) {
|
|
||||||
case 1: // ctrl A
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
printf("\n");
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
kill(0, SIGINT);
|
|
||||||
break;
|
|
||||||
case 4: // EOF or Ctrl+D
|
|
||||||
printf("\n");
|
|
||||||
taos_close(con);
|
|
||||||
// write the history
|
|
||||||
shellWriteHistory();
|
|
||||||
shellExit();
|
|
||||||
break;
|
|
||||||
case 5: // ctrl E
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
printf("\n");
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFreeClear(cmd.buffer);
|
|
||||||
taosMemoryFreeClear(cmd.command);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 11: // Ctrl + K;
|
|
||||||
clearLineAfter(&cmd);
|
|
||||||
break;
|
|
||||||
case 12: // Ctrl + L;
|
|
||||||
system("clear");
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
break;
|
|
||||||
case 21: // Ctrl + U;
|
|
||||||
clearLineBefore(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == '\033') {
|
|
||||||
c = (char)getchar();
|
|
||||||
switch (c) {
|
|
||||||
case '[':
|
|
||||||
c = (char)getchar();
|
|
||||||
switch (c) {
|
|
||||||
case 'A': // Up arrow
|
|
||||||
if (hist_counter != history.hstart) {
|
|
||||||
hist_counter = (hist_counter + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE;
|
|
||||||
resetCommand(&cmd, (history.hist[hist_counter] == NULL) ? "" : history.hist[hist_counter]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B': // Down arrow
|
|
||||||
if (hist_counter != history.hend) {
|
|
||||||
int next_hist = (hist_counter + 1) % MAX_HISTORY_SIZE;
|
|
||||||
|
|
||||||
if (next_hist != history.hend) {
|
|
||||||
resetCommand(&cmd, (history.hist[next_hist] == NULL) ? "" : history.hist[next_hist]);
|
|
||||||
} else {
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
}
|
|
||||||
hist_counter = next_hist;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C': // Right arrow
|
|
||||||
moveCursorRight(&cmd);
|
|
||||||
break;
|
|
||||||
case 'D': // Left arrow
|
|
||||||
moveCursorLeft(&cmd);
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Insert key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Delete key
|
|
||||||
deleteChar(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Page up key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Page down key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 72:
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 70:
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == 0x7f) {
|
|
||||||
// press delete key
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
} else {
|
|
||||||
insertChar(&cmd, &c, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellThreadLoop(void *arg) {
|
|
||||||
if (indicator) {
|
|
||||||
getOldTerminalMode();
|
|
||||||
indicator = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
|
|
||||||
setThreadName("shellThreadLoop");
|
|
||||||
|
|
||||||
taosThreadCleanupPush(shellCleanup, NULL);
|
|
||||||
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL) {
|
|
||||||
printf("failed to malloc command\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Read command from shell.
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
setTerminalMode();
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
resetTerminalMode();
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
taosMemoryFreeClear(command);
|
|
||||||
shellExit();
|
|
||||||
|
|
||||||
taosThreadCleanupPop(1);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellHistoryPath(char *_history) { snprintf(_history, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), HISTORY_FILE); }
|
|
||||||
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
// fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
positionCursor(cursor_y, LEFT);
|
|
||||||
positionCursor(command_x - cursor_x, DOWN);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
for (int i = 0; i < command_x; i++) {
|
|
||||||
positionCursor(1, UP);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showOnScreen(Command *cmd) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
// fprintf(stderr, "No stream device\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
// Print out the command.
|
|
||||||
char *total_string = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total_string, '\0', MAX_COMMAND_SIZE);
|
|
||||||
if (strcmp(cmd->buffer, "") == 0) {
|
|
||||||
sprintf(total_string, "%s%s", PROMPT_HEADER, cmd->command);
|
|
||||||
} else {
|
|
||||||
sprintf(total_string, "%s%s", CONTINUE_PROMPT, cmd->command);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remain_column = w.ws_col;
|
|
||||||
/* size = cmd->commandSize + prompt_size; */
|
|
||||||
for (char *str = total_string; size < cmd->commandSize + prompt_size;) {
|
|
||||||
int ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
|
||||||
if (ret < 0) break;
|
|
||||||
size += ret;
|
|
||||||
/* assert(size >= 0); */
|
|
||||||
int width = taosWcharWidth(wc);
|
|
||||||
if (remain_column > width) {
|
|
||||||
printf("%lc", wc);
|
|
||||||
remain_column -= width;
|
|
||||||
} else {
|
|
||||||
if (remain_column == width) {
|
|
||||||
printf("%lc\n\r", wc);
|
|
||||||
remain_column = w.ws_col;
|
|
||||||
} else {
|
|
||||||
printf("\n\r%lc", wc);
|
|
||||||
remain_column = w.ws_col - width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = total_string + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total_string);
|
|
||||||
/* for (int i = 0; i < size; i++){ */
|
|
||||||
/* char c = total_string[i]; */
|
|
||||||
/* if (k % w.ws_col == 0) { */
|
|
||||||
/* printf("%c\n\r", c); */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* printf("%c", c); */
|
|
||||||
/* } */
|
|
||||||
/* k += 1; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
// Position the cursor
|
|
||||||
int cursor_pos = cmd->screenOffset + prompt_size;
|
|
||||||
int ecmd_pos = cmd->endOffset + prompt_size;
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
// int cursor_y = cursor % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
int command_y = ecmd_pos % w.ws_col;
|
|
||||||
// int command_y = (command.size() + prompt_size) % w.ws_col;
|
|
||||||
positionCursor(command_y, LEFT);
|
|
||||||
positionCursor(command_x, UP);
|
|
||||||
positionCursor(cursor_x, DOWN);
|
|
||||||
positionCursor(cursor_y, RIGHT);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellCleanup(void *arg) { resetTerminalMode(); }
|
|
||||||
|
|
||||||
void shellExit() {
|
|
||||||
taos_cleanup();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context) { tsem_post(&cancelSem); }
|
|
||||||
|
|
||||||
void *cancelHandler(void *arg) {
|
|
||||||
setThreadName("cancelHandler");
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (tsem_wait(&cancelSem) != 0) {
|
|
||||||
taosMsleep(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTerminalMode();
|
|
||||||
printf("\nReceive ctrl+c or other signal, quit shell.\n");
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int checkVersion() {
|
|
||||||
if (sizeof(int8_t) != 1) {
|
|
||||||
printf("taos int8 size is %d(!= 1)", (int)sizeof(int8_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int16_t) != 2) {
|
|
||||||
printf("taos int16 size is %d(!= 2)", (int)sizeof(int16_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int32_t) != 4) {
|
|
||||||
printf("taos int32 size is %d(!= 4)", (int)sizeof(int32_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int64_t) != 8) {
|
|
||||||
printf("taos int64 size is %d(!= 8)", (int)sizeof(int64_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global configurations
|
|
||||||
SShellArgs args = {
|
|
||||||
.host = NULL,
|
|
||||||
.user = NULL,
|
|
||||||
.database = NULL,
|
|
||||||
.timezone = NULL,
|
|
||||||
.is_raw_time = false,
|
|
||||||
.is_use_passwd = false,
|
|
||||||
.dump_config = false,
|
|
||||||
.file = "\0",
|
|
||||||
.dir = "\0",
|
|
||||||
.threadNum = 5,
|
|
||||||
.commands = NULL,
|
|
||||||
.pktLen = 1000,
|
|
||||||
.pktNum = 100,
|
|
||||||
.pktType = "TCP",
|
|
||||||
.netTestRole = NULL,
|
|
||||||
#ifndef TD_WINDOWS
|
|
||||||
.password = NULL,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void shellDumpConfig() {
|
|
||||||
if (!args.dump_config) return;
|
|
||||||
|
|
||||||
SConfig *pCfg = taosGetCfg();
|
|
||||||
if (NULL == pCfg) {
|
|
||||||
printf("TDengine read global config failed!\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
cfgDumpCfg(pCfg, 0, 1);
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellTestNetWork() {
|
|
||||||
if (args.netTestRole && args.netTestRole[0] != 0) {
|
|
||||||
taosNetTest(args.netTestRole, args.host, args.port, args.pktLen, args.pktNum, args.pktType);
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellCheckServerStatus() {
|
|
||||||
if (!args.status && !args.verbose) return;
|
|
||||||
|
|
||||||
TSDB_SERVER_STATUS code;
|
|
||||||
do {
|
|
||||||
char details[1024] = {0};
|
|
||||||
code = taos_check_server_status(args.host, args.port, details, args.verbose ? 1024 : 0);
|
|
||||||
switch (code) {
|
|
||||||
case TSDB_SRV_STATUS_UNAVAILABLE:
|
|
||||||
printf("0: unavailable\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_NETWORK_OK:
|
|
||||||
printf("1: network ok\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_SERVICE_OK:
|
|
||||||
printf("2: service ok\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_SERVICE_DEGRADED:
|
|
||||||
printf("3: service degraded\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_EXTING:
|
|
||||||
printf("4: exiting\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strlen(details) != 0) {
|
|
||||||
printf("%s\n\n", details);
|
|
||||||
}
|
|
||||||
if (code == TSDB_SRV_STATUS_NETWORK_OK && args.verbose) {
|
|
||||||
taosMsleep(1000);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellExecute() {
|
|
||||||
TAOS *con = shellInit(&args);
|
|
||||||
if (con == NULL) {
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tsem_init(&cancelSem, 0, 0) != 0) {
|
|
||||||
printf("failed to create cancel semphore\n");
|
|
||||||
shellExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
TdThread spid;
|
|
||||||
taosThreadCreate(&spid, NULL, cancelHandler, NULL);
|
|
||||||
|
|
||||||
taosSetSignal(SIGTERM, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGINT, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGHUP, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGABRT, shellQueryInterruptHandler);
|
|
||||||
|
|
||||||
shellGetGrantInfo(con);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
taosThreadCreate(&pid, NULL, shellThreadLoop, con);
|
|
||||||
taosThreadJoin(pid, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (!checkVersion()) shellExit();
|
if (shellCheckIntSize() != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
shellParseArgs(argc, argv, &args);
|
if (shellParseArgs(argc, argv) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_version) {
|
||||||
|
shellPrintVersion();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_gen_auth) {
|
||||||
|
shellGenerateAuth();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_help) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
taos_init();
|
taos_init();
|
||||||
shellDumpConfig();
|
|
||||||
shellCheckServerStatus();
|
|
||||||
shellTestNetWork();
|
|
||||||
shellExecute();
|
|
||||||
|
|
||||||
return 0;
|
if (shell.args.is_dump_config) {
|
||||||
|
shellDumpConfig();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_startup || shell.args.is_check) {
|
||||||
|
shellCheckServerStatus();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(shell.args.netrole, "client") == 0 || strcmp(shell.args.netrole, "server") == 0) {
|
||||||
|
shellTestNetWork();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shellExecute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,27 +13,32 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
void shellTestNetWork() {}
|
||||||
|
|
||||||
|
#if 0
|
||||||
#define ALLOW_FORBID_FUNC
|
#define ALLOW_FORBID_FUNC
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "taosdef.h"
|
|
||||||
#include "tmsg.h"
|
|
||||||
#include "taoserror.h"
|
|
||||||
#include "tlog.h"
|
|
||||||
#include "tglobal.h"
|
|
||||||
#include "trpc.h"
|
|
||||||
#include "rpcHead.h"
|
#include "rpcHead.h"
|
||||||
#include "tchecksum.h"
|
|
||||||
#include "syncMsg.h"
|
#include "syncMsg.h"
|
||||||
|
#include "taosdef.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
#include "tchecksum.h"
|
||||||
|
#include "tglobal.h"
|
||||||
|
#include "tlog.h"
|
||||||
|
#include "tmsg.h"
|
||||||
|
#include "trpc.h"
|
||||||
|
|
||||||
#include "osSocket.h"
|
#include "osSocket.h"
|
||||||
|
|
||||||
#define MAX_PKG_LEN (64 * 1000)
|
#define MAX_PKG_LEN (64 * 1000)
|
||||||
#define MAX_SPEED_PKG_LEN (1024 * 1024 * 1024)
|
#define MAX_SPEED_PKG_LEN (1024 * 1024 * 1024)
|
||||||
#define MIN_SPEED_PKG_LEN 1024
|
#define MIN_SPEED_PKG_LEN 1024
|
||||||
#define MAX_SPEED_PKG_NUM 10000
|
#define MAX_SPEED_PKG_NUM 10000
|
||||||
#define MIN_SPEED_PKG_NUM 1
|
#define MIN_SPEED_PKG_NUM 1
|
||||||
#define BUFFER_SIZE (MAX_PKG_LEN + 1024)
|
#define BUFFER_SIZE (MAX_PKG_LEN + 1024)
|
||||||
|
|
||||||
extern int tsRpcMaxUdpSize;
|
extern int tsRpcMaxUdpSize;
|
||||||
|
|
||||||
|
@ -321,9 +326,8 @@ static int32_t taosNetCheckUdpPort(STestInfo *info) {
|
||||||
iDataNum = recvfrom(clientSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&serverAddr, &sin_size);
|
iDataNum = recvfrom(clientSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&serverAddr, &sin_size);
|
||||||
|
|
||||||
if (iDataNum < 0 || iDataNum != info->pktLen) {
|
if (iDataNum < 0 || iDataNum != info->pktLen) {
|
||||||
uError("UDP: received ack:%d bytes(expect:%d) from port:%d since %s", iDataNum, info->pktLen, info->port, strerror(errno));
|
uError("UDP: received ack:%d bytes(expect:%d) from port:%d since %s", iDataNum, info->pktLen, info->port,
|
||||||
taosCloseSocket(&pSocket);
|
strerror(errno)); taosCloseSocket(&pSocket); return -1;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taosCloseSocket(&pSocket);
|
taosCloseSocket(&pSocket);
|
||||||
|
@ -468,11 +472,13 @@ static void taosNetCheckSpeed(char *host, int32_t port, int32_t pkgLen,
|
||||||
|
|
||||||
uint64_t endTime = taosGetTimestampUs();
|
uint64_t endTime = taosGetTimestampUs();
|
||||||
uint64_t el = endTime - startTime;
|
uint64_t el = endTime - startTime;
|
||||||
printf("progress:%5d/%d\tstatus:%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", i, pkgNum, code, el/1000.0, pkgLen/(el/1000000.0)/1024.0/1024.0);
|
printf("progress:%5d/%d\tstatus:%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", i, pkgNum, code, el/1000.0,
|
||||||
|
pkgLen/(el/1000000.0)/1024.0/1024.0);
|
||||||
}
|
}
|
||||||
int64_t endT = taosGetTimestampUs();
|
int64_t endT = taosGetTimestampUs();
|
||||||
uint64_t elT = endT - startT;
|
uint64_t elT = endT - startT;
|
||||||
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pkgNum, elT/1000.0, pkgLen/(elT/1000000.0)/1024.0/1024.0*totalSucc);
|
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pkgNum, elT/1000.0,
|
||||||
|
pkgLen/(elT/1000000.0)/1024.0/1024.0*totalSucc);
|
||||||
|
|
||||||
rpcClose(pRpcConn);
|
rpcClose(pRpcConn);
|
||||||
|
|
||||||
|
@ -512,3 +518,5 @@ void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t p
|
||||||
|
|
||||||
tsLogEmbedded = 0;
|
tsLogEmbedded = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _BSD_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#define _XOPEN_SOURCE
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
bool shellRegexMatch(const char *s, const char *reg, int32_t cflags) {
|
||||||
|
regex_t regex;
|
||||||
|
char msgbuf[100] = {0};
|
||||||
|
|
||||||
|
/* Compile regular expression */
|
||||||
|
if (regcomp(®ex, reg, cflags) != 0) {
|
||||||
|
fprintf(stderr, "Fail to compile regex");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute regular expression */
|
||||||
|
int32_t reti = regexec(®ex, s, 0, NULL, 0);
|
||||||
|
if (!reti) {
|
||||||
|
regfree(®ex);
|
||||||
|
return true;
|
||||||
|
} else if (reti == REG_NOMATCH) {
|
||||||
|
regfree(®ex);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||||
|
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
|
||||||
|
regfree(®ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellCheckIntSize() {
|
||||||
|
if (sizeof(int8_t) != 1) {
|
||||||
|
printf("taos int8 size is %d(!= 1)", (int)sizeof(int8_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int16_t) != 2) {
|
||||||
|
printf("taos int16 size is %d(!= 2)", (int)sizeof(int16_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int32_t) != 4) {
|
||||||
|
printf("taos int32 size is %d(!= 4)", (int)sizeof(int32_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int64_t) != 8) {
|
||||||
|
printf("taos int64 size is %d(!= 8)", (int)sizeof(int64_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPrintVersion() { printf("version: %s\n", version); }
|
||||||
|
|
||||||
|
void shellGenerateAuth() {}
|
||||||
|
|
||||||
|
void shellDumpConfig() {
|
||||||
|
SConfig *pCfg = taosGetCfg();
|
||||||
|
if (pCfg == NULL) {
|
||||||
|
printf("TDengine read global config failed!\n");
|
||||||
|
} else {
|
||||||
|
cfgDumpCfg(pCfg, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellCheckServerStatus() {
|
||||||
|
TSDB_SERVER_STATUS code;
|
||||||
|
|
||||||
|
do {
|
||||||
|
char details[1024] = {0};
|
||||||
|
code = taos_check_server_status(shell.args.host, shell.args.port, details, 1024);
|
||||||
|
switch (code) {
|
||||||
|
case TSDB_SRV_STATUS_UNAVAILABLE:
|
||||||
|
printf("0: unavailable\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_NETWORK_OK:
|
||||||
|
printf("1: network ok\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_SERVICE_OK:
|
||||||
|
printf("2: service ok\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_SERVICE_DEGRADED:
|
||||||
|
printf("3: service degraded\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_EXTING:
|
||||||
|
printf("4: exiting\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strlen(details) != 0) {
|
||||||
|
printf("%s\n\n", details);
|
||||||
|
}
|
||||||
|
if (code == TSDB_SRV_STATUS_NETWORK_OK && shell.args.is_startup) {
|
||||||
|
taosMsleep(1000);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
Loading…
Reference in New Issue