分类: 其他平台
2017-06-04 22:03:20
【郭昌明 SA16225079 + 《软件工程(C编码实践篇)》MOOC课程作业 】
一 实验要求
1.为menu子系统设计接口,并写用户范例代码来实现原来的功能;
2.使用make和make clean来编译程序和清理自动生成的文件;
3.使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
4.可以使用getopt函数获取命令行参数。
二 实验环境
实验楼
三 实验步骤
1.在Code/shiyanlou_cs122目录下新创建一个目录lab7
2.将lab5的代码复制到lab7
$ cp -r lab5/* lab7
3.按照老师的视频中的思路修改代码,首先编写menu.h,代码如下:
然后修改menu.c,主要是Menuconfig()和ExcuteMenu()这两个函数,代码如下
#include #include #include #include "linktable.h" #include "menu.h" #define CMD_MAX_LEN 128 #define CMD_MAX_ARGV_LEN 128 #define DESC_LEN 1024 #define CMD_NUM 10 tLinkTable * head = NULL; void Help(int argc, char *argv[]); /* data struct and its operations */ typedef struct DataNode
{
tLinkTableNode * pNext; char* cmd; char* desc; void (*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, (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 MenuConfig(char * cmd, char * desc, void (*handler)(int argc, char *argv[]))
{
tDataNode* pNode = NULL; if (head == NULL)
{
head = CreateLinkTable();
pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "help";
pNode->desc = "Menu 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);
} int ExecuteMenu()
{ while(1)
{ int argc = 0; char *argv[CMD_MAX_ARGV_LEN]; char cmd[CMD_MAX_LEN]; char *pcmd = NULL;
printf("Input a cmd number > ");
pcmd = fgets(cmd, CMD_MAX_LEN, stdin); if (pcmd == NULL)
{ continue;
}
pcmd = strtok(pcmd, " "); while (pcmd != NULL && argc < CMD_MAX_ARGV_LEN)
{
argv[argc] = pcmd;
argc++;
pcmd = strtok(NULL, " ");
} if (argc == 1)
{ int len = strlen(argv[0]);
*(argv[0] + len - 1) = '\0';
}
tDataNode *p = FindCmd(head, argv[0]); if( p == NULL)
{
printf("This is a wrong cmd!\n "); continue;
}
printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL)
{
p->handler(argc, argv);
}
}
} void Help(int argc, char *argv[])
{
ShowAllCmd(head);
}
然后编写test.c,代码如下:
#include #include #include #include "menu.h" int Quit(int argc, char **argv) { exit(0);
} int Hello(int argc, char **argv) { printf("Hello! You are the best!"); return 1;
} int main(int argc, char **argv) {
MenuConfig("version", "xxx v1.0(Menu program v3.0.0 inside)", NULL);
MenuConfig("quit", "quit from the menu", Quit);
MenuConfig("hello","hello cmd",Hello);
ExcuteMenu(); return 0;
}
然后编写MakeFile,代码如下:
#makefile for Menu Program CC_PTHREAD_FLAGS = -lpthread
CC_FLAGS = -c
CC_OUTPUT_FLAGS = -o
CC_MATH = -lm
CC = gcc
RM = rm
RM_FLAGS = -f
TARGET = test
OBJS = linktable.o menu.o test.o all: $(OBJS)
$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS) $(CC_MATH)
.c.o: $(CC) $(CC_FLAGS) $< clean: $(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak
四 实验结果
实验结果如下图:
五 遇到的问题和解决方法
make的时候遇到报错,* missing separator. Stop.
通过网上查询资料,将命令行的空格,改成TAB键即可。因为在Makefile文件中,命令必须以【tab】键开始。
六 实验总结
实验的目的是为menu子系统设计接口,并写用户范例代码来实现原来的功能。
通过本实验,了解menu程序设计为可重用子模块的过程,使menu子系统支持带参数的复杂命令,加深了对规范化编程的理解。