前面已经能获取到输入的字符了,接着就是解析这些字符,判断,符合要求的,执行对应的函数。而对应的函数,就是需要实现的命令。本文从具体的命令实现逐步倒推,最后对接上一文章。

一、命令函数

Linux 中,基本上每条命令都有参数及帮助信息,仿照这些功能,给出实现函数指针及结构体:

/** Monitor Command Table*/
typedef int (*cmd_func)(int argc, char * const argv[]);struct cmd_tbl_s {char    *name;        /* Command Name            */int     maxargs;    /* maximum number of arguments    */cmd_func cmd;       /* Implementation function    */char    *usage;        /* Usage message    (short)    */
#ifdef    CONFIG_SYS_LONGHELPchar    *help;    /* Help  message    (long)    */
#endif
#ifdef CONFIG_AUTO_COMPLETE/* do auto completion on the arguments */int     (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};typedef struct cmd_tbl_s    cmd_tbl_t;/* someone should implement the table */
extern cmd_tbl_t cmd_table[];

为保持命令的独立性,设置cmd_func函数指针。命令结构体为全局变量,下面给出其定义及对应命令的实现:


/* just a foolish command table */
cmd_tbl_t cmd_table[] =
{{"help", CONFIG_SYS_MAXARGS, do_help, "print help info."},{"print", 1, do_print, "print the env."},{"exit", 1, do_exit, "exit..."},{NULL, 0, NULL, NULL},
};int do_help(int argc, char * const argv[])
{_do_help(cmd_table, sizeof(cmd_table)/sizeof(cmd_tbl_t), argc, argv);return 0;
}int do_print(int argc, char * const argv[])
{myprintf("in %s\n", __FUNCTION__);return 0;
}int do_exit(int argc, char * const argv[])
{exit(0);return 0;
}

以上就是具体命令的实现过程,可以将每条命令都理解为一个单独的可带参数的程序。

二、查找命令

查找命令名称前,需要先对输入的字符串进行解析,实现函数如下:

int parse_line (char *line, char *argv[])
{int nargs = 0;#ifdef DEBUG_PARSERcmd_printf ("parse_line: \"%s\"\n", line);
#endifwhile (nargs < CONFIG_SYS_MAXARGS){/* skip any white space */while ((*line == ' ') || (*line == '\t')){++line;}if (*line == '\0'){    /* end of line, no more args    */argv[nargs] = NULL;
#ifdef DEBUG_PARSERcmd_printf ("parse_line: nargs=%d\n", nargs);
#endifreturn (nargs);}argv[nargs++] = line;    /* begin of argument string    *//* find end of string */while (*line && (*line != ' ') && (*line != '\t')){++line;}if (*line == '\0'){    /* end of line, no more args    */argv[nargs] = NULL;
#ifdef DEBUG_PARSERcmd_printf ("parse_line: nargs=%d\n", nargs);
#endifreturn (nargs);}*line++ = '\0';        /* terminate current arg     */}cmd_printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);#ifdef DEBUG_PARSERcmd_printf ("parse_line: nargs=%d\n", nargs);
#endifreturn (nargs);
}

输出参数为argv数组,此即为命令参数列表,其中argv[0]即命令名称,返回值为命令参数个数,即argc。这就是我们熟悉的C语言 main 函数的参数。

查找命令实际是搜索结构体数组cmd_table中的命令名称。如果找到返回名称,反之为空。

cmd_tbl_t* find_cmd_tbl3(const char* cmd, cmd_tbl_t *table)
{const char *p;char *q;cmd_tbl_t *c, *found;int nmatches, longest;longest = 0;nmatches = 0;found = 0;for (c = table; (p = c->name) != NULL; c++){for (q = cmd; *q == *p++; q++)if (*q == 0)        /* exact match? */return (c);if (!*q){return NULL;}}return NULL;
}cmd_tbl_t *find_cmd (const char* cmd)
{//int len = sizeof(cmd_table) / sizeof(cmd_tbl_t);//return find_cmd_tbl(cmd, cmd_table, len);//return find_cmd_tbl2(cmd, cmd_table);return find_cmd_tbl3(cmd, cmd_table);
}

注意,如果命令数量过多,不宜使用从头遍历的方法查找。本文工程仅为示例,暂不研究效率。

三、汇总运行

运行命令函数实现如下,

int run_command (const char *cmd)
{cmd_tbl_t *cmdtp;char cmdbuf[CB_SIZE];    /* working copy of cmd        */char *token;            /* start of token in cmdbuf    */char *sep;            /* end of token (separator) in cmdbuf *///char finaltoken[CB_SIZE];char *str = cmdbuf;char *argv[CONFIG_SYS_MAXARGS + 1];    /* NULL terminated    */int argc, inquotes;int repeatable = 1;int rc = 0;#ifdef DEBUG_PARSERcmd_printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);cmd_puts (cmd ? cmd : "NULL");    /* use puts - string may be loooong */cmd_puts ("\"\n");
#endif//clear_ctrlc();        /* forget any previous Control C */if (!cmd || !*cmd){return -1;    /* empty command */}if (strlen(cmd) >= CB_SIZE){cmd_puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);/* Process separators and check for invalid* repeatable commands*/#ifdef DEBUG_PARSERcmd_printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endifwhile (*str) {/** Find separator, or string end* Allow simple escape of ';' by writing "\;"*/for (inquotes = 0, sep = str; *sep; sep++){if ((*sep=='\'') &&(*(sep-1) != '\\'))inquotes=!inquotes;if (!inquotes &&(*sep == ';') &&    /* separator        */( sep != str) &&    /* past string start    */(*(sep-1) != '\\'))    /* and NOT escaped    */break;}/** Limit the token to data between separators*/token = str;if (*sep){str = sep + 1;    /* start of command for next pass */*sep = '\0';}elsestr = sep;    /* no more commands for next pass */
#ifdef DEBUG_PARSERcmd_printf ("token: \"%s\"\n", token);
#endif/* Extract arguments */if ((argc = parse_line (token, argv)) == 0){rc = -1;    /* no command at all */continue;}/* Look up command in command table */if ((cmdtp = find_cmd(argv[0])) == NULL){cmd_printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1;    /* give up after bad command */continue;}/* found - check max args */if (argc > cmdtp->maxargs){cmd_usage(cmdtp);rc = -1;continue;}/* OK - call function to do the command */if ((cmdtp->cmd) (argc, argv) != 0){rc = -1;}}//return rc ? rc : repeatable;return rc;
}

主要过程有解析字符串parse_line,查找命令结构数组find_cmd,最后运行函数指针。

四、主函数

入口函数及倒计时函数如下:

int abortboot(int delay)
{int abort = 0;int i = 0;myprintf("Hit any key to stop autoboot: %2d ", delay);while ((delay > 0) && (!abort)){--delay;for (i = 0; !abort && i < 100; ++i){if (mytstc()){abort = 1;delay = 0;mygetc();break;}mysleep(10);}myprintf("\b\b\b%2d ", delay);}myputc('\n');return abort;
}int readline_test(void)
{static char lastcommand[CB_SIZE] = {0};int len;if (!abortboot(5)){myprintf("Aotu run.\n");return 0;}myprintf("You abort.\n");while (1){len = readline(PROMPT, lastcommand);if (len > 0){//printf("len: %d\n", len);if (len >= CB_SIZE){myprintf("command line too large.\n");break;}//strcpy(lastcommand, console_buffer);//printf("[echo]: %s\n", lastcommand);}else if (len == 0){//printf("nothing input.\n");// do nothing}if (len == -1){myputs("<INTERRUPT>\n");}else{run_command(lastcommand);}}return 0;
}

至此,一个“命令终端”实现完毕。可对其底层的字符处理进行修改,以适应不同环境。除此外,其它业务逻辑完全无变化。

李迟 2020.9.30

“命令终端”的实现3-命令的执行相关推荐

  1. linux查看执行过的命令行,在Linux命令终端中查看和编辑曾执行过的命令 – LINUX笔记 – CFEI.NET...

    今天我们来讲讲linux的知识,积累的这些知识就是我们以后的财富,各位加油. 因为水平有限,难免有疏忽或者不准确的地方,希望大家能够直接指出来,我会及时改正.一切为了知识的分享. history 命令 ...

  2. linux看以前敲过的指令,在Linux命令终端中查看和编辑曾执行过的命令

    history history 命令可以用来显示曾执行过的命令,也可以根据显示的治疗来重新执行需要的命令 n 显示n个最近的记录 -a 添加记录 -r 读取记录,但不会添加内容记录 -w 覆盖原有的h ...

  3. Linux 的命令终端(CMD)的快捷键(Keyboard of MacBook)

    文章目录 常用 移动光标 编辑命令 查找历史命令 控制命令 命令终端界面滚屏 命令终端页签切换 奇葩 常用 快捷键 说明 Ctrl + A 光标跳到本行的行首 Ctrl + E 光标跳到本行的行尾 C ...

  4. 如何通过命令终端访问本地/局域网/远程的MySQL数据库_访问数据库_连接数据库_登录数据库

    文章目录 Windows系统下 访问本地MySQL数据库 访问远程主机的MySQL数据库 本地安装了MySQL数据库 本地没有安装MySQL Linux系统下 退出数据库登录 Windows系统下 访 ...

  5. “命令终端”的实现1-准备篇

    李迟注: 这几篇文章写于2012年底,因故未发表,前不久,音视频群里的树哥询问一个技术方案,想到以前曾经实现过,就把工程发给他.现在发表出来,除修正个别严重的病句外,其它没有修改.从行文看,还有很大提 ...

  6. 【图文解析 】Linux命令终端,又看会了,浮夸

    Linux命令终端 在桌面空白处,点击鼠标右键,在下拉菜单选项中,选择Open in Terminal,然后出现右下图对话框,这个对话框就是命令终端,将是我们与该linux打交道最多的地方,任何该li ...

  7. Ubuntu命令终端查看使用过的命令

    使用history命令 cyf@ubuntu:~$ history 但是这样会显示出所有使用过的命令,可以在history后加上less cyf@ubuntu:~$ history | less 会显 ...

  8. 用命令行编译java并生成可执行的jar包

    1.编写源代码 编写源文件:CardLayoutDemo.java并保存,例如:I:\myApp\CardLayoutDemo.java.程序结构如下: package test;import jav ...

  9. linux按顺序运行命令,linux – 安排cron作业打开终端并按顺序运行命令

    以下答案[在分隔符之后]假定您要在终端的[内部]内运行第二个命令.否则你只需要交换cronjob上的命令(因为目前,就像你拥有它一样,echo只会在终端退出后执行),例如: 0 23 * * * ec ...

最新文章

  1. Unity创建游戏VFX视觉特效-初级到中级
  2. 今天重新建立了个eclipse 的maven项目,提示org.junit找不到
  3. 【连载】优秀程序员的45个习惯之45——及时通报进展与问题
  4. vsftpd配置文件详细介绍
  5. Spring的Bean实例化、属性注入、对象注入、复杂注入(基于xml配置方式)
  6. php怎么把字符转成大写,php怎么把字符串转换为大写
  7. Java集合系列---红黑树(基于HashMap 超详细!!!)
  8. linux work有关的命令,VM workstation 中linux 命令
  9. 区块链需要学习哪些东西_区块链主要学习哪些知识?
  10. 怎么用debug看jdbc查询的resultset中查出的数据_用了这个 ORM 工具,我只用一天就把项目数据库给换了
  11. android selector 开始自定义样式
  12. Eureka 注册中心 简单搭建
  13. java用1234组成_java编程题,java1234组成三位数不重复
  14. phpWord 读取word模板,替换相应变量
  15. 26个大小写字母对应的哈希值
  16. Dbeaver Phoenix 各种报错
  17. git pages部署静态页面,可以免费发布简历之类的静态网页。
  18. java编写活期储蓄帐目管理_活期储蓄账目管理系统
  19. Hive 3.1.2Linux CentOs 安装,踩坑 Dbeaver 连接Hive
  20. 【CSS3 属性】CSS 3 transform:scale 与 transform:translate 作用在同一div元素,导致元素位置偏离

热门文章

  1. “我没搞懂元宇宙,但一天能赚9w块”
  2. 英特尔成立集成光电研究中心 加速光互连I/O创新
  3. OPPO Reno7/Reno7 Pro今天开售:首发IMX709超感光猫眼镜头
  4. 外媒:苹果公司将在美国为其“苹果汽车”生产电池
  5. 马斯克再带货狗狗币:超7成网友票选狗狗币为未来货币
  6. 钱准备好!苹果官方账号泄密:iPhone 12明晚发布有戏
  7. 云集CEO肖尚略直播首秀,4小时带货5150万元
  8. 10大淘宝直播之城公布:杭州、广州、连云港位列前三
  9. 华为P40系列发布时间或敲定:继续在3月26日亮相?
  10. 苹果悬赏100万美元找漏洞 辞职的理由找到了!