ReadLine使用

前言

最近看到不少服务自带命令行,可以查询当前服务运行状态,感觉非常有用,这样就可以实时查询状态,不必打印各种日志,简化后续维护工作

Readline示例

借用人家的,稍微改了点点

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>

/* 提示符 */
#define PROMPT "clover>>"

//命令结构体
typedef int (*CmdProcFunc)(void);
typedef struct{
    char         *pszCmd;
    CmdProcFunc  fpCmd;
}CMD_PROC;

//命令处理函数定义
#define MOCK_FUNC(funcName) \
    int funcName(void){printf("  Enter "#funcName"!\n"); return 0;}

MOCK_FUNC(ShowMeInfo);
MOCK_FUNC(SetLogCtrl);
MOCK_FUNC(TestBatch);
MOCK_FUNC(TestEndianOper);

//命令表项宏,用于简化书写
#define CMD_ENTRY(cmdStr, func)     {cmdStr, func}
#define CMD_ENTRY_END               {NULL,   NULL}

//命令表
static CMD_PROC gCmdMap[] = {
    CMD_ENTRY("ShowMeInfo",       ShowMeInfo),
    CMD_ENTRY("SetLogCtrl",       SetLogCtrl),
    CMD_ENTRY("TestBatch",        TestBatch),
    CMD_ENTRY("TestEndian",       TestEndianOper),

    CMD_ENTRY_END
};
#define CMD_MAP_NUM     (sizeof(gCmdMap)/sizeof(CMD_PROC)) - 1/*End*/

//返回gCmdMap中的CmdStr列(必须为只读字符串),以供CmdGenerator使用
static char *GetCmdByIndex(unsigned int dwCmdIndex)
{
    if(dwCmdIndex >=  CMD_MAP_NUM)
        return NULL;
    return gCmdMap[dwCmdIndex].pszCmd;
}

//执行命令
static int ExecCmd(char *pszCmdLine)
{
    if(NULL == pszCmdLine)
        return -1;

    unsigned int dwCmdIndex = 0;
    for(; dwCmdIndex < CMD_MAP_NUM; dwCmdIndex++)
    {
        if(!strcmp(pszCmdLine, gCmdMap[dwCmdIndex].pszCmd))
            break;
    }
    if(CMD_MAP_NUM == dwCmdIndex)
        return -1;
    gCmdMap[dwCmdIndex].fpCmd(); //调用相应的函数

    return 0;
}

//剔除字符串首尾的空白字符(含空格)
static char *StripWhite(char *pszOrig)
{
    if(NULL == pszOrig)
        return "NUL";

    char *pszStripHead = pszOrig;
    while(isspace(*pszStripHead))
        pszStripHead++;

    if('\0' == *pszStripHead)
        return pszStripHead;

    char *pszStripTail = pszStripHead + strlen(pszStripHead) - 1;
    while(pszStripTail > pszStripHead && isspace(*pszStripTail))
        pszStripTail--;
    *(++pszStripTail) = '\0';

    return pszStripHead;
}

void ReadCmdLine(char *cmd, size_t cmdlen)
{
    //读取用户输入的命令行
    char *pRead = readline(PROMPT);

    //剔除命令行首尾的空白字符。若剔除后的命令不为空,则存入历史列表
    char *pTrim = StripWhite(pRead);
    if(pTrim && *pTrim)
    {
        add_history(pTrim);
    }
    snprintf(cmd, cmdlen, "%s", pTrim);

    free(pRead);
    pRead = NULL;

    return;
}

static char *CmdGenerator(const char *pszText, int dwState)
{
    static int dwListIdx = 0, dwTextLen = 0;
    if(!dwState)
    {
        dwListIdx = 0;
        dwTextLen = strlen(pszText);
    }

    //rl_line_buffer用户全部输入内容
    //printf("%s, %d,%s\n", pszText, dwState,rl_line_buffer);

    //当输入字符串与命令列表中某命令部分匹配时,返回该命令字符串
    const char *pszName = NULL;
    while((pszName = GetCmdByIndex(dwListIdx)))
    {
        dwListIdx++;

        if(!strncmp (pszName, pszText, dwTextLen))
        {
            return strdup(pszName);
        }
    }

    rl_attempted_completion_over = 1;//不进行文件匹配
    return NULL;
}

static char **CmdCompletion(const char *pszText, int dwStart, int dwEnd)
{
    char **pMatches = NULL;

    if(0 == dwStart)    /* 进处理第一个单词 */
    {
        pMatches = rl_completion_matches(pszText, CmdGenerator);
    }
    else
    {
        /* 后续单词不处理,可根据需要修改 */
        rl_attempted_completion_over = 1;//不进行文件匹配
    }

    return pMatches;
}

int main(void)
{
    char cmd[128];
    /* 初始化自动补全函数 */
    rl_attempted_completion_function = CmdCompletion;
    /* 主循环 */
    while(1)
    {
        cmd[0] = '\0';
        /* 读取输入 */
        ReadCmdLine(cmd, sizeof(cmd));
        /* 执行命令 */
        ExecCmd(cmd);
    }

    return 0;
}

编译:

gcc -Wall -o ReadLine Readline.c  -lreadline -lncurses

示例比较简单,就是输入一些东西,然后能通过TAB自动补全或显示待选项
先调用readline函数进行输入处理,readline中会响应tab键,然后在屏幕上输出待选项在这里插入图片描述
readline会调用rl_attempted_completion_function,该函数会进行补全处理
如果输入的内容不能匹配预制的内容,那么默认动作会去匹配文件夹下的文件T_T
如果不想匹配文件那么把rl_attempted_completion_over设置成非0即可^_^

未解决问题

内存检查发现有泄漏

valgrind --leak-check=full --show-reachable=yes ./ReadLine

==21728== LEAK SUMMARY:
==21728==    definitely lost: 0 bytes in 0 blocks
==21728==    indirectly lost: 0 bytes in 0 blocks
==21728==      possibly lost: 0 bytes in 0 blocks
==21728==    still reachable: 90,251 bytes in 167 blocks
==21728==         suppressed: 0 bytes in 0 blocks

还不知道怎么解决,请各路大神指教

参考

https://blog.csdn.net/xuancbm/article/details/81436681
https://www.cnblogs.com/clover-toeic/p/3892688.html
https://tiswww.case.edu/php/chet/readline/readline.html#IDX256

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值