1. 增加Vector方法

2. 增加HShellLex
This commit is contained in:
coffee 2025-04-24 14:25:55 +08:00
parent 164b291f11
commit 18573eae26
4 changed files with 378 additions and 0 deletions

103
include/HShellLex.h Normal file
View 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_

View File

@ -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
View 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();
}
}

View File

@ -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);