天天看点

实验七:将menu设计为可重用的子系统 实验目录 实验要求 实验过程 实验心得

实验目录

实验要求

实验过程

实验心得

实验要求

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 = ;
    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 -=  ;
        pthread_mutex_unlock(&(pLinkTable->mutex));
        free(p);
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = ;
    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 +=  ;
    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 -=  ;
        if(pLinkTable->SumOfNode == )
        {
            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 -=  ;
            if(pLinkTable->SumOfNode == )
            {
                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) == )
   {
        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 ;
}
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 ;
}
/* menu program */
int ExcuteMenu()
{
   /* cmd line begins */
    while()
    {
        // init argc
        int argc = ;
        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 == )
        {
            int len = strlen(argv[]);
            *(argv[] + len - ) = '\0';
        }
        tDataNode *p = FindCmd(head, argv[]);
        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 ;
}
           

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();
}
int ls(int argc, char **argv)
{
    const char *optString = "lah";
    opterr = ;
    int opt;
    while ((opt = getopt(argc, argv, optString)) != )
    {
        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 = ;
    return ;
}
int HelloFunc(int argc, char **argv)
{
    printf("Hello! You are the best!"); 
    return ;
}
int QuitFunc(int argc, char **argv)
{
    exit();
    return ;
}
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 ;
}
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 ;
}
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 ;
}
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 ;
}
           

7.由于有Makefile文件,直接使用make命令即可进行编译;

实验七:将menu设计为可重用的子系统 实验目录 实验要求 实验过程 实验心得
实验七:将menu设计为可重用的子系统 实验目录 实验要求 实验过程 实验心得

8.实验结果

实验七:将menu设计为可重用的子系统 实验目录 实验要求 实验过程 实验心得

9.使用git进行代码托管

git add lab7

git commit -m lab7

git push

实验心得

1.实验过程中出现错误

实验七:将menu设计为可重用的子系统 实验目录 实验要求 实验过程 实验心得

原因:在Makefile文件中,命令必须以【tab】键开始。所以在3行命令前使用tab键即可。

2.本次实验完成了通用菜单命令子程序的实现,本节也学习了一些概念,例如接口定义不要太具体,也不要太通用。为了让编译操作更简便,我们使用Makefile工程文件来直接执行多行命令;除此之外可以定义宏来使得工程文件更加可维护。对于传递参数的程序,Shell将命令行解析成argc和argv传递给执行程序。另外还有fgets和gets的区别在于gets有缓冲区溢出的危险。