- 网易云课堂昵称 :coker1994
- 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006
- 实验github地址:https://github.com/mamengnan/mmnslab.git
实验步骤
linktable.c
和linktable.h
与上次的实验一样,这里不在赘述。menu.h
的定义,菜单的添加函数和执行函数。
/* add cmd to menu */
int MenuConfig(char* cmd, char* desc, int (*handler)(int argc, char *argv[]));
/* Menu Engine Execute */
int ExecuteMenu();
menu.c
的实现,与原来的menu.c相比,此次实验增加了MenuConfig
函数来添加指令,ExecuteMenu
函数来执行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "linktable.h"
#include "menu.h"
tLinkTable * head = NULL;
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
#define CMD_MAX_ARGV_NUM 10
/* data struct and its operations */
typedef struct DataNode
{
tLinkTableNode * pNext;
char* cmd;
char* desc;
int (*handler)(int argc, char *argv[]);
} tDataNode;
int SearchCondition(tLinkTableNode * pLinkTableNode, void *args)
{
char *cmd = (char *)args;
tDataNode * pNode = (tDataNode *)pLinkTableNode;
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,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(int argc, char *argv[])
{
ShowAllCmd(head);
return 0;
}
int MenuConfig(char* cmd, char* desc, int (*handler)(int argc, char *argv[]))
{
tDataNode *pNode = NULL;
if(head == NULL)
{
head = CreateLinkTable();
pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "help";
pNode->desc = "This is the help list";
pNode->handler = Help;
AddLinkTableNode(head, (tLinkTableNode*)pNode);
}
pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = cmd;
pNode->desc = desc;
pNode->handler = handler;
AddLinkTableNode(head, (tLinkTableNode*)pNode);
return 0;
}
/* menu program */
int ExecuteMenu()
{
/* cmd line begins */
while(1)
{
int argc = 0;
char *argv[CMD_MAX_ARGV_NUM];
char cmd[CMD_MAX_LEN];
char *pcmd = NULL;
printf("Input a command> ");
pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
tDataNode *p = FindCmd(head, cmd);
if( pcmd == NULL)
{
continue;
}
pcmd = strtok(pcmd, " ");
while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
{
argv[argc] = pcmd;
argc ++;
pcmd = strtok(NULL, " ");
}
if(argc == 1)
{
int len = strlen(argv[0]);
*(argv[0] + len -1) = '\0';
}
tDataNode *pn = (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)argv[0]);
if(pn == NULL)
{
printf("This is a wrong cmd!\n");
continue;
}
if(pn->handler != NULL)
{
pn->handler(argc, argv);
}
}
return 0;
}
test.c
作为测试模块,实现了菜单的添加和运行。
#include <stdio.h>
#include <stdlib.h>
#include "linktable.h"
#include "menu.h"
int Exit(int argc, char *argv[])
{
printf("Bye-bye\n");
exit(0);
}
int Version(int argc, char *argv[])
{
printf("menu program v3.0\n");
}
int main(int argc, char *argv[])
{
MenuConfig("version", "menu program v3.0", Version);
MenuConfig("exit", "Exit this program", Exit);
ExecuteMenu();
return 0;
}
- 通过getopt函数 int getopt(int argc,char const argv[ ],const char optstring);可以对optstring所指的字符串作为短参数列表进行带参数的不同输出。当我们输入测试命令“test -a”时,将输出“aa”;当我们输入测试命令“test -b”时,将输出“bb”
int testOpt(int argc, char** argv)
{
const char * optString = "abc";
opterr = 0;
int opt;
while((opt = getopt(argc, argv, optString)) != -1)
{
switch(opt)
{
case 'a':
printf("aa\n");
break;
case 'b':
printf("bb\n");
break;
default:
break;
}
}
optind = 0;
return 0;
}
Makefile
的实现
运行结果
复审代码
从github下载代码重新编译运行
实验小结
本次实验通过对menu.c
的修改,使得接口更加通用。同时Makefile
文件降低了使用者的操作复杂度,只需make
和make clean
指令即可。