第4章 文件和目录_贯穿案例2:mini shell
Posted 浅墨浓香
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第4章 文件和目录_贯穿案例2:mini shell相关的知识,希望对你有一定的参考价值。
6. 贯穿案例2:mini shell(1)
【阶段性任务】实现cd、pwd和quit命令
//job.h
#ifndef __JOB_H__ #define __JOB_H__ //接收命令行参数 typedef struct { char** args; //对应于主函数中的char* argv[]参数(含进程名本身) }Program; //命令行中可以包含多个程序(命令),如 //#date;ls -l,单个或多个命令通过cmd传入Job结构体中 typedef struct { char* cmd; //单条命令或多条命令(用分号隔开) int progs_num; //作业中包含程序的数量 Program* progs; //各个程序的命令行参数 }Job; //创建作业 extern Job* create_job(char* cmd); //销毁作业 extern void destroy_job(Job* job); //创建进程(命令) extern Program* create_program(char** arg); //销毁进程(命令) extern void destroy_program(Program* prog); //将命令加入作业中 extern int add_program(Job* job, Program* prog); #endif
//job.c
#include "job.h" #include <malloc.h> #include <assert.h> #include <string.h> //创建作业 Job* create_job(char* cmd) { Job* job = (Job*)malloc(sizeof(Job)); assert( job != NULL); job->cmd = (char*)malloc(sizeof(char) * strlen(cmd)); assert(job->cmd != NULL); strcpy(job->cmd, cmd); job->progs_num = 0; job->progs = NULL; return job; } //销毁作业 void destroy_job(Job* job) { assert(job != NULL); free(job->progs); free(job->cmd); free(job); } //arg格式:command arg0 arg1 ==> 返回3 static int arg_num(char** arg) { int ret = 0; char* start = arg[0]; while(start != NULL){ start = arg[++ret]; } return ret; } //创建进程(命令) Program* create_program(char** arg) { Program* prog = (Program*)malloc(sizeof(Program)); assert(prog != NULL); int counter = arg_num(arg); prog->args = (char**)calloc(counter + 1, sizeof(char*)); //以NULL结尾 int i = 0; for(i=0; i< counter; i++){ int len = strlen(arg[i]); prog->args[i] = (char*)malloc(len); assert(prog->args[i] != NULL); strcpy(prog->args[i], arg[i]); } prog->args[i] = NULL; //指针数组,以NULL结尾 return prog; } //销毁进程(命令) void destroy_program(Program* prog) { assert(prog != NULL); int i = 0; while(prog->args[i] != NULL) { free(prog->args[i++]); } free(prog->args); free(prog); } //将命令加入作业中 int add_program(Job* job, Program* prog) { //重新申请一片空间以增加一条命令进来,放入job->progs中 Program* ps = (Program*)malloc(sizeof(Program) * (job->progs_num + 1)); memcpy(ps, job->progs, job->progs_num * sizeof(Program)); ps[job->progs_num++] = *prog;//将新的进程(命令)加入进来 free(job->progs); //释放旧的程序(命令)组 job->progs = ps; return job->progs_num - 1; //返回新命令的索引号 }
//mshell.c
#include "job.h" #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <string.h> #include <assert.h> char* prompt = "mshell> "; //命令行的提示符 #define MAX_COMMAND_LEN 256 //命令行最多的字符数 //cd命令 void cd_fun(Program* prog) { if(chdir(prog->args[1]) < 0){ perror("cd error"); } } //pwd命令 void pwd_fun(Program* prog) { char buffer[256]; memset(buffer, 0, sizeof(buffer)); if(getcwd(buffer, sizeof(buffer)) == NULL){ perror("pwd error"); } printf("%s\\n", buffer); } //分析命令所带的参数(含进程名本身) void split_cmd(Job* job, char* arguments) { char** args = (char**)malloc(MAX_COMMAND_LEN * sizeof(char*)); assert( args != NULL); char* cmd = strtok(arguments, " "); args[0] = (char*)malloc(strlen(cmd) * sizeof(char)); //命令本身 strcpy(args[0], cmd); int i = 1; char* s = NULL; while((s = strtok(NULL, " ")) != NULL){ //将参数分隔出来 args[i] = (char*)malloc(strlen(s) * sizeof(char)); strcpy(args[i++], s); } //根据args创建一个Program Program* prog = create_program(args); add_program(job, prog); int j = 0; for(j=0; j < i; j++){ free(args[j]); } free(args); } //多条命令的解析 void parse_cmd(Job* job, char* line) { char buff [MAX_COMMAND_LEN]; //以“;”号分隔多条命令 char* pos = line; char* start = line; int count = 0; while( start < (line + strlen(line)) ){ memset(buff, 0, sizeof(buff)); if((pos = strchr(pos, \';\')) == NULL) { pos = line + strlen(line); } count = pos-start; if(count > 0 ){ memcpy(buff, start, count); split_cmd(job, buff); } start = ++pos; } } //执行命令 void execute_cmd(Job* job) { int i = 0; for(i=0; i<job->progs_num; i++) { //cd命令 if(!strcmp(job->progs[i].args[0], "cd")){ cd_fun(&job->progs[i]); } //pwd命令 if(!strcmp(job->progs[i].args[0], "pwd")){ pwd_fun(&job->progs[i]); } //quit命令 if(!strcmp(job->progs[i].args[0], "quit")){ exit(0); return; } } } int main(int argc, char* argv[]) { char buffer[MAX_COMMAND_LEN]; memset(buffer, 0, MAX_COMMAND_LEN); ssize_t size = strlen(prompt) * sizeof(char); write(STDOUT_FILENO, prompt, size); ssize_t len = 0; while(1){ len = read(STDIN_FILENO, buffer, MAX_COMMAND_LEN); buffer[len -1] = 0; //以NULL结尾 if(strlen(buffer) > 0){ Job* job = create_job(buffer); //解析命令 parse_cmd(job, buffer); //执行命令 execute_cmd(job); destroy_job(job); } write(STDOUT_FILENO, prompt, size); memset(buffer, 0, MAX_COMMAND_LEN); } return 0; }
以上是关于第4章 文件和目录_贯穿案例2:mini shell的主要内容,如果未能解决你的问题,请参考以下文章