实验目录
实验要求
实验过程
实验心得
实验要求
1.为menu子系统设计接口,并写用户范例代码来实现原来的功能;
2.使用make和make clean来编译程序和清理自动生成的文件;
3.使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
4.可以使用getopt函数获取命令行参数。
实验过程
1.编写linkable.h
#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_
#include <pthread.h>
#define SUCCESS 0
#define FAILURE (-1)
/*
* LinkTable Node Type
*/
typedef struct LinkTableNode tLinkTableNode;
/*
* LinkTable Type
*/
typedef struct LinkTable tLinkTable;
/*
* Create a LinkTable
*/
tLinkTable * CreateLinkTable();
/*
* Delete a LinkTable
*/
int DeleteLinkTable(tLinkTable *pLinkTable);
/*
* Add a LinkTableNode to LinkTable
*/
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
* Delete a LinkTableNode from LinkTable
*/
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
/*
* Search a LinkTableNode from LinkTable
* int Conditon(tLinkTableNode * pNode);
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args),void *args);
/*
* get LinkTableHead
*/
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
* get next LinkTableNode
*/
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
#endif /* _LINK_TABLE_H_ */
2.编写linktable.c
#include<stdio.h>
#include<stdlib.h>
#include"linktable.h"
typedef struct LinkTableNode
{
struct LinkTableNode * pNext;
}tLinkTableNode;
typedef struct LinkTable
{
tLinkTableNode *pHead;
tLinkTableNode *pTail;
int SumOfNode;
pthread_mutex_t mutex;
}tLinkTable;
/*
* Create a LinkTable
*/
tLinkTable * CreateLinkTable()
{
tLinkTable * pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));
if(pLinkTable == NULL)
{
return NULL;
}
pLinkTable->pHead = NULL;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 0;
pthread_mutex_init(&(pLinkTable->mutex), NULL);
return pLinkTable;
}
/*
* Delete a LinkTable
*/
int DeleteLinkTable(tLinkTable *pLinkTable)
{
if(pLinkTable == NULL)
{
return FAILURE;
}
while(pLinkTable->pHead != NULL)
{
tLinkTableNode * p = pLinkTable->pHead;
pthread_mutex_lock(&(pLinkTable->mutex));
pLinkTable->pHead = pLinkTable->pHead->pNext;
pLinkTable->SumOfNode -= 1 ;
pthread_mutex_unlock(&(pLinkTable->mutex));
free(p);
}
pLinkTable->pHead = NULL;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 0;
pthread_mutex_destroy(&(pLinkTable->mutex));
free(pLinkTable);
return SUCCESS;
}
/*
* Add a LinkTableNode to LinkTable
*/
int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
pNode->pNext = NULL;
pthread_mutex_lock(&(pLinkTable->mutex));
if(pLinkTable->pHead == NULL)
{
pLinkTable->pHead = pNode;
}
if(pLinkTable->pTail == NULL)
{
pLinkTable->pTail = pNode;
}
else
{
pLinkTable->pTail->pNext = pNode;
pLinkTable->pTail = pNode;
}
pLinkTable->SumOfNode += 1 ;
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
/*
* Delete a LinkTableNode from LinkTable
*/
int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
pthread_mutex_lock(&(pLinkTable->mutex));
if(pLinkTable->pHead == pNode)
{
pLinkTable->pHead = pLinkTable->pHead->pNext;
pLinkTable->SumOfNode -= 1 ;
if(pLinkTable->SumOfNode == 0)
{
pLinkTable->pTail = NULL;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
tLinkTableNode * pTempNode = pLinkTable->pHead;
while(pTempNode != NULL)
{
if(pTempNode->pNext == pNode)
{
pTempNode->pNext = pTempNode->pNext->pNext;
pLinkTable->SumOfNode -= 1 ;
if(pLinkTable->SumOfNode == 0)
{
pLinkTable->pTail = NULL;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
pTempNode = pTempNode->pNext;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return FAILURE;
}
/*
* Search a LinkTableNode from LinkTable
* int Conditon(tLinkTableNode * pNode);
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void *args),void * args)
{
if(pLinkTable == NULL || Conditon == NULL)
{
return NULL;
}
tLinkTableNode * pNode = pLinkTable->pHead;
// while(pNode != pLinkTable->pTail)
while(pNode != NULL)
{
if(Conditon(pNode, args) == SUCCESS)
{
return pNode;
}
pNode = pNode->pNext;
}
return NULL;
}
/*
* get LinkTableHead
*/
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
if(pLinkTable == NULL)
{
return NULL;
}
return pLinkTable->pHead;
}
/*
* get next LinkTableNode
*/
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return NULL;
}
tLinkTableNode * pTempNode = pLinkTable->pHead;
while(pTempNode != NULL)
{
if(pTempNode == pNode)
{
return pTempNode->pNext;
}
pTempNode = pTempNode->pNext;
}
return NULL;
}
3.编写menu.h
#ifndef _MENU_H_
#define _MENU_H_
int MenuConfig(char *cmd ,char *desc, int (*handler)(int argc ,char *agrv[]));
int ExecuteMenu();
#endif
注意两个函数MenuConfig,ExecuteMenu;
4.编写menu.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linktable.h"
#include "menu.h"
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
#define CMD_MAX_ARGV_NUM 32
tLinkTable * head = NULL;
int Help(int argc, char **argv);
/* data structure 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\t - \t%s\n", pNode->cmd, pNode->desc);
pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
}
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 = "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);
return 0;
}
/* menu program */
int ExcuteMenu()
{
/* cmd line begins */
while(1)
{
// init argc
int argc = 0;
char *argv[CMD_MAX_ARGV_NUM];
char cmd[CMD_MAX_LEN];
char *pcmd = NULL;
// input cmd
printf("Input a cmd > ");
pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
if (pcmd == NULL)
{
continue;
}
// convert cmd line to argc/argv;
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 *p = FindCmd(head, argv[0]);
if( p == NULL)
{
printf("This is a wrong cmd!\n ");
continue;
}
printf("%s\n", p->desc);
if(p->handler != NULL) {
p->handler(argc, argv);
}
}
}
int Help(int argc, char **argv)
{
ShowAllCmd(head);
return 0;
}
5.编写Makefile文件
CC_FLAGS = -c
CC_OUTPUT_FLAGS = -o
CC = gcc
TARGET = test
OBJS = linktable.o menu.o test.o
RM = rm
RM_FLAGS = -f
all: $(OBJS)
$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS)
.c.o:
$(CC) $(CC_FLAGS) $<
clean:
$(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.baki
6.编写测试文件test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "menu.h"
int Quit(int argc, char **argv)
{
exit(0);
}
int ls(int argc, char **argv)
{
const char *optString = "lah";
opterr = 0;
int opt;
while ((opt = getopt(argc, argv, optString)) != -1)
{
switch (opt)
{
case 'l':
printf("this -l option\n");
break;
case 'a':
printf("this -a option\n");
break;
case 'h':
printf("in this cmd, you have 3 option can use:\n");
printf("-l\n");
printf("-a\n");
printf("-h\n");
break;
default:
break;
}
}
// reset global valuable optind
optind = 0;
return 0;
}
int HelloFunc(int argc, char **argv)
{
printf("Hello! You are the best!");
return 1;
}
int QuitFunc(int argc, char **argv)
{
exit(0);
return 1;
}
int GreaterFunc(int argc, char **argv)
{
int a,b,c;
scanf("%d",&a);
scanf("%d",&b);
c=a>b?a:b;
printf("The greater one is %d",c);
return 1;
}
int SmallerFunc(int argc, char **argv)
{
int a,b,c;
scanf("%d",&a);
scanf("%d",&b);
c=a>b?b:a;
printf("The smaller one is %d",c);
return 1;
}
int PlusFunc(int argc, char **argv)
{
int a,b,c;
scanf("%d",&a);
scanf("%d",&b);
c=a+b;
printf("The result is %d",c);
return 1;
}
int main(int argc, char **argv)
{
MenuConfig("version", "xxx v1.0(Menu program v3.0.0 inside)", NULL);
MenuConfig("ls", "test arg option", ls);
MenuConfig("quit", "quit from the menu", Quit);
MenuConfig("hello","hello cmd",HelloFunc);
MenuConfig("greater","greater cmd",GreaterFunc);
MenuConfig("smaller","smaller cmd",SmallerFunc);
MenuConfig("plus","return a+b",PlusFunc);
ExcuteMenu();
return 0;
}
7.由于有Makefile文件,直接使用make命令即可进行编译;
8.实验结果
9.使用git进行代码托管
git add lab7
git commit -m lab7
git push
实验心得
1.实验过程中出现错误
原因:在Makefile文件中,命令必须以【tab】键开始。所以在3行命令前使用tab键即可。
2.本次实验完成了通用菜单命令子程序的实现,本节也学习了一些概念,例如接口定义不要太具体,也不要太通用。为了让编译操作更简便,我们使用Makefile工程文件来直接执行多行命令;除此之外可以定义宏来使得工程文件更加可维护。对于传递参数的程序,Shell将命令行解析成argc和argv传递给执行程序。另外还有fgets和gets的区别在于gets有缓冲区溢出的危险。