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 = ;
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 = ;
char* start = arg[]; 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 + , sizeof(char*)); //以NULL结尾 int i = ;
for(i=; 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 = ;
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 + ));
memcpy(ps, job->progs, job->progs_num * sizeof(Program)); ps[job->progs_num++] = *prog;//将新的进程(命令)加入进来 free(job->progs); //释放旧的程序(命令)组
job->progs = ps; return job->progs_num - ; //返回新命令的索引号
}

//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[]) < ){
perror("cd error");
}
} //pwd命令
void pwd_fun(Program* prog)
{
char buffer[];
memset(buffer, , 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[] = (char*)malloc(strlen(cmd) * sizeof(char)); //命令本身
strcpy(args[], cmd); int i = ;
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 = ;
for(j=; 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 = ;
while( start < (line + strlen(line)) ){
memset(buff, , sizeof(buff));
if((pos = strchr(pos, ';')) == NULL)
{
pos = line + strlen(line);
} count = pos-start;
if(count > ){
memcpy(buff, start, count);
split_cmd(job, buff);
}
start = ++pos;
}
} //执行命令
void execute_cmd(Job* job)
{
int i = ;
for(i=; i<job->progs_num; i++)
{
//cd命令
if(!strcmp(job->progs[i].args[], "cd")){
cd_fun(&job->progs[i]);
} //pwd命令
if(!strcmp(job->progs[i].args[], "pwd")){
pwd_fun(&job->progs[i]);
} //quit命令
if(!strcmp(job->progs[i].args[], "quit")){
exit();
return;
}
}
} int main(int argc, char* argv[])
{
char buffer[MAX_COMMAND_LEN];
memset(buffer, , MAX_COMMAND_LEN); ssize_t size = strlen(prompt) * sizeof(char);
write(STDOUT_FILENO, prompt, size); ssize_t len = ;
while(){
len = read(STDIN_FILENO, buffer, MAX_COMMAND_LEN);
buffer[len -] = ; //以NULL结尾 if(strlen(buffer) > ){
Job* job = create_job(buffer); //解析命令
parse_cmd(job, buffer);
//执行命令
execute_cmd(job); destroy_job(job);
} write(STDOUT_FILENO, prompt, size);
memset(buffer, , MAX_COMMAND_LEN);
} return ;
}

第4章 文件和目录(5)_贯穿案例2:mini shell(1)的更多相关文章

  1. 第8章 信号(6)_贯穿案例2:mini shell(3)

    4. 贯穿案例2:mini shell(3) (1)之前存在问题 ①刚运行时,mshell作为前台进程.运行的其他命令会被加入新的进程组,并且调用tcsetpgrp将这个进程组设置为前台进程组,因此m ...

  2. 零基础学Python--------第10章 文件及目录操作

    第10章 文件及目录操作 10.1 基本文件操作 在Python中,内置了文件(File)对象.在使用文件对象时,首先需要通过内置的open() 方法创建一个文件对象,然后通过对象提供的方法进行一些基 ...

  3. 第7章 进程关系(5)_贯穿案例2:mini shell(2)

    5. 贯穿案例2:mini shell(2) (1)己经完成的功能:pwd.cd.exit命令 (2)阶段性目标: ①env.export.echo及其他命令 ②标准输入.输出重定向"> ...

  4. UNIX环境高级编程 第4章 文件和目录

    第三章说明了关于文件I/O的基本函数,主要是针对普通regular类型文件.本章描述文件的属性,除了regular文件还有其他类型的文件. 函数stat.fstat.fstatat和lstat sta ...

  5. apue学习笔记(第四章 文件和目录)

    本章将描述文件系统的其他特性和文件的性质. 函数stat.fstat.fstatat和lstat #include <sys/stat.h> int stat(const char *re ...

  6. Linux命令应用大词典-第 15章 文件、目录权限和属性

    15.1 chmod:更改文件和目录的模式 15.2 chown:更改文件和目录的用户所有者和组群所有者 15.3 chgrp:更改文件或目录的所属组 15.4 umask:显示和设置文件及目录创建默 ...

  7. UNIX系统高级编程——第四章-文件和目录-总结

    文件系统: 以UNIX系统V文件系统为例: 磁盘分为区,每个分区都有自己的文件系统: ​ i节点是固定长度的记录项,包含了文件的相关信息.目录项包含文件名和i节点号.stat结构中除文件名和i节点编号 ...

  8. 《Unix环境高级编程》读书笔记 第4章-文件和目录

    1. stat结构的基本形式: on error 24. 设备特殊文件 每个文件系统所在的存储设备都由其主.次设备号表示. 设备号所用的数据类型是基本系统数据类型dev_t. 主设备号标识设备驱动程序 ...

  9. apue 第4章 文件和目录

    获取文件属性 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(c ...

  10. 《UNIX环境高级编程》(APUE) 笔记第四章 - 文件和目录

    4 - 文件和目录 1. 函数 stat.fstat.fstatat 和 lstat #inlcude <sys/stat.h> int stat(const char *restrict ...

随机推荐

  1. WebGL编程指南案例解析之平移和旋转的math库实现

    这里说的math库实现,指的是,通过一般的加减乘除(角度计算)来更新坐标值. 因为涉及到坐标的变化,所以这里都是基于对顶点着色器的修改 平移: var vShader = ` attribute ve ...

  2. tomcat版本号的修改

    我的是8.5.0我将其改为8.0.0    其他版本改也是一样      我改这个版本号就是因为eclipse上没有tomcat8.5.0的配置  所以将其改为8.0.0     在配置web服务器时 ...

  3. Tomcat必会的企业级配置调优

    Tomcat服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选. ======== 完美的分割线 ...

  4. 第十章 企业项目开发--分布式缓存Redis(2)

    注意:本章代码是在上一章的基础上进行添加修改,上一章链接<第九章 企业项目开发--分布式缓存Redis(1)> 上一章说了ShardedJedisPool的创建过程,以及redis五种数据 ...

  5. hihocoder1545 : 小Hi和小Ho的对弈游戏(树上博弈&nim博弈)

    描述 小Hi和小Ho经常一起结对编程,他们通过各种对弈游戏决定谁担任Driver谁担任Observer. 今天他们的对弈是在一棵有根树 T 上进行的.小Hi和小Ho轮流进行删除操作,其中小Hi先手. ...

  6. 实验吧—密码学——WP之 传统知识+古典密码

    仔细读题,发现有价值的信息: 几个不同的年份:“+甲子”:key值结构 首先我们并不知道这些年份在这里代表着什么,那么我们就去百度一下发现了如下所示的六十甲子顺序表 而在表中每个年份前都有数字,将他们 ...

  7. gtx860M,cuda9路1080p多高斯运动检测测试

    多高斯背景差分,非常吃cpu,特别是多路视屏,所以想用gpu做检测 后面的跟踪一系列的规则判断用cpu opencv+cuda+stl做了个测试 代码: // MTTestCudaMog.cpp : ...

  8. Nolia 给CC添加过滤器

    思路: 1.使用jqurey-tagput ,做得不好看,领导不满意 2.使用bootstrap select2这个控件, 思路: 1.添加css和js的文件 2.添加标签的时候,根据id拼接标签,a ...

  9. 【转】python基础-编码与解码

    [转自:https://www.cnblogs.com/OldJack/p/6658779.html] 一.什么是编码 编码是指信息从一种形式或格式转换为另一种形式或格式的过程. 在计算机中,编码,简 ...

  10. 引用,引用形參,指针形參与指向指针的引用形參,内存泄露及free相关

    (另:关于"引用"更具体的讨论.见此.) 由做UVa133引发的一系列问题及讨论 1.引用类型    C++ Primer P51 引用就是对象的还有一个名字,使用多个变量名指向同 ...