版本库URL:https://github.com/swagnhen/Advanced-Software-Engineering-Exercise.git
实验要求
1)用可重用的链表模块来实现命令行菜单小程序,执行某个命令时调用一个特定的函数作为执行动作;
2)链表模块的接口设计要足够通用,命令行菜单小程序的功能保持不变;
3)可以将通用的Linktable模块集成到我们的menu程序中;
4)接口规范;
实验内容
可重用链表实现包含于linkedlist.h与linkedlist.c中
shell中各命令功能的实现包含在cmdopt.h与cmdopt.c中
main函数包含于shelllet.c中
通过gcc编译时请使用命令
gcc linkedlist.c cmdopt.c shelllet.c -o shelllet
可重用链表设计
typedef struct Node
{
struct Node *next;
} Node;
typedef struct LinkedList
{
Node *head; /*指向链表头结点*/
Node *tail; /*指向链表尾节点*/
int len; /*记录链表长度*/
} LinkedList;
LinkedList *initLinkedList(); /*初始化整个链表*/
int delLinkedList(LinkedList *l); /*删除整个链表*/
int addNode(LinkedList *l, Node *n); /*向链表尾添加一个节点*/
int delNode(LinkedList *l, Node *n); /*删除某一节点*/
Node *getHeadNode(LinkedList *l); /*取链表头结点*/
Node *getNextNode(LinkedList *l, Node *n); /*取节点n的下一个节点*/
功能指令链表节点设计
typedef struct CmdNode
{
Node *next;
char *cmd; /*该节点所对应指令*/
int (*handler)(); /*指令cmd所对应的功能函数*/
} CmdNode;
int initMenuData(LinkedList **l); /*初始化功能指令链表*/
CmdNode *findCmd(LinkedList *head, char *cmd); /*根据cmd字段寻找某一功能指令节点*/
具体实现
linkedlist.c
#include <stdio.h>
#include <stdlib.h>
#include "linkedlist.h"
LinkedList *initLinkedList()
{
LinkedList *l = (LinkedList *)malloc(sizeof(LinkedList));
if (l == NULL)
{
return NULL;
}
l->head = NULL;
l->tail = NULL;
l->len = 0;
return l;
}
int delLinkedList(LinkedList *l)
{
if (l == NULL)
{
return -1;
}
while (l->head != NULL)
{
Node *p = l->head;
l->head = l->head->next;
free(p);
l->len--;
}
l->head = NULL;
l->tail = NULL;
l->len = 0;
free(l);
return 0;
}
int addNode(LinkedList *l, Node *n)
{
if (l == NULL || n == NULL)
{
return -1;
}
if (l->head == NULL)
{
l->head = n;
}
if (l->tail == NULL)
{
l->tail = n;
}
else
{
l->tail->next = n;
l->tail = n;
l->tail->next = NULL;
}
l->len++;
return 0;
}
int delNode(LinkedList *l, Node *n)
{
if (l == NULL || n == NULL)
{
return -1;
}
if (l->head == n)
{
l->head = l->head->next;
l->len--;
if (l->len == 0)
{
l->tail = NULL;
}
return 0;
}
Node *temp = l->head;
while (temp != NULL)
{
if (temp->next == n)
{
temp->next = temp->next->next;
l->len--;
if (l->len == 0)
{
l->tail = NULL;
}
return 0;
}
temp = temp->next;
}
return -1;
}
Node *getHeadNode(LinkedList *l)
{
if (l == NULL || l->head == NULL)
{
return NULL;
}
return l->head;
}
Node *getNextNode(LinkedList *l, Node *n)
{
if (l == NULL || n == NULL)
{
return NULL;
}
Node *temp = l->head;
while (temp != NULL)
{
if (temp == n)
{
return temp->next;
}
temp = temp->next;
}
return NULL;
}
cmdopt.c
#include "cmdopt.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int initMenuData(LinkedList **l)
{
*l = initLinkedList();
CmdNode *p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "add";
p->handler = cmdAdd;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "minus";
p->handler = cmdMinus;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "multiply";
p->handler = cmdMultiply;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "divide";
p->handler = cmdDivide;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "quit";
p->handler = cmdQuit;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "showuid";
p->handler = cmdShowUID;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "help";
p->handler = cmdHelp;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "hello";
p->handler = cmdHello;
addNode(*l, (Node *)p);
p = (CmdNode *)malloc(sizeof(CmdNode));
p->cmd = "";
p->handler = cmdElse;
addNode(*l, (Node *)p);
return 0;
}
CmdNode *findCmd(LinkedList *l, char *cmd)
{
if (l == NULL || cmd == NULL)
{
return NULL;
}
CmdNode *p = (CmdNode *)getHeadNode(l);
while (p != NULL)
{
if (strcmp(p->cmd, cmd) == 0)
{
return p;
}
p = (CmdNode *)getNextNode(l, (Node *)p);
}
p = l->tail;
return p;
}
void cmdAdd()
{
int a, b;
printf(">>>");
scanf("%i", &a);
printf(">>>");
scanf("%i", &b);
printf(">>>%i\n", a + b);
}
void cmdMinus()
{
int a, b;
printf(">>>");
scanf("%i", &a);
printf(">>>");
scanf("%i", &b);
printf(">>>%i\n", a - b);
}
void cmdMultiply()
{
int a, b;
printf(">>>");
scanf("%i", &a);
printf(">>>");
scanf("%i", &b);
printf(">>>%i\n", a * b);
}
void cmdDivide()
{
int a, b;
printf(">>>");
scanf("%i", &a);
printf(">>>");
scanf("%i", &b);
printf(">>>%i\n", a / b);
}
void cmdHello()
{
printf(">>>Welcome to shelllet!\n");
}
void cmdQuit()
{
printf("**********Shelllet End**********\n");
exit(0);
}
void cmdShowUID()
{
printf(">>>UID: %i\n", getuid());
}
void cmdHelp()
{
printf("|help\n");
printf("|hello\n");
printf("|add\n");
printf("|minus\n");
printf("|multiply\n");
printf("|divide\n");
printf("|showuid\n");
printf("|quit\n");
}
void cmdElse()
{
printf(">>>Wrong Commend\n");
}
shelllet.c
#include "cmdopt.h"
#include <stdio.h>
#include <string.h>
int main()
{
LinkedList *l = NULL;
initMenuData(&l);
char cmd[128];
printf("**********Shelllet Running**********\n");
while (1)
{
printf(">>>");
scanf("%s", cmd);
CmdNode *p = findCmd(l, cmd);
if (p != NULL && p->handler != NULL)
p->handler();
}
return 0;
}
运行效果
实验总结与问题
上周没看视频没想到居然分离是指加个链表,真是失败
我就一直在想为什么要弄个链表,链表本身是动态扩充的,但是到我们这个项目里链表所包含的内容(命令行的各种函数)都是写死在代码段里的,动态容器存储静态内容,加功能还是得重新编译,这不是南辕北辙么?
不过孟大师是厉害,这课上的总能有意想不到的收获
后来想考虑Linux的shell实现,它的各种功能都对应一个文件。建一个链表,每次都扫描某一目录中的所有文件,这样就比较合理,还能直接通过增减文件控制shell功能
不过这样可能就比较复杂,还是得用系统调用
所以简化了一下这个简单shell就变成这样了吧