内容
- 用可重用的链表模块来实现命令行菜单小程序,执行某个命令时调用一个特定的函数作为执行动作;
- 链表模块的接口设计要足够通用,命令行菜单小程序的功能保持不变;
- 可以将通用的Linktable模块集成到我们的menu程序中;
- 接口规范,使用callback函数;
- 为menu子系统设计接口,并写用户范例代码来实现原来的功能
- 使用make和make clean来编译程序和清理自动生成的文件
- 使menu子系统支持带参数的复杂命令,自定义一个带参数的复杂命令get()函数(get -n name -v version命令)
- 使用getopt函数获取命令行参数
代码
Makefile
CC_PTHREAD_FLAGS = -lpthread
CC_FLAGS = -c
CC_OUTPUT_FLAGS = -o
CC = gcc
RM = rm
RM_FLAGS = -f
TARGET = test
OBJS = linktable.o menu.o test.o
all: $(OBJS)
$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS)
.c.o:
$(CC) $(CC_FLAGS) $<
clean:
$(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak
/**************************************************************************************************/
/* Copyright (C) SSE@USTC, 2015 */
/* */
/* FILE NAME : menu.c */
/* PRINCIPAL AUTHOR : ch */
/* SUBSYSTEM NAME : menu */
/* MODULE NAME : menu */
/* LANGUAGE : C */
/* TARGET ENVIRONMENT : ANY */
/* DATE OF FIRST RELEASE : 2015/10/30 */
/* DESCRIPTION : This is a menu program */
/**************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "menu.h"
#include "linktable.h"
int Help();
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
#define CMD_MAX_ARGV_NUM 10
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,(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;
}
/* menu program */
tLinkTable * head = NULL;
/**
* add command to menu;
* initiate commandline;
*/
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 Engine Execute */
int ExecuteMenu()
{
int argc = 0;
char cmd_temp[CMD_MAX_LEN];
char *pcmd = NULL;
char *argv_temp[CMD_MAX_ARGV_NUM];
char *cmd = NULL;
char **argv = NULL;
char **argv_ini = argv_temp;
/* cmd line begins */
while(1)
{
// initiate before circle
cmd = cmd_temp;
argv = argv_ini;
argc = 0;
pcmd = NULL;
printf("Input a cmd number > ");
//scanf("%s", cmd);
pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
/* input Nothing */
if(pcmd == NULL)
{
continue;
}
/* convert pcmd 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 length = strlen(argv[0]);
/* change '\n' to '\0' at the end of the cmd */
*(argv[0] + length - 1) = '\0';
}
//printf("Argv[0] is %s\n", argv[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);
}
}
}
int Help()
{
ShowAllCmd(head);
return 0;
}
#ifndef _MENU_H
#define _MENU_H
/* add command to menu */
int MenuConfig(char *cmd, char *desc, int (*handler)(int argc, char* argv[]));
/* Menu Engine Execute */
int ExecuteMenu();
#endif
linktable.c
/********************************************************************/
/* Copyright (C) SSE-USTC, 2015 */
/* */
/* FILE NAME : linktabe.c */
/* PRINCIPAL AUTHOR : ch */
/* SUBSYSTEM NAME : LinkTable */
/* MODULE NAME : LinkTable */
/* LANGUAGE : C */
/* TARGET ENVIRONMENT : ANY */
/* DATE OF FIRST RELEASE : 2015/10/30 */
/* DESCRIPTION : interface of Link Table */
/********************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include"linktable.h"
struct LinkTable
{
tLinkTableNode *pHead;
tLinkTableNode *pTail;
int SumOfNode;
pthread_mutex_t mutex;
};
/*
* 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 != 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;
}
linktable.h
/********************************************************************/
/* Copyright (C) SSE-USTC, 2015 */
/* */
/* FILE NAME : linktabe.h */
/* PRINCIPAL AUTHOR : ch */
/* SUBSYSTEM NAME : LinkTable */
/* MODULE NAME : LinkTable */
/* LANGUAGE : C */
/* TARGET ENVIRONMENT : ANY */
/* DATE OF FIRST RELEASE : 2015/10/30 */
/* DESCRIPTION : interface of Link Table */
/********************************************************************/
#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_
#include <pthread.h>
#define SUCCESS 0
#define FAILURE (-1)
/*
* LinkTable Node Type
*/
typedef struct LinkTableNode
{
struct LinkTableNode * pNext;
}tLinkTableNode;
/*
* LinkTable Type
*/
typedef struct LinkTable tLinkTable;
//typedef struct LinkTable
//{
// tLinkTableNode *pHead;
// tLinkTableNode *pTail;
// int SumOfNode;
// pthread_mutex_t mutex;
//}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_ */
test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "menu.h"
extern char *optarg;
extern int cmderror;
extern int optind;
int Quit(int argc, char *argv[])
{
exit(0);
}
int Get(int argc, char *argv[])
{
if (argc == 1)
{
printf("get cmd is none!\n");
return 0;
}
int cmd = 's';
while((cmd = getopt(argc, argv, "n:v:")) != -1)
{
switch(cmd)
{
case 'n':
printf("Get, argv is %s\n", optarg); break;
case 'v':
printf("Get, argv is %s\n", optarg); break;
case ':':
switch (cmd)
{
case 'n':
printf("Get, -n:\n"); break;
case 'v':
printf("Get, -v:\n"); break;
case '\n':
break;
default:
printf("Usage: %s [-n] [-v] argc\n", argv[0]);
}
break;
default:
printf("Usage: %s [-n argc1] [-v argc2] \n", argv[0]); break;
}
}
optind = 1;
return 0;
}
int main(int argc, char *argv[])
{
MenuConfig("version", "Menu program v2.0!", NULL);
MenuConfig("quit", "Quit from Menu", Quit);
MenuConfig("get", "Get something", Get);
ExecuteMenu();
}
testlintable.c
/**************************************************************************************************/
/* Copyright (C) SSE@USTC, 2015 */
/* */
/* FILE NAME : testlinktable.c */
/* PRINCIPAL AUTHOR : ch */
/* SUBSYSTEM NAME : testlinktable */
/* MODULE NAME : testlinktable */
/* LANGUAGE : C */
/* TARGET ENVIRONMENT : ANY */
/* DATE OF FIRST RELEASE : 2015/10/30 */
/* DESCRIPTION : This is a testlinktable program */
/**************************************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"linktable.h"
#define debug
typedef struct Node
{
tLinkTableNode * pNext;
int data;
}tNode;
tNode * Search(tLinkTable *pLinkTable);
int SearchCondition(tLinkTableNode * pLinkTableNode);
int main()
{
int i;
tLinkTable * pLinkTable = CreateLinkTable();
assert(pLinkTable != NULL);
for(i = 0; i < 10; i++)
{
tNode* pNode = (tNode*)malloc(sizeof(tNode));
pNode->data = i;
debug("AddLinkTableNode\n");
AddLinkTableNode(pLinkTable,(tLinkTableNode *)pNode);
}
/* search by callback */
debug("SearchLinkTableNode\n");
tNode* pTempNode = (tNode*)SearchLinkTableNode(pLinkTable,SearchCondition);
printf("%d\n",pTempNode->data);
/* search one by one */
pTempNode = Search(pLinkTable);
printf("%d\n",pTempNode->data);
debug("DelLinkTableNode\n");
DelLinkTableNode(pLinkTable,(tLinkTableNode *)pTempNode);
free(pTempNode);
DeleteLinkTable(pLinkTable);
}
tNode * Search(tLinkTable *pLinkTable)
{
debug("Search GetLinkTableHead\n");
tNode * pNode = (tNode*)GetLinkTableHead(pLinkTable);
while(pNode != NULL)
{
if(pNode->data == 5)
{
return pNode;
}
debug("GetNextLinkTableNode\n");
pNode = (tNode*)GetNextLinkTableNode(pLinkTable,(tLinkTableNode *)pNode);
}
return NULL;
}
int SearchCondition(tLinkTableNode * pLinkTableNode)
{
tNode * pNode = (tNode *)pLinkTableNode;
if(pNode->data == 6)
{
return SUCCESS;
}
return FAILURE;
}
