c语言实例|实现简单的命令行
嵌入式系统开发,经常需要用到命令行功能,比如uboot命令行。
命令行可以增加程序运行的灵活性,方便我们调试程序,大幅提高我们开发效率。
本文通过过一个简单的例子,来教大家如何实现一个简单的命令行模块,
该模块可以很方便的移植到自己的c项目中。
完整源码获取,见文末。
一、设计思想
二、实现
1、结构体
模块支持的命令相关信息,我们用结构体 struct _cmdnum来维护。
typedefvoid(*CMDFUNC)(char[][256],intargc);typedefstruct_cmdnum{char*cmd;intindex;intparamcount;CMDFUNC callback;char*info;}CMDNUM,*PCMDNUM;| 成员 | 含义 |
|---|---|
| char *cmd | 命令名字 |
| int index | 命令下标 |
| int paramcount | 命令参数个数 |
| CMDFUNC callback | 命令对应回调函数 |
2、支持的命令
本问例子中加了4个命令:
| 功能 | 参数个数 | 回调函数 | |
|---|---|---|---|
| help | 显示所有命令信息 | 0 | showhelp() |
| :– | :– | exit | 退出当前进程 |
| test | 打印所有参数信息,测试用 | 3 | test() |
| send | 将输入的16进制字符串,转换成16进制整形数并存入数组中 | MAX_PARAM_NUM | send() |
定义如下:
CMDNUM cmdlist[]={{"help",1,0,showhelp},{"exit",2,0,quit},{"test",3,3,test},{"send",4,MAX_PARAM_NUM,send},};3、相关函数
- getline()
#include<stdio.h>ssize_tgetline(char**lineptr,size_t*n,FILE*stream);从文件流stream读取一行数据,结果保存到*lineptr中,结尾包括空字符和换行符。
- parsecmd()
voidparsecmd(char*s)解析命令行内容,主要通过函数stripcmd/getcmdindex实现。
- stripcmd
intstripcmd(char*s,charcmds[][256])借助库函数strtok,通过空格将命令行s中各个参数分隔开,提取出参数,然后存储到二维数组**char cmds[256]**中,
- getcmdindex
intgetcmdindex(char*name)通过命令名字name,遍历数组cmdlist[],并得到数组下标index。
4、核心代码
CMDNUM cmdlist[]={{"help",1,0,showhelp,"show all cmd info"},{"exit",2,0,quit,"quit application"},{"test",3,3,test,"[param...]print params"},{"send",3,MAX_PARAM_NUM,senddata,"[xx...]converts data from sting to hex and store to buf"},};voidparsecmd(char*s){charcmd[MAX_PARAM_NUM][256];intargc=0;intindex=-1;argc=stripcmd(s,cmd);//printf("argc=%d\n",argc);index=getcmdindex(cmd[0]);if(index==-1){if(argc>0){cprintf(RED,"\tNo such commond \n");}return;}elseif(argc>0){cmdlist[index].callback(cmd,argc);}}UINT8hex2char(UINT8 ch){if((ch>='0')&&(ch<='9')){returnch-'0';}if((ch>='a')&&(ch<='f')){returnch-'a'+10;}if((ch>='A')&&(ch<='F')){returnch-'A'+10;}return(UINT8)0xff;}UCHARstringToByte(char*str){UCHAR bytes=0;if(strlen(str)==1){bytes=0<<4|hex2char(str[0]);}else{bytes=hex2char(str[0])<<4|hex2char(str[1]);}returnbytes;}//7e 01 02 01 00 07 07 01 00 00 00 c6 51 2a 7evoidsenddata(charargv[][256],intargc){inti=0;intlen=0;UCHAR buf[256]={0};if(argc<2){return;}for(i=1;i<argc;i++){buf[i-1]=stringToByte(argv[i]);}cprintf(GREEN,"\n buf:");for(i=0;i<argc-1;i++){cprintf(GREEN,"%02x ",buf[i]);}putchar('\n');}voidtest(charargv[][256],intargc){inti=0;for(i=0;i<argc;i++){cprintf(YEL,"\targv[%d]:%s\n",i,argv[i]);}return;}voidshowsysinfo(void){cprintf(D_GREEN_H,"---------------yikoulinux cmdline demo-----------\n");}voidquit(charcmd[][256],intargc){cprintf(RED_H,"exit to system \n");exit(0);}voidshowhelp(charcmd[][256],intargc){inti=0;for(i=0;i<sizeof(cmdlist)/sizeof(CMDNUM);i++){cprintf(GREEN_H,"\t%s",cmdlist[i].cmd);cprintf(YEL_H,"\t%s\n",cmdlist[i].info);}return;}intmain(intargc,char*argv[]){char*line;intret=0;size_tlen_line=0;showsysinfo();while(1){fflush(stdin);cprintf(D_GREEN_H,DEV_NAME"# ");ret=getline(&line,&len_line,stdin);if(ret==-1){break;}parsecmd(line);free(line);line=NULL;}return0;}