写在前面

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. iOS开源项目:PullToRefresh

    PullToRefresh实现了类似微博下拉刷新的功能:https://github.com/sonnyparlin/PullToRefresh 首先把PullToRefreshView.h, Pul ...

  2. awk排序作业

    输入:给定一个hotelinfo文件,文件格式如下: shanghai_city_7208      上海全季酒店淮海路店 shanghai_city_14744     锦江之星上海金山城市沙滩店 ...

  3. 数学图形(1.39)TN constant curve

    这是个类似巴黎铁塔的曲线. #http://www.mathcurve.com/courbes2d/tn/tn.shtml vertices = t = to (PI*0.999) a = s = s ...

  4. css3动画属性系列之transform细讲旋转rotate

    1.语法: transform: none |  <transform-function> [<transform-function>]* 2.取值: none         ...

  5. sqllite3

    OS X自从10.4后把SQLite这套相当出名的数据库软件,放进了作业系统工具集里.OS X包装的是第三版的SQLite,又称SQLite3.这套软件有几个特色: 软件属于公共财(public do ...

  6. SQLServer 之 Group By 和 Compute By

    创建测试表,如下: CREATE TABLE tableTest ( Id INT PRIMARY KEY, DepartMent ), Name ), Salary int ) 添加测试数据,如下图 ...

  7. iOS 检查app版本更新操作

    iOS 检查app版本更新操作 1:获取本地安装的版本信息: [NSString stringWithFormat:@"Version %@ (%@)", [[[NSBundle ...

  8. nginx-rtmp流媒体服务器搭建【转】

    nginx-rtmp https://github.com/pengqiuyuan/nginx-rtmp nginx-rtmp 流媒体服务器的搭建(采集桌面,手机直播) 在线Demo,直播自己的pc机 ...

  9. postgresql-slony-I同步复制配置步骤

    主数据库: 172.16.254.21 端口:5432 从数据库: 172.16.254.22 端口:5432 步骤1:主从均安装slon apt-get install slon-bin 步骤2:主 ...

  10. mysql 禁制远程连接

    改表法:把host地址改为% use mysql; update user set host = '%' where user = 'root'and host="127.0.0.1&quo ...