实验七:将menu设计为可重用的子系统

实验七:将menu设计为可重用的子系统

咸蛋超级咸 + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

实验要求:

  • 为menu子系统设计接口,并写用户范例代码来实现原来的功能
  • 使用make和make clean来编译程序和清理自动生成的文件;
  • 使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
  • 可以使用getopt函数获取命令行参数。

实验过程:

  • 使用github建立远程仓库,并下载到本地,github的地址:github
    这里写图片描述

  • 编码

  • linktable.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_ */
  • 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 Condition(tLinkTableNode * pNode);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Condition(tLinkTableNode * pNode, void * args), void * args)
{
    if(pLinkTable == NULL || Condition == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)
    {    
        if(Condition(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;
}
  • menu.h
#ifndef _menu
#define _menu
int MenuConfig(char * cmd, char * desc, void (*handler)(int argc, char *argv[]));
int ExecuteMenu();
#endif
  • menu.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
    printf("--------------------------------------------\n");
    while(pNode != NULL)
    {
        printf("%s: \t %s\n", pNode->cmd, pNode->desc);
        pNode= (tDataNode*)GetNextLinkTableNode(head, (tLinkTableNode*)pNode);
    }
    printf("--------------------------------------------\n");
    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 command > ");
        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);
}

  • mymenu.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "menu.h"

void version(int argc, char *argv[]);
void showtime(int argc, char *argv[]);
void pwd(int argc, char *argv[]);
void add(int argc, char *argv[]);
void sub(int argc, char *argv[]);
void mul(int argc, char *argv[]);
void div(int argc, char *argv[]);
void quit(int argc, char *argv[]);

int main(int argc,char* argv[])
{
    MenuConfig("version","Menu Program V1.0",               version);
    MenuConfig("time",  "Show system time",                 showtime);
    MenuConfig("pwd",   "Show current working directory",   pwd);
    MenuConfig("add",   "make a add of two numbers",        add);
    MenuConfig("sub",   "make a sub of two numbers",        sub);
    MenuConfig("mul",   "make a mul of two numbers",        mul);
    MenuConfig("div",   "make a div of two numbers",        div);
    MenuConfig("quit",  "Exit menu program",                quit);
    ExecuteMenu();
}


void version(int argc, char *argv[])
{
    printf("Menu Program V1.0\n");
}
void  showtime(int argc, char *argv[])
{
    struct tm *ptr;
    time_t it;
    it = time(NULL);
    ptr = localtime(&it);
    printf("%4d年%02d月%02d日  %d:%d:%d\n", ptr->tm_year + 1900, ptr->tm_mon + 1, ptr->tm_mday, 
                                          ptr->tm_hour, ptr->tm_min,ptr->tm_sec);
}


void  pwd(int argc, char *argv[])
{
    char buf[256];
    getcwd(buf, sizeof(buf));
    printf("当前路径:  %s\n", buf);
}


 void  add(int argc, char *argv[])
 {
    if(argc != 3)
    {
        printf("error count of calculate\n");
    }
    int num1 = atoi(argv[1]), num2 = atoi(argv[2]);
    printf("%d + %d = %d\n", num1, num2, num1 + num2);
 }


 void  sub(int argc, char *argv[])
 {
    if(argc != 3)
    {
        printf("error count of calculate\n");
    }
    int num1 = atoi(argv[1]), num2 = atoi(argv[2]);
    printf("%d - %d = %d\n", num1, num2, num1 - num2);
 }


 void  mul(int argc, char *argv[])
 {
    if(argc != 3)
    {
        printf("error count of calculate\n");
    }
    int num1 = atoi(argv[1]), num2 = atoi(argv[2]);
    printf("%d * %d = %d\n", num1, num2, num1 * num2);
 }


 void  div(int argc, char *argv[])
 {
    if(argc != 3)
    {
        printf("error count of calculate\n");
    }
    int num1 = atoi(argv[1]), num2 = atoi(argv[2]);
    if(num2 != 0)
    {
        printf("%d / %d = %d\n", num1, num2, num1 / num2);
    }
    else
    {
        printf("ERROR: don't division 0\n");
    }
 }


 void  quit(int argc, char *argv[])
 {
     exit(0);
 }
  • makefile
CC_PTHREAD_FLAGS   = -lpthread
CC_FLAGS           = -c
CC_OUTPUT_FLAGS    = -o
CC                 = gcc
RM                 = rm
RM_FLAGS           = -f
TARGET             = mymenu
OBJS               = linktable.o menu.o mymenu.o

all:    $(OBJS)
    $(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS)

.c.o:
    $(CC) $(CC_FLAGS) $<

clean:
    $(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak  

调试运行

  • 使用make命令
    这里写图片描述
  • 运行并使用命令
    这里写图片描述
    这里写图片描述
  • 上传github
    这里写图片描述

实验总结

(1)Makefile实现对几个.h和.c文件进行编译的工作,即只需make一下就能完成该功能,无需输入复杂的命令;删除编译过后的文件以及备份文件只需make clean一下即可。
(2)liktable.c和linktable.h分别声明定义了可重用链表的数据结构以及对链表的操作,本次实验的数据就是存储在该链表中的,而调用各个函数也就是对链表的遍历并取出某个结点存储的函数地址,之后执行操作。
(3)menu.c和menu.h是基于上述链表来构造对menu的基本框架,包括存储命令的数据结构以及命令查找功能。
(4)mymenu.c中定义了一些简单的命令诸如求和、比大小、退出等等。
(5)menu子系统支持带参数的命令,可用getopt函数获取命令行参数,本次实验中的add,sub,mul都可以实现对于不同的参数会做出不同的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值