介绍CppShell
写在前面
最近心血来潮又造了个轮子,其实启发我的是bajdcc/jMiniLang中的管道思想,java运行着太慢,因而用C艹实现一把。
如题图所示,使用非常非常简单。
- range生成有限/无穷数列,`range 0`生成自然数无穷数列,`range 1 10`生成1到10
 - take N,表示从有限/无穷数列中摘取前N行
 - last N,表示从有限数列中取倒数N行,当然了如果数列是无穷的,那么GG
 - load FILENAME,加载文件
 - save FILENAME,保存至文件
 
设计思路
首先当然是解析命令行输入啦,然后则是处理与输出。
一、处理命令
假如命令是诸如`load 1.txt | uppercase | save 2.txt`,以“|”作分隔,分隔后得到单一程序命令行,再以空格作分隔。
用式子来表示是:
- 用户输入command_string
 - applications = command_string.split('|')
 
对applications中每一app,app_args = app.split(' '),然后app_name = app_args[0],删除app_args[0],得到后面的参数arguments下面的任务是,根据app_name和arguments来创建应用程序。
二、创建应用程序
我们以`range 1 100 | save 2.txt`为例,意义为“生成1到100的数列,然后保存至文件”。
所以必须生成两个程序range和save,那么两者是什么关系呢?
思考一下:生成数列,将数列保存至文件。即:以数列作输入,文件为输出。得到:range => save。即save的输入是range的输出,是从前向后逐渐依赖的关系,换句话说,后者调用前者。
这里用到了装饰者模式,既然后者调用前者,那么后者将前者包裹起来即可。应用程序的创建涉及工厂模式,没什么大过花哨的C++技巧。
三、应用程序接口设计
其实也就是“流”接口的设计。参考众多流设计,这里我只实现最简单的:
- bool available() const,返回流是否可用/到末尾
 - char next(),读取当前字符,并准备下个字符
 
应用程序只要重载这两个接口即可。
代码实现
1. Shell
void CShell::exec(const std::string& cmd)
{
auto s = std::split(cmd, '|');
std::vector<app_t> cmder;
std::vector<std::string> names;
std::vector<std::vector<std::string>> arg;
for (auto& str : s)
{
str = std::trim(str);
auto part = std::split(str, ' ');
if (part.empty())
return error("empty argument");
names.push_back(part[0]);
auto apt = CApp::get_type_by_name(part[0]);
if (apt == app_none)
return error("invalid application: " + str);
part.erase(part.begin());
cmder.push_back(apt);
arg.push_back(part); // 应用程序参数
}
auto inner = CApp::create(app_null); // 最里层程序
std::shared_ptr<CApp> app;
for (uint32_t i = 0; i < cmder.size(); i++)
{
app = CApp::create(cmder[i]); // 工厂模式创建应用程序
if (app->set_arg(arg[i]) != 0)
return error(names[i] + ": " + app->get_err());
app->set_inner_app(inner); // 装饰模式进行包装
inner = app;
}
while (app->available()) // 正式工作!
{
auto c = app->next();
if (c != '\0')
std::cout << c;
}
} void CShell::error(const std::string& str)
{
std::cerr << str << std::endl;
}
2. App
enum app_t
{
app__begin,
app_none,
app_null,
app_pipe,
app_range,
app_take,
app_last,
app_load,
app_save,
app__end
}; class CApp
{
public:
CApp();
virtual ~CApp(); static std::shared_ptr<CApp> create(app_t type);
static app_t get_type_by_name(const std::string &name); int set_arg(std::vector<std::string> arg);
virtual int init() = 0; void set_inner_app(std::shared_ptr<CApp> app); std::string get_err() const; virtual bool available() const = 0;
virtual char next() = 0; protected:
std::vector<std::string> args;
std::string error;
std::shared_ptr<CApp> inner;
}; // 创建
std::shared_ptr<CApp> CApp::create(app_t type)
{
switch (type)
{
case app_none:
break;
case app_null:
return std::make_shared<CAppNull>();
case app_pipe:
return std::make_shared<CAppPipe>();
case app_range:
return std::make_shared<CAppRange>();
case app_take:
return std::make_shared<CAppTake>();
case app_last:
return std::make_shared<CAppLast>();
case app_load:
return std::make_shared<CAppLoad>();
case app_save:
return std::make_shared<CAppSave>();
default:
break;
}
assert(!"invalid type");
return nullptr;
}
3. AppLoad
就举这一个例子吧
int CAppTake::init() // 初始化
{
if (args.size() == 1) // 有一个参数
{
start = 1; // 计数开始
end = atoi(args[0].c_str()); // 计数结束
}
else
{
error = "invalid argument size";
return -1;
}
return 0;
} bool CAppTake::available() const
{
return start <= end || !data.empty();
} char CAppTake::next()
{
if (data.empty())
{
if (!available()) // 上一流已经中止
return '\0';
while (inner->available()) // 上一流有数据
{
auto c = inner->next();
data.push(c);
if (c == '\n') // 读取一行到data中
break;
}
start++; // 计数加一
if (data.empty()) // 没有数据了
return '\0';
}
auto ch = data.front(); // 输出读取的一行数据
data.pop();
return ch;
}
阶段性总结
总之,做这个轮子还是挺愉悦的~因为并未脱离舒适区。。就当复习吧。
好吧,其实写这玩意是因为bash中的awk、sed、grep等查找替换太复杂了,还不如自己做个。
由https://zhuanlan.zhihu.com/p/26591115备份。
介绍CppShell的更多相关文章
- CSS3 background-image背景图片相关介绍
		
这里将会介绍如何通过background-image设置背景图片,以及背景图片的平铺.拉伸.偏移.设置大小等操作. 1. 背景图片样式分类 CSS中设置元素背景图片及其背景图片样式的属性主要以下几个: ...
 - MySQL高级知识- MySQL的架构介绍
		
[TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...
 - Windows Server 2012 NIC Teaming介绍及注意事项
		
Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...
 - Linux下服务器端开发流程及相关工具介绍(C++)
		
去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把自己接触到的这些东西记录下来,为后来者提供参考,相当于一个路 ...
 - JavaScript var关键字、变量的状态、异常处理、命名规范等介绍
		
本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...
 - HTML DOM 介绍
		
本篇主要介绍DOM内容.DOM 节点.节点属性以及获取HTML元素的方法. 目录 1. 介绍 DOM:介绍DOM,以及对DOM分类和功能的说明. 2. DOM 节点:介绍DOM节点分类和节点层次. 3 ...
 - HTML 事件(一) 事件的介绍
		
本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...
 - HTML5 介绍
		
本篇主要介绍HTML5规范的内容和页面上的架构变动. 目录 1. HTML5介绍 1.1 介绍 1.2 内容 1.3 浏览器支持情况 2. 创建HTML5页面 2.1 <!DOCTYPE> ...
 - ExtJS 4.2 介绍
		
本篇介绍ExtJS相关知识,是以ExtJS4.2.1版本为基础进行说明,包括:ExtJS的特点.MVC模式.4.2.1GPL版本资源的下载和说明以及4种主题的演示. 目录 1. 介绍 1.1 说明 1 ...
 
随机推荐
- 最新office2003密钥
			
Microsoft Office Professional Edition 2003GWH28-DGCMP-P6RC4-6J4MT-3HFDY Office2003序列号注册码sn: WFDWY-XQ ...
 - Qt 维护工具MaintenanceTool.exe 使用
			
QT如何管理组件(解决“要继续此操作,至少需要一个有效且已启用的储存库”问题) 转载2017-10-26 01:48:46 标签:qt QT的组件管理软件并没有在开始菜单或者桌面添加快捷方式(5.9版 ...
 - C# 7-Zip Executable
			
7-Zip can be used in C# programs. It provides excellent compression ratios. We embed the 7-Zip comma ...
 - SQL Server 2008新特性——策略管理
			
策略管理是SQL Server 2008中的一个新特性,用于管理数据库实例.数据库以及数据库对象的各种属性.策略管理在SSMS的对象资源管理器数据库实例下的“管理”节点下,如图: 从图中可以看到,策略 ...
 - 数字证书相关技术 : Versign信任签章
			
资料网址: 淘宝网站可信服务 http://www.ert7.com/case/eb/1391.html Versign信任签章 http://www.ert7.com/verisign/ssl/29 ...
 - [Python爬虫] 之七:selenium webdriver定位不到元素的五种原因及解决办法(转载)
			
转载:http://www.51testing.com/html/87/300987-831171.html 1.动态id定位不到元素for example: //WebElement ...
 - Qt正则表达式提取数据
			
这几天在上嵌入式课程设计,需要用到Qt,这个是信号与槽的,寒假的时候也简单学习了一些,但是没有怎么深入,又回过来看了看Qt,发现Qt的ui界面配置与Android的好像,当然Qt也可以拿来开发Andr ...
 - 图结构练习——BFS——从起始点到目标点的最短步数(邻接表+BFS)
			
图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描写叙述 在古老的魔兽传说中.有两个军团,一个 ...
 - [Functional Programming] Function signature
			
It is really important to understand function signature in functional programming. The the code exam ...
 - 将应用发布到WasLiberty的两种方法
			
1.直接将War放到defaultserver(或其它自定义server)的dropin目录. 一放进去,war中的app就会随着server启动起来,这个war是会被解压的,用find / -nam ...