linenoise是一个命令行编辑库(line editing library),readline的替代品,可以用于tab自动补全方法的实现。目前linenoise已经在Redis, MongoDB,Android中使用。其支持特性如下:
1) 尽可能简小,无配置,支持BSD授权。
2) 单行或多行编辑模式,实现常用的快捷键绑定。
3)支持历史键入文本查询。
4)兼容性。
5)大约只有1100行代码。
6)只使用VT100 escapes键码的子集。
注:readline是一个提供了交互式的文本编辑功能的开源跨平台程序库,它最早由Brian Fox使用C语言开发,于1989年发布。
linenoise库核心文件仅仅是linenoise.c和linenoise.h,在linenoise.h中定义了一个数据结构linenoiseCompletions,用于记录一行行完整的匹配输入。
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
其中:
a)len表示完整的匹配输入的数目。
b)cvec相当于一个二维字符数组char[len][ ],用于记录len条匹配输入。
注意:真正的匹配输入需要在自己的注册函数中完成,也就是linenoise中的completionCallback。
static linenoiseCompletionCallback *completionCallback = NULL;
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
图3.2 History函数调用
4、函数通过linenoiseHistoryLoad提供用户加载文件中的history记录,需要用户自己调用。
其实linenoiseHistoryLoad也是通过linenoiseHistoryAdd来添加history历史记录的,linenoiseHistoryAdd也可以供用户自己调用。
5、对于与linenoise edit相关度函数都是在completeEdit()函数中调用的,具体代码就不再赘述。
四、示例代码:
由于completionCallback函数需要用户自己去定义的自动补全方法,下面是一个示例代码,仅供参考。
SYS_CMD cmd[SYS_CMD_NUM] = {
{"enable", ENABLE},
{"disable", DISABLE},
{"log", LOG},
{"dump", DUMP},
{"all", ALL},
{"status", 0},
{"help", 0},
{"exit", 0},
};
list componentList;
void tabCompletion(const char *buf, linenoiseCompletions *lc) {
unsigned int index =0, uLen = 0;
const char *pLastWord = NULL;
char *completion = NULL;
if (buf) {
pLastWord = buf;
if (strlen(buf) > 0) {
pLastWord += strlen(buf) - 1;
while (uLen < strlen(buf) && *pLastWord != ' ') {
pLastWord--; uLen++;
}
pLastWord++;
uLen = strlen(pLastWord);
}
uLen = strlen(buf) - uLen;
completion = (char *)malloc(sizeof(char) * (uLen + MAX_CMD_LEN));
if (completion == NULL) {
return;
}
memset(completion, 0, sizeof(char) * (uLen + MAX_CMD_LEN));
strncpy(completion, buf, uLen);
for(index = 0; index < SYS_CMD_NUM; index++) {
if(strncmp(cmd[index].cmd, pLastWord, strlen(pLastWord)) == 0){
strcpy(&completion[uLen],cmd[index].cmd);
linenoiseAddCompletion(lc,completion);
}
}
free(completion);
}
}