1. 增加Vector方法
2. 增加HShellLex
This commit is contained in:
parent
164b291f11
commit
18573eae26
103
include/HShellLex.h
Normal file
103
include/HShellLex.h
Normal file
@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
#ifndef _H_SHELL_LEX_
|
||||
#define _H_SHELL_LEX_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef uint8_t HShellLenType;
|
||||
#define HSHELL_ERROR_INDEX (0xff)
|
||||
|
||||
///< 可配置最多可注册回调多少个
|
||||
#ifndef HSHELL_CALL_MAX
|
||||
#define HSHELL_CALL_MAX 5
|
||||
#endif
|
||||
|
||||
///< 命令行缓存长度
|
||||
#ifndef HSHELL_CMD_LINE_BUFFER
|
||||
#define HSHELL_CMD_LINE_BUFFER 32
|
||||
#endif
|
||||
|
||||
///< 解析token参数的最大个数
|
||||
#ifndef HSHELL_CMD_TOKEN_MAX
|
||||
#define HSHELL_CMD_TOKEN_MAX 5
|
||||
#endif
|
||||
|
||||
///< 使用专门接口避免日志系统关闭日志打印导致命令不输出的问题
|
||||
#define HSHELL_PRINTF(format, ...) printf(format, ##__VA_ARGS__)
|
||||
|
||||
|
||||
///< 处理命令行token
|
||||
typedef struct __attribute__ ((__packed__)) HShellCmdToken
|
||||
{
|
||||
const uint8_t* str; ///< 指向每项数据开头, 如 echo 123 会有2个token, 一个str指向echo, 一个str指向123
|
||||
uint8_t len; ///< 数据长度
|
||||
} HShellCmdToken;
|
||||
|
||||
// 匹配映射表初始化每项的辅助宏
|
||||
#define HSHELL_MATCH_ITEM(token, str) {token, sizeof(str) - 1, (const uint8_t *)str}
|
||||
|
||||
///< 匹配映射表
|
||||
typedef struct __attribute__ ((__packed__)) HShellMatch
|
||||
{
|
||||
HShellLenType token; ///< 匹配后对应的映射值
|
||||
uint8_t matchLen; ///< 需要匹配的字符串长度
|
||||
const uint8_t *match; ///< 需要匹配的字符串
|
||||
} HShellMatch;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 命令行解析回调
|
||||
* @param key 命令行解析的首个token
|
||||
* @param tokens 原始token, 可自行处理后续命令的所需的参数
|
||||
* @param tokensLen 原始token个数
|
||||
**/
|
||||
typedef void (*shellCall)(HShellLenType key, const HShellCmdToken *tokens, int tokensLen);
|
||||
|
||||
/**
|
||||
* @brief 解析命令行数据, 将解析后的数据写入tokens, 内存还是str, tokens是指向tokens的指针
|
||||
* @brief str 命令行数据
|
||||
* @brief strLen 命令行数据长度
|
||||
* @brief tokens 命令行解析后写入的token
|
||||
* @brief tokensLen toknes长度
|
||||
* @return 返回token个数
|
||||
**/
|
||||
uint8_t HShellLex(const uint8_t *str, int strLen, HShellCmdToken *tokens, int tokensLen);
|
||||
|
||||
/**
|
||||
* @brief 查找token匹配对应token枚举值, 判断是否忽略大小写
|
||||
* @param token 命令行解析的token
|
||||
* @param matches 匹配映射表
|
||||
* @param matchLen 匹配映射表个数
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 返回对应token映射值, 如果不存在返回 HSHELL_ERROR_INDEX
|
||||
**/
|
||||
HShellLenType HShellMatchToken(const HShellCmdToken *token, const HShellMatch *matches, int matchLen, uint8_t ignoreCase);
|
||||
|
||||
/**
|
||||
* @brief 注册命令行解析回调, 如果存在匹配映射表则覆盖原有映射
|
||||
* @param matches 匹配映射表
|
||||
* @param matchLen 匹配映射表个数
|
||||
* @param call 命令行解析回调
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 返回注册的索引, 错误返回 -1
|
||||
**/
|
||||
int16_t HSHellRegister(const HShellMatch *matches, int matchLen, shellCall call, uint8_t ignoreCase);
|
||||
|
||||
/**
|
||||
* @brief 注销命令行解析回调
|
||||
* @param index 注销的索引
|
||||
**/
|
||||
void HSHellUnregister(int16_t index);
|
||||
|
||||
/**
|
||||
* @brief 添加命令行数据, 直到换行'\n'才处理
|
||||
* @param str 命令行数据
|
||||
* @param strLen 命令行数据长度
|
||||
**/
|
||||
void HShellAddCmdData(uint8_t data);
|
||||
void HSHellAddCmdDatas(uint8_t *data, int len);
|
||||
|
||||
#endif // _H_SHELL_LEX_
|
||||
@ -100,10 +100,13 @@ typedef struct __attribute__ ((__packed__)) _HVector32 {
|
||||
|
||||
// 添加数据, 成功返回1, 失败返回 0
|
||||
uint8_t HVectorAddData(HVectorType *vector, HVectorDataType data);
|
||||
uint8_t HVectorInsertData(HVectorType *vector, HVectorLenType index, HVectorDataType data);
|
||||
// 添加字节数据, 超出仅复制到最大长度, 返回复制长度
|
||||
HVectorLenType HVectorAddBytes(HVectorType *vector, const uint8_t *datas, HVectorLenType byteLen);
|
||||
// 添加对应格式数据, 要求datas类型是同一对应位类型, 长度为字节长度, 超出仅复制到最大长度, 返回复制长度
|
||||
HVectorLenType HVectorAddDatas(HVectorType *vector, const void *datas, HVectorLenType byteLen);
|
||||
// 设置数据, 可超出使用长度, 用于配置空字符
|
||||
void HVectorSetData(HVectorType *vector, HVectorLenType index, HVectorDataType data);
|
||||
|
||||
// 获取数据, 失败返回 HVECTOR_ERROR
|
||||
HVectorDataType HVectorGetData(HVectorType *vector, HVectorLenType index);
|
||||
|
||||
249
src/HShellLex.c
Normal file
249
src/HShellLex.c
Normal file
@ -0,0 +1,249 @@
|
||||
|
||||
|
||||
#include <HShellLex.h>
|
||||
#include <HVector.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#ifndef LogD
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#define LogD(format, ...) printf("[%s:%s:%d]" format "\r\n", __FILE_NAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LogD(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||
|
||||
|
||||
struct __attribute__((packed)) HShellCmd {
|
||||
const HShellMatch *match; ///< 匹配表
|
||||
shellCall call; ///< 回调
|
||||
uint8_t matchLen; ///< 匹配表长度
|
||||
uint8_t ignoreCase : 1; ///< 忽略大小写
|
||||
};
|
||||
|
||||
// 回调注册
|
||||
static struct HShellCmd shellCmd_[HSHELL_CALL_MAX];
|
||||
// 命令行数据
|
||||
static HVECTOR_DEFINE(cmdBuffer_, HSHELL_CMD_LINE_BUFFER);
|
||||
// 解析参数
|
||||
static HShellCmdToken cmdTokens_[HSHELL_CMD_TOKEN_MAX];
|
||||
// 光标位置
|
||||
static uint8_t cursorPos;
|
||||
|
||||
|
||||
uint8_t HShellLex(const uint8_t *str, int strLen, HShellCmdToken *tokens, int tokensLen) {
|
||||
if (str == NULL || tokens == NULL || tokensLen <= 0) {
|
||||
LogD("str[%p] is nullptr or Tokens[%p] is nullptr or len[%d]", str, tokens, tokensLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tokenIndex = 0;
|
||||
for (int i = 0; i < strLen; ++i) {
|
||||
if (tokenIndex >= tokensLen) {
|
||||
LogD("Tokens[%d] is full, index[%d], currParseIndex[%d]", tokensLen, tokenIndex, i);
|
||||
break;
|
||||
}
|
||||
|
||||
// 跳过空白字符
|
||||
if (isspace(str[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int j = i;
|
||||
for (; j < strLen; ++j) {
|
||||
if (isspace(str[j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tokens[tokenIndex].str = str + i;
|
||||
tokens[tokenIndex].len = j - i;
|
||||
tokenIndex++;
|
||||
i = j;
|
||||
}
|
||||
|
||||
return tokenIndex;
|
||||
}
|
||||
|
||||
HShellLenType HShellMatchToken(const HShellCmdToken *token, const HShellMatch *matches, int matchesLen, uint8_t ignoreCase) {
|
||||
if (token == NULL || matches == NULL || matchesLen <= 0) {
|
||||
LogD("Tokens[%p] or matches[%p] is nullptr or len[%d]", token, matches, matchesLen);
|
||||
return HSHELL_ERROR_INDEX;
|
||||
}
|
||||
|
||||
int (*cmpFunc)(const char *, const char *, size_t) = ignoreCase ? strncasecmp : strncmp;
|
||||
for (int i = 0; i < matchesLen; ++i) {
|
||||
if (token->len != matches[i].matchLen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmpFunc((const char *)token->str, (const char *)matches[i].match, token->len) == 0) {
|
||||
return matches[i].token;
|
||||
}
|
||||
}
|
||||
|
||||
return HSHELL_ERROR_INDEX;
|
||||
}
|
||||
|
||||
int16_t HSHellRegister(const HShellMatch *matches, int matchLen, shellCall call, uint8_t ignoreCase) {
|
||||
if (matches == NULL || matchLen <= 0 || call == NULL) {
|
||||
LogD("matches[%p] or matchLen[%d] or call[%p] is nullptr", matches, matchLen, call);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < HSHELL_CALL_MAX; ++i) {
|
||||
if (shellCmd_[i].match == matches) {
|
||||
LogD("call[%p] is exist, override write index[%d]", call, i);
|
||||
shellCmd_[i].call = call;
|
||||
shellCmd_[i].matchLen = matchLen;
|
||||
shellCmd_[i].ignoreCase = ignoreCase ? 1 : 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
if (shellCmd_[i].match == NULL) {
|
||||
shellCmd_[i].match = matches;
|
||||
shellCmd_[i].call = call;
|
||||
shellCmd_[i].matchLen = matchLen;
|
||||
shellCmd_[i].ignoreCase = ignoreCase ? 1 : 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
LogD("call table is full");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void HSHellUnregister(int16_t index) {
|
||||
if (index < 0 || index >= HSHELL_CALL_MAX) {
|
||||
LogD("error index[%d]", index);
|
||||
return;
|
||||
}
|
||||
|
||||
shellCmd_[index].match = NULL;
|
||||
shellCmd_[index].call = NULL;
|
||||
shellCmd_[index].matchLen = 0;
|
||||
}
|
||||
|
||||
static void ShellParse()
|
||||
{
|
||||
if (HVectorEmpty(cmdBuffer_)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
uint8_t len = HShellLex((const uint8_t *)HVectorGetByteDataPtr(cmdBuffer_, 0), HVectorGetUseByteLen(cmdBuffer_), cmdTokens_, HSHELL_CMD_TOKEN_MAX);
|
||||
LogD("lex parse len[%d], dataLen[%d]", len, HVectorGetUseByteLen(cmdBuffer_));
|
||||
if (len <= 0) {
|
||||
LogD("lex parse len[%d] empty", len);
|
||||
return ;
|
||||
}
|
||||
|
||||
for (int i = 0; i < HSHELL_CALL_MAX; ++i) {
|
||||
if (shellCmd_[i].match == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HShellLenType key = HShellMatchToken(cmdTokens_, shellCmd_[i].match, shellCmd_[i].matchLen, shellCmd_[i].ignoreCase);
|
||||
if (key != HSHELL_ERROR_INDEX) {
|
||||
shellCmd_[i].call(key, cmdTokens_, len);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintCmdData() {
|
||||
if (HVectorEmpty(cmdBuffer_)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
HVectorSetData(cmdBuffer_, HVectorGetUseLen(cmdBuffer_), '\0');
|
||||
HSHELL_PRINTF("\r\x1b[K%s", (const char *)HVectorGetByteDataPtr(cmdBuffer_, 0));
|
||||
}
|
||||
|
||||
///< 返回1需要打印数据
|
||||
static uint8_t AddCmdData(uint8_t data) {
|
||||
enum eEscStaus {
|
||||
kEscNone,
|
||||
kEsc,
|
||||
kEscCsi,
|
||||
};
|
||||
|
||||
static uint8_t escStatus = kEscNone;
|
||||
switch (escStatus) {
|
||||
case kEsc: {
|
||||
if (data == '[') {
|
||||
escStatus = kEscCsi;
|
||||
return 0;
|
||||
}
|
||||
} break;
|
||||
case kEscCsi: {
|
||||
if (data == 'D') {
|
||||
// 左键
|
||||
if (cursorPos > 0) {
|
||||
--cursorPos;
|
||||
}
|
||||
return 0;
|
||||
} else if (data == 'C') {
|
||||
// 右键
|
||||
if (cursorPos < HVectorGetUseLen(cmdBuffer_)) {
|
||||
++cursorPos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
escStatus = kEscNone;
|
||||
switch (data) {
|
||||
case 0x1b: escStatus = kEsc; return 0;
|
||||
case '\t':
|
||||
case '\r': return 0;
|
||||
case '\n': {
|
||||
cursorPos = 0;
|
||||
ShellParse();
|
||||
HVectorClear(cmdBuffer_);
|
||||
} return 0;
|
||||
case '\b': {
|
||||
if (cursorPos > 0) {
|
||||
HVectorRemoveData(cmdBuffer_, cursorPos - 1, 1);
|
||||
cursorPos--;
|
||||
}
|
||||
} return 1;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (isprint(data) == 0) {
|
||||
LogD("not print char[%x]", data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (HVectorInsertData(cmdBuffer_, cursorPos, data) == 0) {
|
||||
LogD("buffer is full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cursorPos++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void HShellAddCmdData(uint8_t data) {
|
||||
if (AddCmdData(data)) {
|
||||
PrintCmdData();
|
||||
}
|
||||
}
|
||||
|
||||
void HSHellAddCmdDatas(uint8_t *data, int len) {
|
||||
uint8_t needPrint = 0;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
needPrint |= AddCmdData(data[i]);
|
||||
}
|
||||
|
||||
if (HVectorGetUseLen(cmdBuffer_) > 0 && needPrint) {
|
||||
PrintCmdData();
|
||||
}
|
||||
}
|
||||
@ -136,6 +136,21 @@ uint8_t HVectorAddData(HVectorType *vector, HVectorDataType data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t HVectorInsertData(HVectorType *vector, HVectorLenType index, HVectorDataType data) {
|
||||
HVectorLenType len = GetVectorUseLen(vector);
|
||||
if (index > len) {
|
||||
LogD("index[%d] error, len[%d]", index, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HVectorLenType typeSize = GetVectorTypeSize(vector);
|
||||
uint8_t *dest = (uint8_t *)GetVectorDataBytePtr(vector, index * typeSize);
|
||||
memmove(dest + typeSize, dest, (len - index) * typeSize);
|
||||
SetVectorData(vector, index, data);
|
||||
SetVectorUseLen(vector, len + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
HVectorLenType HVectorAddBytes(HVectorType *vector, const uint8_t *datas, HVectorLenType byteLen) {
|
||||
HVectorLenType useLen = GetVectorUseLen(vector);
|
||||
HVectorLenType maxLen = GetVectorByteLen(vector) - useLen;
|
||||
@ -158,6 +173,14 @@ HVectorLenType HVectorAddDatas(HVectorType *vector, const void *datas, HVectorLe
|
||||
return HVectorAddBytes(vector, (const uint8_t *)datas, byteLen * GetVectorTypeSize(vector)) / GetVectorTypeSize(vector);
|
||||
}
|
||||
|
||||
void HVectorSetData(HVectorType *vector, HVectorLenType index, HVectorDataType data) {
|
||||
if (index >= GetVectorLen(vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetVectorData(vector, index, data);
|
||||
}
|
||||
|
||||
// 获取数据, 失败返回 HVECTOR_ERROR
|
||||
HVectorDataType HVectorGetData(HVectorType *vector, HVectorLenType index) {
|
||||
return GetVectorData(vector, index);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user