1 Star 0 Fork 9

WennianYan / 通用命令行接口

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
gm_cli.c 26.83 KB
一键复制 编辑 原始数据 按行查看 历史
tom 提交于 2021-06-17 01:12 . 添加静态注册命令支持
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
/*******************************************************************************
** 文件名称:gm_cli_mgr.c
** 文件作用:通用命令行接口
** 编写作者:Tom Free 付瑞彪
** 编写时间:2020-08-09
** 文件备注:
** 更新记录:
** 2020-08-09 -> 创建文件
** <Tom Free 付瑞彪>
** 2021-03-18 -> 修改宏来适配不同编译器
** <Tom Free 付瑞彪>
** 2021-06-17 -> 增加自动命令注册和静态注册选项
** <Tom Free 付瑞彪>
**
** Copyright (c) 2018-2021 付瑞彪 All Rights Reserved
**
** 1 Tab == 4 Spaces UTF-8 ANSI C Language(C99)
*******************************************************************************/
#include "gm_cli.h"
#include "string.h"
#include "stdio.h"
#include "stdarg.h"
#include "stdlib.h"
#if (GM_CLI_CC == GM_CLI_CC_VS)
/* Microsoft VC/C++ 编译器没有找到段起始和终止的操作宏,需要特殊处理 */
__declspec(allocate(".gm_cli_cmd_section$a"))
static const gm_cli_cmd_t __gm_cli_cmd_begin =
{
.name = "__start",
.usage = "start of cli",
.cb = NULL,
};
__declspec(allocate(".gm_cli_cmd_section$c"))
static const gm_cli_cmd_t __gm_cli_cmd_end =
{
.name = "__end",
.usage = "end of cli",
.cb = NULL,
};
#endif /* GM_CLI_CC == GM_CLI_CC_VS */
#if (GM_CLI_CC == GM_CLI_CC_MINGW)
__attribute__((used)) __attribute__((section(".gm_cli_cmd_section$a")))
static const gm_cli_cmd_t __gm_cli_cmd_begin =
{
.name = "__start",
.usage = "start of cli",
.cb = NULL,
};
__attribute__((used)) __attribute__((section(".gm_cli_cmd_section$c")))
static const gm_cli_cmd_t __gm_cli_cmd_end =
{
.name = "__end",
.usage = "end of cli",
.cb = NULL,
};
#endif /* GM_CLI_CC == GM_CLI_CC_VS */
/* 输入状态定义 */
typedef enum
{
GM_CLI_INPUT_WAIT_NORMAL, /* 等待正常字符 */
GM_CLI_INPUT_WAIT_SPEC_KEY, /* 等待特殊字符 */
GM_CLI_INPUT_WAIT_FUNC_KEY, /* 等待功能字符 */
#if (GM_CLI_CC == GM_CLI_CC_VS) || (GM_CLI_CC == GM_CLI_CC_MINGW) || \
((GM_CLI_CC == GM_CLI_CC_ANY) && defined _MSC_VER)
GM_CLI_INPUT_WAIT_FUNC_KEY1, /* 等待功能字符1 */
#endif
} gm_cli_input_status_t;
/* CLI管理器 */
typedef struct
{
char line[GM_CLI_LINE_CHAR_MAX]; /* 一行字符串存储 */
unsigned int input_count; /* 输入的字符数量 */
unsigned int input_cusor; /* 输入的光标位置 */
gm_cli_input_status_t input_status; /* 当前输入的状态 */
gm_cli_out_char_cb_t *pf_outchar; /* 输出字符回调函数 */
const int* p_cmd_start; /* 命令存储区起始指针 */
const int* p_cmd_end; /* 命令存储区结束指针 */
const char* p_cmd_notice; /* 命令提示符 */
/* 打印函数使用的字符串缓存 */
char printf_str[GM_CLI_PRINTF_BUF_MAX];
/* 备份字符串,用于翻历史记录时保存当前 */
char backup_str[GM_CLI_LINE_CHAR_MAX];
char history_str[GM_CLI_HISTORY_LINE_MAX][GM_CLI_LINE_CHAR_MAX];
unsigned int history_total; /* 历史总记录条数 */
unsigned int history_index; /* 历史存储索引 */
unsigned int history_inquire_index; /* 历史查询索引 */
unsigned int history_inquire_count; /* 历史查询数量计数器 */
} gm_cli_mgr_t;
/* CLI控制 */
static gm_cli_mgr_t gm_cli_mgr =
{
.input_count = 0,
.input_cusor = 0,
.input_status = GM_CLI_INPUT_WAIT_NORMAL,
.pf_outchar = NULL,
.p_cmd_start = NULL,
.p_cmd_end = NULL,
.p_cmd_notice = GM_CLI_DEFAULT_CMD_PROMPT,
.history_total = 0,
.history_index = 0,
.history_inquire_index = 0,
.history_inquire_count =0,
};
/* 读取下一个命令 */
static const gm_cli_cmd_t* gm_cli_get_next_cmd(const int* const addr)
{
#if (GM_CLI_CC == GM_CLI_CC_VS)
const int *ptr = addr;
ptr += sizeof(gm_cli_cmd_t) / sizeof(const int);
while (ptr < gm_cli_mgr.p_cmd_end)
{
if ((*ptr) != 0)
{
return (const gm_cli_cmd_t*)ptr;
}
ptr++;
}
#else /* GM_CLI_CC == GM_CLI_CC_VS */
const int *ptr = (const int*)((char*)addr + sizeof(gm_cli_cmd_t));
if (ptr < gm_cli_mgr.p_cmd_end)
{
return (const gm_cli_cmd_t*)ptr;
}
#endif /* GM_CLI_CC == GM_CLI_CC_VS */
return NULL;
}
/* 搜索命令 */
static const gm_cli_cmd_t* gm_cli_search_cmd(const char* const cmd_name)
{
const gm_cli_cmd_t* p_ret = NULL;
const gm_cli_cmd_t* p_temp;
p_temp = (gm_cli_cmd_t*)gm_cli_mgr.p_cmd_start;
while (p_temp != NULL)
{
if (strcmp(p_temp->name, cmd_name) == 0)
{
p_ret = p_temp;
break;
}
p_temp = gm_cli_get_next_cmd((const int*)p_temp);
}
return p_ret;
}
/* 初始化cli管理器 */
void gm_cli_mgr_init(void)
{
#if (GM_CLI_CC == GM_CLI_CC_MDK_ARM)
extern const int gm_cli_cmd_section$$Base;
extern const int gm_cli_cmd_section$$Limit;
gm_cli_mgr.p_cmd_start = (const int*)&gm_cli_cmd_section$$Base;
gm_cli_mgr.p_cmd_end = (const int*)&gm_cli_cmd_section$$Limit;
#elif (GM_CLI_CC == GM_CLI_CC_GCC_LINUX)
extern const gm_cli_cmd_t gm_cli_cmd_section_start;
extern const gm_cli_cmd_t gm_cli_cmd_section_end;
gm_cli_mgr.p_cmd_start = (const int*)&gm_cli_cmd_section_start;
gm_cli_mgr.p_cmd_end = (const int*)&gm_cli_cmd_section_end;
#elif ((GM_CLI_CC == GM_CLI_CC_IAR_ARM) || (GM_CLI_CC == GM_CLI_CC_IAR_STM8))
gm_cli_mgr.p_cmd_start = (const int*)__section_begin(".gm_cli_cmd_section");
gm_cli_mgr.p_cmd_end = (const int*)__section_end(".gm_cli_cmd_section");
#elif (GM_CLI_CC == GM_CLI_CC_VS) || (GM_CLI_CC == GM_CLI_CC_MINGW)
unsigned int* ptr_begin, *ptr_end;
/* 找寻起始位置 */
ptr_begin = (unsigned int*)&__gm_cli_cmd_begin;
ptr_begin += (sizeof(gm_cli_cmd_t) / sizeof(unsigned int));
while ((*ptr_begin) == 0) ptr_begin++;
/* 找寻终止位置 */
ptr_end = (unsigned int *)&__gm_cli_cmd_end;
ptr_end--;
while ((*ptr_end) == 0) ptr_end--;
/* 判断是否合法 */
if (ptr_begin < ptr_end)
{
gm_cli_mgr.p_cmd_start = (const int*)(ptr_begin);
gm_cli_mgr.p_cmd_end = (const int*)(ptr_end);
}
else
{
gm_cli_mgr.p_cmd_start = NULL;
gm_cli_mgr.p_cmd_end = NULL;
}
#elif (GM_CLI_CC == GM_CLI_CC_ANY)
gm_cli_mgr.p_cmd_start = (const int*)&gm_cli_static_cmds[0];
const gm_cli_cmd_t *ptr = &gm_cli_static_cmds[0];
while (ptr->name != NULL) ptr++;
gm_cli_mgr.p_cmd_end = (const int*)ptr;
#else
gm_cli_mgr.p_cmd_start = NULL;
gm_cli_mgr.p_cmd_end = NULL;
#endif
gm_cli_mgr.input_count = 0;
gm_cli_mgr.input_cusor = 0;
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_NORMAL;
gm_cli_mgr.pf_outchar = NULL;
gm_cli_mgr.p_cmd_notice = GM_CLI_DEFAULT_CMD_PROMPT;
memset(gm_cli_mgr.line, 0, sizeof(gm_cli_mgr.line));
memset(gm_cli_mgr.printf_str, 0, sizeof(gm_cli_mgr.printf_str));
memset(gm_cli_mgr.backup_str, 0, sizeof(gm_cli_mgr.backup_str));
memset(gm_cli_mgr.history_str, 0, sizeof(gm_cli_mgr.history_str));
}
/* 设置输出字符回调函数 */
void gm_cli_set_out_char_cb(gm_cli_out_char_cb_t *out_char_cb)
{
if (out_char_cb != NULL)
{
gm_cli_mgr.pf_outchar = out_char_cb;
}
}
/* 设置命令提示符 */
void gm_cli_set_cmd_prompt(const char* const p_notice)
{
if (p_notice != NULL)
{
gm_cli_mgr.p_cmd_notice = p_notice;
}
else
{
gm_cli_mgr.p_cmd_notice = GM_CLI_DEFAULT_CMD_PROMPT;
}
}
/* 启动命令行 */
void gm_cli_start(void)
{
gm_cli_put_str("\r\n");
gm_cli_put_str(gm_cli_mgr.p_cmd_notice);
}
/* 打印字符 */
void gm_cli_put_char(const char ch)
{
if (gm_cli_mgr.pf_outchar != NULL)
{
gm_cli_mgr.pf_outchar(ch);
}
}
/* 打印字符串 */
void gm_cli_put_str(const char* const str)
{
const char* ptemp = str;
if (str == NULL)
{
return;
}
if (gm_cli_mgr.pf_outchar != NULL)
{
while (*ptemp)
{
gm_cli_mgr.pf_outchar(*ptemp);
ptemp++;
}
}
}
/* 通用打印函数,替代默认printf */
void gm_cli_printf(const char* const fmt, ...)
{
va_list ap;
va_start(ap, fmt);
#if (GM_CLI_CC == GM_CLI_CC_VS) || ((GM_CLI_CC == GM_CLI_CC_ANY) && defined _MSC_VER)
vsprintf_s(gm_cli_mgr.printf_str, sizeof(gm_cli_mgr.printf_str), fmt, ap);
#else
vsprintf(gm_cli_mgr.printf_str, fmt, ap);
#endif
gm_cli_put_str(gm_cli_mgr.printf_str);
va_end(ap);
}
/* 上键处理 */
static void gm_cli_parse_up_key(void)
{
unsigned int len;
if (gm_cli_mgr.history_total == 0)
{
/* 无记录 */
return;
}
if (gm_cli_mgr.history_inquire_count == 0)
{
/* 从未上翻记录,备份当前输入 */
memcpy(gm_cli_mgr.backup_str, gm_cli_mgr.line, sizeof(gm_cli_mgr.line));
/* 搜索记录位置设置到当前记录处 */
gm_cli_mgr.history_inquire_index = gm_cli_mgr.history_index;
}
/* 查看是否已经搜索完成 */
if (gm_cli_mgr.history_inquire_count < gm_cli_mgr.history_total)
{
/* 搜索编号往前找一个记录编号 */
if (gm_cli_mgr.history_inquire_index == 0)
{
gm_cli_mgr.history_inquire_index = GM_CLI_HISTORY_LINE_MAX - 1;
}
else
{
gm_cli_mgr.history_inquire_index--;
}
/* 搜索数量加1 */
gm_cli_mgr.history_inquire_count++;
/* 光标之后的行数据清除掉 */
len = gm_cli_mgr.input_count - gm_cli_mgr.input_cusor;
for (unsigned int i = 0; i < len; i++)
{
gm_cli_put_char(' ');
}
/* 清除所有的行数据 */
for (unsigned int i = 0; i < gm_cli_mgr.input_count; i++)
{
gm_cli_put_str("\b \b");
}
/* 导入历史输入 */
memcpy(gm_cli_mgr.line, gm_cli_mgr.history_str[gm_cli_mgr.history_inquire_index], sizeof(gm_cli_mgr.line));
gm_cli_mgr.input_count = (unsigned int)strlen(gm_cli_mgr.line);
gm_cli_mgr.input_cusor = gm_cli_mgr.input_count;
/* 显示历史记录 */
gm_cli_put_str(gm_cli_mgr.line);
}
}
/* 下键处理 */
static void gm_cli_parse_down_key(void)
{
unsigned int len;
if ((gm_cli_mgr.history_total == 0) ||
(gm_cli_mgr.history_inquire_count == 0))
{
/* 无记录或无上翻 */
return;
}
/* 查询数量减一 */
gm_cli_mgr.history_inquire_count--;
/* 删除当前行内容 */
len = gm_cli_mgr.input_count - gm_cli_mgr.input_cusor;
for (unsigned int i = 0; i < len; i++)
{
gm_cli_put_char(' ');
}
for (unsigned int i = 0; i < gm_cli_mgr.input_count; i++)
{
gm_cli_put_str("\b \b");
}
if (gm_cli_mgr.history_inquire_count == 0)
{
/* 恢复备份的输入 */
memcpy(gm_cli_mgr.line, gm_cli_mgr.backup_str, sizeof(gm_cli_mgr.line));
}
else
{
/* 更新索引 */
gm_cli_mgr.history_inquire_index++;
gm_cli_mgr.history_inquire_index %= GM_CLI_HISTORY_LINE_MAX;
/* 取出历史 */
memcpy(gm_cli_mgr.line, gm_cli_mgr.history_str[gm_cli_mgr.history_inquire_index], sizeof(gm_cli_mgr.line));
}
/* 重新更新坐标 */
gm_cli_mgr.input_count = (unsigned int)strlen(gm_cli_mgr.line);
gm_cli_mgr.input_cusor = gm_cli_mgr.input_count;
/* 显示输入行 */
gm_cli_put_str(gm_cli_mgr.line);
}
/* 左键处理 */
static void gm_cli_parse_left_key(void)
{
if (gm_cli_mgr.input_cusor > 0)
{
gm_cli_put_char('\b');
gm_cli_mgr.input_cusor--;
}
}
/* 右键处理 */
static void gm_cli_parse_right_key(void)
{
if ((gm_cli_mgr.input_count > 0) &&
(gm_cli_mgr.input_cusor < gm_cli_mgr.input_count))
{
gm_cli_put_char(gm_cli_mgr.line[gm_cli_mgr.input_cusor]);
gm_cli_mgr.input_cusor++;
}
}
/* 功能键处理返回:0 - 已处理的功能字符,-1 - 未处理的字符 */
static int gm_cli_parse_func_key(const char ch)
{
/* XSHELL终端,超级终端等功能码 */
if (ch == (char)0x1B)
{
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_SPEC_KEY;
return 0;
}
else if (gm_cli_mgr.input_status == GM_CLI_INPUT_WAIT_SPEC_KEY)
{
if (ch == (char)0x5b)
{
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_FUNC_KEY;
return 0;
}
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_NORMAL;
}
else if (gm_cli_mgr.input_status == GM_CLI_INPUT_WAIT_FUNC_KEY)
{
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_NORMAL;
if (ch == (char)0x41) /* 上 */
{
gm_cli_parse_up_key();
return 0;
}
else if (ch == (char)0x42) /* 下 */
{
gm_cli_parse_down_key();
return 0;
}
else if (ch == (char)0x44) /* 左 */
{
gm_cli_parse_left_key();
return 0;
}
else if (ch == (char)0x43) /* 右 */
{
gm_cli_parse_right_key();
return 0;
}
}
#if (GM_CLI_CC == GM_CLI_CC_VS) || (GM_CLI_CC == GM_CLI_CC_MINGW) || \
((GM_CLI_CC == GM_CLI_CC_ANY) && defined _MSC_VER)
/* windows命令行功能码 */
if (ch == (char)0xE0)
{
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_FUNC_KEY1;
return 0;
}
else if (gm_cli_mgr.input_status == GM_CLI_INPUT_WAIT_FUNC_KEY1)
{
gm_cli_mgr.input_status = GM_CLI_INPUT_WAIT_NORMAL;
if (ch == (char)0x48) /* 上 */
{
gm_cli_parse_up_key();
return 0;
}
else if (ch == (char)0x50) /* 下 */
{
gm_cli_parse_down_key();
return 0;
}
else if (ch == (char)0x4B) /* 左 */
{
gm_cli_parse_left_key();
return 0;
}
else if (ch == (char)0x4D) /* 右 */
{
gm_cli_parse_right_key();
return 0;
}
}
#endif /* _MSC_VER */
return -1;
}
/* 判断字符串是否空,返回:0 - 空,-1 - 非空 */
static int gm_cli_str_empty_check(const char* const str)
{
const char* p_tmp = str;
while (*p_tmp)
{
if ((*p_tmp) != ' ')
{
return -1;
}
p_tmp++;
}
return 0;
}
/* 字符串匹配 */
static int gm_cli_str_completion(const char* const str, const char* const substr)
{
unsigned int len1 = (unsigned int)strlen(str);
unsigned int len2 = (unsigned int)strlen(substr);
unsigned int i = 0;
if (len2 > len1)
{
return -1;
}
for (i = 0; i < len2; i++)
{
if (str[i] != substr[i])
{
return -1;
}
}
return 0;
}
/* 删除开头的空格 */
static const char* gm_cli_delete_start_space(const char* const str)
{
unsigned int i = 0;
unsigned int len = (unsigned int)strlen(str);
while ((str[i] == ' ') && (str[i] != '\0') && (i < len))
{
i++;
}
return (const char*)(str + i);
}
/* tab键处理 */
static void gm_cli_parse_tab_key(void)
{
const gm_cli_cmd_t *p_temp, *p_find_first_cmd = NULL;
unsigned int find_count = 0, len;
const char *p_line_start;
/* 检测是否是空白行 */
if (gm_cli_str_empty_check(gm_cli_mgr.line) == 0)
{
return;
}
/* 取消前面的空白 */
p_line_start = gm_cli_delete_start_space(gm_cli_mgr.line);
p_temp = (gm_cli_cmd_t*)gm_cli_mgr.p_cmd_start;
/* 查询命令 */
while (p_temp != NULL)
{
if (gm_cli_str_completion(p_temp->name, p_line_start) == 0)
{
if (find_count == 0)
{
p_find_first_cmd = p_temp;
}
else if (find_count == 1)
{
gm_cli_put_str("\r\n");
gm_cli_put_str(p_find_first_cmd->name);
gm_cli_put_str("\r\n");
gm_cli_put_str(p_temp->name);
gm_cli_put_str("\r\n");
}
else
{
gm_cli_put_str(p_temp->name);
gm_cli_put_str("\r\n");
}
find_count++;
}
p_temp = gm_cli_get_next_cmd((const int*)p_temp);
}
if (find_count == 1)
{
/* 删除当前行内容 */
len = gm_cli_mgr.input_count - gm_cli_mgr.input_cusor;
for (unsigned int i = 0; i < len; i++)
{
gm_cli_put_char(' ');
}
for (unsigned int i = 0; i < gm_cli_mgr.input_count; i++)
{
gm_cli_put_str("\b \b");
}
/* 自动填充行 */
memset(gm_cli_mgr.line, '\0', sizeof(gm_cli_mgr.line));
memcpy(gm_cli_mgr.line, p_find_first_cmd->name, strlen(p_find_first_cmd->name));
/* 重新更新坐标 */
gm_cli_mgr.input_count = (unsigned int)strlen(gm_cli_mgr.line);
gm_cli_mgr.input_cusor = gm_cli_mgr.input_count;
/* 显示输入行 */
gm_cli_put_str(gm_cli_mgr.line);
}
else if (find_count > 1)
{
/* 显示提示符 */
gm_cli_put_str(gm_cli_mgr.p_cmd_notice);
/* 重新更新坐标 */
gm_cli_mgr.input_count = (unsigned int)strlen(gm_cli_mgr.line);
gm_cli_mgr.input_cusor = gm_cli_mgr.input_count;
/* 显示输入行 */
gm_cli_put_str(gm_cli_mgr.line);
}
}
/* 退格键处理 */
static void gm_cli_parse_backspace_key(void)
{
int i, count;
if (gm_cli_mgr.input_cusor == 0)
{
/* 未输入,直接跳过 */
return;
}
/* 更新位置 */
gm_cli_mgr.input_cusor--;
gm_cli_mgr.input_count--;
if (gm_cli_mgr.input_cusor == gm_cli_mgr.input_count)
{
/* 末尾置0 */
gm_cli_mgr.line[gm_cli_mgr.input_count] = '\0';
/* 光标在最后 */
gm_cli_put_str("\b \b");
}
else
{
/* 计算需要搬移的字符数 */
count = gm_cli_mgr.input_count - gm_cli_mgr.input_cusor;
/* 搬移 */
for (i = 0; i < count; i++)
{
gm_cli_mgr.line[gm_cli_mgr.input_cusor + i] = gm_cli_mgr.line[gm_cli_mgr.input_cusor + i + 1];
}
/* 末尾置0 */
gm_cli_mgr.line[gm_cli_mgr.input_count] = '\0';
/* 重新刷新显示 */
gm_cli_put_char('\b');
gm_cli_put_str(&gm_cli_mgr.line[gm_cli_mgr.input_cusor]);
gm_cli_put_str(" \b");
/* 光标回位 */
for (i = 0; i < count; i++)
{
gm_cli_put_char('\b');
}
}
}
/* 回车换行键处理 */
static void gm_cli_parse_enter_key(void)
{
unsigned int i;
int argc = 0;
char* argv[GM_CLI_CMD_ARGS_NUM_MAX];
const gm_cli_cmd_t* p_cmd;
/* 回车,处理命令时可能有输出 */
gm_cli_put_str("\r\n");
if (gm_cli_mgr.input_count > 0)
{
/* 备份进入历史记录 */
memcpy(gm_cli_mgr.history_str[gm_cli_mgr.history_index++], gm_cli_mgr.line, sizeof(gm_cli_mgr.line));
gm_cli_mgr.history_index %= GM_CLI_HISTORY_LINE_MAX;
if (gm_cli_mgr.history_total < GM_CLI_HISTORY_LINE_MAX)
{
gm_cli_mgr.history_total++;
}
gm_cli_mgr.history_inquire_index = 0;
gm_cli_mgr.history_inquire_count = 0;
/* 分析字符串 */
for (i = 0; i < gm_cli_mgr.input_count;)
{
/* 跳过空格并替换为0 */
while ((gm_cli_mgr.line[i] == ' ') && (i < gm_cli_mgr.input_count))
{
gm_cli_mgr.line[i++] = '\0';
}
if (i >= gm_cli_mgr.input_count)
{
break;
}
if (argc >= GM_CLI_CMD_ARGS_NUM_MAX)
{
gm_cli_put_str("Too many args! Line will replace follow:\r\n < ");
for (int j = 0; j < argc; j++)
{
gm_cli_put_str(argv[j]);
gm_cli_put_char(' ');
}
gm_cli_put_str(">\r\n");
break;
}
argv[argc++] = &gm_cli_mgr.line[i];
/* 跳过中间的字符串 */
while ((gm_cli_mgr.line[i] != ' ') && (i < gm_cli_mgr.input_count))
{
i++;
}
if (i >= gm_cli_mgr.input_count)
{
break;
}
}
if (argc > 0)
{
p_cmd = gm_cli_search_cmd(argv[0]);
if (p_cmd != NULL)
{
if (p_cmd->link != NULL)
{
p_cmd = p_cmd->link;
}
if (p_cmd->cb)
{
p_cmd->cb(argc, argv);
}
}
else
{
gm_cli_put_str("Not found command \"");
gm_cli_put_str(argv[0]);
gm_cli_put_str("\"\r\n");
}
}
}
/* 清空行,为下一次输入准备 */
gm_cli_put_str(gm_cli_mgr.p_cmd_notice);
memset(gm_cli_mgr.line, 0, sizeof(gm_cli_mgr.line));
gm_cli_mgr.input_cusor = gm_cli_mgr.input_count = 0;
}
/* 通用可显示字符处理 */
static void gm_cli_parse_common_char(const char ch)
{
int i, count;
if (gm_cli_mgr.input_count > (GM_CLI_LINE_CHAR_MAX - 1))
{
return;
}
if (gm_cli_mgr.input_cusor == gm_cli_mgr.input_count)
{
/* 光标在最后 */
gm_cli_mgr.line[gm_cli_mgr.input_cusor++] = ch;
gm_cli_mgr.input_count++;
gm_cli_put_char(ch);
}
else
{
/* 光标不在最后,计算需要搬移的字符数 */
count = gm_cli_mgr.input_count - gm_cli_mgr.input_cusor;
/* 搬移 */
for (i = count; i > 0; i--)
{
gm_cli_mgr.line[gm_cli_mgr.input_cusor + i] = gm_cli_mgr.line[gm_cli_mgr.input_cusor + i - 1];
}
gm_cli_mgr.line[gm_cli_mgr.input_cusor] = ch;
gm_cli_put_char(ch);
gm_cli_mgr.input_count++;
gm_cli_mgr.input_cusor++;
gm_cli_put_str(&gm_cli_mgr.line[gm_cli_mgr.input_cusor]);
/* 光标回位 */
for (i = 0; i < count; i++)
{
gm_cli_put_char('\b');
}
}
}
/* 解析一个字符 */
void gm_cli_parse_char(const char ch)
{
/* 过滤无效字符 */
if ((ch == (char)0x00) ||
(ch == (char)0xFF))
{
return;
}
/* 功能码 */
if (gm_cli_parse_func_key(ch) == 0)
{
return;
}
/* 字符解析 */
if (ch == '\t')
{
/* Tab */
gm_cli_parse_tab_key();
}
else if ((ch == (char)0x7F) || (ch == (char)0x08))
{
/* 退格 */
gm_cli_parse_backspace_key();
}
if ((ch == '\r') || (ch == '\n'))
{
/* 回车或换行 */
gm_cli_parse_enter_key();
}
else if ((ch >= ' ') && (ch <= '~'))
{
gm_cli_parse_common_char(ch);
}
}
#if GM_CLI_CMD_REG_BY_CC_SECTION
/* 编译器命令导出方式可以防耦合,将函数声明为局部函数 */
#define CMD_CB_CALL_PREFIX static
#else
/* 静态注册方式需要导出默认命令函数,不能加static */
#define CMD_CB_CALL_PREFIX
#endif /* GM_CLI_CMD_REG_BY_CC_SECTION */
/* 内部命令-help */
CMD_CB_CALL_PREFIX int gm_cli_internal_cmd_help(int argc, char* argv[])
{
const gm_cli_cmd_t* p_temp;
const gm_cli_cmd_t* p_temp1;
int found_flag = 0;
if (argc == 1)
{
p_temp = (gm_cli_cmd_t*)gm_cli_mgr.p_cmd_start;
gm_cli_put_str("System all command:\r\n");
while (p_temp != NULL)
{
gm_cli_put_str(" ");
gm_cli_put_str(p_temp->name);
if (p_temp->link != NULL)
{
gm_cli_put_str(" -> ");
p_temp1 = p_temp->link;
gm_cli_put_str(p_temp1->name);
}
gm_cli_put_str("\r\n");
p_temp = gm_cli_get_next_cmd((const int*)p_temp);
}
}
else if (argc == 2)
{
p_temp = (gm_cli_cmd_t*)gm_cli_mgr.p_cmd_start;
found_flag = 0;
while (p_temp != NULL)
{
if (strcmp(p_temp->name, argv[1]) == 0)
{
gm_cli_put_str("command:");
gm_cli_put_str(p_temp->name);
if (p_temp->link != NULL)
{
gm_cli_put_str(" -> ");
p_temp = p_temp->link;
gm_cli_put_str(p_temp->name);
}
gm_cli_put_str("\r\n usage:");
gm_cli_put_str(p_temp->usage);
gm_cli_put_str("\r\n");
found_flag = 1;
break;
}
p_temp = gm_cli_get_next_cmd((const int*)p_temp);
}
if (found_flag == 0)
{
gm_cli_put_str("Not found command \"");
gm_cli_put_str(argv[1]);
gm_cli_put_str("\"\r\n");
}
}
else
{
gm_cli_put_str("Too many args! Only support less then 2 args\r\n");
}
return 0;
}
/* 导出help命令 */
GM_CLI_CMD_EXPORT(help,
"help [cmd-name] -- list the command and usage",
gm_cli_internal_cmd_help);
/* 设置help的别名'?' */
GM_CLI_CMD_ALIAS(help, "?");
/* 内部命令-history */
CMD_CB_CALL_PREFIX int gm_cli_internal_cmd_history(int argc, char* argv[])
{
unsigned int i, count, num;
if (argc == 1)
{
num = gm_cli_mgr.history_total;
}
else if (argc == 2)
{
count = atoi(argv[1]);
if (gm_cli_mgr.history_total > count)
{
num = count;
}
else
{
num = gm_cli_mgr.history_total;
}
}
else
{
gm_cli_put_str("Too many args! Only support less then 2 args\r\n");
return 0;
}
for (i = 0, count = gm_cli_mgr.history_index; i < num; i++)
{
if (count == 0)
{
count = GM_CLI_HISTORY_LINE_MAX - 1;
}
else
{
count--;
}
gm_cli_put_str(" ");
gm_cli_put_str(gm_cli_mgr.history_str[count]);
gm_cli_put_str("\r\n");
}
return 0;
}
/* 导出history命令 */
GM_CLI_CMD_EXPORT(history,
"history [num] -- list the history command",
gm_cli_internal_cmd_history);
/* 内部命令-test */
CMD_CB_CALL_PREFIX int gm_cli_internal_cmd_test(int argc, char* argv[])
{
gm_cli_printf("cmd -> %s\r\n", argv[0]);
for (int i = 1; i < argc; i++)
{
gm_cli_printf("arg%d -> %s\r\n", i, argv[i]);
}
return 0;
}
/* 导出test命令 */
GM_CLI_CMD_EXPORT(test,
"test [args] -- test the cli",
gm_cli_internal_cmd_test);
C
1
https://gitee.com/WennianYan/gm_cli.git
git@gitee.com:WennianYan/gm_cli.git
WennianYan
gm_cli
通用命令行接口
develop

搜索帮助

53164aa7 5694891 3bd8fe86 5694891