linux c read函数返回值,Linuxc - GNU Readline 库及编程简介

GNU Readline 库及编程简介

简介

用过 Bash 命令行的一定知道,Bash 有几个特性:

TAB 键可以用来命令补全

↑ 或 ↓ 键可以用来快速输入历史命令

还有一些交互式行编辑快捷键:

C-A / C-E 将光标移到行首/行尾

C-B / C-F 将光标向左/向右移动一个位置

C-D 删除光标下的一个字符

C-K 删除光标及光标到行尾的所有字符

C-U 删除光标到行首的所有字符

...

同样的操作在很多交互式程序都有类似的操作,例如 ftp、gdb 等等,那么你是否想过这些是如何实现的呢?如果我们要做一个命令行下的交互式开源软件,是否希望也能有这些命令补全、搜索历史命令、行编辑快捷键等等这些人性化的交互方式呢?

要想实现这些,你有两种途径:可以自己写程序实现,或者调用开源的库 Readline Lib。例如上面介绍的 bash、ftp、gdb 等等软件都使用了 GNU 的开源跨平台库,为其提供交互式的文本编辑功能。当然需要注意的是,Readline Library 是 GNU 自由软件,在 GNU GPL V3 协议下发布,因此如果你的程序中需要用到该库,也必须遵守相关协议。

本文首先简单介绍一下该库的基本使用方法,后面会稍微详细介绍下如何使用 Readline 来自定义命令补全功能。

Readline 基本操作

输入读取

很多命令行交互式程序交互方式都差不多,输出提示符,等待用户输入命令,用户输入命令之后按回车,程序开始解析命令并执行。那么这里面有个动作是读入用户的输入,以前我们也许使用 gets() 这样的函数来实现,当我们使用 Readline 库时,可以使用 readline() 函数来替换它,该函数在 ANSI C 中定义如下:

char *readline (char *prompt);

该函数带有一个参数 prompt,表示命令提示符,例如 ftp 中就是 "ftp>",用户在后面可以输入命令,当按下回车键时,程序读入该行(不包括最后的换行符)存入字符缓冲区中,readline 的返回值就是该行文本的指针。注意:当该行文本不需要使用时,需要释放该指针指向的空间,防止内存泄漏。当读入 EOF时,如果还未读入其它字符,则返回 (char *) NULL,否则读入结束,与读入换行效果相同。

命令补全

除了能读入用户的输入,我们有时希望交互更简单些,例如命令补全。当有很多命令时,如果希望用户都能准确记忆命令的拼写是困难的,那么一般做法是按下 TAB 键进行命令提示及补全,如 ftp 下输入一个字符c 之后按下 TAB 键,会列出所有以 c 开头的命令:

ftp> c

case cd cdup chmod close cr

readline 函数其实已经给用户默认的 TAB 补全的功能:根据当前路径下文件名来补全。

如果你不想 Readline 根据文件名补全,你可以通过 rl_bind_key() 函数来改变 TAB 键的行为。该函数的原型为:

int rl_bind_key(int key, int (*function)());

该函数带有两个参数:key 是你想绑定键的 ASCII 码字符表示,function 是当 key 键按下时触发调用函数的地址。如果想按下 TAB 键就输入一个制表符本身,可以将 TAB 绑定到 rl_insert() 函数,这是 Readline 库提供的函数。如果 key 不是有效的 ASCII 码值(0~255之间),rl_bind_key() 返回非 0。

这样,禁止 TAB 的默认行为,下面这样做就可以了:

rl_bind_key('\t', rl_insert);

这个代码需要在你程序一开始就调用;你可以写一个函数叫 initialize_readline() 来执行这个动作和其它一些必要的初始化,例如安装用户自定义补全。

当我们希望输入 TAB 时不是列出当前路径下的所有文件,而是列出程序内置的一些命令,例如上面举到 ftp 的例子,这种行为称为自定义补全。 该操作较复杂,我们留在后面一节主要介绍。

历史记录

基本操作还有一个——搜索历史。我们希望输入过的命令行,还可以通过 C-p 或者 C-s 来搜索到,那么就需要将命令行加入到历史列表中,可以调用 add_history() 函数来完成。但尽量将空行也加入到历史列表中,因为空行占用历史列表的空间而且也毫无用处。综上,我们可以写出一个 Readline 版的 gets() 函数 rl_gets():

/* A static variable for holding the line. */

static char *line_read = (char *)NULL;

/* Read a string, and return a pointer to it. Returns NULL on EOF. */

char *

rl_gets ()

{

/* If the buffer has already been allocated, return the memory

to the free pool. */

if (line_read)

{

free (line_read);

line_read = (char *)NULL;

}

/* Get a line from the user. */

line_read = readline ("");

/* If the line has any text in it, save it on the history. */

if (line_read && *line_read)

add_history (line_read);

return (line_read);

}

自定义补全

上面也提到了什么是自定义补全,无疑这在命令行交互式程序中是非常重要的,直接影响到用户体验。Readline 库提供了两种比较常用的补全方式——按照文件名补全和按照用户名补全,分别对应 Readline 中已经实现的两个函数 rl_filename_completion_function 和 rl_username_completion_function。如果我们既不希望按照文件名和用户名来补全,希望按照程序的命令补全,应该怎么做呢?也很容易想到,只要实现自己的补全函数就好了。

Readline 补全的工作原理如下:

用户接口函数 rl_complete() 调用 rl_completion_matches() 来产生可能的补全列表;

内部函数 rl_completion_matches() 使用程序提供的 generator 函数来产生补全列表,并返回这些匹配的数组,在此之前需要将 generator 函数的地址放到 rl_completion_entry_function 变量中,例如上面提到的按文件名或用户名补全函数就是不同的 generators;

generator 函数在 rl_completion_matches() 中不断被调用,每次返回一个字符串。generator 函数带有两个参数:text 是需要补全的单词的部分,state 在函数第一次调用时为 0,接下来调用时非 0。generator 函数返回 (char *)NULL 通知 rl_completion_matches() 没有剩下可能的匹配。

Readline 库中有个变量 rl_attempted_completion_function,改变量类型是一个函数指针rl_completion_func_t *,我们可以将该变量设置我们自定义的产生匹配的函数,该按下 TAB 键时会调用该函数,函数具有三个参数:

text: 该参数是待补全的单词的部分,例如在 Bash 提示符后输入一个 c 字符,按下 TAB,此时 text指向的是 "c" 字符串的指针;在 Bash 提示符后输入一个 cd /home/gu 字符串,按下 TAB,此时 text指向的是"/home/gu" 字符串的指针;

start: text 字符串在该行输入中的起始位置,例如对于上面的例子,第一种情况下是 0,第二种情况下是 3;

end: text 字符串在该行输入中的结束位置,例如对于上面的例子,第一种情况下是 1,第二种情况下是 11。

我们自定义的补全函数可以根据传入的参数来设置我们希望按照什么方式补全,例如对于 Bash 下的 cd命令,我们希望开始是命令补全,当命令补全之后,后面接着跟的是文件名补全,这样可以使用rl_completion_matches() 来绑定使用哪种 generator,rl_completion_matches() 函数的原型是:

char ** rl_completion_matches (const char *text, rl_compentry_func_t *entry_func)

带有两个参数:text 就是上面介绍的传入的待补全的单词,第二个参数 entry_func 是上面反复介绍的generator 函数的指针。该函数的返回值是 generator 产生的可能匹配 text 的字符串数组指针,该数组的最后一项是 NULL 指针。

好了,上面说了这么多关于自定义补全的函数和变量,到底怎么用呢,估计还是比较模糊,那么看一个例子估计就很清楚了,这个例子是 Readline 官方提供的示例程序,由于比较长,就不在这里贴出来了,你可以在 http://cnswww.cns.cwru.edu/ph... 找到。

总结

其实,虽然说了很多,但还只是 Readline 库的皮毛,这个库的功能远远比这强大的多,如果想深入了解并且运用,你必须要做三件事:

Read The Fucking Manual:阅读官方的 文档

Read The Fucking Source Code:阅读官方提供的例子代码,如果想了解更深入可以去看 Readline 的源码

Show Your Code:自己动手写几个例子试试,如果有机会运用到你的项目中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331668.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java泛型——桥方法

【0】README 0.1)以下内容转自: http://www.cnblogs.com/ggjucheng/p/3352519.html 【1】泛型约束和局限性—— 类型擦除所带来的麻烦 1.1)继承泛型类型的多态麻烦。(—— 子类没有覆盖住父类的方法 ) 看看下面这个…

Hibernate框架之入门配置

一、Hibernate导入相关的包参考:http://blog.csdn.net/tunni/article/details/54982160这些包包括相应数据库驱动、hibernate.zip下lib目录下的jar包,其中必须包是required目录下的.jar二、在项目classpath(类路径,即src目录下&am…

annotations_Spring Annotations我从来没有机会使用第2部分:@ConfigurationProperties

annotations几天前,我在检查其他内容时不小心偶然发现了Spring Boot项目中的Spring注释。 我们都知道如何将带有“ Value”的属性值绑定到类,并且我们都知道如果要绑定多个属性,这可能会很麻烦。 Spring Boot可以为您提供帮助。 您可以使用“…

linux下检测硬盘,【转载】linux下硬盘监控诊断工具SmartTools

对于windwos下raid卡具备告警功能,当硬盘故障、raid卡告警时,可以发邮件给管理员。IBM、HP、Dell都支持。但在linux下,就没有找到相关的好工具了,今天到陈沙克的博客上到一篇关于linux下硬盘监控诊断工具SmartTools,感…

hibernate框架之主键生成

一、 hibernate 框架中主键的生成策略 (1)native: 表示由设置的方言决定采用什么数据库生成主键方式,根据底层数据库能力选择identity、sequence中的一个。 例如:在MySQL中会采用自增长的方式,主键字段必须都是整形类型;在Oracle数…

java泛型通配符

【0】README 0.1)以下内容转自: http://blog.csdn.net/baple/article/details/25056169 0.2) T 有类型 ? 未知类型 一、通配符的上界(extends关键字) 既然知道List并不是List的子类型,那就需…

jdk 1.8 内存可见性_JDK 14中的常规,安全和确定性外部内存访问

jdk 1.8 内存可见性在“ JDK 14 Rampdown:Build 27 ”一文中,我总结了JDK 14 Early Access Build #27中新增的许多针对JDK 14的功能。 已经存在另一种JDK 14 Early Access Build,并且此[ Build 28(2019/12/18&#xff…

linux开启防火墙ping,如何在防火墙中放开ping

如何在防火墙中放开ping操作时需要注意的几项:1,注意iptables各版本间的区别我们的server os最旧的版本是redhat 7.3 kernel是2.4.20-18.7最新的server os最新的版本是centos 5, kernel是2.6.18-8差距很大iptables以模块形式运行在内核的空间,用lsmod可以看到所以它与内核的版本…

Hibernate: You have an error in your SQL syntax; check the manual that corresponds to your MySQL

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ...Hibernate 出现这样的错误是因为表中的字段名使用了sql的保留字,不要使用保留字 一、mysql的保留字主要有&#xff1…

java.io 包

java.io 通过数据流、序列化和文件系统提供系统输入和输出。 请参见: 接口摘要CloseableCloseable 是可以关闭的数据源或目标。DataInputDataInput 接口用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构。DataOutputDataOutput 接口用…

linux系统怎么安装pr,Linux安装后的配置

系统:CentOS-6.31.NVIDIA驱动的安装与配置Linux本身的显卡驱动是能够满足平常应用的,但是有时候我们为了获得3D效果,或者更流畅的视频体验,我们会安装新的显卡驱动。这时候就需要安装闭源驱动了,个人认为闭源的驱动更为好一些&…

java第三阶段源代码_有效Java第三版的源代码已更新为使用较新的功能

java第三阶段源代码那些已经阅读了有效Java 第三版的人可能知道与该书相关的源代码可以在GitHub上获得 。 jbloch / effective-java-3e-source-code项目拥有1700多个星星,截至撰写本文时,它已被分叉了近800次。 在有效Java的第三版中, Java的…

《线性代数及其应用》

【0】README 0.1)以下内容转自: http://blog.csdn.net/ljbkiss/article/details/7194719 【1】正文干货 1.1) 断断续续的终于把 《线性代数及其应用(Linear Algebra and Its Application) David C.Lay》 这本书看完了…

micrometer_具有InlfuxDB的Spring Boot和Micrometer第1部分:基础项目

micrometer对于那些关注此博客的人来说,难怪我会经常使用InfluxDB。 我喜欢这样一个事实,它是一个真正的单一用途的数据库(时间序列),具有许多功能,并且还带有企业支持。 Spring也是我选择的工具之一。 因…

如何在win7(xp)home version下安装 rose 32 bit

【0】README 0.1) 以下部分内容转自 http://blog.csdn.net/encienqi/article/details/5578725 【1】 干货开始 如果是家庭版(win7 or WindowsXPHomeEdition)请先按以下步骤修改部分文件后再安装: 1.1)安装Microsoft Orca工具 step1&#x…

接口 Closeable

java.io 接口 Closeable public interface Closeable Closeable 是可以关闭的数据源或目标。调用 close 方法可释放对象保存的资源(如打开文件)。 从以下版本开始:1.5方法摘要 void close() 关闭此流并释放与此流关联的所有系统资源。 方法详…

Linux下python包放在哪,在alpinlinux中使用apk安装的Python包

我想用apk在Alpine Linux中安装一些Python包。我用numpy作为下面的例子。文档文件FROM python:3-alpineRUN apk add --update py3-numpy我建立我的码头形象$ docker build -t python-numpy .Sending build context to Docker daemon 2.048kBStep 1/2 : FROM python:3-alpine---…

spring 消息传递机制_Spring再次涵盖了您:继续进行消费者驱动的消息传递合同测试...

spring 消息传递机制在上一篇文章中,我们已经开始讨论基于消息的通信中的消费者驱动的合同测试 。 在今天的帖子中,我们将在测试工具箱中包含另一个工具,但是在此之前,让我对显微镜下的系统进行快速回顾。 它有两项服务&#xff0…

接口 DataInput

java.io接口 DataInput 所有已知子接口:ImageInputStream, ImageOutputStream, ObjectInput所有已知实现类:DataInputStream, FileCacheImageInputStream, FileCacheImageOutputStream, FileImageInputStream, FileImageOutputStream, ImageInputStreamI…

java反射机制总结

【0】README 0.1)以下内容转自: http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html 0.2)for source code, please visit (1~14 source code : https://github.com/pacosonTang/core-java-volume/blob/master…