mirror of
https://github.com/NevermindZZT/letter-shell.git
synced 2025-01-21 10:02:54 +08:00
772 lines
19 KiB
C
772 lines
19 KiB
C
/**
|
||
* @file shell.c
|
||
* @author Letter (NevermindZZT@gmail.cn)
|
||
* @brief letter shell
|
||
* @version 2.0.0
|
||
* @date 2018-12-29
|
||
*
|
||
* @Copyright (c) 2018 Letter
|
||
*
|
||
*/
|
||
|
||
#include "shell.h"
|
||
#include "string.h"
|
||
|
||
#if SHELL_AUTO_PRASE == 1
|
||
#include "shell_ext.h"
|
||
#endif
|
||
|
||
static unsigned short shellDisplay(SHELL_TypeDef *shell, const char *string);
|
||
static void shellDisplayItem(SHELL_TypeDef *shell, unsigned short index);
|
||
static void shellHelp(SHELL_TypeDef *shell, int argc, char *argv[]);
|
||
|
||
#if SHELL_USING_CMD_EXPORT != 1
|
||
/**
|
||
* @brief shell默认命令表
|
||
*
|
||
* @note 当使用命令表方式定义命令的时候,此表才会生效
|
||
* @note 添加命令时,可使用SHELL_CMD_ITEM宏,如SHELL_CMD_ITEM(help, shellHelp, command help)
|
||
* @note 可不使用默认命令表,初始化完成之后,可调用shellSetCommandList接口设置命令表
|
||
*/
|
||
const SHELL_CommandTypeDef shellDefaultCommandList[] =
|
||
{
|
||
SHELL_CMD_ITEM_EX(help, shellHelp, command help, help [command] --show help info of command),
|
||
};
|
||
#endif
|
||
|
||
|
||
/**
|
||
* @brief shell初始化
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
void shellInit(SHELL_TypeDef *shell)
|
||
{
|
||
shellDisplay(shell, "\r\n\r\n");
|
||
shellDisplay(shell, "+=========================================================+\r\n");
|
||
shellDisplay(shell, "| (C) COPYRIGHT 2018 Letter |\r\n");
|
||
shellDisplay(shell, "| Letter shell v"SHELL_VERSION" |\r\n");
|
||
shellDisplay(shell, "| Build: "__DATE__" "__TIME__" |\r\n");
|
||
shellDisplay(shell, "+=========================================================+\r\n");
|
||
shell->length = 0;
|
||
shell->cursor = 0;
|
||
shell->historyCount = 0;
|
||
shell->historyFlag = 0;
|
||
shell->historyOffset = 0;
|
||
shell->status = SHELL_IN_NORMAL;
|
||
shell->command = SHELL_DEFAULT_COMMAND;
|
||
shellDisplay(shell, shell->command);
|
||
|
||
#if SHELL_USING_CMD_EXPORT == 1
|
||
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
|
||
extern const unsigned int shellCommand$$Base;
|
||
extern const unsigned int shellCommand$$Limit;
|
||
|
||
shell->commandBase = (SHELL_CommandTypeDef *)(&shellCommand$$Base);
|
||
shell->commandNumber = ((unsigned int)(&shellCommand$$Limit)
|
||
- (unsigned int)(&shellCommand$$Base))
|
||
/ sizeof(SHELL_CommandTypeDef);
|
||
#elif defined(__ICCARM__)
|
||
shell->commandBase = (SHELL_CommandTypeDef *)(__section_begin("shellCommand"));
|
||
shell->commandNumber = ((unsigned int)(__section_end("shellCommand"))
|
||
- (unsigned int)(__section_begin("shellCommand")))
|
||
/ sizeof(SHELL_CommandTypeDef);
|
||
#elif defined(__GNUC__)
|
||
extern const unsigned int _shell_command_start;
|
||
extern const unsigned int _shell_command_end;
|
||
|
||
shell->commandBase = (SHELL_CommandTypeDef *)(&_shell_command_start);
|
||
shell->commandNumber = ((unsigned int)(&_shell_command_end)
|
||
- (unsigned int)(&_shell_command_start))
|
||
/ sizeof(SHELL_CommandTypeDef);
|
||
#else
|
||
#error not supported compiler, please use command table mode
|
||
#endif
|
||
#else
|
||
shell->commandBase = (SHELL_CommandTypeDef *)shellDefaultCommandList;
|
||
shell->commandNumber = sizeof(shellDefaultCommandList) / sizeof(SHELL_CommandTypeDef);
|
||
#endif
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell设置命令表
|
||
*
|
||
* @param shell shell对象
|
||
* @param base 命令表基址
|
||
* @param size 命令数量
|
||
*
|
||
* @note 此接口不可在shellInit之前调用
|
||
* @note 不调用此接口,则使用默认命令表或命令导出形成的命令表(取决于命令定义方式)
|
||
*/
|
||
void shellSetCommandList(SHELL_TypeDef *shell, SHELL_CommandTypeDef *base, unsigned short size)
|
||
{
|
||
shell->commandBase = base;
|
||
shell->commandNumber = size;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell显示字符串
|
||
*
|
||
* @param shell shell对象
|
||
* @param string 字符串
|
||
* @return unsigned short 字符串长度
|
||
*/
|
||
static unsigned short shellDisplay(SHELL_TypeDef *shell, const char *string)
|
||
{
|
||
unsigned short count = 0;
|
||
if (shell->write == NULL)
|
||
{
|
||
return 0;
|
||
}
|
||
while(*string)
|
||
{
|
||
shell->write(*string++);
|
||
count ++;
|
||
}
|
||
return count;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell显示字符
|
||
*
|
||
* @param data 字符
|
||
*/
|
||
static void shellDisplayByte(SHELL_TypeDef *shell, char data)
|
||
{
|
||
if (shell->write == NULL)
|
||
{
|
||
return;
|
||
}
|
||
shell->write(data);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell字符串复制
|
||
*
|
||
* @param dest 目标字符串
|
||
* @param src 源字符串
|
||
* @return unsigned short 字符串长度
|
||
*/
|
||
static unsigned short shellStringCopy(char *dest, char* src)
|
||
{
|
||
unsigned short count = 0;
|
||
while (*(src + count))
|
||
{
|
||
*(dest + count) = *(src + count);
|
||
count++;
|
||
}
|
||
*(dest + count) = 0;
|
||
return count;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell字符串比较
|
||
*
|
||
* @param dest 目标字符串
|
||
* @param src 源字符串
|
||
* @return unsigned short 匹配长度
|
||
*/
|
||
static unsigned short shellStringCompare(char* dest, char *src)
|
||
{
|
||
unsigned short match = 0;
|
||
unsigned short i = 0;
|
||
|
||
while (*(dest +i) && *(src + i))
|
||
{
|
||
if (*(dest + i) != *(src +i))
|
||
{
|
||
break;
|
||
}
|
||
match ++;
|
||
i++;
|
||
}
|
||
return match;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell删除
|
||
*
|
||
* @param shell shell对象
|
||
* @param length 删除的长度
|
||
*/
|
||
static void shellDelete(SHELL_TypeDef *shell, unsigned short length)
|
||
{
|
||
while (length--)
|
||
{
|
||
shellDisplay(shell, "\b \b");
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell清除输入
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
static void shellClearLine(SHELL_TypeDef *shell)
|
||
{
|
||
for (short i = shell->length - shell->cursor; i > 0; i--)
|
||
{
|
||
shellDisplayByte(shell, ' ');
|
||
}
|
||
shellDelete(shell, shell->length);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell历史记录添加
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
static void shellHistoryAdd(SHELL_TypeDef *shell)
|
||
{
|
||
if (strcmp(shell->history[shell->historyFlag - 1], shell->buffer) == 0)
|
||
{
|
||
return;
|
||
}
|
||
if (shellStringCopy(shell->history[shell->historyFlag], shell->buffer) != 0)
|
||
{
|
||
shell->historyFlag++;
|
||
}
|
||
if (++shell->historyCount > SHELL_HISTORY_MAX_NUMBER)
|
||
{
|
||
shell->historyCount = SHELL_HISTORY_MAX_NUMBER;
|
||
}
|
||
if (shell->historyFlag >= SHELL_HISTORY_MAX_NUMBER)
|
||
{
|
||
shell->historyFlag = 0;
|
||
}
|
||
shell->historyOffset = 0;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell历史记录查找
|
||
*
|
||
* @param shell shell对象
|
||
* @param dir 查找方向
|
||
*/
|
||
static void shellHistory(SHELL_TypeDef *shell, unsigned char dir)
|
||
{
|
||
if (dir == 0)
|
||
{
|
||
if (shell->historyOffset--
|
||
<= -((shell->historyCount > shell->historyFlag)
|
||
? shell->historyCount : shell->historyFlag))
|
||
{
|
||
shell->historyOffset = -((shell->historyCount > shell->historyFlag)
|
||
? shell->historyCount : shell->historyFlag);
|
||
}
|
||
}
|
||
else if (dir == 1)
|
||
{
|
||
if (++shell->historyOffset > 0)
|
||
{
|
||
shell->historyOffset = 0;
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
shellClearLine(shell);
|
||
if (shell->historyOffset == 0)
|
||
{
|
||
shell->cursor = shell->length = 0;
|
||
}
|
||
else
|
||
{
|
||
if ((shell->length = shellStringCopy(shell->buffer,
|
||
shell->history[(shell->historyFlag + SHELL_HISTORY_MAX_NUMBER
|
||
+ shell->historyOffset) % SHELL_HISTORY_MAX_NUMBER])) == 0)
|
||
{
|
||
return;
|
||
}
|
||
shell->cursor = shell->length;
|
||
shellDisplay(shell, shell->buffer);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell回车输入处理
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
static void shellEnter(SHELL_TypeDef *shell)
|
||
{
|
||
unsigned char paramCount = 0;
|
||
unsigned char quotes = 0;
|
||
unsigned char record = 1;
|
||
SHELL_CommandTypeDef *base;
|
||
unsigned char runFlag = 0;
|
||
|
||
if (shell->length == 0)
|
||
{
|
||
shellDisplay(shell, shell->command);
|
||
return;
|
||
}
|
||
|
||
*(shell->buffer + shell->length++) = 0;
|
||
|
||
shellHistoryAdd(shell);
|
||
|
||
for (unsigned short i = 0; i < shell->length; i++)
|
||
{
|
||
if ((quotes != 0 ||
|
||
(*(shell->buffer + i) != ' ' &&
|
||
*(shell->buffer + i) != '\t' &&
|
||
*(shell->buffer + i) != ',')) &&
|
||
*(shell->buffer + i) != 0)
|
||
{
|
||
if (*(shell->buffer + i) == '\"')
|
||
{
|
||
quotes = quotes ? 0 : 1;
|
||
#if SHELL_AUTO_PRASE == 0
|
||
*(shell->buffer + i) = 0;
|
||
continue;
|
||
#endif
|
||
}
|
||
if (record == 1)
|
||
{
|
||
shell->param[paramCount++] = shell->buffer + i;
|
||
record = 0;
|
||
}
|
||
if (*(shell->buffer + i) == '\\' &&
|
||
*(shell->buffer + i) != 0)
|
||
{
|
||
i++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*(shell->buffer + i) = 0;
|
||
record = 1;
|
||
}
|
||
}
|
||
shell->length = 0;
|
||
shell->cursor = 0;
|
||
if (paramCount == 0)
|
||
{
|
||
shellDisplay(shell, shell->command);
|
||
return;
|
||
}
|
||
|
||
shellDisplay(shell, "\r\n");
|
||
base = shell->commandBase;
|
||
if (strcmp((const char *)shell->param[0], "help") == 0)
|
||
{
|
||
shellHelp(shell, paramCount, shell->param);
|
||
shellDisplay(shell, shell->command);
|
||
return;
|
||
}
|
||
for (unsigned char i = 0; i < shell->commandNumber; i++)
|
||
{
|
||
if (strcmp((const char *)shell->param[0], (base + i)->name) == 0)
|
||
{
|
||
runFlag = 1;
|
||
#if SHELL_AUTO_PRASE == 0
|
||
(base + i)->function(paramCount, shell->param);
|
||
#else
|
||
shellExtRun((base + i)->function, paramCount, shell->param);
|
||
#endif
|
||
}
|
||
}
|
||
if (runFlag == 0)
|
||
{
|
||
shellDisplay(shell, "Command not found\r\n");
|
||
}
|
||
shellDisplay(shell, shell->command);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell退格输入处理
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
static void shellBackspace(SHELL_TypeDef *shell)
|
||
{
|
||
if (shell->length == 0)
|
||
{
|
||
return;
|
||
}
|
||
if (shell->cursor == shell->length)
|
||
{
|
||
shell->length--;
|
||
shell->cursor--;
|
||
shell->buffer[shell->length] = 0;
|
||
shellDelete(shell, 1);
|
||
}
|
||
else if (shell->cursor > 0)
|
||
{
|
||
for (short i = 0; i < shell->length - shell->cursor; i++)
|
||
{
|
||
shell->buffer[shell->cursor + i - 1] = shell->buffer[shell->cursor + i];
|
||
}
|
||
shell->length--;
|
||
shell->cursor--;
|
||
shell->buffer[shell->length] = 0;
|
||
shellDisplayByte(shell, '\b');
|
||
for (short i = shell->cursor; i < shell->length; i++)
|
||
{
|
||
shellDisplayByte(shell, shell->buffer[i]);
|
||
}
|
||
shellDisplayByte(shell, ' ');
|
||
for (short i = shell->length - shell->cursor + 1; i > 0; i--)
|
||
{
|
||
shellDisplayByte(shell, '\b');
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell Tab键输入处理
|
||
*
|
||
* @param shell shell对象
|
||
*/
|
||
static void shellTab(SHELL_TypeDef *shell)
|
||
{
|
||
unsigned short maxMatch = SHELL_COMMAND_MAX_LENGTH;
|
||
unsigned short lastMatchIndex = 0;
|
||
unsigned short matchNum = 0;
|
||
unsigned short length;
|
||
SHELL_CommandTypeDef *base = shell->commandBase;
|
||
|
||
if (shell->length != 0)
|
||
{
|
||
shell->buffer[shell->length] = 0;
|
||
for (short i = 0; i < shell->commandNumber; i++)
|
||
{
|
||
if (shellStringCompare(shell->buffer,
|
||
(char *)(base + i)->name)
|
||
== shell->length)
|
||
{
|
||
if (matchNum != 0)
|
||
{
|
||
if (matchNum == 1)
|
||
{
|
||
shellDisplay(shell, "\r\n");
|
||
}
|
||
shellDisplayItem(shell, lastMatchIndex);
|
||
length = shellStringCompare((char *)(base + lastMatchIndex)->name,
|
||
(char *)(base +i)->name);
|
||
maxMatch = (maxMatch > length) ? length : maxMatch;
|
||
}
|
||
lastMatchIndex = i;
|
||
matchNum ++;
|
||
}
|
||
}
|
||
|
||
if (matchNum == 0)
|
||
{
|
||
return;
|
||
}
|
||
if (matchNum == 1)
|
||
{
|
||
shellClearLine(shell);
|
||
}
|
||
if (matchNum != 0)
|
||
{
|
||
shell->length = shellStringCopy(shell->buffer,
|
||
(char *)(base + lastMatchIndex)->name);
|
||
}
|
||
if (matchNum > 1)
|
||
{
|
||
shellDisplayItem(shell, lastMatchIndex);
|
||
shellDisplay(shell, shell->command);
|
||
shell->length = maxMatch;
|
||
}
|
||
shell->buffer[shell->length] = 0;
|
||
shell->cursor = shell->length;
|
||
shellDisplay(shell, shell->buffer);
|
||
}
|
||
else
|
||
{
|
||
shellHelp(shell, 1, (void *)0);
|
||
shellDisplay(shell, shell->command);
|
||
}
|
||
|
||
#if SHELL_LONG_HELP == 1
|
||
static int time = 0;
|
||
|
||
if (SHELL_GET_TICK())
|
||
{
|
||
if (matchNum == 1 && SHELL_GET_TICK() - time < SHELL_DOUBLE_CLICK_TIME)
|
||
{
|
||
shellClearLine(shell);
|
||
for (short i = shell->length; i >= 0; i--)
|
||
{
|
||
shell->buffer[i + 5] = shell->buffer[i];
|
||
}
|
||
shellStringCopy(shell->buffer, "help");
|
||
shell->buffer[4] = ' ';
|
||
shell->length += 5;
|
||
shell->cursor = shell->length;
|
||
shellDisplay(shell, shell->buffer);
|
||
}
|
||
time = SHELL_GET_TICK();
|
||
}
|
||
#endif /** SHELL_LONG_HELP == 1 */
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell正常按键处理
|
||
*
|
||
* @param shell shell对象
|
||
* @param data 输入的数据
|
||
*/
|
||
static void shellNormal(SHELL_TypeDef *shell, char data)
|
||
{
|
||
|
||
if (shell->length < SHELL_COMMAND_MAX_LENGTH - 1)
|
||
{
|
||
if (shell->length == shell->cursor)
|
||
{
|
||
shell->buffer[shell->length++] = data;
|
||
shell->cursor++;
|
||
shellDisplayByte(shell, data);
|
||
}
|
||
else
|
||
{
|
||
for (short i = shell->length - shell->cursor; i > 0; i--)
|
||
{
|
||
shell->buffer[shell->cursor + i] = shell->buffer[shell->cursor + i - 1];
|
||
}
|
||
shell->buffer[shell->cursor++] = data;
|
||
shell->buffer[++shell->length] = 0;
|
||
for (short i = shell->cursor - 1; i < shell->length; i++)
|
||
{
|
||
shellDisplayByte(shell, shell->buffer[i]);
|
||
}
|
||
for (short i = shell->length - shell->cursor; i > 0; i--)
|
||
{
|
||
shellDisplayByte(shell, '\b');
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
shellDisplay(shell, "\r\nWarnig: Command is too long\r\n");
|
||
shellDisplay(shell, shell->command);
|
||
shellDisplay(shell, shell->buffer);
|
||
shell->cursor = shell->length;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell ansi控制系列处理
|
||
*
|
||
* @param shell shell对象
|
||
* @param data 输入的数据
|
||
*/
|
||
void shellAnsi(SHELL_TypeDef *shell, char data)
|
||
{
|
||
switch ((unsigned char)(shell->status))
|
||
{
|
||
case SHELL_ANSI_CSI:
|
||
switch (data)
|
||
{
|
||
case 0x41: /** 方向上键 */
|
||
shellHistory(shell, 0);
|
||
break;
|
||
|
||
case 0x42: /** 方向下键 */
|
||
shellHistory(shell, 1);
|
||
break;
|
||
|
||
case 0x43: /** 方向右键 */
|
||
if (shell->cursor < shell->length)
|
||
{
|
||
shellDisplayByte(shell, shell->buffer[shell->cursor]);
|
||
shell->cursor++;
|
||
}
|
||
break;
|
||
|
||
case 0x44: /** 方向左键 */
|
||
if (shell->cursor > 0)
|
||
{
|
||
shellDisplayByte(shell, '\b');
|
||
shell->cursor--;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
shell->status = SHELL_IN_NORMAL;
|
||
break;
|
||
|
||
case SHELL_ANSI_ESC:
|
||
if (data == 0x5B)
|
||
{
|
||
shell->status = SHELL_ANSI_CSI;
|
||
}
|
||
else
|
||
{
|
||
shell->status = SHELL_IN_NORMAL;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell处理
|
||
*
|
||
* @param shell shell对象
|
||
* @param data 输入数据
|
||
*/
|
||
void shellHandler(SHELL_TypeDef *shell, char data)
|
||
{
|
||
if (shell->status == SHELL_IN_NORMAL)
|
||
{
|
||
switch (data)
|
||
{
|
||
case '\r':
|
||
case '\n':
|
||
shellEnter(shell);
|
||
break;
|
||
|
||
case '\b':
|
||
case 0x7F:
|
||
shellBackspace(shell);
|
||
break;
|
||
|
||
case '\t':
|
||
shellTab(shell);
|
||
break;
|
||
|
||
case 0x1B:
|
||
shell->status = SHELL_ANSI_ESC;
|
||
break;
|
||
|
||
default:
|
||
shellNormal(shell, data);
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
shellAnsi(shell, data);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
#if SHELL_USING_TASK == 1
|
||
/**
|
||
* @brief shell 任务
|
||
*
|
||
* @param param shell对象
|
||
*
|
||
* @note 使用操作系统时,定义的shell read函数必须是阻塞式的
|
||
* @note 不使用操作系统时,可以通过不断查询的方式使用shell,修改宏SHELL_TASK_WHILE
|
||
* 为0,然后在主循环中不断调用此函数
|
||
*/
|
||
void shellTask(void *param)
|
||
{
|
||
SHELL_TypeDef *shell = (SHELL_TypeDef *)param;
|
||
char data;
|
||
if (shell->read == NULL)
|
||
{
|
||
shellDisplay(shell, "error: shell.read() must be defined\r\n");
|
||
while (1) ;
|
||
}
|
||
#if SHELL_TASK_WHILE == 1
|
||
while (1)
|
||
{
|
||
#endif
|
||
if (shell->read(&data) == 0)
|
||
{
|
||
shellHandler(shell, data);
|
||
}
|
||
#if SHELL_TASK_WHILE == 1
|
||
}
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
|
||
/**
|
||
* @brief shell显示一条命令信息
|
||
*
|
||
* @param shell shell对象
|
||
* @param index 要显示的命令索引
|
||
*/
|
||
static void shellDisplayItem(SHELL_TypeDef *shell, unsigned short index)
|
||
{
|
||
unsigned short spaceLength;
|
||
SHELL_CommandTypeDef *base = shell->commandBase;
|
||
|
||
spaceLength = 22 - shellDisplay(shell, (base + index)->name);
|
||
spaceLength = (spaceLength > 0) ? spaceLength : 4;
|
||
do {
|
||
shellDisplay(shell, " ");
|
||
} while (--spaceLength);
|
||
shellDisplay(shell, "--");
|
||
shellDisplay(shell, (base + index)->desc);
|
||
shellDisplay(shell, "\r\n");
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief shell帮助
|
||
*
|
||
* @param shell shell对象
|
||
* @param argc 参数个数
|
||
* @param argv 参数
|
||
*/
|
||
static void shellHelp(SHELL_TypeDef *shell, int argc, char *argv[])
|
||
{
|
||
#if SHELL_LONG_HELP == 1
|
||
if (argc == 1)
|
||
{
|
||
#endif /** SHELL_LONG_HELP == 1 */
|
||
shellDisplay(shell, "\r\nCOMMAND LIST:\r\n\r\n");
|
||
for(unsigned short i = 0; i < shell->commandNumber; i++)
|
||
{
|
||
shellDisplayItem(shell, i);
|
||
}
|
||
#if SHELL_LONG_HELP == 1
|
||
}
|
||
else if (argc == 2) {
|
||
SHELL_CommandTypeDef *base = shell->commandBase;
|
||
for (unsigned char i = 0; i < shell->commandNumber; i++)
|
||
{
|
||
if (strcmp((const char *)argv[1], (base + i)->name) == 0)
|
||
{
|
||
|
||
shellDisplay(shell, "command help --");
|
||
shellDisplay(shell, (base + i)->name);
|
||
shellDisplay(shell, ":\r\n");
|
||
shellDisplay(shell, (base + i)->desc);
|
||
shellDisplay(shell, "\r\n");
|
||
if ((base + i)->help)
|
||
{
|
||
shellDisplay(shell, (base + i)->help);
|
||
shellDisplay(shell, "\r\n");
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
shellDisplay(shell, "command not found\r\n");
|
||
}
|
||
#endif /** SHELL_LONG_HELP == 1 */
|
||
}
|
||
SHELL_EXPORT_CMD_EX(help, shellHelp, command help, help [command] --show help info of command);
|