commit f533771f7084e4927e84fc61088bae052278031b Author: hqm <13720409820@163.com> Date: Mon Sep 6 14:50:38 2021 +0800 basic func is ok diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..77fa569 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "gcc - 生成和调试活动文件", + "type": "cppdbg", + "request": "launch", + "program": "${fileDirname}/../xcmder", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "为 gdb 启用整齐打印", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "", + "miDebuggerPath": "/usr/bin/gdb" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a5ef78d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc 生成活动文件", + "command": "/usr/bin/gcc", + "args": [ + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "调试器生成的任务。" + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e2aa9b --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +include example/Makefile +INC += ./ +OBJ += xcmd.o +BIN = xcmder +VPATH := example +OBJ_WITH_BUILD_DIR:=$(addprefix build/,$(OBJ)) + +all: mkbuilddir $(OBJ_WITH_BUILD_DIR) + gcc $(OBJ_WITH_BUILD_DIR) -o $(BIN) + +build/%.o:%.c + gcc -c -I$(INC) -o $@ $< + +.PHONY:mkbuilddir +mkbuilddir: + mkdir -p build + +.PHONY:clean +clean: + rm -rf build + + diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..f6e12e9 --- /dev/null +++ b/example/Makefile @@ -0,0 +1 @@ +OBJ += test_cmds.o linux_main.o \ No newline at end of file diff --git a/example/linux_main.c b/example/linux_main.c new file mode 100644 index 0000000..7b72ef4 --- /dev/null +++ b/example/linux_main.c @@ -0,0 +1,60 @@ +#include +#include "xcmd.h" +#include +#include +#include +#include + +extern void test_cmd_init(xcmder_t *cmder); + +int getch(void) +{ + struct termios tm, tm_old; + int fd = 0, ch; + + if (tcgetattr(fd, &tm) < 0) {//保存现在的终端设置 + return -1; + } + + tm_old = tm; + cfmakeraw(&tm);//更改终端设置为原始模式,该模式下所有的输入数据以字节为单位被处理 + if (tcsetattr(fd, TCSANOW, &tm) < 0) {//设置上更改之后的设置 + return -1; + } + + ch = getchar(); + if (tcsetattr(fd, TCSANOW, &tm_old) < 0) {//更改设置为最初的样子 + return -1; + } + + return ch; +} + +int cmd_get_char(char *ch) +{ + *ch = getch(); + return 1; +} + +int cmd_put_char(char ch) +{ + putchar(ch); + return 1; +} + +int main(void) +{ + printf("hello\n"); + + xcmder_t* cmder = xcmd_create_default(cmd_get_char, cmd_put_char); + if(cmder) + { + test_cmd_init(cmder); + xcmd_exec(cmder, "help"); + while(1) + { + xcmd_task(cmder); + } + } + return 1; +} \ No newline at end of file diff --git a/example/linux_xmcder_wrapper.c b/example/linux_xmcder_wrapper.c new file mode 100644 index 0000000..d8b87fb --- /dev/null +++ b/example/linux_xmcder_wrapper.c @@ -0,0 +1,74 @@ +#include "linux_xmcder_wrapper.h" +#include +#include +#include +#include + +xcmder_t *g_cmder = NULL; + +extern void test_cmd_init(xcmder_t *cmder); + +int getch(void) +{ + struct termios tm, tm_old; + int fd = 0, ch; + + if (tcgetattr(fd, &tm) < 0) {//保存现在的终端设置 + return -1; + } + + tm_old = tm; + cfmakeraw(&tm);//更改终端设置为原始模式,该模式下所有的输入数据以字节为单位被处理 + if (tcsetattr(fd, TCSANOW, &tm) < 0) {//设置上更改之后的设置 + return -1; + } + + ch = getchar(); + if (tcsetattr(fd, TCSANOW, &tm_old) < 0) {//更改设置为最初的样子 + return -1; + } + + return ch; +} + +int cmd_get_char(char *ch) +{ + *ch = getch(); + return 1; +} + +int cmd_put_char(char ch) +{ + putchar(ch); + return 1; +} + +cmd_t default_cmds[] = +{ + {"clear", cmd_clear, "clear screen", NULL}, + {"help", cmd_help, "show this list", NULL}, + {"exit", cmd_exit, "exit xcmder", NULL}, +}; + + +void linux_cmd_register(cmd_t *cmds, uint16_t number) +{ + if(g_cmder) + { + xcmd_register(g_cmder, default_cmds, sizeof(cmds)/sizeof(cmd_t)); + } +} + +int linux_xcmder_init(void) +{ + g_cmder = xcmd_create_default(cmd_get_char, cmd_put_char); + if(g_cmder) + { + linux_cmd_register(default_cmds, sizeof(cmds)/sizeof(cmd_t)); + return 0; + } + else + { + return -1; + } +} \ No newline at end of file diff --git a/example/linux_xmcder_wrapper.h b/example/linux_xmcder_wrapper.h new file mode 100644 index 0000000..a4cbad9 --- /dev/null +++ b/example/linux_xmcder_wrapper.h @@ -0,0 +1,10 @@ +#ifndef LINUX_XMCDER_WRAPPER_H +#define LINUX_XMCDER_WRAPPER_H + +#include "xcmd.h" + + +void linux_xcmder_init(void); +void linux_cmd_register(cmd_t *cmds, uint16_t number); + +#endif /*LINUX_XMCDER_WRAPPER*/ \ No newline at end of file diff --git a/example/test_cmds.c b/example/test_cmds.c new file mode 100755 index 0000000..c54eac7 --- /dev/null +++ b/example/test_cmds.c @@ -0,0 +1,114 @@ +#include "xcmd.h" +#include +#include +#include + +xcmder_t *g_cmder = NULL; + +#define EXIT_MESSAGE() printf("press \"q\" or \"Q\" to exit!\r\n") +#define EXIT_CHECK() \ + do \ + (toupper(GET_CHAR()) == 'Q') \ + { \ + uint8_t c; \ + if (GET_CHAR(&c)) \ + { \ + switch (c) \ + case 'q': \ + case 'Q': \ + case 0x1B: \ + return; \ + } \ + } \ + while (0); + +uint8_t param_check(int need, int argc, char*argv[]) +{ + uint8_t i,ret = 0; + if(need<(argc)) + { + ret = 1; + } + else + { + printf("err need %d but input %d:\r\n", need, argc-1); + printf("input= "); + for(i=0; i= 32) && (c <= 126)) + +int cmdGetParam(char* msg, char*delim, char* get[], int maxNum) +{ + int i,ret; + char *ptr = NULL; + ptr = strtok(msg, delim); + for(i=0; ptr!=NULL &&i= maxNum) + { + break; + } + msg++; + } + return ret; +} + +void cmdPrintStr(xcmder_t * cmder, char* str) +{ + while(*str) + { + cmder->putchar(*str++); + } +} + +static uint16_t cmdBytesEncode(xcmder_t * cmder, uint8_t byte) +{ + uint16_t ret = byte; + + switch(cmder->encodeCaseStu) + { + case 0: + if(byte==0x1B) //1~2 + { + cmder->encodeCaseStu = 1; + ret = CMD_COMBINE_NONE; + } + break; + case 1: + if(byte==0x5B) + { + cmder->encodeCaseStu++; + ret = CMD_COMBINE_NONE; + } + else + { + cmder->encodeCaseStu = 0; + } + break; + case 2: + if(byte == 0x41) + { + cmder->encodeCaseStu = 0; + ret = CMD_COMBINE_CHAR_UP; + } + else if(byte == 0x42) + { + cmder->encodeCaseStu = 0; + ret = CMD_COMBINE_CHAR_DW; + } + else if(byte == 0x43) + { + cmder->encodeCaseStu = 0; + ret = CMD_COMBINE_CHAR_RIGHT; + } + else if(byte == 0x44) + { + cmder->encodeCaseStu = 0; + ret = CMD_COMBINE_CHAR_LEFT; + } + else + { + cmder->encodeCaseStu = 0; + ret = CMD_COMBINE_NONE; + } + break; + default: + break; + } + + return ret; +} + +void cmdDelLine(xcmder_t *cmder) +{ + char (*buf)[cmder->parser.historyLen] = (char (*)[cmder->parser.historyLen])cmder->parser.buf; + uint16_t len = strlen(buf[cmder->parser.historyCursor]); + if(len) + { + cmdPrintStr(cmder, "\r->"); + for(uint16_t i=0; iputchar(' '); + } + cmdPrintStr(cmder, "\r->"); + } +} + +void cmdInsertChar(xcmder_t *cmder, char c) +{ + char (*buf)[cmder->parser.historyLen] = (char (*)[cmder->parser.historyLen])cmder->parser.buf; + char *line = buf[cmder->parser.historyCursor]; + if(cmder->parser.bytesNum < cmder->parser.bufLen-1) + { + for(uint16_t i = cmder->parser.bytesNum; i>cmder->parser.cursor;i--) + { + line[i] = line[i-1]; + } + cmder->parser.bytesNum++; + line[cmder->parser.bytesNum] = '\0'; + line[cmder->parser.cursor++] = c; + + cmdPrintStr(cmder, "\r->"); + cmdPrintStr(cmder, line); + cmdPrintStr(cmder, "\r->"); + + /* move cursor */ + for(uint16_t i = 0; iparser.cursor; i++) + { + cmdPrintStr(cmder, "\x1B\x5B\x43"); + } + } +} + +void cmdDelChar(xcmder_t *cmder) +{ + char (*buf)[cmder->parser.historyLen] = (char (*)[cmder->parser.historyLen])cmder->parser.buf; + char *line = buf[cmder->parser.historyCursor]; + if(cmder->parser.cursor > 0) + { + for(uint16_t i = cmder->parser.cursor-1; iparser.bytesNum-1; i++) + { + line[i] = line[i+1]; + } + cmder->parser.bytesNum--; + cmder->parser.cursor--; + line[cmder->parser.bytesNum] = ' '; + cmdPrintStr(cmder, "\r->"); + cmdPrintStr(cmder, line); + cmdPrintStr(cmder, "\r->"); + + /* move cursor */ + for(uint16_t i = 0; iparser.cursor; i++) + { + cmdPrintStr(cmder, "\x1B\x5B\x43"); + } + + line[cmder->parser.bytesNum] = '\0'; + } +} + +void cmdCursorLeft(xcmder_t *cmder) +{ + if(cmder->parser.cursor > 0) + { + cmder->parser.cursor--; + } + cmdPrintStr(cmder, "\x1B\x5B\x44"); +} + +void cmdCursorRight(xcmder_t *cmder) +{ + if(cmder->parser.cursor < cmder->parser.bytesNum) + { + cmder->parser.cursor++; + } + cmdPrintStr(cmder, "\x1B\x5B\x43"); +} + +void cmdHistoryDw(xcmder_t *cmder) +{ + char(*buf)[cmder->parser.historyLen] = (char(*)[cmder->parser.historyLen])cmder->parser.buf; + while(cmder->parser.historyNum) + { + cmdDelLine(cmder); + cmder->parser.historyCursor++; + if(cmder->parser.historyCursor>=cmder->parser.historyLen) + { + cmder->parser.historyCursor = 0; + } + uint16_t len = strlen(buf[cmder->parser.historyCursor]); + if (len) + { + cmdPrintStr(cmder, buf[cmder->parser.historyCursor]); + cmder->parser.bytesNum = len; + cmder->parser.cursor = len; + break; + } + } +} + +void cmdHistoryUp(xcmder_t *cmder) +{ + char(*buf)[cmder->parser.historyLen] = (char(*)[cmder->parser.historyLen])cmder->parser.buf; + while(cmder->parser.historyNum) + { + cmdDelLine(cmder); + if (cmder->parser.historyCursor) + { + cmder->parser.historyCursor--; + } + else + { + cmder->parser.historyCursor = cmder->parser.historyLen; + } + uint16_t len = strlen(buf[cmder->parser.historyCursor]); + if (len) + { + cmdPrintStr(cmder, buf[cmder->parser.historyCursor]); + cmder->parser.bytesNum = len; + cmder->parser.cursor = len; + break; + } + } +} + +char* cmdLineEnd(xcmder_t *cmder) +{ + char (*buf)[cmder->parser.historyLen] = (char (*)[cmder->parser.historyLen])cmder->parser.buf; + char* ret = NULL; + if(cmder->parser.bytesNum) + { + ret = buf[cmder->parser.historyCursor]; + + uint16_t temp = cmder->parser.historyCursor; + if(temp) + { + temp--; + } + else + { + temp = cmder->parser.historyLen; + } + + if(strcmp(buf[temp], ret) != 0) + { + if(cmder->parser.historyNum < cmder->parser.historyLen) + { + cmder->parser.historyNum++; + } + cmder->parser.historyCursor++; + if(cmder->parser.historyCursor>=cmder->parser.historyLen) + { + cmder->parser.historyCursor = 0; + } + } + + cmder->parser.bytesNum = 0; + cmder->parser.cursor = 0; + cmdPrintStr(cmder, "\r\n"); + } + else + { + cmdPrintStr(cmder, "\r\n->"); + } + + return ret; +} + +char* cmdParser(xcmder_t * cmder, uint8_t byte) +{ + char* ret = NULL; + uint16_t c = 0; + + c = cmdBytesEncode(cmder, byte); + + if(CMD_IS_DELETE(c)) + { + cmdDelChar(cmder); + } + else if(CMD_IS_PRINT(c)) + { + cmdInsertChar(cmder, c); + } + else if(CMD_IS_UP(c)) + { + cmdHistoryUp(cmder); + } + else if(CMD_IS_DOWN(c)) + { + cmdHistoryDw(cmder); + } + else if(CMD_IS_RIGHT(c)) + { + cmdCursorRight(cmder); + } + else if(CMD_IS_LEFT(c)) + { + cmdCursorLeft(cmder); + } + else if(CMD_IS_ENDLINE(c)) + { + ret = cmdLineEnd(cmder); + } + fflush(stdout); + return ret; +} + +uint8_t xcmd_exec(xcmder_t *cmder, char* str) +{ + int paramNum = 0; + char *cmdParamBuff[cmder->parser.paramLen]; + char temp[cmder->parser.bufLen]; + strncpy(temp, str, cmder->parser.bufLen); + paramNum = cmdGetParam(temp, "., ", cmdParamBuff, cmder->parser.paramLen); + if(paramNum >0) + { + xcmd_match(cmder, paramNum, cmdParamBuff); + } + return paramNum; +} + +int xcmd_register(xcmder_t *cmder, cmd_t *cmds, uint16_t number) +{ + uint16_t i=0; + if(cmder->cmd_list.len == 0) + { + cmder->cmd_list.next = &cmds[i++]; + cmder->cmd_list.next->next = NULL; + ++cmder->cmd_list.len; + } + + while(icmd_list.next; + cmder->cmd_list.next = &cmds[i]; + cmds[i].next = p; + ++cmder->cmd_list.len; + ++i; + } + return cmder->cmd_list.len; +} + +void xcmd_print_list(xcmder_t *cmder) +{ + cmd_t *p = cmder->cmd_list.next; + while(p) + { + printf("%-20s %s\r\n",p->name, p->help); + p = p->next; + } +} + +void xcmd_match(xcmder_t *cmder, int argc, char*argv[]) +{ + cmd_t *p = cmder->cmd_list.next; + uint8_t flag = 0; + while(p) + { + if(strcmp(p->name, argv[0]) == 0) + { + flag = 1; + if(argc>1) + { + if((strcmp(argv[1],"?") == 0) || + (strcmp(argv[1],"-h") == 0)) + { + printf("%s\r\n", p->help); + break; + } + } + p->func(argc, argv); + break; + } + p = p->next; + } + if(flag) + { + printf("\r\n"); + } + else + { + printf("cmd \"%s\" does not exist\r\n", argv[0]); + } +} + +xcmder_t* xcmd_create( + xcmd_get_char_func_t getchar, + xcmd_put_char_func_t putchar, + uint16_t cmdLen, + uint16_t historyLen, + uint16_t paramLen + ) +{ + xcmder_t* cmder = (xcmder_t*)malloc(sizeof(xcmder_t)); + if(cmder == NULL) + { + goto create_cmder_failure; + } + if(getchar && putchar) + { + cmder->parser.buf = (char*)malloc(cmdLen*historyLen); + cmder->parser.historyLen = historyLen; + cmder->parser.bufLen = cmdLen*historyLen; + if(cmder->parser.buf == NULL) + { + goto failure; + } + + cmder->parser.paramLen = paramLen; + cmder->parser.param = (char**)malloc(sizeof(char*)*paramLen); + if(cmder->parser.param == NULL) + { + goto failure; + } + + + cmder->parser.bytesNum = 0; + cmder->parser.historyNum = 0; + cmder->parser.cursor = 0; + cmder->parser.historyCursor = 0; + cmder->parser.ishistory = 0; + + cmder->encodeCaseStu = 0; + cmder->getchar = getchar; + cmder->putchar = putchar; + cmder->_initOK = 1; + + cmder->cmd_list.len = 0; + cmder->cmd_list.next = NULL; + } + else + { + goto failure; + } + return cmder; + +failure: + if(cmder->parser.param) + { + free(cmder->parser.param); + cmder->parser.param = NULL; + } + if(cmder->parser.buf) + { + free(cmder->parser.buf); + cmder->parser.buf = NULL; + } +create_cmder_failure: + if(cmder) + { + free(cmder); + cmder = NULL; + } + return NULL; +} + +void xcmd_destory(xcmder_t* cmder) +{ + if(cmder) + { + if(cmder->parser.param) + { + free(cmder->parser.param); + cmder->parser.param = NULL; + } + if(cmder->parser.buf) + { + free(cmder->parser.buf); + cmder->parser.buf = NULL; + } + free(cmder); + } +} + +void xcmd_task(xcmder_t* cmder) +{ + uint8_t c; + char *str = NULL; + if(cmder && cmder->_initOK) + { + if(cmder->getchar(&c)) + { + str = cmdParser(cmder, c); + if(str) + { + xcmd_exec(cmder, str); + } + } + } + +} + + + + + diff --git a/xcmd.h b/xcmd.h new file mode 100755 index 0000000..6056707 --- /dev/null +++ b/xcmd.h @@ -0,0 +1,73 @@ +#ifndef XCMD_H +#define XCMD_H + +#include +#include +#include +#include +#include +#include + +typedef void(*cmd_func_t)(int argv, char* argc[]); +typedef int (*xcmd_get_char_func_t)(uint8_t *); +typedef int (*xcmd_put_char_func_t)(uint8_t ch); + +typedef struct __cmd +{ + char* name; + cmd_func_t func; + char* help; + struct __cmd *next; +}cmd_t; + +typedef struct +{ + xcmd_get_char_func_t getchar; + xcmd_put_char_func_t putchar; + struct + { + char *buf; + char **param; + uint16_t paramLen; + uint16_t historyLen; + uint16_t bufLen; + + uint16_t historyNum; + uint16_t bytesNum; + + uint16_t historyCursor; + uint16_t cursor; + uint8_t ishistory; + } parser; + + struct + { + uint16_t len; + cmd_t *next; + }cmd_list; + + uint8_t encodeCaseStu; + uint8_t _initOK; +} xcmder_t; + +int xcmd_register(xcmder_t *cmder, cmd_t *cmds, uint16_t number); +void xcmd_match(xcmder_t *cmder, int argc, char*argv[]); +void xcmd_print_list(xcmder_t *cmder); +uint8_t xcmd_exec(xcmder_t *cmder, char *str); +void xcmd_destory(xcmder_t* cmder); +void xcmd_task(xcmder_t *cmder); +xcmder_t *xcmd_create( + xcmd_get_char_func_t getchar, + xcmd_put_char_func_t putchar, + uint16_t cmdLen, + uint16_t historyLen, + uint16_t paramLen); + +#define xcmd_create_default(getchar, putchar) \ + xcmd_create((xcmd_get_char_func_t)getchar, \ + (xcmd_put_char_func_t)putchar, \ + 64, \ + 10, \ + 16); + +#endif /*XCMD_H*/ diff --git a/xcmder b/xcmder new file mode 100755 index 0000000..2223684 Binary files /dev/null and b/xcmder differ