“软件工程(C编码实践篇)”实验报告

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

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

【孙剑峰 SA16225264 + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

代码地址: http://git.shiyanlou.com/csxiaoyao/shiyanlou_cs122/src/master

1. 实验要求

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

2. 实验过程

  1. 从文件夹lab5中拷贝文件至新建文件夹lab7
  1. 新建一个menu.h文件,其代码如下:

    #ifndef _menu
    #define _menu
    int MenuConfig(char* cmd, char* desc, int (*handler)());
    int ExecuteMenu();
    #endif
    
  2. 再创建一个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
    
  3. 用ExcuteMenu取代main函数并作相应修改

    int ExecuteMenu()
    {
        //InitMenuData(&head); 
        //char cmd[81];
       /* cmd line begins */
        while(1)
        {
            //char cmd[CMD_MAX_LEN];
            int argc = 0;
            char *argv[CMD_MAX_ARGV_LEN];
            //char cmd[CMD_MAX_LEN];
            char *pcmd = NULL;
            printf("Input a cmd number > ");
            //scanf("%s", cmd);
            pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
    
            if(pcmd == NULL)
            {
                continue;
            }
    
            pcmd = strtok(pcmd, " ");
    
            while(pcmd != NULL && argc < CMD_MAX_ARGC_LEN)
            {
                printf("%s\n", pcmd);
                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);
            }
    
        }
    }
    
  4. 改写ExcuteConfig

    int MenuConfig(char *cmd, char *desc, int (*handler)(int argc, char *argv[]))
    {
        tDataNode *pNode = NULL;
        if(head == NULL)
        {
            head = (tLinkTable *)CreateLinkTable();
            pNode = (tDataNode *)malloc(sizeof(tDataNode));
            pNode->cmd = "help";
            pNode->desc = "Help 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);
    }
    
  5. 编写test.c文件

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include "linktable.h"
    #include "menu.h"
    /*
    int getopt(int argc, char * const argv[], const char *optstring);
    extern char *optarg;
    extern int optind, opterr, optopt;
    */
    int Quit(int argc, char* argv[]);
    int main(int argc, char* argv[])
    {
        MenuConfig("version", "Menu Program V3.0", NULL);
        MenuConfig("quit", "Quit from Menu Program V3.0", Quit);
        ExecuteMenu();
    }
    int Quit(int argc, char* argv[])
    {
        int oc;
        char *b_opt_arg;
        while((oc = getopt(argc, argv, "cl:\n")) != -1)
        {
            switch(oc)
            {
                case 'c':
                    printf("Clean Success,exiting\n");
                    //delay(2000);
                    sleep(2);
                    break;
                case 'l':
                    b_opt_arg = optarg;
                    printf("Log :%s\n",optarg);
                    //delay(2000);
                    sleep(2);
                    break;
                case '\n':
                    break;
            }
        }
        exit(0);
    }
    

3. 运行结果

图片描述

4. 实验总结

本次实验通过为menu设计子系统接口,进一步提高了menu小程序的可重用性和模块化。Makefile的使用实现了自动化的脚本,省去了每次敲很多的编译命令。

最新评论
暂无评论~