写在前面

bajdcc/CppShell

最近心血来潮又造了个轮子,其实启发我的是bajdcc/jMiniLang中的管道思想,java运行着太慢,因而用C艹实现一把。

如题图所示,使用非常非常简单。

  1. range生成有限/无穷数列,`range 0`生成自然数无穷数列,`range 1 10`生成1到10

  2. take N,表示从有限/无穷数列中摘取前N行
  3. last N,表示从有限数列中取倒数N行,当然了如果数列是无穷的,那么GG
  4. load FILENAME,加载文件
  5. save FILENAME,保存至文件

设计思路

首先当然是解析命令行输入啦,然后则是处理与输出。

一、处理命令

假如命令是诸如`load 1.txt | uppercase | save 2.txt`,以“|”作分隔,分隔后得到单一程序命令行,再以空格作分隔。

用式子来表示是:

  1. 用户输入command_string

  2. 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++技巧。

三、应用程序接口设计

其实也就是“流”接口的设计。参考众多流设计,这里我只实现最简单的:

  1. bool available() const,返回流是否可用/到末尾

  2. 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的更多相关文章

  1. CSS3 background-image背景图片相关介绍

    这里将会介绍如何通过background-image设置背景图片,以及背景图片的平铺.拉伸.偏移.设置大小等操作. 1. 背景图片样式分类 CSS中设置元素背景图片及其背景图片样式的属性主要以下几个: ...

  2. MySQL高级知识- MySQL的架构介绍

    [TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...

  3. Windows Server 2012 NIC Teaming介绍及注意事项

    Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...

  4. Linux下服务器端开发流程及相关工具介绍(C++)

    去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把自己接触到的这些东西记录下来,为后来者提供参考,相当于一个路 ...

  5. JavaScript var关键字、变量的状态、异常处理、命名规范等介绍

    本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...

  6. HTML DOM 介绍

    本篇主要介绍DOM内容.DOM 节点.节点属性以及获取HTML元素的方法. 目录 1. 介绍 DOM:介绍DOM,以及对DOM分类和功能的说明. 2. DOM 节点:介绍DOM节点分类和节点层次. 3 ...

  7. HTML 事件(一) 事件的介绍

    本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...

  8. HTML5 介绍

    本篇主要介绍HTML5规范的内容和页面上的架构变动. 目录 1. HTML5介绍 1.1 介绍 1.2 内容 1.3 浏览器支持情况 2. 创建HTML5页面 2.1 <!DOCTYPE> ...

  9. ExtJS 4.2 介绍

    本篇介绍ExtJS相关知识,是以ExtJS4.2.1版本为基础进行说明,包括:ExtJS的特点.MVC模式.4.2.1GPL版本资源的下载和说明以及4种主题的演示. 目录 1. 介绍 1.1 说明 1 ...

随机推荐

  1. 如何从MATLAB里面保存出分辨率高的图形

    MATLAB堪称科技工作者的倚天屠龙,其科学计算,简洁的编程风格,友好的图形界面等等,都使得它颇受欢迎.MATLAB作图相当简单,而且美观,但是,缺点是分辨率低,一直没有发现,直到最近一期刊编辑告诉我 ...

  2. C# 7-Zip Executable

    7-Zip can be used in C# programs. It provides excellent compression ratios. We embed the 7-Zip comma ...

  3. 2014Esri全球用户大会——亮点系列之产品技术

    2014年Esri全球用户大会已于7月14日~18日隆重召开,让我们一起来回味下面精彩内容: 序:大会主题"Creating Our Future" [解读]:     传达两个核 ...

  4. eclipse 添加 Courier New 字体

    下载了eclipse3.7,发现这个版本默认的字体不是Courier New,后来通过eclipse->windows->preferences->general->apper ...

  5. LXD 2.0 系列(一):LXD 入门

    LXD是提供了RESTAPI的LXC 容器管理器,主要是管理linux容器的第三方管理器.也许现在您还没有听说过,下面我们就来入门——介绍一下LXD 什么是 LXD ? 简单地说,LXD 就是一个提供 ...

  6. Android程序的反编译对抗研究

    转自: http://www.freebuf.com/tools/76884.html 一.前言 对抗反编译是指让apk文件或者dex文件无法正常通过反编译工具,而且有可能导致工具异常或者崩溃,如ap ...

  7. ExplorerControls的显示问题

    我们都知道ArcGIS桌面版本"添加数据"的功能是弹出一选择对话框,如下图所示,但我们总想搞自己的,以便融入自己的风格.下图左边是ArcGIS自带的"添加数据" ...

  8. Myeclipse2013下载,安装,破解,介绍(CSDN首发)

    MyEclipse 2013新特性 根据官方最新消息,MyEclipse 2013已经正式发布!MyEclipse 2013支持HTML5.JQuery和主流的Javascript 库. 随着MyEc ...

  9. 算法笔记_033:十六进制转八进制(Java)

    目录 1 问题描述 2 解决方案 2.1 注意问题 2.2 具体实现代码   1 问题描述 具体问题描述 给定n个十六进制正整数,输出它们对应的八进制数. 输入格式 输入的第一行为一个正整数n (1& ...

  10. JUnit 3.8 通过反射测试私有方法

    测试私有(private)的方法有两种: 1)把目标类的私有方法(修饰符:private)修改为(public),不推荐,因为修改了源程序不佳 2)通过反射 (推荐) 代码演示: 目标程序 Priva ...