【发布时间】:2013-12-16 19:00:33
【问题描述】:
我正在从事一个学校项目,该项目基本上是在 UNIX 中创建一个简单的 shell。 但我被我项目的历史部分困住了。关于历史部分的解释如下:
history - 此命令用于维护以前发出的命令的历史记录。
o 历史记录 - 在您的 shell 中打印最多 10 个最近输入的命令。
哦! number - 用户应该能够通过以下方式重复先前发出的命令 打字! number,其中 number 指示要重复哪个命令。
请注意! 1 用于重复返回的命令列表中编号为 1 的命令 历史,和! -1 用于重复上一个命令。
我的代码直到历史部分在这里:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;
struct Node
{
pid_t pid;
char *pname;
int index;
struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;
NodePtr list = NULL;
void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{
NodePtr newPtr, prePtr, curPtr;
newPtr = malloc(sizeof(Node));
if (newPtr != NULL )
{
newPtr->pid = pid;
newPtr->pname = name;
newPtr->index = indx;
newPtr->nextPtr = NULL;
prePtr = NULL;
curPtr = *currentPtr;
while (curPtr != NULL )
{
prePtr = curPtr;
curPtr = curPtr->nextPtr;
}
if (prePtr == NULL )
{
newPtr->nextPtr = *currentPtr;
*currentPtr = newPtr;
}
else
{
prePtr->nextPtr = newPtr;
newPtr->nextPtr = curPtr;
}
}
}
void printJob(NodePtr curPtr)
{
if (curPtr == NULL )
{
printf("Running: List is empty.\n");
printf("Terminated: List is empty.\n");
}
else
{
printf("Running:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
curPtr = curPtr->nextPtr;
}
printf("Finished:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
curPtr->pid);
curPtr = curPtr->nextPtr;
}
}
}
void ioredirection()
{
int input = -1, output = -1, append = -1;
int k, d, fdinput, fdoutput;
for (k = 0; argsexec[k] != NULL ; k++)
{
if (strcmp(argsexec[k], "<") == 0)
{
argsexec[k] = NULL;
input = k;
d = 1;
}
else if (strcmp(argsexec[k], ">") == 0)
{
argsexec[k] = NULL;
output = k;
d = 2;
}
else if (strcmp(argsexec[k], ">>") == 0)
{
argsexec[k] = NULL;
append = k;
d = 3;
}
if (d == 1)
{
fdinput = open(argsexec[input + 1], O_RDONLY, 0);
dup2(fdinput, STDIN_FILENO);
close(fdinput);
execvp(argsexec[0], argsexec);
}
if (d == 2)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);
dup2(fdoutput, STDOUT_FILENO);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
for (y = output; y < MAXARGNUM - 2; y++)
argsexec[y] = argsexec[y + 2];
argsexec[MAXARGNUM - 2] = NULL;
}
if (d == 3)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
}
}
}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
if (end == begin)
{
begin = " ";
end = begin + 1;
}
size_t len = end - begin;
*dir = malloc(len + 1);
memmove(*dir, begin, len);
(*dir)[len] = '\0';
}
size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{ //returns the size of the splitted parts of the string.
const char *begin = path;
const char *end;
size_t num_dirs = 0;
while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
{
add_path(&dirs[num_dirs++], begin, end);
begin = end + 1;
}
if (num_dirs < max_dirs && *begin != '\0')
add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
return num_dirs;
}
void clearArgs()
{
int i;
for (i = 0; i < MAXARGNUM; ++i)
{
argsexec[i] = NULL;
}
}
int Ampersand()
{
int i;
for (i = 0; argsexec[i] != NULL ; i++)
{
if (strcmp(argsexec[i], "&") == 0)
{
return 1;
}
else
{
return 0;
}
}
}
void Setup()
{
while (1)
{
path = malloc((MAXCHARNUM + 1) * sizeof(char));
clearArgs();
fprintf(stderr, "333sh: ", NULL );
gets(str); //get the next commands
while (strlen(str) == 0)
{ //if the user enters empty string or space, ignore this input, read again.
fprintf(stderr, "333sh: ", NULL );
gets(str);
}
size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
const char *path = getenv("PATH"); //get the system's path
ioredirection();
char * const arguments[] =
{ argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
argsexec[5], argsexec[6], argsexec[7], (void*) NULL };
name = argsexec[0];
pid_t pid = fork();
wait(NULL );
if (Ampersand())
{
if (pid == 0)
{
int in = 1;
addJob(&list, pid, name, in);
}
}
if (pid == 0)
{
if (!Ampersand())
{
if (path == NULL )
{ //execl part
execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
}
else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
{
system("ls");
}
else if (strcmp(argsexec[0], "clr") == 0)
{
system("clear");
}
else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
{
system("pwd");
}
else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
{
printJob(list);
}
else
{ //execvp part
execvp(argsexec[0], arguments);
}
}
}
}
}
int main(int argc, char const *argv[])
{
Setup();
return 0;
}
那么我该如何设计这个项目的历史部分呢?任何想法都将不胜感激。很抱歉问了这么长的代码。 谢谢
【问题讨论】: