仅供技术点的分享,抄袭者就算了,所以main.c就不贴了
/*
* split_line.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mini_shell.h"
#define is_delim(x) ((x)==' '||(x)=='\t')
char *new_str(char *s, int l) {
char *rv = emalloc(l + 1);
rv[l] = '\0';
strncpy(rv, s, l);
return rv;
}
// 返回shell中获取到的一行命令
char *next_cmd(char *prompt, FILE *fp) {
char *buf; /* the buffer */
int buf_size = 0; /* total size */
int pos = 0; /* current position */
int c; /* input char */
printf("%s", prompt); /* prompt user */
while ((c = getc(fp)) != EOF) {
/* need space? */
if (pos + 1 >= buf_size) { /* 1 for \0 */
if (buf_size == 0) buf = emalloc(BUFSIZ); /* y: 1st time */
else buf = erealloc(buf, buf_size + BUFSIZ); /* or expand */
buf_size += BUFSIZ; /* update size */
}
/* end of command? */
if (c == '\n') break;
/* no, add to buffer */
buf[pos++] = c;
}
if (c == EOF && pos == 0) return NULL; /* EOF and no input */
buf[pos] = '\0';
return buf;
}
// 将每个句子依空格再次拆分
char **split_sentence(char *line) {
char **args;
int spots; /* spots in table */
int buf_space; /* bytes in table */
int arg_num = 0; /* slots used */
char *cp = line; /* pos in string */
char *start;
int len;
if (line == NULL) /* handle special case */
return NULL;
args = emalloc(BUFSIZ); /* initialize array */
buf_space = BUFSIZ;
spots = BUFSIZ / sizeof(char *);
while (*cp != '\0') {
while (is_delim(*cp)) /* skip leading spaces */
cp++;
if (*cp == '\0') /* quit at end-o-string */
break;
/* make sure the array has room (+1 for NULL) */
if (arg_num + 1 >= spots) {
args = erealloc(args, buf_space + BUFSIZ);
buf_space += BUFSIZ;
spots += (BUFSIZ / sizeof(char *));
}
/* mark start, then find end of word */
start = cp;
len = 1;
while (*++cp != '\0' && !(is_delim(*cp))) len++;
args[arg_num++] = new_str(start, len);
}
args[arg_num] = NULL;
return args;
}
// 依管道符将命令拆分为几个句子,如果没有管道符,则只有一个句子
char ***split_line(char *line) {
if (!line) return NULL;
char ***orders = emalloc(BUFSIZ);
int buf_space = BUFSIZ;
int spots = BUFSIZ / sizeof(char **);
int sen_num = 0;
char *p = line;
do {
while (is_delim(*p)) /* skip leading spaces */
p++;
if (*p == '\0') /* quit at end-o-string */
break;
if (sen_num + 1 >= spots) {
orders = erealloc(orders, buf_space + BUFSIZ);
buf_space += BUFSIZ;
spots += BUFSIZ / sizeof(char **);
}
char *end = p;
while (*end != '\0' && *end != '|') end++;
char *sentence = emalloc(end - p + 1); // 由管道符隔开的为一个sentence
strncpy(sentence, p, end - p);
sentence[end - p] = 0;
orders[sen_num++] = split_sentence(sentence);
if (*end) p = end + 1; // '|'
else p = end; // '\0'
} while (*p);
orders[sen_num] = 0;
return orders;
}
// 释放在堆区申请的内存
void freelist(char ***list) {
for (char ***t = list; *t; t++)
for (char **tt = *t; *tt; tt++)
free(*tt);
for (char ***t = list; *t; t++)
free(*t);
free(list);
}
void *emalloc(size_t n) {
void *rv;
if ((rv = malloc(n)) == NULL) fatal("out of memory", "", 1);
return rv;
}
void *erealloc(void *p, size_t n) {
void *rv;
if ((rv = realloc(p, n)) == NULL)
fatal("realloc() failed", "", 1);
return rv;
}
/*
* execute.c - code used by mini shell to execute commands
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <glob.h> // 利用glob()函数进行*的匹配
int redirect(char **cmd) {
int ard = 0; // append redirect, 追加重定向
int rd = 0; // 非追加重定向
while (*cmd) {
char *p = *cmd;
int fd;
if (ard || rd) {
if (ard) fd = open(p, O_CREAT | O_APPEND | O_WRONLY, 0644);
else fd = open(p, O_CREAT | O_TRUNC | O_WRONLY, 0644);
dup2(fd, 1);
close(fd);
return 0;
}
while (*p && *p != '>') p++;
if (*p) { // 如果有重定向符 >
*p = '\0', p++;
if (*p == '>') ard = 1; // 追加重定向
else rd = 1; // 不是追加重定向
*cmd = NULL;
}
cmd++;
}
if (ard || rd) return -1;
else return 0;
}
// 执行解析好的命令
int execute(char ***argv) {
pid_t pid;
int child_info = -1;
int fds[2], fd = 0;
while (*argv) {
pipe(fds);
if ((pid = fork()) == -1) perror("fork");
else if (pid == 0) {
close(fds[0]);
dup2(fd, 0);
if (*(argv + 1)) dup2(fds[1], 1);
else {
if (redirect(*argv) == -1) { // 重定向后无内容
printf("zsh: parse error near `\\n'\n");
exit(1);
}
}
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
glob_t buf;
buf.gl_offs = buf.gl_pathc = 0; // 初始化 offset 和 path_count
// 计算offset,即第一个命令和后续命令选项的个数
char **word = *argv;
word++, buf.gl_offs++; // 命令
while (*word && **word == '-') word++, buf.gl_offs ++ ; // 选项
// GLOB_NOCHECK的作用是没有匹配的文件名时,使用模式串。用在 grep txt 类的命令中对 "txt" 的处理上
if (*word) glob(*word++, GLOB_DOOFFS | GLOB_NOCHECK, NULL, &buf); // 第一个参数
while (*word) glob(*word++, GLOB_DOOFFS | GLOB_APPEND | GLOB_NOCHECK, NULL, &buf); // 后续参数
// 调用 glob() 会将 gl_pathv[] 的前offset个置为空,因此,要在调用 glob() 后对其赋值
word = *argv, buf.gl_offs = 0; // 重置
buf.gl_pathv[buf.gl_offs++] = *word++; // 命令
while (*word && **word == '-') buf.gl_pathv[buf.gl_offs++] = *word++; // 选项
if (buf.gl_pathc) execvp((*argv)[0], &buf.gl_pathv[0]); // 调用过glob()函数,即可能有*的情况
else execvp((*argv)[0], *argv); // 没调用过,则不会有*
perror("cannot execute command");
exit(1);
} else {
if (wait(&child_info) == -1) perror("wait");
close(fds[1]);
fd = fds[0];
argv++;
}
}
return child_info;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章