一、实验要求
1.为menu子系统设计接口,并写用户范例代码来实现原来的功能;
2.使用make和make clean来编译程序和清理自动生成的文件;
3.使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
4.可以使用getopt函数获取命令行参数。
二、实验内容
1.clone并进入共享文件夹
2.为menu子系统设计接口,并写用户范例代码来实现原来的功能。
1)用vim编写menu.h的代码:
2)用vim编写menu.c的代码:
具体代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "linktable.h"
#include "menu.h"
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
/* data struct and its operations */
typedef struct DataNode
{
tLinkTableNode * pNext;
char* cmd;
char* desc;
int (*handler)(int agrc, char* agrv[]);
} tDataNode;
tLinkTable * head = NULL;
int SearchCondition(tLinkTableNode * pLinkTableNode, void* args)
{
tDataNode * pNode = (tDataNode *)pLinkTableNode;
char* cmd = (char*)args;
if(strcmp(pNode->cmd, cmd) == 0)
{
return SUCCESS;
}
return FAILURE;
}
/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
return (tDataNode*)SearchLinkTableNode(head,SearchCondition,(void*)cmd);
}
/* show all cmd in listlist */
int ShowAllCmd(tLinkTable * head)
{
tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
while(pNode != NULL)
{
printf("%s - %s\n", pNode->cmd, pNode->desc);
pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
}
return 0;
}
int help()
{
printf("**************************help****************************\n");
printf("List all the cmd of menu program:\n");
ShowAllCmd(head);
printf("**************************end*****************************\n");
}
int MenuConfig(char* cmd, char* desc, int (*handler)(int agrc, char* agrv[]))
{
if(head == NULL)
{
head = CreateLinkTable();
tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "help";
pNode->desc = "List all the cmd of menu";
pNode->handler = help;
AddLinkTableNode(head, (tLinkTableNode *)pNode);
}
tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = cmd;
pNode->desc = desc;
pNode->handler = handler;
AddLinkTableNode(head, (tLinkTableNode *)pNode);
return 0;
}
int ExecuteMenu()
{
/* cmd line begins */
char input[CMD_MAX_LEN];
printf("gitDongHub menu [version 3.0]\n");
printf("gitDongHub@copyright at 2017/09/24\n");
printf("If you need help, please type help\n");
while(1)
{
int agrc = 0;
char* agrv[CMD_MAX_LEN];
char* cmd = NULL;
printf("cmd>>");
cmd = fgets(input, CMD_MAX_LEN, stdin);
if(cmd == NULL)
{
continue;
}
/*converts cmd to agrc and agrv*/
cmd = strtok(cmd, " ");
while(cmd != NULL && agrc < CMD_MAX_LEN)
{
agrv[agrc] = cmd;
agrc ++;
cmd = strtok(NULL, " ");
}
if(agrc == 1)
{
int len = strlen(agrv[0]);
*(agrv[0] + (len - 1)) = '\0';
}
tDataNode* p = FindCmd(head, agrv[0]);
if(p == NULL)
{
printf("the cmd you input isn't exist\n");
continue;
}
if(p->handler != NULL)
{
p->handler(agrc, agrv);
}
}
return 0;
}
3)编写test.c作为用户执行接口,使用getopt函数获取命令行参数,使menu子系统支持带参数的复杂命令。
具体代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "menu.h"
#include "linktable.h"
int quit();
int echo(int argc, char* argv[]);
int main(int argc, char* argv)
{
MenuConfig("quit","quit from the menu program", quit);
MenuConfig("echo","printf all you input in the terminal", echo);
ExecuteMenu();
return 0;
}
int quit()
{
exit(0);
return 0;
}
int echo(int argc, char* argv[])
{
int i;
if(argc == 1)
{
printf("echo on\n");
}
for(i = 1;i < argc;i ++)
{
printf("%d:%s\n",i, argv[i]);
}
return 0;
}
4.使用make和make clean来编译程序和清理自动生成的文件
1)编写Makefile文件
2)用make命令进行编译:
3)生成的文件如下:
4)运行test的结果:
5.将代码push到GitHub
push成功
我的github地址:https://github.com/lili0001002/cs122/tree/master/lab7
三、实验收获
- 知道了当编译的文件较多时,可以使用Makefile来简化编译过程。Makefile工程文件也是代码,要考虑可维护性。
- 通过编写menu接口,可以提高menu子系统的可重用性。
- 知道了如何利用argc,argv和getopt来处理命令行参数。从而使得用户对命令行有更多的更精确的控制。
- gets存在缓冲区溢出的问题,所以程序不能用gets的而是用fgets。