├── .github
└── workflows
│ ├── build.yml
│ ├── coverity.yml
│ └── release.yml
├── .gitignore
├── ChangeLog.md
├── INSTALL.md
├── LICENSE
├── Make.os9
├── Makefile.am
├── README.md
├── autogen.sh
├── configure.ac
├── debian
├── .gitignore
├── README.Debian
├── changelog
├── compat
├── control
├── copyright
├── dirs
├── docs
├── libeditline-dev.install
├── libeditline1.install
├── libeditline1.symbols
├── rules
└── source
│ └── format
├── docs
├── HACKING.md
├── README
└── TODO.md
├── examples
├── .gitignore
├── Makefile.am
├── cli.c
├── excallback.c
├── fileman.c
└── testit.c
├── include
├── Makefile.am
└── editline.h
├── libeditline.pc.in
├── m4
└── .gitignore
├── man
├── Makefile.am
└── editline.3
└── src
├── .gitignore
├── Makefile.am
├── complete.c
├── editline.c
├── editline.h
├── os9.h
├── sysos9.c
├── sysunix.c
└── unix.h
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Bob the Builder
2 |
3 | # Run on all branches, including all pull requests, except the 'dev'
4 | # branch which we use for Coverity Scan (limited tokens/day)
5 | on:
6 | push:
7 | branches:
8 | - '**'
9 | - '!dev'
10 | pull_request:
11 | branches:
12 | - '**'
13 |
14 | jobs:
15 | build:
16 | name: ${{ matrix.compiler }}
17 | runs-on: ubuntu-latest
18 | strategy:
19 | matrix:
20 | compiler: [gcc, clang]
21 | fail-fast: false
22 | env:
23 | MAKEFLAGS: -j3
24 | CC: ${{ matrix.compiler }}
25 | steps:
26 | - uses: actions/checkout@v4
27 | - name: Configure
28 | run: |
29 | ./autogen.sh
30 | ./configure --prefix= --disable-silent-rules \
31 | --enable-sigstop --enable-terminal-bell
32 | - name: Build
33 | run: |
34 | make
35 | - name: Install to ~/tmp and Inspect
36 | run: |
37 | DESTDIR=~/tmp make install-strip
38 | ls -lR ~/tmp
39 |
--------------------------------------------------------------------------------
/.github/workflows/coverity.yml:
--------------------------------------------------------------------------------
1 | name: Coverity Scan
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'dev'
7 |
8 | env:
9 | PROJECT_NAME: editline
10 | CONTACT_EMAIL: troglobit@gmail.com
11 | COVERITY_NAME: troglobit-editline
12 | COVERITY_PROJ: troglobit%2Feditline
13 |
14 | jobs:
15 | coverity:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Fetch latest Coverity Scan MD5
20 | id: var
21 | env:
22 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
23 | run: |
24 | wget -q https://scan.coverity.com/download/cxx/linux64 \
25 | --post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
26 | -O coverity-latest.tar.gz.md5
27 | echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
28 | - uses: actions/cache@v4
29 | id: cache
30 | with:
31 | path: coverity-latest.tar.gz
32 | key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
33 | restore-keys: |
34 | ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
35 | ${{ runner.os }}-coverity-
36 | ${{ runner.os }}-coverity
37 | - name: Download Coverity Scan
38 | env:
39 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
40 | run: |
41 | if [ ! -f coverity-latest.tar.gz ]; then
42 | wget -q https://scan.coverity.com/download/cxx/linux64 \
43 | --post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
44 | -O coverity-latest.tar.gz
45 | else
46 | echo "Latest Coverity Scan available from cache :-)"
47 | md5sum coverity-latest.tar.gz
48 | fi
49 | mkdir coverity
50 | tar xzf coverity-latest.tar.gz --strip 1 -C coverity
51 | - name: Configure
52 | run: |
53 | ./autogen.sh
54 | ./configure --prefix= --enable-sigstop --enable-terminal-bell --enable-examples
55 | - name: Build
56 | run: |
57 | export PATH=`pwd`/coverity/bin:$PATH
58 | cov-build --dir cov-int make
59 | - name: Submit results to Coverity Scan
60 | env:
61 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
62 | run: |
63 | tar czvf ${PROJECT_NAME}.tgz cov-int
64 | curl \
65 | --form project=${COVERITY_NAME} \
66 | --form token=$TOKEN \
67 | --form email=${CONTACT_EMAIL} \
68 | --form file=@${PROJECT_NAME}.tgz \
69 | --form version=trunk \
70 | --form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
71 | https://scan.coverity.com/builds?project=${COVERITY_PROJ}
72 | - name: Upload build.log
73 | uses: actions/upload-artifact@v4
74 | with:
75 | name: coverity-build.log
76 | path: cov-int/build-log.txt
77 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release General
2 |
3 | on:
4 | push:
5 | tags:
6 | - '[0-9]+.[0-9]+*'
7 |
8 | jobs:
9 | release:
10 | name: Build and upload release tarball
11 | if: startsWith(github.ref, 'refs/tags/')
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - name: Creating Makefiles ...
16 | run: |
17 | ./autogen.sh
18 | ./configure --prefix=
19 | - name: Build release ...
20 | run: |
21 | make release
22 | mkdir -p artifacts/
23 | mv ../*.tar.* artifacts/
24 | - name: Extract ChangeLog entry ...
25 | run: |
26 | awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
27 | |head -n -1 > release.md
28 | cat release.md
29 | - uses: ncipollo/release-action@v1
30 | with:
31 | name: Editline v${{ github.ref_name }}
32 | bodyFile: "release.md"
33 | artifacts: "artifacts/*"
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | */.libs/
3 | *.lo
4 | *.o
5 | *.pc
6 | .deps
7 | .testit_history
8 | GPATH
9 | GRTAGS
10 | GTAGS
11 | Makefile
12 | Makefile.in
13 | aclocal.m4
14 | archive
15 | autom4te.cache
16 | compile
17 | config.guess
18 | config.h
19 | config.h.in
20 | config.log
21 | config.status
22 | config.sub
23 | configure
24 | depcomp
25 | install-sh
26 | libtool
27 | ltmain.sh
28 | missing
29 | stamp-h1
30 |
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | All notable changes to the project are documented in this file.
5 |
6 |
7 | [1.17.1][] - 2020-02-23
8 | -----------------------
9 |
10 | ### Fixes
11 | - Fix #38: Fix for multiline representing as one line
12 | - Fix packaging, missing files in libeditline1, regression from 1.16.0
13 | - Fix packaging, update to latest std version
14 | - Fix formatting of function names in man page
15 | - Restore tar.gz distribution, for usability on systems that do not
16 | have xz in their default install
17 |
18 |
19 | [1.17.0][] - 2020-01-05
20 | -----------------------
21 |
22 | ### Changes
23 | - Simple multi-line support by Dima Volynets, @dvolynets
24 |
25 | ### Fixes
26 | - Fix return value from `read_history()` and `write_history()`, could
27 | return `errno` instead of `EOF` to indicate error. Now both functions
28 | have uniform return values on error
29 | - Handle internal `realloc()` errors better. Now memory is not leaked
30 | if `realloc()` fails
31 | - Fix possible NULL pointer dereference in key binding lookup function
32 |
33 |
34 | [1.16.1][] - 2019-06-07
35 | -----------------------
36 |
37 | ### Changes
38 | - Major updates to the `editline.3` man page
39 | - Cleanup of examples `cli.c` and `fileman.c`
40 | - Add example of hidden input prompt to `cli.c`
41 |
42 | ### Fixes
43 | - Fix #20: `configure --disable-eof` does not bite
44 | - Fix #23: Make Ctrl-L clear the screan instead of starting a new line
45 | Like Ctrl-D, which exits, Ctrl-L only clears the screen when the line
46 | is empty and the cursor is at the start of the line, otherwise Ctrl-L
47 | will redraw/refresh the current line.
48 | - Fix #24: Fix behavior when TTY is narrower than column width, by Will Dietz
49 | - Fix #25: Avoid continuously duplicate commands in history
50 | - Fix #31: Aborting i-search with Ctrl-C should not generate signal
51 |
52 |
53 | [1.16.0][] - 2018-09-16
54 | -----------------------
55 |
56 | Event loop callback support.
57 |
58 | ### Changes
59 | - `rl_unintialize()`, new function to free all memory, by Claus Fischer
60 | - `rl_insert_text()`, new GNU Readline compat function
61 | - `rl_refresh_line()`, new GNU Readline compat function
62 | - `rl_callback_*()`, alternate interface to plain `readline()` for event
63 | loops. Modeled after the GNU Readline API
64 | - `rl_completion_entry_function`, and `rl_attempted_completion_function`
65 | are two new GNU Readline compat user hooks for the completion framework
66 | - `rl_completion_matches()` and `rl_filename_completion_function()`
67 | are two new GNU Readline compat functions
68 | - Add new example: `fileman.c` from GNU Readline to demonstrate the
69 | level of compatibility of the revamped completion framework
70 | - Add support for Ctrl-Right and Ctrl-Left, forward/backward word
71 | - Add .deb package to official release target
72 |
73 | ### Fixes
74 | - Fixed header guards, avoid using leading `__`
75 | - Spell check fixes
76 | - Remove duplicate code in history check
77 | - Use `NULL` instead of `0`, and `-1` instead of `NULL`, where applicable
78 | - Misc. minor Coverity Scan fixes
79 | - Misc. minor fixes to `testit.c` example code
80 | - Add `-Wextra` to std `CFLAGS`
81 | - Check `fclose()` return value in in `write_history()` and `read_history()`
82 | - Initialize global variables and reset to `NULL` on `free()`
83 | - Fix off-by-one in forward kill word, avoid deleting too much
84 | - Skip (or kill) leading whitespace when skipping (or killing) forwards
85 |
86 |
87 | [1.15.3][] - 2017-09-07
88 | -----------------------
89 |
90 | Bug fix release.
91 |
92 | ### Changes
93 | - Refactor all enable/disable configure options, same problem as in #7
94 |
95 | ### Fixes
96 | - Fix #7: `--enable-termcap` configure option does not work. The script
97 | enabled termcap by default rather than the other way around.
98 |
99 | Also, check for terminfo as well, when `--enable-termcap` is selected.
100 |
101 |
102 | [1.15.2][] - 2016-06-06
103 | -----------------------
104 |
105 | Bug fixes and minor feature creep in `pkg-config` support.
106 |
107 | ### Changes
108 | - Prevent mangling of symbols when linking with C++. Patch courtesy of
109 | Jakub Pawlowski
110 | - Add `libeditline.pc` for `pkg-config`
111 |
112 | ### Fixes
113 | - Do not assume a termcap library exists, check for `tgetent()` in
114 | curses, ncurses, tinfo and termcap libraries
115 | - Call `tty_flush()` when user calls `rl_forced_update_display()`
116 | to prevent screen becoming garbled. Patch by Jakub Pawlowski
117 |
118 |
119 | [1.15.1][] - 2015-11-16
120 | -----------------------
121 |
122 | Bug fixes only.
123 |
124 | ### Changes
125 | - Update README with origin of this version of editline
126 |
127 | ### Fixes
128 | - Fix build system, don't force automake v1.11, require at least v1.11
129 | - Fix build problem with examples using `--enable-termcap`
130 |
131 |
132 | [1.15.0][] - 2015-09-10
133 | -----------------------
134 |
135 | ### Changes
136 | - Add support for `--disable-eof` and `--disable-sigint` to disable
137 | default Ctrl-D and Ctrl-C behavior
138 | - Add support for `el_no_hist` to disable access to and auto-save of history
139 | - GNU readline compat functions for prompt handling and redisplay
140 | - Refactor: replace variables named 'new' with non-reserved word
141 | - Add support for [Travis-CI][], continuous integration with GitHub
142 | - Add support for [Coverity Scan][], the best static code analyzer,
143 | integrated with [Travis-CI][] -- scan runs for each push to master
144 | - Rename NEWS.md --> ChangeLog.md, with symlinks for make install
145 | - Attempt to align with http://keepachangelog.com/ for this file
146 | - Cleanup and improve Markdown syntax in [README.md][]
147 | - Add API and example to [README.md][], inspired by [libuEv][]
148 | - Removed generated files from version control. Use `./autogen.sh`
149 | to generate the `configure` script when working from GIT. This
150 | does not affect distributed tarballs
151 |
152 | ### Fixes
153 | - Fix issue #2, regression in Ctrl-D (EOF) behavior. Regression
154 | introduced in [1.14.1][]. Fixed by @TobyGoodwin
155 | - Fix memory leak in completion handler. Found by [Coverity Scan][].
156 | - Fix suspicious use of `sizeof(char **)`, same as `sizeof(char *)` but
157 | non-portable. Found by [Coverity Scan][]
158 | - Fix out-of-bounds access in user key binding routines
159 | Found by [Coverity Scan][].
160 | - Fix invisible example code in man page
161 |
162 |
163 | [1.14.2][] - 2014-09-14
164 | -----------------------
165 |
166 | Bug fixes only.
167 |
168 | ### Fixes
169 | - Fix `el_no_echo` bug causing secrets to leak when disabling no-echo
170 | - Handle `EINTR` in syscalls better
171 |
172 |
173 | [1.14.1][] - 2014-09-14
174 | -----------------------
175 |
176 | Minor fixes and additions.
177 |
178 | ### Changes
179 | - Don't print status message on `stderr` in key binding funcions
180 | - Export `el_del_char()`
181 | - Check for and return pending signals when detected
182 | - Allow custom key bindings ...
183 |
184 | ### Fixes
185 | - Bug fixes ...
186 |
187 |
188 | [1.14.0][] - 2010-08-10
189 | -----------------------
190 |
191 | Major cleanups and further merges with Debian editline package.
192 |
193 | ### Changes
194 | - Merge in changes to `debian/` from `editline_1.12-6.debian.tar.gz`
195 | - Migrate to use libtool
196 | - Make `UNIQUE_HISTORY` configurable
197 | - Make scrollback history (`HIST_SIZE`) configurable
198 | - Configure options for toggling terminal bell and `SIGSTOP` (Ctrl-Z)
199 | - Configure option for using termcap to read/control terminal size
200 | - Rename Signal to `el_intr_pending`, from Festival speech-tools
201 | - Merge support for capitalizing words (`M-c`) from Festival
202 | speech-tools by Alan W Black
203 | - Fallback backspace handling, in case `tgetstr("le")` fails
204 |
205 | ### Fixes
206 | - Cleanups and fixes thanks to the Sparse static code analysis tool
207 | - Merge `el_no_echo` patch from Festival speech-tools
208 | - Merge fixes from Heimdal project
209 | - Completely refactor `rl_complete()` and `rl_list_possib()` with
210 | fixes from the Heimdal project. Use `rl_set_complete_func()` and
211 | `rl_set_list_possib_func()`. Default completion callbacks are now
212 | available as a configure option `--enable-default-complete`
213 | - Memory leak fixes
214 | - Actually fix 8-bit handling by reverting old Debian patch
215 | - Merge patch to improve compatibility with GNU readline, thanks to
216 | Steve Tell from way back in 1997 and 1998
217 |
218 |
219 | [1.13.0][] - 2010-03-09
220 | -----------------------
221 |
222 | Adaptations to Debian editline package.
223 |
224 | ### Changes
225 | - Major version number bump, adapt to Jim Studt's v1.12
226 | - Import `debian/` directory and adapt it to configure et al.
227 | - Change library name to libeditline to distinguish it from BSD libedit
228 |
229 |
230 | [0.3.0][] - 2009-02-08
231 | ----------------------
232 |
233 | ### Changes
234 | - Support for ANSI arrow keys using configure --enable-arrow-keys
235 |
236 |
237 | [0.2.3][] - 2008-12-02
238 | ----------------------
239 |
240 | ### Changes
241 | - Patches from Debian package merged
242 | - Support for custom command completion
243 |
244 |
245 | [0.1.0][] - 2008-06-07
246 | ----------------------
247 |
248 | ### Changes
249 | - First version, forked from Minix current 2008-06-06
250 |
251 |
252 | [UNRELEASED]: https://github.com/troglobit/finit/compare/1.17.1...HEAD
253 | [1.17.1]: https://github.com/troglobit/finit/compare/1.17.0...1.17.1
254 | [1.17.0]: https://github.com/troglobit/finit/compare/1.16.1...1.17.0
255 | [1.16.1]: https://github.com/troglobit/finit/compare/1.16.0...1.16.1
256 | [1.16.0]: https://github.com/troglobit/finit/compare/1.15.3...1.16.0
257 | [1.15.3]: https://github.com/troglobit/finit/compare/1.15.2...1.15.3
258 | [1.15.2]: https://github.com/troglobit/finit/compare/1.15.1...1.15.2
259 | [1.15.1]: https://github.com/troglobit/finit/compare/1.15.0...1.15.1
260 | [1.15.0]: https://github.com/troglobit/finit/compare/1.14.2...1.15.0
261 | [1.14.2]: https://github.com/troglobit/finit/compare/1.14.1...1.14.2
262 | [1.14.1]: https://github.com/troglobit/finit/compare/1.14.0...1.14.1
263 | [1.14.0]: https://github.com/troglobit/finit/compare/1.13.0...1.14.0
264 | [1.13.0]: https://github.com/troglobit/finit/compare/0.3.0...1.13.0
265 | [0.3.0]: https://github.com/troglobit/finit/compare/0.2.3...0.3.0
266 | [0.2.3]: https://github.com/troglobit/finit/compare/0.1.0...0.2.3
267 | [0.1.0]: https://github.com/troglobit/finit/compare/0.0.0...0.1.0
268 | [libuEv]: http://github.com/troglobit/libuev
269 | [Travis-CI]: https://travis-ci.org/troglobit/uftpd
270 | [Coverity Scan]: https://scan.coverity.com/projects/2947
271 | [README.md]: https://github.com/troglobit/editline/blob/master/README.md
272 |
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
1 | HowTo Build Minix Editline
2 | ==========================
3 |
4 | Minix editline use the GNU configure tools, which includes autoconf,
5 | automake and libtool. This enables high levels of portability and ease
6 | of use. In most cases all you need to do is unpack the tarball, enter
7 | the directory and type:
8 |
9 | ./configure
10 |
11 | There are are, however, more options available. For instance, sometimes
12 | it is useful to build editline as a static library, type:
13 |
14 | ./configure --disable-shared
15 |
16 | By default editline employs a default handler for the TAB key, pressing
17 | it once completes to the nearest matching filename in the current
18 | working directory, or it can display a listing of possible completions.
19 | For some uses this default is not desirable at all, type:
20 |
21 | ./configure --disable-default-complete
22 |
23 | An even more common desire is to change the default install location.
24 | By default all configure scripts setup /usr/local as the install
25 | "prefix", to change this type:
26 |
27 | ./configure --prefix=/home/troglobit/tmp
28 |
29 | Advanced users are encouraged to read up on --libdir, --mandir, etc. in
30 | the GNU Configure and Build System.
31 |
32 | For more available options, type:
33 |
34 | ./configure --help
35 |
36 | To build and install, simply type:
37 |
38 | make
39 |
40 | followed by
41 |
42 | sudo make install
43 |
44 | Good Luck!
45 | //Joachim
46 |
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 1992,1993 Simmule Turner and Rich Salz
2 | All rights reserved.
3 |
4 | This software is not subject to any license of the American Telephone
5 | and Telegraph Company or of the Regents of the University of California.
6 |
7 | Permission is granted to anyone to use this software for any purpose on
8 | any computer system, and to alter it and redistribute it freely, subject
9 | to the following restrictions:
10 | 1. The authors are not responsible for the consequences of use of this
11 | software, no matter how awful, even if they arise from flaws in it.
12 | 2. The origin of this software must not be misrepresented, either by
13 | explicit claim or by omission. Since few users ever read sources,
14 | credits must appear in the documentation.
15 | 3. Altered versions must be plainly marked as such, and must not be
16 | misrepresented as being the original software. Since few users
17 | ever read sources, credits must appear in the documentation.
18 | 4. This notice may not be removed or altered.
19 |
--------------------------------------------------------------------------------
/Make.os9:
--------------------------------------------------------------------------------
1 | ## $Revision: 1.2 $
2 | ##
3 | ## OS-9 makefile for editline library.
4 | ##
5 |
6 | .SUFFIXES:
7 |
8 | RFILES = editline.r complete.r sysos9.r
9 |
10 | %.r: %.c
11 | cc68 -r -Dstrchr=index -Dstrrchr=rindex -DNEED_STRDUP -DSYS_OS9 $*.c
12 |
13 | testit: testit.r editline.lib
14 | cc68 -f=testit testit.r -l=editline.lib
15 |
16 | $(RFILES): $(RFILES:%.r=%.c)
17 |
18 | editline.lib: $(RFILES)
19 | cat $(RFILES) >$@
20 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | pkgconfigdir = $(libdir)/pkgconfig
2 | pkgconfig_DATA = libeditline.pc
3 | doc_DATA = README.md LICENSE
4 | EXTRA_DIST = README.md LICENSE ChangeLog.md INSTALL.md
5 | SUBDIRS = src include man
6 |
7 | if ENABLE_EXAMPLES
8 | SUBDIRS += examples
9 | endif
10 |
11 | ## Check if tagged in git
12 | release-hook:
13 | if [ ! `git tag | grep $(PACKAGE_VERSION) | grep $(PACKAGE_VERSION)` ]; then \
14 | echo; \
15 | printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \
16 | printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \
17 | if [ "$$yorn" != "y" -a "$$yorn" != "Y" ]; then \
18 | printf "OK, aborting release.\n"; \
19 | exit 1; \
20 | fi; \
21 | echo; \
22 | else \
23 | echo; \
24 | printf "\e[1m\e[42mFound GIT release tag $(PACKAGE_VERSION)\e[0m\n"; \
25 | printf "\e[1m\e[44m>>Remember to push tags!\e[0m\n"; \
26 | echo; \
27 | fi
28 |
29 | # lintian --profile debian -i -I --show-overrides ../$PKG.changes
30 | package:
31 | dpkg-buildpackage -uc -us -B
32 |
33 | ## Target to run when building a release
34 | release: release-hook distcheck
35 | @for file in $(DIST_ARCHIVES); do \
36 | md5sum $$file > ../$$file.md5; \
37 | sha256sum $$file > ../$$file.sha256; \
38 | done
39 | @mv $(DIST_ARCHIVES) ../
40 | @echo
41 | @echo "Resulting release files:"
42 | @echo "========================================================================="
43 | @for file in $(DIST_ARCHIVES); do \
44 | printf "%-40s Distribution tarball\n" $$file; \
45 | printf "%-40s " $$file.md5; cat ../$$file.md5 | cut -f1 -d' '; \
46 | printf "%-40s " $$file.sha256; cat ../$$file.sha256 | cut -f1 -d' '; \
47 | done
48 | @for file in `cd ..; ls *$(PACKAGE)*_$(subst _,.,$(VERSION))*`; do \
49 | printf "%-40s Debian/Ubuntu package file\n" $$file; \
50 | done
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Editline
2 | ========
3 | [![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status]][Coverity Scan]
4 |
5 |
6 | Table of Contents
7 | -----------------
8 |
9 | * [Introduction](#introduction)
10 | * [API](#api)
11 | * [Example](#example)
12 | * [Build & Install](#build--install)
13 | * [Origin & References](#origin--references)
14 |
15 |
16 | Introduction
17 | ------------
18 |
19 | This is a small [line editing][] library. It can be linked into almost
20 | any program to provide command line editing and history functions. It
21 | is call compatible with the [FSF readline][] library, but at a fraction
22 | of the size, and as a result fewer features. It is also distributed
23 | under a much more liberal [License][].
24 |
25 | The small size (<30k), lack of dependencies (ncurses not needed!), and
26 | the free license should make this library interesting to many embedded
27 | developers.
28 |
29 | Editline has several optional build-time features that can be enabled by
30 | supplying different options to the GNU configure script. See the output
31 | from configure --help for details. Some useful hints on how
32 | to use the library is available in the `examples/` directory.
33 |
34 | Editline is maintained collaboratively at [GitHub][1].
35 |
36 | > **Note:** Windows is not a supported target for editline.
37 |
38 |
39 | Example
40 | -------
41 |
42 | Below is a very brief example to illustrate how one can use Editline to
43 | create a simple CLI, Ctrl-D exits the program. A slightly more advanced
44 | example is Jush, , a small and very
45 | simplistic UNIX shell. The Editline sources also include an `examples/`
46 | sub-directory.
47 |
48 | 1. Build and install the library, preferably using a [release tarball][]
49 | The configure script defaults to a `/usr/local` prefix.
50 |
51 | tar xf editline-1.15.3.tar.xz
52 | cd editline-1.15.3/
53 | ./configure --prefix=/usr
54 | make all
55 | sudo make install
56 |
57 | 2. Place the below source code in a separate project directory,
58 | e.g. `~/src/example.c`
59 |
60 | ```C
61 | #include
62 | #include
63 | #include
64 |
65 | int main(void)
66 | {
67 | char *p;
68 |
69 | while ((p = readline("CLI> ")) != NULL) {
70 | puts(p);
71 | free(p);
72 | }
73 |
74 | return 0;
75 | }
76 | ```
77 |
78 | 3. Compile the example:
79 |
80 | cd ~/src/
81 | make LDLIBS=-leditline example
82 |
83 | Here I use `make` and rely on its implicit (built-in) rules to handle
84 | all the compiler magic, but you may want to create your own Makefile for
85 | the project. In particular if you don't change the default prefix
86 | (above), because then you need to specify the search path for the
87 | include file(s) and the library manually.
88 |
89 | A simple `~/src/Makefile` could look like this:
90 |
91 | CFLAGS = -I/usr/local/include
92 | LDFLAGS = -L/usr/local/lib
93 | LDLIBS = -leditline
94 | EXEC = example
95 | OBJS = example.o
96 |
97 | all: $(EXEC)
98 |
99 | $(EXEC): $(OBJS)
100 |
101 | clean:
102 | $(RM) $(OBJS) $(EXEC)
103 |
104 | distclean: clean
105 | $(RM) *.o *~ *.bak
106 |
107 | Then simply type `make` from your `~/src/` directory. You can also use
108 | `pkg-config` for your `~/src/Makefile`, replace the following lines:
109 |
110 | CFLAGS = $(shell pkg-config --cflags libeditline)
111 | LDFLAGS = $(shell pkg-config --libs-only-L libeditline)
112 | LDLIBS = $(shell pkg-config --libs-only-l libeditline)
113 |
114 | Then simply type make, like above.
115 |
116 | However, most `.rpm` based distributions `pkg-config` doesn't search in
117 | `/usr/local` anymore, so you need to call make like this:
118 |
119 | PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig make
120 |
121 | Debian/Ubuntu based systems do not have this problem.
122 |
123 |
124 | API
125 | ---
126 |
127 | Here is the libeditline interfaces. It has a small compatibility layer
128 | to [FSF readline][], which may not be entirely up-to-date.
129 |
130 | ```C
131 | /* Editline specific global variables. */
132 | int el_no_echo; /* Do not echo input characters */
133 | int el_no_hist; /* Disable auto-save of and access to history,
134 | * e.g. for password prompts or wizards */
135 | int el_hist_size; /* Size of history scrollback buffer, default: 15 */
136 |
137 | /* Editline specific functions. */
138 | char * el_find_word (void);
139 | void el_print_columns (int ac, char **av);
140 | el_status_t el_ring_bell (void);
141 | el_status_t el_del_char (void);
142 |
143 | /* Callback function for key binding */
144 | typedef el_status_t el_keymap_func_t(void);
145 |
146 | /* Bind key to a callback, use CTL('f') to change Ctrl-F, for example */
147 | el_status_t el_bind_key (int key, el_keymap_func_t function);
148 | el_status_t el_bind_key_in_metamap (int key, el_keymap_func_t function);
149 |
150 | /* For compatibility with FSF readline. */
151 | int rl_point;
152 | int rl_mark;
153 | int rl_end;
154 | int rl_inhibit_complete;
155 | char *rl_line_buffer;
156 | const char *rl_readline_name;
157 |
158 | void (*rl_deprep_term_function)(void);
159 | void rl_deprep_terminal (void);
160 | void rl_reset_terminal (const char *terminal_name);
161 |
162 | void rl_initialize (void);
163 | void rl_uninitialize (void); /* Free all internal memory */
164 |
165 | void rl_save_prompt (void);
166 | void rl_restore_prompt (void);
167 | void rl_set_prompt (const char *prompt);
168 |
169 | void rl_clear_message (void);
170 | void rl_forced_update_display (void);
171 |
172 | /* Main function to use, saves history by default */
173 | char *readline (const char *prompt);
174 |
175 | /* Use to save a read line to history, when el_no_hist is set */
176 | void add_history (const char *line);
177 |
178 | /* Load and save editline history from/to a file. */
179 | int read_history (const char *filename);
180 | int write_history (const char *filename);
181 |
182 | /* Magic completion API, see examples/cli.c for more info */
183 | rl_complete_func_t *rl_set_complete_func (rl_complete_func_t *func);
184 | rl_list_possib_func_t *rl_set_list_possib_func (rl_list_possib_func_t *func);
185 |
186 | /* Alternate interface to plain readline(), for event loops */
187 | void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler);
188 | void rl_callback_read_char (void);
189 | void rl_callback_handler_remove (void);
190 | ```
191 |
192 |
193 | Build & Install
194 | ---------------
195 |
196 | Editline was originally designed for older UNIX systems and Plan 9. The
197 | current maintainer works exclusively on GNU/Linux systems, so it may use
198 | GCC and GNU Make specific extensions here and there. This is not on
199 | purpose and patches or pull requests to correct this are most welcome!
200 |
201 | 0. Call ./autogen.sh if you build from git
202 | 1. Configure editline with default features: ./configure
203 | 2. Build the library and examples: make all
204 | 3. Install using make install
205 |
206 | The `$DESTDIR` environment variable is honored at install. For more
207 | options, see ./configure --help
208 |
209 | Remember to run `ldconfig` after install to update the linker cache. If
210 | you've installed to a non-standard location (`--prefix`) you may also
211 | have to update your `/etc/ld.so.conf`, or use `pkg-confg` to build your
212 | application (above).
213 |
214 | **NOTE:** RedHat/Fedora/CentOS and other `.rpm`-based distributions do
215 | not consider `/usr/local` as standard path anymore. So make sure to
216 | `./configure --prefix=/usr`, otherwise the build system use the GNU
217 | default, which is `/usr/local`. The Debian based distributions, like
218 | Ubuntu, do not have this problem.
219 |
220 |
221 | Origin & References
222 | --------------------
223 |
224 | This [line editing][] library was created by [Rich Salz][] and Simmule
225 | Turner and in 1992. It is distributed with a “[C News][]-like” license,
226 | similar to the [BSD license][]. Rich's current version is however under
227 | the Apache license. For details on the licensing terms of this version
228 | of the software, see [License][].
229 |
230 | This version of the editline library was forked from the [Minix 2][]
231 | source tree and is *not* related to the similarily named NetBSD version
232 | that [Jess Thrysøe][jess] disitributes to the world outside *BSD. The
233 | libraries have much in common, but the latter is heavily refactored and
234 | also relies on libtermcap (usually supplied by ncurses), whereas this
235 | library only uses termios from the standard C library.
236 |
237 | Patches and bug fixes from the following forks, based on the original
238 | [comp.sources.unix][] posting, have been merged:
239 |
240 | * Debian [libeditline][]
241 | * [Heimdal][]
242 | * [Festival][] speech-tools
243 | * [Steve Tell][]'s editline patches
244 |
245 | The version numbering scheme today follows that of the Debian version,
246 | details available in the [ChangeLog.md][]. The current [maintainer][]
247 | was unaware of the Debian version for quite some time, so a different
248 | name and versioning scheme was used. In June 2009 this was changed to
249 | line up alongside Debian, with the intent is to eventually merge the
250 | efforts.
251 |
252 | Outstanding issues are listed in the [TODO.md][] file.
253 |
254 | [1]: https://github.com/troglobit/editline
255 | [line editing]: https://github.com/troglobit/editline/blob/master/docs/README
256 | [release tarball]: https://github.com/troglobit/editline/releases
257 | [maintainer]: http://troglobit.com
258 | [C News]: https://en.wikipedia.org/wiki/C_News
259 | [TODO.md]: https://github.com/troglobit/editline/blob/master/docs/TODO.md
260 | [ChangeLog.md]: https://github.com/troglobit/editline/blob/master/ChangeLog.md
261 | [FSF readline]: http://www.gnu.org/software/readline/
262 | [Rich Salz]: https://github.com/richsalz/editline/
263 | [comp.sources.unix]: http://ftp.cs.toronto.edu/pub/white/pub/rc/editline.shar
264 | [Minix 2]: http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/editline/
265 | [jess]: http://thrysoee.dk/editline/
266 | [BSD license]: http://en.wikipedia.org/wiki/BSD_licenses
267 | [libeditline]: http://packages.qa.debian.org/e/editline.html
268 | [Heimdal]: http://www.h5l.org
269 | [Festival]: http://festvox.org/festival/
270 | [Steve Tell]: http://www.cs.unc.edu/~tell/dist.html
271 | [License]: https://github.com/troglobit/editline/blob/master/LICENSE
272 | [License Badge]: https://img.shields.io/badge/License-C%20News-orange.svg
273 | [GitHub]: https://github.com/troglobit/editline/actions/workflows/build.yml/
274 | [GitHub Status]: https://github.com/troglobit/editline/actions/workflows/build.yml/badge.svg
275 | [Coverity Scan]: https://scan.coverity.com/projects/2982
276 | [Coverity Status]: https://scan.coverity.com/projects/2982/badge.svg
277 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | autoreconf -W portability -visfm
4 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(editline, 1.17.2-pre, https://github.com/troglobit/editline/issues)
2 | AC_CONFIG_AUX_DIR(aux)
3 | AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
4 | AM_SILENT_RULES([yes])
5 |
6 | AC_CONFIG_MACRO_DIR([m4])
7 | AC_CONFIG_SRCDIR([src/editline.c])
8 | AC_CONFIG_HEADERS([config.h])
9 | AC_CONFIG_FILES([Makefile libeditline.pc src/Makefile include/Makefile man/Makefile examples/Makefile])
10 |
11 | # Checks for programs.
12 | AC_PROG_CC
13 | AC_PROG_INSTALL
14 |
15 | # Checks for libraries.
16 | LT_INIT
17 |
18 | # Checks for header files.
19 | AC_HEADER_DIRENT
20 | AC_HEADER_STAT
21 |
22 | # Check for malloc.h instead of AC_FUNC_MALLOC/REALLOC AIX and others
23 | # mess up the traditional malloc check.
24 | AC_CHECK_HEADERS([malloc.h signal.h stdlib.h string.h termcap.h termio.h termios.h sgtty.h unistd.h])
25 |
26 | # In termios.h or in sys/ioctl.g?
27 | AC_HEADER_TIOCGWINSZ
28 |
29 | # Overrides and types, should be a check.
30 | AC_DEFINE([SYS_UNIX], [1], [Default to UNIX backend, should be detected.])
31 | AC_TYPE_SIZE_T
32 |
33 | # Checks for library functions.
34 | AC_FUNC_CLOSEDIR_VOID
35 | AC_PROG_GCC_TRADITIONAL
36 | AC_FUNC_STAT
37 | AC_CHECK_FUNCS([strchr strdup strrchr tcgetattr perror])
38 |
39 | #
40 | # Available features
41 | #
42 | AC_ARG_ENABLE(unique-history,
43 | [AS_HELP_STRING([--disable-unique-history],
44 | [Disable uniqify of scrollback. Default: duplicate entries are ignored. Use this to save dupes.])])
45 |
46 | AC_ARG_ENABLE(arrow-keys,
47 | [AS_HELP_STRING([--disable-arrow-keys], [Disable ANSI arrow keys.])])
48 |
49 | AC_ARG_ENABLE(eof,
50 | [AS_HELP_STRING([--disable-eof], [Disable default EOF (Ctrl-D) behavior.])])
51 |
52 | AC_ARG_ENABLE(sigint,
53 | [AS_HELP_STRING([--disable-sigint], [Disable default SIGINT (Ctrl-C) behavior.])])
54 |
55 | AC_ARG_ENABLE(sigstop,
56 | [AS_HELP_STRING([--enable-sigstop], [Enable SIGSTOP (Ctrl-Z) behavior.])])
57 |
58 | AC_ARG_ENABLE(terminal-bell,
59 | [AS_HELP_STRING([--enable-terminal-bell], [Enable terminal bell on completion.])])
60 |
61 | AC_ARG_ENABLE(termcap,
62 | AS_HELP_STRING([--enable-termcap], [Use termcap library to query terminal size.]))
63 |
64 | AC_ARG_ENABLE([examples],
65 | [AS_HELP_STRING([--enable-examples], [Build examples/ directory])],
66 | [], [enable_examples=no])
67 |
68 | #
69 | # Check what features have been enabled
70 | #
71 | AS_IF([test "x$enable_unique_history" != "xno"], [
72 | AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.])])
73 |
74 | AS_IF([test "x$enable_terminal_bell" != "xno"], [
75 | AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.])])
76 |
77 | AS_IF([test "x$enable_eof" != "xno"], [
78 | AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-D) key.])])
79 |
80 | AS_IF([test "x$enable_sigint" != "xno"], [
81 | AC_DEFINE(CONFIG_SIGINT, 1, [Define to enable SIGINT (Ctrl-C) key.])])
82 |
83 | AS_IF([test "x$enable_sigstop" = "xyes"], [
84 | AC_DEFINE(CONFIG_SIGSTOP, 1, [Define to enable SIGSTOP (Ctrl-Z) key.])])
85 |
86 | AS_IF([test "x$enable_terminal_bell" = "xyes"], [
87 | AC_DEFINE(CONFIG_TERMINAL_BELL, 1, [Define to enable terminal bell on completion.])])
88 |
89 | AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes])
90 |
91 | # Check for a termcap compatible library if enabled
92 | AS_IF([test "x$enable_termcap" = "xyes"], [
93 | AC_DEFINE(CONFIG_USE_TERMCAP, 1, [Define to use the termcap library for terminal size.])
94 | AC_CHECK_LIB(terminfo, tgetent, , [
95 | AC_CHECK_LIB(termcap, tgetent, , [
96 | AC_CHECK_LIB(tinfo, tgetent, , [
97 | AC_CHECK_LIB(curses, tgetent, , [
98 | AC_CHECK_LIB(ncurses, tgetent, , [
99 | AC_MSG_ERROR([Cannot find a termcap capable library, try installing Ncurses.])])
100 | ])
101 | ])
102 | ])
103 | ])
104 | ])
105 |
106 | # Generate all files
107 | AC_OUTPUT
108 |
--------------------------------------------------------------------------------
/debian/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | *.debhelper
3 | *.substvars
4 | autoreconf.*
5 | debhelper-build-stamp
6 | files
7 | tmp/*
8 | libeditline-dev/*
9 | libeditline0/*
10 | libeditline1/*
11 |
--------------------------------------------------------------------------------
/debian/README.Debian:
--------------------------------------------------------------------------------
1 | editline for Debian
2 | ----------------------
3 |
4 | This is packaged in typical Debian form with a shared library version and
5 | a static library version. It will be a rare package that wishes to
6 | use the shared library form, the static one is only adds about 12.5kb
7 | to your program.
8 |
9 | -- Jim Studt , Fri, 5 May 2000 13:25:51 -0500
10 |
--------------------------------------------------------------------------------
/debian/changelog:
--------------------------------------------------------------------------------
1 | editline (1.17.1) stable; urgency=medium
2 |
3 | * Fix multiline representing as one line
4 | * Fix missing content in libedtline1, introduced in 1.16.0
5 | * Update packaging to latest std version
6 |
7 | -- Joachim Nilsson Sun, 23 Feb 2020 18:46:41 +0100
8 |
9 | editline (1.17.0) unstable; urgency=medium
10 |
11 | * Simple multi-line support
12 | * Handle internal realloc() errors better
13 | * Fix return value from read_history() and write_history()
14 | * Fix potential NULL pointer dereference in key binging lookup
15 |
16 | -- Joachim Nilsson Sun, 05 Jan 2020 09:47:34 +0100
17 |
18 | editline (1.16.1) unstable; urgency=medium
19 |
20 | * Minor bug fix and documentation update release.
21 | * Add missing pkg-config .pc file to -dev package
22 |
23 | -- Joachim Nilsson Fri, 07 Jun 2019 11:45:50 +0200
24 |
25 | editline (1.16.0) unstable; urgency=medium
26 |
27 | * New upstream release, v1.60.0
28 | + Event loop support
29 | + New GNU Readline compat functions and callbacks
30 | + Minor compat fixes for movement and deletion
31 | * Bump .so/ABI version => libeditline1
32 | * New maintainer, upstream author
33 |
34 | -- Joachim Nilsson Sun, 16 Sep 2018 09:45:53 +0200
35 |
36 | editline (1.15.3-1) unstable; urgency=medium
37 |
38 | * New upstream bug fix release, v1.15.3
39 |
40 | -- Joachim Nilsson Thu, 07 Sep 2017 01:24:19 +0200
41 |
42 | editline (1.15.2-1) unstable; urgency=medium
43 |
44 | * New upstream bug fix release, v1.15.2
45 |
46 | -- Joachim Nilsson Wed, 06 Jun 2016 20:04:35 +0200
47 |
48 | editline (1.15.1-1) unstable; urgency=medium
49 |
50 | * New upstream bug fix release, v1.15.1
51 |
52 | -- Joachim Nilsson Wed, 16 Nov 2015 21:17:17 +0200
53 |
54 | editline (1.15.0-1) unstable; urgency=medium
55 |
56 | * New upstream release, v1.15.0
57 |
58 | -- Joachim Nilsson Wed, 10 Sep 2015 13:26:03 +0200
59 |
60 | editline (1.14.2-1) unstable; urgency=low
61 |
62 | * Minor bugfix release:
63 | + Fix `el_no_echo` bug causing secrets to leak when disabling no-echo
64 | + Handle `EINTR` in syscalls better
65 |
66 | -- Joachim Nilsson Sun, 14 Sep 2014 04:27:25 +0200
67 |
68 | editline (1.14.1-1) unstable; urgency=low
69 |
70 | * New release.
71 | + Minor fixes to key binding.
72 | + Check signals and custom keys before acting on them in readline().
73 | + Update maintainer email address.
74 |
75 | -- Joachim Nilsson Mon, 8 Jul 2013 17:04:00 +0100
76 |
77 | editline (1.14.0-1) unstable; urgency=low
78 |
79 | * Update to new configure based build.
80 |
81 | -- Joachim Nilsson Wed, 11 Aug 2010 13:28:00 +0100
82 |
83 | editline (1.12-6) unstable; urgency=low
84 |
85 | * Switch package format to 3.0 (quilt).
86 | * 200_fix-truncation-at-64-char.diff: fix invalid 64-char truncation in
87 | batch mode, courtesy of Mark O'Donohue. Thanks to Damyan Ivanov for
88 | forwarding the patch from Ubuntu (Closes: #508640).
89 |
90 | -- Sam Hocevar Sun, 03 Jan 2010 15:45:34 +0100
91 |
92 | editline (1.12-5) unstable; urgency=low
93 |
94 | * New maintainer (Closes: #229962).
95 | * debian/changelog:
96 | + Removed emacs helper variables.
97 | * debian/control:
98 | + Set policy to 3.6.1.0.
99 | + Set debhelper build dependency to (>= 4.0).
100 | + Use the default dh_shlibs information, since the API is rock stable
101 | (Closes: #131139).
102 | + Removed the libc6-dev dependency in the -dev package.
103 | + Rephrased the short and long descriptions.
104 | * debian/copyright:
105 | + Replaced "Author(s)" with "Author".
106 | * debian/rules:
107 | + Removed obsolete call to dh_suidregister.
108 | + Use debian/compat instead of DH_COMPAT.
109 | * include_editline.h:
110 | + Added a minimalist /usr/include/editline.h (Closes: #129544).
111 | * Makefile:
112 | + Call libtool with the proper --mode flags.
113 |
114 | -- Sam Hocevar (Debian packages) Sat, 31 Jan 2004 22:32:35 +0100
115 |
116 | editline (1.12-4) unstable; urgency=low
117 |
118 | * Add a Build-Depends for debhelper and libtool. Thought those
119 | were baseline. closes: #117780
120 |
121 | -- Jim Studt Thu, 15 Nov 2001 19:00:00 -0600
122 |
123 | editline (1.12-3) unstable; urgency=low
124 |
125 | * Make man pages not be in the shared library package.
126 |
127 | -- Jim Studt Sat, 13 Jan 2001 00:03:53 -0600
128 |
129 | editline (1.12-2) unstable; urgency=low
130 |
131 | * Patch to not declare read() and write(), it fails on alphas.
132 |
133 | -- Jim Studt Tue, 12 Sep 2000 16:39:34 -0500
134 |
135 | editline (1.12-1) unstable; urgency=low
136 |
137 | * Initial Release.
138 |
139 | -- Jim Studt Fri, 5 May 2000 13:25:51 -0500
140 |
141 |
--------------------------------------------------------------------------------
/debian/compat:
--------------------------------------------------------------------------------
1 | 10
2 |
--------------------------------------------------------------------------------
/debian/control:
--------------------------------------------------------------------------------
1 | Source: editline
2 | Section: devel
3 | Priority: optional
4 | Build-Depends: debhelper (>= 10), libtool
5 | Maintainer: Joachim Wiberg
6 | Standards-Version: 4.3.0
7 |
8 | Package: libeditline-dev
9 | Architecture: any
10 | Section: libdevel
11 | Depends: libeditline1 (= ${binary:Version}), ${misc:Depends}
12 | Description: development files for libeditline
13 | This is a line-editing library. It can be linked into almost any program
14 | to provide command-line editing and recall. It is call-compatible with a
15 | subset of the FSF readline library, but it is a fraction of the size (and
16 | offers fewer features).
17 | .
18 | This package contains the developer files: static libraries, headers,
19 | manpages.
20 |
21 | Package: libeditline1
22 | Architecture: any
23 | Section: libs
24 | Depends: ${shlibs:Depends}, ${misc:Depends}
25 | Description: line editing library similar to readline
26 | This is a line-editing library. It can be linked into almost any program
27 | to provide command-line editing and recall. It is call-compatible with a
28 | subset of the FSF readline library, but it is a fraction of the size (and
29 | offers fewer features).
30 | .
31 | This package contains the runtime library only.
32 |
--------------------------------------------------------------------------------
/debian/copyright:
--------------------------------------------------------------------------------
1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: editline
3 | Upstream-Contact: Joachim Wiberg
4 | Source: http://github.com/troglobit/editline
5 | Comment: This package was originally debianized by Jim Studt
6 | on Fri, 5 May 2000 13:25:51 -0500. It was received from, then upstream
7 | author, Rich Salz
8 |
9 | Files: *
10 | Copyright: 1992,1993 Simmule Turner and Rich Salz.
11 | License: C-News
12 |
13 | Files: debian/*
14 | Copyright: 2010-2020 Joachim Wiberg
15 | License: BSD-2-clause
16 |
17 | License: C-News
18 | This software is not subject to any license of the American Telephone
19 | and Telegraph Company or of the Regents of the University of California.
20 | .
21 | Permission is granted to anyone to use this software for any purpose on
22 | any computer system, and to alter it and redistribute it freely, subject
23 | to the following restrictions:
24 | 1. The authors are not responsible for the consequences of use of this
25 | software, no matter how awful, even if they arise from flaws in it.
26 | 2. The origin of this software must not be misrepresented, either by
27 | explicit claim or by omission. Since few users ever read sources,
28 | credits must appear in the documentation.
29 | 3. Altered versions must be plainly marked as such, and must not be
30 | misrepresented as being the original software. Since few users
31 | ever read sources, credits must appear in the documentation.
32 | 4. This notice may not be removed or altered.
33 |
--------------------------------------------------------------------------------
/debian/dirs:
--------------------------------------------------------------------------------
1 | usr/lib
2 | usr/include
3 |
--------------------------------------------------------------------------------
/debian/docs:
--------------------------------------------------------------------------------
1 | README.md
2 |
--------------------------------------------------------------------------------
/debian/libeditline-dev.install:
--------------------------------------------------------------------------------
1 | usr/include/*.h
2 | usr/lib/*/libeditline*.*a
3 | usr/lib/*/libeditline.so
4 | usr/lib/*/pkgconfig/*
5 | usr/share/man/man3/*
6 |
--------------------------------------------------------------------------------
/debian/libeditline1.install:
--------------------------------------------------------------------------------
1 | usr/lib/*/libeditline.so.*
2 |
--------------------------------------------------------------------------------
/debian/libeditline1.symbols:
--------------------------------------------------------------------------------
1 | libeditline.so.1 libeditline1 #MINVER#
2 | * Build-Depends-Package: libeditline-dev
3 | add_history@Base 1.17.1
4 | el_bind_key@Base 1.17.1
5 | el_bind_key_in_metamap@Base 1.17.1
6 | el_del_char@Base 1.17.1
7 | el_filename_complete@Base 1.17.1
8 | el_filename_list_possib@Base 1.17.1
9 | el_find_word@Base 1.17.1
10 | el_hist_size@Base 1.17.1
11 | el_next_hist@Base 1.17.1
12 | el_no_echo@Base 1.17.1
13 | el_no_hist@Base 1.17.1
14 | el_prev_hist@Base 1.17.1
15 | el_print_columns@Base 1.17.1
16 | el_ring_bell@Base 1.17.1
17 | prompt_len@Base 1.17.1
18 | read_history@Base 1.17.1
19 | readline@Base 1.17.1
20 | rl_add_slash@Base 1.17.1
21 | rl_attempted_completion_function@Base 1.17.1
22 | rl_attempted_completion_over@Base 1.17.1
23 | rl_callback_handler_install@Base 1.17.1
24 | rl_callback_handler_remove@Base 1.17.1
25 | rl_callback_read_char@Base 1.17.1
26 | rl_clear_message@Base 1.17.1
27 | rl_complete@Base 1.17.1
28 | rl_completion_entry_function@Base 1.17.1
29 | rl_completion_matches@Base 1.17.1
30 | rl_deprep_term_function@Base 1.17.1
31 | rl_deprep_terminal@Base 1.17.1
32 | rl_end@Base 1.17.1
33 | rl_eof@Base 1.17.1
34 | rl_erase@Base 1.17.1
35 | rl_event_hook@Base 1.17.1
36 | rl_filename_completion_function@Base 1.17.1
37 | rl_forced_update_display@Base 1.17.1
38 | rl_getc@Base 1.17.1
39 | rl_getc_function@Base 1.17.1
40 | rl_inhibit_complete@Base 1.17.1
41 | rl_initialize@Base 1.17.1
42 | rl_insert_text@Base 1.17.1
43 | rl_instream@Base 1.17.1
44 | rl_intr@Base 1.17.1
45 | rl_kill@Base 1.17.1
46 | rl_line_buffer@Base 1.17.1
47 | rl_list_possib@Base 1.17.1
48 | rl_mark@Base 1.17.1
49 | rl_meta_chars@Base 1.17.1
50 | rl_outstream@Base 1.17.1
51 | rl_point@Base 1.17.1
52 | rl_prep_term_function@Base 1.17.1
53 | rl_prep_terminal@Base 1.17.1
54 | rl_prompt@Base 1.17.1
55 | rl_quit@Base 1.17.1
56 | rl_readline_name@Base 1.17.1
57 | rl_refresh_line@Base 1.17.1
58 | rl_reset_terminal@Base 1.17.1
59 | rl_restore_prompt@Base 1.17.1
60 | rl_save_prompt@Base 1.17.1
61 | rl_set_complete_func@Base 1.17.1
62 | rl_set_getc_func@Base 1.17.1
63 | rl_set_list_possib_func@Base 1.17.1
64 | rl_set_prompt@Base 1.17.1
65 | rl_ttyset@Base 1.17.1
66 | rl_uninitialize@Base 1.17.1
67 | write_history@Base 1.17.1
68 |
--------------------------------------------------------------------------------
/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # export DH_VERBOSE=1
3 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all
4 | export DEB_CFLAGS_MAINT_APPEND = -W -Wall -Wextra -O3
5 | export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
6 |
7 | NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
8 |
9 | include /usr/share/dpkg/default.mk # provides DEB_VERSION
10 |
11 | %:
12 | dh $@ --with autoreconf
13 |
14 | override_dh_installchangelogs:
15 | dh_installchangelogs ChangeLog.md
16 |
17 |
--------------------------------------------------------------------------------
/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (native)
2 |
--------------------------------------------------------------------------------
/docs/HACKING.md:
--------------------------------------------------------------------------------
1 | Maintenance and Release Checklist
2 | =================================
3 |
4 | Maintenance
5 | -----------
6 |
7 | * Encourage contributors to write tests, in particular for new features
8 | * Run tests regularly, use Travis-CI to do this automatically
9 | * Leverage GitHub issues for milestone planning
10 | * Reference issues from GitHub pull requests to alert issue subscribers
11 | * Bump library ABI version just before release!
12 |
13 |
14 | Release Checklist
15 | -----------------
16 |
17 | * Update ChangeLog, follow http://keepachangelog.com/ loosely
18 | - Inform users in a plain language of changes and bug fixes
19 | - Do *not* copy-paste GIT commit logs!
20 | - Order entries according to importance, most relevant first
21 | * Run unit tests: `make check`
22 | * Make at least one `-rcN` release and test it in an actual real project
23 | * **REMEMBER:** bump ABI version according to below rules
24 | * Tag
25 | * Push last commit(s) *and* tags to GitHub
26 | * Make release
27 |
28 | make distclean
29 | ./autogen.sh
30 | ./configure
31 | make release
32 |
33 | * Create new release in GitHub releases page
34 | * Copy and paste ChangeLog entry, check any stale links!
35 | * Upload release tarball and MD5 files
36 |
37 |
38 | Library Versioning
39 | ------------------
40 |
41 | Editline relies on GNU Libtool for building the library. For a user of
42 | the library it is important to maintain a clear ABI versioning scheme.
43 | This is not the same as the Editline version, but rather the library
44 | "compatibility level".
45 |
46 | The Editline ABI version is specified in `src/Makefile.am` and looks
47 | like this:
48 |
49 | libeditline_la_LDFLAGS = -version-info 0:0:0
50 | \ \ `-- age
51 | \ `--- revision
52 | `---- current
53 |
54 | It must be updated according to the [GNU Libtool recommendations][1]:
55 |
56 | 1. Start with version information of `0:0:0` for each libtool library.
57 | 2. Update the version information only immediately before a public
58 | release of your software. More frequent updates are unnecessary, and
59 | only guarantee that the current interface number gets larger faster.
60 | 3. If the library *source code has changed at all* since the last update,
61 | then increment revision (`c:r:a` becomes `c:r+1:a`).
62 | 4. If any *interfaces have been added, removed, or changed* since the
63 | last update, increment current, and set revision to 0.
64 | 5. If any *interfaces have been added* since the last public release,
65 | then increment age.
66 | 6. If any *interfaces have been removed or changed* since the last
67 | public release, then set age to 0.
68 |
69 | The libtool ABI versioning logic is very confusing but works if you just
70 | disable your brain and follow the rules, one by one.
71 |
72 | **Example #1:** a new function has been added, none of the existing ones
73 | have changed. The initial version is 1:0:0, we follow the rules above to
74 | the letter: increase revision, increase current and set revision to zero,
75 | and finally increase age. This, rather confusingly, gives us 2:0:1 which
76 | libtool then translates to `libeditline.so.1.1.0`.
77 |
78 | **Example #2:** some existing functions are changed, they now return an
79 | `int` instead of `void`. The initial version is 0:0:0, and we follow the
80 | rules again: increment revision, increment current and set revision to
81 | zero, set age to zero. This gives us 1:0:0, which is then translated to
82 | `libeditline.so.1.0.0`.
83 |
84 | ### Note
85 |
86 | Usually, non-developers have no interest in running development versions
87 | (releases are frequent enough), and developers are expected to know how
88 | to juggle versions. In such an ideal world, it is good enough to bump
89 | the library version just prior to a release, point 2.
90 |
91 | However, if releases are few and far between, distributors may start to
92 | use snapshots. When a distributor uses a snapshot, the distributor has
93 | to handle the library version manually. Things can get ugly when the
94 | distributor has released an intermediate version with a bumped library
95 | version, and when the official release is bumped to that version, the
96 | distributor will then have to bump the library version for the official
97 | release, and it can be confusing if someone reports bugs on versions
98 | that you didn't even know existed.
99 |
100 | The problem with bumping the version with every change is that if your
101 | interface is not finished, the version number might run away, and it
102 | looks pretty bad if a library is at version 262. It kind of tells the
103 | user that the library interface is volatile, which is not good for
104 | business.
105 |
106 | [1]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
107 |
--------------------------------------------------------------------------------
/docs/README:
--------------------------------------------------------------------------------
1 | Original Minix README
2 | =====================
3 |
4 | Below is the original Minix editline README file. It has been
5 | split into a modified README and LICENSE file.
6 |
7 | -- Joachim Nilsson, June 7th 2008
8 |
9 | -----------------------------------------------------------------
10 | $Revision: 5 $
11 |
12 | This is a line-editing library. It can be linked into almost any
13 | program to provide command-line editing and recall.
14 |
15 | It is call-compatible with the FSF readline library, but it is a
16 | fraction of the size (and offers fewer features). It does not use
17 | standard I/O. It is distributed under a "C News-like" copyright.
18 |
19 | Configuration is done in the Makefile. Type "make testit" to get
20 | a small slow shell for testing.
21 |
22 | An earlier version was distributed with Byron's rc. Principal
23 | changes over that version include:
24 | Faster.
25 | Is eight-bit clean (thanks to brendan()cs!widener!edu)
26 | Written in K&R C, but ANSI compliant (gcc all warnings)
27 | Propagates EOF properly; rc trip test now passes
28 | Doesn't need or use or provide memmove.
29 | More robust
30 | Calling sequence changed to be compatible with readline.
31 | Test program, new manpage, better configuration
32 | More system-independant; includes Unix and OS-9 support.
33 |
34 | This contains some changes since the posting to comp.sources.misc:
35 | Bugfix for completion on absolute pathnames.
36 | Better handling of M-n versus showing raw 8bit chars.
37 | Better signal handling.
38 | Now supports termios/termio/sgttyb ioctl's.
39 | Add M-m command to toggle how 8bit data is displayed.
40 |
41 | There is one known bug:
42 | History-searching redraws the line wrong if the text
43 | retrieved is shorter then the prompt.
44 |
45 | Enjoy,
46 | Rich $alz
47 |
48 |
49 | Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved.
50 |
51 | This software is not subject to any license of the American Telephone
52 | and Telegraph Company or of the Regents of the University of California.
53 |
54 | Permission is granted to anyone to use this software for any purpose on
55 | any computer system, and to alter it and redistribute it freely, subject
56 | to the following restrictions:
57 | 1. The authors are not responsible for the consequences of use of this
58 | software, no matter how awful, even if they arise from flaws in it.
59 | 2. The origin of this software must not be misrepresented, either by
60 | explicit claim or by omission. Since few users ever read sources,
61 | credits must appear in the documentation.
62 | 3. Altered versions must be plainly marked as such, and must not be
63 | misrepresented as being the original software. Since few users
64 | ever read sources, credits must appear in the documentation.
65 | 4. This notice may not be removed or altered.
66 |
67 | --
68 | $PchId: README,v 1.3 1996/02/22 21:18:51 philip Exp $
69 |
--------------------------------------------------------------------------------
/docs/TODO.md:
--------------------------------------------------------------------------------
1 | TODO
2 | ====
3 |
4 | Issues in need of work. Mostly compatibility with GNU readline,
5 | BSD [libedit][], and usability improvements.
6 |
7 | Remember, the general idea is to keep this library small with no
8 | external dependencies, except for a generic C library.
9 |
10 |
11 | Check what's needed to run the fileman example
12 | ----------------------------------------------
13 |
14 | The BSD libedit library has imported the GNU readline "fileman" example
15 | into its tree to demonstrate the abilities of that library. This would
16 | also be quite useful for this library!
17 |
18 | The first task is to investigate the depependencies and form TODO list
19 | items detailing what is missing and, if possible, proposals how to
20 | implement including any optional configure flags.
21 |
22 |
23 | Other minor TODO's
24 | ------------------
25 |
26 | - Instead of supporting multiline input, try the Emacs approach, line
27 | scrolling.
28 | - Add support for `rl_bind_key()`, currently only en editline specific
29 | `el_bind_key()` exists.
30 | - Make `char *rl_prompt;` globally visible.
31 | - Add support for `rl_set_prompt()`
32 | - Add support for `--enable-utf8` to configure script
33 | - Use `strcmp(nl_langinfo(CODESET), "UTF-8")` to look for utf8 capable
34 | terminal
35 | - Implement simple UTF-8 parser according to
36 | http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
37 |
38 |
39 | [gnu]: http://www.delorie.com/gnu/docs/readline/rlman_41.html#IDX288
40 | [libuEv]: https://github.com/troglobit/libuev/
41 | [libedit]: http://www.thrysoee.dk/editline/
42 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | cli
3 | testit
4 | excallback
5 | fileman
6 |
--------------------------------------------------------------------------------
/examples/Makefile.am:
--------------------------------------------------------------------------------
1 | noinst_PROGRAMS = testit cli excallback fileman
2 | LDADD = $(top_builddir)/src/libeditline.la
3 | AM_CPPFLAGS = -DEDITLINE_LIBRARY
4 | AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
5 | AM_LDFLAGS = -static
6 |
--------------------------------------------------------------------------------
/examples/cli.c:
--------------------------------------------------------------------------------
1 | /* Custom CLI command completion.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
4 | *
5 | * This software is not subject to any license of the American Telephone
6 | * and Telegraph Company or of the Regents of the University of California.
7 | *
8 | * Permission is granted to anyone to use this software for any purpose on
9 | * any computer system, and to alter it and redistribute it freely, subject
10 | * to the following restrictions:
11 | * 1. The authors are not responsible for the consequences of use of this
12 | * software, no matter how awful, even if they arise from flaws in it.
13 | * 2. The origin of this software must not be misrepresented, either by
14 | * explicit claim or by omission. Since few users ever read sources,
15 | * credits must appear in the documentation.
16 | * 3. Altered versions must be plainly marked as such, and must not be
17 | * misrepresented as being the original software. Since few users
18 | * ever read sources, credits must appear in the documentation.
19 | * 4. This notice may not be removed or altered.
20 | */
21 |
22 | #include "editline.h"
23 | #include
24 |
25 | #define HISTORY "/tmp/.cli-history"
26 |
27 | static char *list[] = {
28 | "foo ", "bar ", "bsd ", "cli ", "ls ", "cd ", "malloc ", "tee ", NULL
29 | };
30 |
31 | /* Attempt to complete the pathname, returning an allocated copy.
32 | * Fill in *unique if we completed it, or set it to 0 if ambiguous. */
33 | static char *my_rl_complete(char *token, int *match)
34 | {
35 | int i;
36 | int index = -1;
37 | int matchlen = 0;
38 | int count = 0;
39 |
40 | for (i = 0; list[i]; i++) {
41 | int partlen = strlen(token); /* Part of token */
42 |
43 | if (!strncmp(list[i], token, partlen)) {
44 | index = i;
45 | matchlen = partlen;
46 | count ++;
47 | }
48 | }
49 |
50 | if (count == 1) {
51 | *match = 1;
52 | return strdup(list[index] + matchlen);
53 | }
54 |
55 | return NULL;
56 | }
57 |
58 | /* Return all possible completions. */
59 | static int my_rl_list_possib(char *token, char ***av)
60 | {
61 | int i, num, total = 0;
62 | char **copy;
63 |
64 | for (num = 0; list[num]; num++)
65 | ;
66 |
67 | if (!num)
68 | return 0;
69 |
70 | copy = malloc(num * sizeof(char *));
71 | for (i = 0; i < num; i++) {
72 | if (!strncmp(list[i], token, strlen (token))) {
73 | copy[total] = strdup(list[i]);
74 | total++;
75 | }
76 | }
77 | *av = copy;
78 |
79 | return total;
80 | }
81 |
82 | el_status_t list_possible(void)
83 | {
84 | char **av;
85 | char *word;
86 | int ac;
87 |
88 | word = el_find_word();
89 | ac = rl_list_possib(word, &av);
90 | if (word)
91 | free(word);
92 | if (ac) {
93 | el_print_columns(ac, av);
94 | while (--ac >= 0)
95 | free(av[ac]);
96 | free(av);
97 |
98 | return CSmove;
99 | }
100 |
101 | return el_ring_bell();
102 | }
103 |
104 | el_status_t do_suspend(void)
105 | {
106 | puts("Abort!");
107 | return CSstay;
108 | }
109 |
110 | static void breakit(int signo)
111 | {
112 | (void)signo;
113 | puts("Got SIGINT");
114 | }
115 |
116 | /* Use el_no_echo when reading passwords and similar */
117 | static int unlock(const char *passwd)
118 | {
119 | char *prompt = "Enter password: ";
120 | char *line;
121 | int rc = 1;
122 |
123 | el_no_echo = 1;
124 |
125 | while ((line = readline(prompt))) {
126 | rc = strncmp(line, passwd, strlen(passwd));
127 | free(line);
128 |
129 | if (rc) {
130 | printf("\nWrong password, please try again, it's secret.\n");
131 | continue;
132 | }
133 |
134 | printf("\nAchievement unlocked!\n");
135 | break;
136 | }
137 |
138 | el_no_echo = 0;
139 |
140 | return rc;
141 | }
142 |
143 | int main(void)
144 | {
145 | char *line;
146 | char *prompt = "cli> ";
147 |
148 | signal(SIGINT, breakit);
149 |
150 | /* Setup callbacks */
151 | rl_set_complete_func(&my_rl_complete);
152 | rl_set_list_possib_func(&my_rl_list_possib);
153 |
154 | el_bind_key('?', list_possible);
155 | el_bind_key(CTL('Z'), do_suspend);
156 | read_history(HISTORY);
157 |
158 | while ((line = readline(prompt))) {
159 | if (!strncmp(line, "unlock", 6) && unlock("secret")) {
160 | free(line);
161 | fprintf(stderr, "\nSecurity breach, user logged out!\n");
162 | break;
163 | }
164 |
165 | if (*line != '\0')
166 | printf("\t\t\t|%s|\n", line);
167 | free(line);
168 | }
169 |
170 | write_history(HISTORY);
171 |
172 | return 0;
173 | }
174 |
175 | /**
176 | * Local Variables:
177 | * c-file-style: "k&r"
178 | * c-basic-offset: 4
179 | * End:
180 | */
181 |
--------------------------------------------------------------------------------
/examples/excallback.c:
--------------------------------------------------------------------------------
1 | /*
2 | From: Jeff Solomon
3 | Date: Fri, 9 Apr 1999 10:13:27 -0700 (PDT)
4 | To: chet@po.cwru.edu
5 | Subject: new readline example
6 | Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU>
7 |
8 | Chet,
9 |
10 | I've been using readline 4.0. Specifically, I've been using the perl
11 | version Term::ReadLine::Gnu. It works great.
12 |
13 | Anyway, I've been playing around the alternate interface and I wanted
14 | to contribute a little C program, callback.c, to you that you could
15 | use as an example of the alternate interface in the /examples
16 | directory of the readline distribution.
17 |
18 | My example shows how, using the alternate interface, you can
19 | interactively change the prompt (which is very nice imo). Also, I
20 | point out that you must roll your own terminal setting when using the
21 | alternate interface because readline depreps (using your parlance) the
22 | terminal while in the user callback. I try to demostrate what I mean
23 | with an example. I've included the program below.
24 |
25 | To compile, I just put the program in the examples directory and made
26 | the appropriate changes to the EXECUTABLES and OBJECTS line and added
27 | an additional target 'callback'.
28 |
29 | I compiled on my Sun Solaris2.6 box using Sun's cc.
30 |
31 | Let me know what you think.
32 |
33 | Jeff
34 | */
35 |
36 | #if defined (HAVE_CONFIG_H)
37 | #include
38 | #endif
39 |
40 | #include
41 | #include
42 | #include
43 |
44 | #ifdef HAVE_STDLIB_H
45 | #include
46 | #endif
47 |
48 | #ifdef HAVE_UNISTD_H
49 | #include
50 | #endif
51 |
52 | #include /* xxx - should make this more general */
53 |
54 | #ifdef EDITLINE_LIBRARY
55 | # include "editline.h"
56 | #else
57 | # include
58 | #endif
59 |
60 | /* This little examples demonstrates the alternate interface to using readline.
61 | * In the alternate interface, the user maintains control over program flow and
62 | * only calls readline when STDIN is readable. Using the alternate interface,
63 | * you can do anything else while still using readline (like talking to a
64 | * network or another program) without blocking.
65 | *
66 | * Specifically, this program highlights two importants features of the
67 | * alternate interface. The first is the ability to interactively change the
68 | * prompt, which can't be done using the regular interface since rl_prompt is
69 | * read-only.
70 | *
71 | * The second feature really highlights a subtle point when using the alternate
72 | * interface. That is, readline will not alter the terminal when inside your
73 | * callback handler. So let's so, your callback executes a user command that
74 | * takes a non-trivial amount of time to complete (seconds). While your
75 | * executing the command, the user continues to type keystrokes and expects them
76 | * to be re-echoed on the new prompt when it returns. Unfortunately, the default
77 | * terminal configuration doesn't do this. After the prompt returns, the user
78 | * must hit one additional keystroke and then will see all of his previous
79 | * keystrokes. To illustrate this, compile and run this program. Type "sleep" at
80 | * the prompt and then type "bar" before the prompt returns (you have 3
81 | * seconds). Notice how "bar" is re-echoed on the prompt after the prompt
82 | * returns? This is what you expect to happen. Now comment out the 4 lines below
83 | * the line that says COMMENT LINE BELOW. Recompile and rerun the program and do
84 | * the same thing. When the prompt returns, you should not see "bar". Now type
85 | * "f", see how "barf" magically appears? This behavior is un-expected and not
86 | * desired.
87 | */
88 |
89 | void process_line(char *line);
90 | int change_prompt(void);
91 | char *get_prompt(void);
92 |
93 | int prompt = 1;
94 | char prompt_buf[40], line_buf[256];
95 | tcflag_t old_lflag;
96 | cc_t old_vtime;
97 | struct termios term;
98 |
99 | int
100 | main()
101 | {
102 | fd_set fds;
103 |
104 | /* Adjust the terminal slightly before the handler is installed. Disable
105 | * canonical mode processing and set the input character time flag to be
106 | * non-blocking.
107 | */
108 | if( tcgetattr(STDIN_FILENO, &term) < 0 ) {
109 | perror("tcgetattr");
110 | exit(1);
111 | }
112 | old_lflag = term.c_lflag;
113 | old_vtime = term.c_cc[VTIME];
114 | term.c_lflag &= ~ICANON;
115 | term.c_cc[VTIME] = 1;
116 | /* COMMENT LINE BELOW - see above */
117 | if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
118 | perror("tcsetattr");
119 | exit(1);
120 | }
121 |
122 | // rl_add_defun("change-prompt", change_prompt, CTRL('t'));
123 | rl_callback_handler_install(get_prompt(), process_line);
124 |
125 | while(1) {
126 | FD_ZERO(&fds);
127 | FD_SET(fileno(stdin), &fds);
128 |
129 | if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
130 | perror("select");
131 | exit(1);
132 | }
133 |
134 | if( FD_ISSET(fileno(stdin), &fds) ) {
135 | rl_callback_read_char();
136 | }
137 | }
138 |
139 | return 0;
140 | }
141 |
142 | void
143 | process_line(char *line)
144 | {
145 | if( line == NULL ) {
146 | fprintf(stderr, "\n");
147 |
148 | /* reset the old terminal setting before exiting */
149 | term.c_lflag = old_lflag;
150 | term.c_cc[VTIME] = old_vtime;
151 | if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
152 | perror("tcsetattr");
153 | exit(1);
154 | }
155 | exit(0);
156 | }
157 |
158 | if( strcmp(line, "sleep") == 0 ) {
159 | sleep(3);
160 | } else {
161 | fprintf(stderr, "|%s|\n", line);
162 | }
163 |
164 | free (line);
165 | }
166 |
167 | int
168 | change_prompt(void)
169 | {
170 | /* toggle the prompt variable */
171 | prompt = !prompt;
172 |
173 | /* save away the current contents of the line */
174 | strncpy(line_buf, rl_line_buffer, sizeof(line_buf));
175 | line_buf[sizeof(line_buf) - 1] = 0;
176 |
177 | /* install a new handler which will change the prompt and erase the current line */
178 | rl_callback_handler_install(get_prompt(), process_line);
179 |
180 | /* insert the old text on the new line */
181 | rl_insert_text(line_buf);
182 |
183 | /* redraw the current line - this is an undocumented function. It invokes the
184 | * redraw-current-line command.
185 | */
186 | return rl_refresh_line(0, 0);
187 | }
188 |
189 | char *
190 | get_prompt(void)
191 | {
192 | /* The prompts can even be different lengths! */
193 | sprintf(prompt_buf, "%s",
194 | prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> ");
195 | return prompt_buf;
196 | }
197 |
--------------------------------------------------------------------------------
/examples/fileman.c:
--------------------------------------------------------------------------------
1 | /* fileman.c -- A tiny application which demonstrates how to use the
2 | GNU Readline library. This application interactively allows users
3 | to manipulate files and their modes.
4 |
5 | NOTE: this was taken from the GNU Readline documentation and ported
6 | to libedit. A command to output the history list was added.
7 |
8 | */
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "editline.h"
24 |
25 | void too_dangerous(char *caller);
26 | void initialize_readline(const char *prompt);
27 | int execute_line(char *line);
28 | int valid_argument(char *caller, char *arg);
29 |
30 | /* The names of functions that actually do the manipulation. */
31 | int com_list(char *);
32 | int com_view(char *);
33 | int com_history(char *);
34 | int com_rename(char *);
35 | int com_stat(char *);
36 | int com_pwd(char *);
37 | int com_delete(char *);
38 | int com_help(char *);
39 | int com_cd(char *);
40 | int com_quit(char *);
41 |
42 | struct cmd {
43 | char *name; /* User printable name of the function. */
44 | int (*func)(char *); /* Function to call to do the job. */
45 | char *doc; /* Documentation for this function. */
46 | };
47 |
48 | struct cmd commands[] = {
49 | { "cd", com_cd, "Change to directory DIR"},
50 | { "delete", com_delete, "Delete FILE"},
51 | { "help", com_help, "Display this text"},
52 | { "?", com_help, "Synonym for `help'"},
53 | { "list", com_list, "List files in DIR"},
54 | { "ls", com_list, "Synonym for `list'"},
55 | { "pwd", com_pwd, "Print the current working directory"},
56 | { "quit", com_quit, "Quit using Fileman"},
57 | { "rename", com_rename, "Rename FILE to NEWNAME"},
58 | { "stat", com_stat, "Print out statistics on FILE"},
59 | { "view", com_view, "View the contents of FILE"},
60 | { "history", com_history, "List editline history"},
61 | { NULL, NULL, NULL },
62 | };
63 |
64 | /* Forward declarations. */
65 | char *stripwhite(char *string);
66 | struct cmd *find_command(char *name);
67 |
68 | /* ~/.fileman_history */
69 | char *fileman_history;
70 |
71 | /* Prompt base and current */
72 | const char *prompt_init;
73 | char *prompt_curr;
74 |
75 | /* When non-zero, this means the user is done using this program. */
76 | int done;
77 |
78 | int main(int argc, char **argv)
79 | {
80 | char *line, *s;
81 |
82 | setlocale(LC_CTYPE, "");
83 | initialize_readline("(FileMan)");
84 |
85 | /* Loop reading and executing lines until the user quits. */
86 | for (; done == 0;) {
87 | line = readline(NULL);
88 |
89 | if (!line)
90 | break;
91 |
92 | /* Remove leading and trailing whitespace from the line.
93 | Then, if there is anything left, add it to the history list
94 | and execute it. */
95 | s = stripwhite(line);
96 | #if 0
97 | if (*s) {
98 |
99 | char *expansion;
100 | int result;
101 |
102 | result = history_expand(s, &expansion);
103 | if (result < 0 || result == 2) {
104 | fprintf(stderr, "%s\n", expansion);
105 | } else {
106 | add_history(expansion);
107 | execute_line(expansion);
108 | }
109 | free(expansion);
110 | }
111 | #else
112 | execute_line(s);
113 | #endif
114 | free(line);
115 | }
116 |
117 | puts("");
118 | write_history(fileman_history);
119 | free(fileman_history);
120 |
121 | return 0;
122 | }
123 |
124 | /* Execute a command line. */
125 | int execute_line(char *line)
126 | {
127 | int i;
128 | struct cmd *command;
129 | char *word;
130 |
131 | /* Isolate the command word. */
132 | i = 0;
133 | while (line[i] && isspace(line[i]))
134 | i++;
135 | word = line + i;
136 |
137 | while (line[i] && !isspace(line[i]))
138 | i++;
139 |
140 | if (line[i])
141 | line[i++] = '\0';
142 |
143 | command = find_command(word);
144 |
145 | if (!command) {
146 | fprintf(stderr, "%s: No such command for FileMan.\n", word);
147 | return -1;
148 | }
149 |
150 | /* Get argument to command, if any. */
151 | while (isspace(line[i]))
152 | i++;
153 |
154 | word = line + i;
155 |
156 | /* Call the function. */
157 | return command->func(word);
158 | }
159 |
160 | /* Look up NAME as the name of a command, and return a pointer to that
161 | command. Return a NULL pointer if NAME isn't a command name. */
162 | struct cmd *find_command(char *name)
163 | {
164 | int i;
165 |
166 | for (i = 0; commands[i].name; i++)
167 | if (strcmp(name, commands[i].name) == 0)
168 | return &commands[i];
169 |
170 | return NULL;
171 | }
172 |
173 | /*
174 | * Strip whitespace from the start and end of STRING. Return a pointer
175 | * into STRING.
176 | */
177 | char *stripwhite(char *string)
178 | {
179 | char *s, *t;
180 |
181 | for (s = string; isspace(*s); s++) ;
182 |
183 | if (*s == 0)
184 | return s;
185 |
186 | t = s + strlen(s) - 1;
187 | while (t > s && isspace(*t))
188 | t--;
189 | *++t = '\0';
190 |
191 | return s;
192 | }
193 |
194 | /* **************************************************************** */
195 | /* */
196 | /* Interface to Readline Completion */
197 | /* */
198 | /* **************************************************************** */
199 |
200 | char *command_generator(const char *, int);
201 | char **fileman_completion(const char *, int, int);
202 | void fileman_prompt(void);
203 |
204 | /*
205 | * Tell the GNU Readline library how to complete. We want to try to
206 | * complete on command names if this is the first word in the line, or
207 | * on filenames if not.
208 | */
209 | void initialize_readline(const char *prompt)
210 | {
211 | const char *home;
212 | size_t len;
213 |
214 | /* Allow conditional parsing of the ~/.inputrc file. */
215 | rl_readline_name = "FileMan";
216 |
217 | /* Tell the completer that we want a crack first. */
218 | rl_attempted_completion_function = fileman_completion;
219 |
220 | /* Restore command history */
221 | home = getenv("HOME");
222 | len = (home ? strlen(home) : 0) + 14;
223 | fileman_history = malloc(len);
224 | assert(fileman_history);
225 | snprintf(fileman_history, len, "%s/.fileman_history", home ? home : ".");
226 |
227 | read_history(fileman_history);
228 |
229 | /* Prompt is updated when moving around in the tree */
230 | prompt_init = prompt;
231 | fileman_prompt();
232 | }
233 |
234 | /*
235 | * Update prompt when changing directory. Use an allocated string to
236 | * show off the rl_set_prompt() API for issue #51.
237 | */
238 | void fileman_prompt(void)
239 | {
240 | char cwd[1024];
241 | size_t len;
242 |
243 | if (prompt_curr)
244 | free(prompt_curr);
245 |
246 | assert(getcwd(cwd, sizeof(cwd)));
247 | len = strlen(prompt_init) + strlen(cwd) + 10;
248 | prompt_curr = malloc(len);
249 | assert(prompt_curr);
250 |
251 | snprintf(prompt_curr, len, "%s %s/> ", prompt_init, cwd);
252 |
253 | rl_set_prompt(prompt_curr);
254 | }
255 |
256 | /*
257 | * Attempt to complete on the contents of TEXT. START and END
258 | * bound the region of rl_line_buffer that contains the word to
259 | * complete. TEXT is the word to complete. We can use the entire
260 | * contents of rl_line_buffer in case we want to do some simple
261 | * parsing. Returnthe array of matches, or NULL if there aren't any.
262 | */
263 | char **fileman_completion(const char *text, int start, int end)
264 | {
265 | char **matches = NULL;
266 |
267 | /* If this word is at the start of the line, then it is a command
268 | to complete. Otherwise it is the name of a file in the current
269 | directory. */
270 | if (start == 0)
271 | matches = rl_completion_matches(text, command_generator);
272 |
273 | return matches;
274 | }
275 |
276 | /* Generator function for command completion. STATE lets us
277 | know whether to start from scratch; without any state
278 | (i.e. STATE == 0), then we start at the top of the list. */
279 | char *command_generator(const char *text, int state)
280 | {
281 | static int list_index, len;
282 | char *name;
283 |
284 | /* If this is a new word to complete, initialize now. This
285 | includes saving the length of TEXT for efficiency, and
286 | initializing the index variable to 0. */
287 | if (!state) {
288 | list_index = 0;
289 | len = strlen(text);
290 | }
291 |
292 | /* Return the next name which partially matches from the
293 | command list. */
294 | while ((name = commands[list_index].name)) {
295 | list_index++;
296 |
297 | if (strncmp(name, text, len) == 0)
298 | return strdup(name);
299 | }
300 |
301 | /* If no names matched, then return NULL. */
302 | return NULL;
303 | }
304 |
305 | /* **************************************************************** */
306 | /* */
307 | /* FileMan Commands */
308 | /* */
309 | /* **************************************************************** */
310 |
311 | /* String to pass to system (). This is for the LIST, VIEW and RENAME
312 | commands. */
313 | static char syscom[1024];
314 |
315 | /* List the file(s) named in arg. */
316 | int com_list(char *arg)
317 | {
318 | if (!arg)
319 | arg = "";
320 |
321 | sprintf(syscom, "ls -FClg %s", arg);
322 |
323 | return system(syscom);
324 | }
325 |
326 | int com_view(char *arg)
327 | {
328 | if (!valid_argument("view", arg))
329 | return 1;
330 |
331 | sprintf(syscom, "more %s", arg);
332 |
333 | return system(syscom);
334 | }
335 |
336 | int com_history(char *arg)
337 | {
338 | const char *he;
339 |
340 | /* rewind history */
341 | while (el_prev_hist()) ;
342 |
343 | for (he = el_next_hist(); he != NULL; he = el_next_hist())
344 | printf("%s\n", he);
345 |
346 | return 0;
347 | }
348 |
349 | int com_rename(char *arg)
350 | {
351 | too_dangerous("rename");
352 | return 1;
353 | }
354 |
355 | int com_stat(char *arg)
356 | {
357 | struct stat finfo;
358 |
359 | if (!valid_argument("stat", arg))
360 | return 1;
361 |
362 | if (stat(arg, &finfo) == -1) {
363 | perror(arg);
364 | return 1;
365 | }
366 |
367 | printf("Statistics for `%s':\n", arg);
368 |
369 | printf("%s has %ld link%s, and is %lld byte%s in length.\n", arg,
370 | (long)finfo.st_nlink,
371 | (finfo.st_nlink == 1) ? "" : "s",
372 | (long long)finfo.st_size, (finfo.st_size == 1) ? "" : "s");
373 | printf("Inode Last Change at: %s", ctime(&finfo.st_ctime));
374 | printf(" Last access at: %s", ctime(&finfo.st_atime));
375 | printf(" Last modified at: %s", ctime(&finfo.st_mtime));
376 |
377 | return 0;
378 | }
379 |
380 | int com_delete(char *arg)
381 | {
382 | too_dangerous("delete");
383 | return 1;
384 | }
385 |
386 | /* Print out help for ARG, or for all of the commands if ARG is
387 | not present. */
388 | int com_help(char *arg)
389 | {
390 | int i;
391 | int printed = 0;
392 |
393 | for (i = 0; commands[i].name; i++) {
394 | if (!*arg || (strcmp(arg, commands[i].name) == 0)) {
395 | printf("%s\t\t%s.\n", commands[i].name,
396 | commands[i].doc);
397 | printed++;
398 | }
399 | }
400 |
401 | if (!printed) {
402 | printf("No commands match `%s'. Possibilties are:\n", arg);
403 |
404 | for (i = 0; commands[i].name; i++) {
405 | /* Print in six columns. */
406 | if (printed == 6) {
407 | printed = 0;
408 | printf("\n");
409 | }
410 |
411 | printf("%s\t", commands[i].name);
412 | printed++;
413 | }
414 |
415 | if (printed)
416 | printf("\n");
417 | }
418 |
419 | return 0;
420 | }
421 |
422 | /* Change to the directory ARG. */
423 | int com_cd(char *arg)
424 | {
425 | if (chdir(arg) == -1) {
426 | perror(arg);
427 | return 1;
428 | }
429 |
430 | //com_pwd("");
431 | fileman_prompt();
432 | return 0;
433 | }
434 |
435 | /* Print out the current working directory. */
436 | int com_pwd(char *ignore)
437 | {
438 | char dir[1024], *s;
439 |
440 | s = getcwd(dir, sizeof(dir) - 1);
441 | if (!s) {
442 | printf("Error getting pwd: %s\n", dir);
443 | return 1;
444 | }
445 |
446 | printf("Current directory is %s\n", dir);
447 | return 0;
448 | }
449 |
450 | /* The user wishes to quit using this program. Just set DONE
451 | non-zero. */
452 | int com_quit(char *arg)
453 | {
454 | done = 1;
455 | return 0;
456 | }
457 |
458 | /* Function which tells you that you can't do this. */
459 | void too_dangerous(char *caller)
460 | {
461 | fprintf(stderr, "%s: Too dangerous for me to distribute.\n", caller);
462 | fprintf(stderr, "Write it yourself.\n");
463 | }
464 |
465 | /* Return non-zero if ARG is a valid argument for CALLER,
466 | else print an error message and return zero. */
467 | int valid_argument(char *caller, char *arg)
468 | {
469 | if (!arg || !*arg) {
470 | fprintf(stderr, "%s: Argument required.\n", caller);
471 | return 0;
472 | }
473 |
474 | return 1;
475 | }
476 |
477 | /**
478 | * Local Variables:
479 | * c-file-style: "k&r"
480 | * c-basic-offset: 4
481 | * End:
482 | */
483 |
--------------------------------------------------------------------------------
/examples/testit.c:
--------------------------------------------------------------------------------
1 | /* A "micro-shell" to test editline library.
2 | * If given any arguments, commands aren't executed.
3 | *
4 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 | #include
23 | #include
24 | #ifdef HAVE_STDLIB_H
25 | #include
26 | #endif
27 | #ifdef HAVE_STRING_H
28 | #include
29 | #endif
30 | #ifdef HAVE_UNISTD_H
31 | #include
32 | #endif
33 | #include "editline.h"
34 |
35 | #ifndef HAVE_PERROR
36 | extern int errno;
37 | void perror(char *s)
38 | {
39 | fprintf(stderr, "%s: error %d\n", s, errno);
40 | }
41 | #endif /* !HAVE_PERROR */
42 |
43 | int main(int argc, char *argv[] __attribute__ ((unused)))
44 | {
45 | int doit;
46 | char *prompt, *p;
47 |
48 | read_history(".testit_history");
49 |
50 | doit = argc == 1;
51 | if ((prompt = getenv("TESTPROMPT")) == NULL)
52 | prompt = "testit> ";
53 |
54 | while ((p = readline(prompt)) != NULL) {
55 | printf("\t\t\t|%s|\n", p);
56 | if (doit) {
57 | if (strncmp(p, "cd ", 3) == 0) {
58 | if (chdir(&p[3]) < 0)
59 | perror(&p[3]);
60 | } else if (system(p) != 0) {
61 | perror(p);
62 | }
63 | }
64 | free(p);
65 | }
66 |
67 | write_history(".testit_history");
68 | rl_uninitialize();
69 |
70 | return 0;
71 | }
72 |
73 | /**
74 | * Local Variables:
75 | * c-file-style: "k&r"
76 | * c-basic-offset: 4
77 | * End:
78 | */
79 |
--------------------------------------------------------------------------------
/include/Makefile.am:
--------------------------------------------------------------------------------
1 | library_includedir = $(includedir)
2 | library_include_HEADERS = editline.h
3 |
--------------------------------------------------------------------------------
/include/editline.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
3 | * All rights reserved.
4 | *
5 | * This software is not subject to any license of the American Telephone
6 | * and Telegraph Company or of the Regents of the University of California.
7 | *
8 | * Permission is granted to anyone to use this software for any purpose on
9 | * any computer system, and to alter it and redistribute it freely, subject
10 | * to the following restrictions:
11 | * 1. The authors are not responsible for the consequences of use of this
12 | * software, no matter how awful, even if they arise from flaws in it.
13 | * 2. The origin of this software must not be misrepresented, either by
14 | * explicit claim or by omission. Since few users ever read sources,
15 | * credits must appear in the documentation.
16 | * 3. Altered versions must be plainly marked as such, and must not be
17 | * misrepresented as being the original software. Since few users
18 | * ever read sources, credits must appear in the documentation.
19 | * 4. This notice may not be removed or altered.
20 | */
21 | #ifndef EDITLINE_H_
22 | #define EDITLINE_H_
23 |
24 | #include
25 |
26 | /* Handy macros when binding keys. */
27 | #define CTL(x) ((x) & 0x1F)
28 | #define ISCTL(x) ((x) && (x) < ' ')
29 | #define UNCTL(x) ((x) + 64)
30 | #define META(x) ((x) | 0x80)
31 | #define ISMETA(x) ((x) & 0x80)
32 | #define UNMETA(x) ((x) & 0x7F)
33 |
34 | #ifdef __cplusplus
35 | extern "C" {
36 | #endif
37 |
38 | /* Command status codes. */
39 | typedef enum {
40 | CSdone = 0, /* OK */
41 | CSeof, /* Error, or EOF */
42 | CSmove,
43 | CSdispatch,
44 | CSstay,
45 | CSsignal
46 | } el_status_t;
47 |
48 | /* Editline specific types, despite rl_ prefix. From Heimdal project. */
49 | typedef int rl_list_possib_func_t(char*, char***);
50 | typedef el_status_t el_keymap_func_t(void);
51 | typedef int rl_hook_func_t(void);
52 | typedef int rl_getc_func_t(void);
53 | typedef void rl_voidfunc_t(void);
54 | typedef void rl_vintfunc_t(int);
55 | typedef void rl_vcpfunc_t(char *);
56 |
57 | /* FSF Readline compat tupes */
58 | typedef char *rl_complete_func_t (char *, int*);
59 | typedef char *rl_compentry_func_t (const char *, int);
60 | typedef char **rl_completion_func_t (const char *, int, int);
61 |
62 | /* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */
63 | extern int rl_meta_chars;
64 |
65 | /* Editline specific functions. */
66 | extern char * el_find_word(void);
67 | extern void el_print_columns(int ac, char **av);
68 | extern el_status_t el_ring_bell(void);
69 | extern el_status_t el_del_char(void);
70 |
71 | extern el_status_t el_bind_key(int key, el_keymap_func_t function);
72 | extern el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function);
73 |
74 | extern const char *el_next_hist(void);
75 | extern const char *el_prev_hist(void);
76 |
77 | extern char *rl_complete(char *token, int *match);
78 | extern int rl_list_possib(char *token, char ***av);
79 | extern char **rl_completion_matches(const char *token, rl_compentry_func_t *generator);
80 | extern char *rl_filename_completion_function(const char *text, int state);
81 |
82 | /* For compatibility with FSF readline. */
83 | extern int rl_point;
84 | extern int rl_mark;
85 | extern int rl_end;
86 | extern int rl_inhibit_complete;
87 | extern int rl_attempted_completion_over;
88 | extern char *rl_line_buffer;
89 | extern const char *rl_readline_name;
90 | extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */
91 | extern FILE *rl_outstream; /* The stdio stream to which output is flushed. Defaults to stdout if NULL - Not supported yet! */
92 | extern int el_no_echo; /* E.g under emacs, don't echo except prompt */
93 | extern int el_no_hist; /* Disable auto-save of and access to history -- e.g. for password prompts or wizards */
94 | extern int el_hist_size; /* size of history scrollback buffer, default: 15 */
95 |
96 | extern void rl_initialize (void);
97 | extern void rl_reset_terminal (const char *terminal_name);
98 | extern void rl_uninitialize (void);
99 |
100 | extern void rl_save_prompt (void);
101 | extern void rl_restore_prompt (void);
102 | extern void rl_set_prompt (const char *prompt);
103 |
104 | extern void rl_clear_message (void);
105 | extern void rl_forced_update_display(void);
106 |
107 | extern void rl_prep_terminal (int meta_flag);
108 | extern void rl_deprep_terminal (void);
109 |
110 | extern int rl_getc(void);
111 | extern int rl_insert_text (const char *text);
112 | extern int rl_refresh_line (int ignore1, int ignore2);
113 |
114 | extern char *readline (const char *prompt);
115 |
116 | extern void add_history (const char *line);
117 | extern int read_history (const char *filename);
118 | extern int write_history (const char *filename);
119 |
120 | extern rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *func);
121 |
122 | extern rl_completion_func_t *rl_attempted_completion_function;
123 | extern rl_complete_func_t *rl_set_complete_func (rl_complete_func_t *func);
124 | extern rl_list_possib_func_t *rl_set_list_possib_func (rl_list_possib_func_t *func);
125 |
126 | /* Alternate interface to plain readline(), for event loops */
127 | extern void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler);
128 | extern void rl_callback_read_char (void);
129 | extern void rl_callback_handler_remove (void);
130 |
131 | #ifdef __cplusplus
132 | }
133 | #endif
134 |
135 | #endif /* EDITLINE_H_ */
136 |
--------------------------------------------------------------------------------
/libeditline.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@prefix@
2 | exec_prefix=@exec_prefix@
3 | libdir=@libdir@
4 | includedir=@includedir@
5 |
6 | Name: @PACKAGE@
7 | Description: A small line editing library without termcap/curses
8 | Version: @VERSION@
9 | Requires:
10 | Libs: -L${libdir} -leditline
11 | Cflags: -I${includedir}
12 |
13 |
--------------------------------------------------------------------------------
/m4/.gitignore:
--------------------------------------------------------------------------------
1 | *.m4
2 |
--------------------------------------------------------------------------------
/man/Makefile.am:
--------------------------------------------------------------------------------
1 | AUTOMAKE_OPTIONS = foreign
2 |
3 | dist_man_MANS = editline.3
4 |
--------------------------------------------------------------------------------
/man/editline.3:
--------------------------------------------------------------------------------
1 | .Dd February 23, 2020
2 | .Dt EDITLINE 3
3 | .Os
4 | .Sh NAME
5 | .Nm editline
6 | .Nd command-line editing library with history
7 | .Sh LIBRARY
8 | .Lb libeditline
9 | .Sh SYNOPSIS
10 | .In editline.h
11 | .Ft char *
12 | .Fo readline
13 | .Fa const char *prompt
14 | .Fc
15 | .Ft void
16 | .Fo add_history
17 | .Fa const char *line
18 | .Fc
19 | .Ft int
20 | .Fo read_history
21 | .Fa const char *filename
22 | .Fc
23 | .Ft int
24 | .Fo write_history
25 | .Fa const char *filename
26 | .Fc
27 | .Sh DESCRIPTION
28 | .Nm
29 | is a library that provides n line-editing interface with history. It
30 | is intended to be functionally equivalent with the
31 | .Nm readline
32 | library provided by the Free Software Foundation, but much smaller. The
33 | bulk of this manual page describes the basic user interface. More APIs,
34 | both native and for
35 | .Nm readline
36 | compatibility ,
37 | are also available. See the
38 | .Cm editline.h
39 | header file for details.
40 | .Pp
41 | The
42 | .Fn readline
43 | function displays the given
44 | .Fa prompt
45 | on stdout, waits for user input on stdin and then returns a line of text
46 | with the trailing newline removed. The data is returned in a buffer
47 | allocated with
48 | .Xr malloc 3 ,
49 | so the space should be released with
50 | .Xr free 3
51 | when the calling program is done with it.
52 | .Pp
53 | Each line returned is automatically saved in the internal history list,
54 | unless it happens to be equal to the previous line. This is
55 | configurable if you are building editline from source, i.e. if you would
56 | rather like to call
57 | .Fn add_history
58 | manually.
59 | .Pp
60 | The
61 | .Fn read_history
62 | and
63 | .Fn write_history
64 | functions can be used to load and store the history of your application.
65 | .Em Note:
66 | these APIs do not do any tilde or environment variable expansion of the
67 | given filename.
68 | .Ss User Interface
69 | A program that uses this library provides a simple emacs-like editing
70 | interface to its users. A line may be edited before it is sent to the
71 | calling program by typing either control characters or escape sequences.
72 | A control character, shown as a caret followed by a letter, is typed by
73 | holding down the control key while the letter is typed. For example,
74 | .Cm ^A
75 | is a control-A. An escape sequence is entered by typing the escape key
76 | followed by one or more characters. The escape key is abbreviated as
77 | .Cm ESC .
78 | Note that unlike control keys, case matters in escape sequences;
79 | .Cm ESC F
80 | is not the same as
81 | .Cm ESC f .
82 | .Pp
83 | An editing command may be typed anywhere on the line, not just at the
84 | beginning. In addition, a return may also be typed anywhere on the
85 | line, not just at the end.
86 | .Pp
87 | Most editing commands may be given a repeat count,
88 | .Ar n ,
89 | where
90 | .Ar n
91 | is a number. To enter a repeat count, type the escape key, the number,
92 | and then the command to execute. For example,
93 | .Cm ESC 4 ^f
94 | moves forward four characters. If a command may be given a repeat count
95 | then the text
96 | .Cm [n]
97 | is given at the end of its description.
98 | .Pp
99 | The following control characters are accepted:
100 | .Pp
101 | .Bl -tag -width "ESC DEL " -compact
102 | .It ^A
103 | Move to the beginning of the line
104 | .It ^B
105 | Move left (backwards) [n]
106 | .It ^D
107 | Delete character [n]
108 | .It ^E
109 | Move to end of line
110 | .It ^F
111 | Move right (forwards) [n]
112 | .It ^G
113 | Ring the bell
114 | .It ^H
115 | Delete character before cursor (backspace key) [n]
116 | .It ^I
117 | Complete filename (tab key); see below
118 | .It ^J
119 | Done with line (return key)
120 | .It ^K
121 | Kill to end of line (or column [n])
122 | .It ^L
123 | Redisplay line
124 | .It ^M
125 | Done with line (alternate return key)
126 | .It ^N
127 | Get next line from history [n]
128 | .It ^P
129 | Get previous line from history [n]
130 | .It ^R
131 | Search backward (forward if [n]) through history for text; prefixing the
132 | string with a caret (^) forces it to match only at the beginning of a
133 | history line
134 | .It ^T
135 | Transpose characters
136 | .It ^V
137 | Insert next character, even if it is an edit command
138 | .It ^W
139 | Wipe to the mark
140 | .It ^X^X
141 | Exchange current location and mark
142 | .It ^Y
143 | Yank back last killed text
144 | .It ^[
145 | Start an escape sequence (escape key)
146 | .It ^]c
147 | Move forward to next character
148 | .Cm c
149 | .It ^?
150 | Delete character before cursor (delete key) [n]
151 | .El
152 | .Pp
153 | The following escape sequences are provided:
154 | .Pp
155 | .Bl -tag -width "ESC DEL " -compact
156 | .It ESC ^H
157 | Delete previous word (backspace key) [n]
158 | .It ESC DEL
159 | Delete previous word (delete key) [n]
160 | .It ESC SP
161 | Set the mark (space key); see ^X^X and ^Y above
162 | .It ESC\ .
163 | Get the last (or [n]'th) word from previous line
164 | .It ESC\ ?
165 | Show possible completions; see below
166 | .It ESC <
167 | Move to start of history
168 | .It ESC >
169 | Move to end of history
170 | .It ESC b
171 | Move backward a word [n]
172 | .It ESC d
173 | Delete word under cursor [n]
174 | .It ESC f
175 | Move forward a word [n]
176 | .It ESC l
177 | Make word lowercase [n]
178 | .It ESC m
179 | Toggle if 8bit chars display normally or with an
180 | .Ar M-
181 | prefix
182 | .It ESC u
183 | Make word uppercase [n]
184 | .It ESC y
185 | Yank back last killed text
186 | .It ESC v
187 | Show library version
188 | .It ESC w
189 | Make area up to mark yankable
190 | .It ESC nn
191 | Set repeat count to the number nn
192 | .It ESC C
193 | Read from environment variable
194 | .Ar $C ,
195 | where
196 | .Ar C
197 | is an uppercase letter
198 | .El
199 | .Pp
200 | The
201 | .Nm
202 | library has a small macro facility. If you type the escape key followed
203 | by an uppercase letter,
204 | .Ar C ,
205 | then the contents of the environment variable
206 | .Ar $C
207 | are read in as if you had typed them at the keyboard. For example, if
208 | the variable
209 | .Ar $L
210 | contains the following:
211 | .Pp
212 | .Dl ^A^Kecho '^V^[[H^V^[[2J'^M
213 | .Pp
214 | Then typing
215 | .Cm ESC L
216 | will move to the beginning of the line, kill the entire line, enter the
217 | echo command needed to clear the terminal (if your terminal is like a
218 | VT-100), and send the line back to the shell.
219 | .Pp
220 | The
221 | .Nm
222 | library also does filename completion. Suppose the root directory has
223 | the following files in it:
224 | .Pp
225 | .Dl bin vmunix
226 | .Dl core vmunix.old
227 | .Pp
228 | If you type
229 | .Cm rm /v
230 | and then the tab key,
231 | .Nm
232 | will then finish off as much of the name as possible by adding
233 | .Ar munix .
234 | Because the name is not unique, it will then beep. If you type the
235 | escape key and a question mark, it will display the two choices. If you
236 | then type a period and a tab, the library will finish off the filename
237 | for you:
238 | .Pp
239 | .Bd -ragged -offset indent
240 | rm /v[TAB]
241 | .Em munix
242 | \&.[TAB]
243 | .Em old
244 | .Ed
245 | .Pp
246 | The tab key is shown by [TAB] and the automatically-entered text
247 | is shown in italics, or underline.
248 | .Sh USAGE
249 | To include
250 | .Nm
251 | in your program, call it as you do any other function and link your
252 | program with
253 | .Ar -leditline .
254 | .Ss Example
255 | The following brief example lets you enter a line and edit it, then displays it.
256 | .Pp
257 | .Bd -literal -offset indent
258 | #include
259 | #include
260 | #include
261 |
262 | int main(void)
263 | {
264 | char *p;
265 |
266 | while ((p = readline("CLI> "))) {
267 | puts(p);
268 | free(p);
269 | }
270 |
271 | return 0;
272 | }
273 | .El
274 | .Sh AUTHORS
275 | The original editline library was posted to comp.sources.unix newsgroup
276 | by created by Simmule R. Turner and Rich Salz in 1992. It now exists in
277 | several forks: Debian, Minix, Heimdal, Festival speech tools, Mozilla,
278 | Google Gadgets for Linux, and many others. The original manual page was
279 | made by David W. Sanderson.
280 | .Pp
281 | This version stems from the Minix 2 sources, but has since evolved to
282 | include patches from all relevant forks. It is currently maintained by
283 | .An Joachim Wiberg
284 | at
285 | .Lk https://github.com/troglobit/editline "GitHub" .
286 | .Sh BUGS
287 | Does not handle multiple lines or unicode characters well.
288 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | libeditline.a
2 | libeditline.la
3 |
--------------------------------------------------------------------------------
/src/Makefile.am:
--------------------------------------------------------------------------------
1 | lib_LTLIBRARIES = libeditline.la
2 | libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
3 | libeditline_la_CFLAGS = -std=gnu99
4 | libeditline_la_CFLAGS += -W -Wall -Wextra -Wundef -Wunused -Wstrict-prototypes
5 | libeditline_la_CFLAGS += -Werror-implicit-function-declaration -Wshadow -Wcast-qual
6 | libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2:0
7 |
--------------------------------------------------------------------------------
/src/complete.c:
--------------------------------------------------------------------------------
1 | /* History and file completion functions for editline library.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 |
23 | #include
24 | #include "editline.h"
25 |
26 | #define MAX_TOTAL_MATCHES (256 << sizeof(char *))
27 |
28 | int rl_attempted_completion_over = 0;
29 | rl_completion_func_t *rl_attempted_completion_function = NULL;
30 | rl_compentry_func_t *rl_completion_entry_function = NULL;
31 |
32 | /* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */
33 | static int compare(const void *p1, const void *p2)
34 | {
35 | char *const *v1 = (char *const *)p1;
36 | char *const *v2 = (char *const *)p2;
37 |
38 | return strcmp(*v1, *v2);
39 | }
40 |
41 | /* Fill in *avp with an array of names that match file, up to its length.
42 | * Ignore . and .. . */
43 | static int FindMatches(const char *dir, const char *file, char ***avp)
44 | {
45 | char **av;
46 | char **word;
47 | char *p;
48 | DIR *dp;
49 | DIRENTRY *ep;
50 | size_t ac;
51 | size_t len;
52 | size_t choices;
53 | size_t total;
54 |
55 | if ((dp = opendir(dir)) == NULL)
56 | return 0;
57 |
58 | av = NULL;
59 | ac = 0;
60 | len = strlen(file);
61 | choices = 0;
62 | total = 0;
63 | while ((ep = readdir(dp)) != NULL) {
64 | p = ep->d_name;
65 | if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
66 | continue;
67 | if (len && strncmp(p, file, len) != 0)
68 | continue;
69 |
70 | choices++;
71 | if ((total += strlen(p)) > MAX_TOTAL_MATCHES) {
72 | /* This is a bit too much. */
73 | while (ac > 0) free(av[--ac]);
74 | continue;
75 | }
76 |
77 | if ((ac % MEM_INC) == 0) {
78 | word = malloc(sizeof(char *) * (ac + MEM_INC));
79 | if (!word) {
80 | total = 0;
81 | break;
82 | }
83 |
84 | if (ac) {
85 | memcpy(word, av, ac * sizeof(char *));
86 | free(av);
87 | }
88 | *avp = av = word;
89 | }
90 |
91 | if ((av[ac] = strdup(p)) == NULL) {
92 | if (ac == 0)
93 | free(av);
94 | total = 0;
95 | break;
96 | }
97 | ac++;
98 | }
99 |
100 | /* Clean up and return. */
101 | closedir(dp);
102 | if (total > MAX_TOTAL_MATCHES) {
103 | char many[sizeof(total) * 3];
104 |
105 | p = many + sizeof(many);
106 | *--p = '\0';
107 | while (choices > 0) {
108 | *--p = '0' + choices % 10;
109 | choices /= 10;
110 | }
111 |
112 | while (p > many + sizeof(many) - 8)
113 | *--p = ' ';
114 |
115 | if ((p = strdup(p)) != NULL)
116 | av[ac++] = p;
117 |
118 | if ((p = strdup("choices")) != NULL)
119 | av[ac++] = p;
120 | } else {
121 | if (ac)
122 | qsort(av, ac, sizeof(char *), compare);
123 | }
124 |
125 | return ac;
126 | }
127 |
128 | /* Split a pathname into allocated directory and trailing filename parts. */
129 | static int SplitPath(const char *path, char **dirpart, char **filepart)
130 | {
131 | static const char DOT[] = ".";
132 | char *dpart;
133 | char *fpart;
134 |
135 | if ((fpart = strrchr(path, '/')) == NULL) {
136 | if ((dpart = strdup(DOT)) == NULL)
137 | return -1;
138 |
139 | if ((fpart = strdup(path)) == NULL) {
140 | free(dpart);
141 | return -1;
142 | }
143 | } else {
144 | if ((dpart = strdup(path)) == NULL)
145 | return -1;
146 |
147 | dpart[fpart - path + 1] = '\0';
148 | if ((fpart = strdup(fpart + 1)) == NULL) {
149 | free(dpart);
150 | return -1;
151 | }
152 | }
153 | *dirpart = dpart;
154 | *filepart = fpart;
155 |
156 | return 0;
157 | }
158 |
159 | static rl_complete_func_t *el_complete_func = NULL;
160 |
161 | /* For compatibility with the Heimdal project. */
162 | rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func)
163 | {
164 | rl_complete_func_t *old = el_complete_func;
165 | el_complete_func = func;
166 |
167 | return old;
168 | }
169 |
170 | /* Attempt to complete the pathname, returning an allocated copy.
171 | * Fill in *match if we completed it, or set it to 0 if ambiguous. */
172 | char *el_filename_complete(char *pathname, int *match)
173 | {
174 | char **av;
175 | char *dir;
176 | char *file;
177 | char *path;
178 | char *p;
179 | size_t ac;
180 | size_t end;
181 | size_t i;
182 | size_t j;
183 | size_t len;
184 |
185 | if (SplitPath((const char *)pathname, &dir, &file) < 0)
186 | return NULL;
187 |
188 | if ((ac = FindMatches(dir, file, &av)) == 0) {
189 | free(dir);
190 | free(file);
191 |
192 | return NULL;
193 | }
194 |
195 | p = NULL;
196 | len = strlen(file);
197 | if (ac == 1) {
198 | /* Exactly one match -- finish it off. */
199 | *match = 1;
200 | j = strlen(av[0]) - len + 1;
201 | p = malloc(sizeof(char) * (j + 1));
202 | if (p) {
203 | memcpy(p, av[0] + len, j);
204 | len = strlen(dir) + strlen(av[0]) + 2;
205 | path = malloc(sizeof(char) * len);
206 | if (path) {
207 | snprintf(path, len, "%s/%s", dir, av[0]);
208 | rl_add_slash(path, p);
209 | free(path);
210 | }
211 | }
212 | } else {
213 | *match = 0;
214 | if (len) {
215 | /* Find largest matching substring. */
216 | for (i = len, end = strlen(av[0]); i < end; i++) {
217 | for (j = 1; j < ac; j++) {
218 | if (av[0][i] != av[j][i])
219 | goto breakout;
220 | }
221 | }
222 | breakout:
223 | if (i > len) {
224 | j = i - len + 1;
225 | p = malloc(sizeof(char) * j);
226 | if (p) {
227 | memcpy(p, av[0] + len, j);
228 | p[j - 1] = '\0';
229 | }
230 | }
231 | }
232 | }
233 |
234 | /* Clean up and return. */
235 | free(dir);
236 | free(file);
237 | for (i = 0; i < ac; i++)
238 | free(av[i]);
239 | free(av);
240 |
241 | return p;
242 | }
243 |
244 | char *rl_filename_completion_function(const char *text, int state)
245 | {
246 | static char **av, *dir, *file;
247 | static size_t i, ac;
248 |
249 | if (!state) {
250 | if (SplitPath(text, &dir, &file) < 0)
251 | return NULL;
252 |
253 | ac = FindMatches(dir, file, &av);
254 | if (!ac) {
255 | free(dir);
256 | free(file);
257 | return NULL;
258 | }
259 |
260 | i = 0;
261 | }
262 |
263 | if (i < ac) {
264 | size_t len = (dir ? strlen(dir) : 0) + strlen(av[i]) + 3;
265 | char *ptr = malloc(len);
266 |
267 | if (ptr) {
268 | snprintf(ptr, len, "%s%s", dir, av[i++]);
269 | if (ac == 1)
270 | rl_add_slash(ptr, ptr);
271 |
272 | return ptr;
273 | }
274 | }
275 |
276 | while (i > 0)
277 | free(av[--i]);
278 |
279 | if (av) {
280 | free(av);
281 | av = NULL;
282 | }
283 | if (dir) {
284 | free(dir);
285 | dir = NULL;
286 | }
287 | if (file) {
288 | free(file);
289 | file = NULL;
290 | }
291 |
292 | return NULL;
293 | }
294 |
295 | /* Similar to el_find_word(), but used by GNU Readline API */
296 | static char *rl_find_token(size_t *len)
297 | {
298 | const char *ptr;
299 | int pos;
300 |
301 | for (pos = rl_point; pos < rl_end; pos++) {
302 | if (isspace((unsigned char) rl_line_buffer[pos])) {
303 | if (pos > 0)
304 | pos--;
305 | break;
306 | }
307 | }
308 |
309 | ptr = &rl_line_buffer[pos];
310 | while (pos >= 0 && !isspace((unsigned char) rl_line_buffer[pos])) {
311 | if (pos == 0)
312 | break;
313 |
314 | pos--;
315 | }
316 |
317 | if (ptr != &rl_line_buffer[pos]) {
318 | *len = (size_t)(ptr - &rl_line_buffer[pos]);
319 | return &rl_line_buffer[pos];
320 | }
321 |
322 | return NULL;
323 | }
324 |
325 | /*
326 | * "uses an application-supplied generator function to generate the list
327 | * of possible matches, and then returns the array of these matches. The
328 | * caller should place the address of its generator function in
329 | * rl_completion_entry_function"
330 | */
331 | char **rl_completion_matches(const char *token, rl_compentry_func_t *generator)
332 | {
333 | int state = 0, num = 0;
334 | char **array, *entry;
335 |
336 | if (!generator) {
337 | generator = rl_completion_entry_function;
338 | if (!generator)
339 | generator = rl_filename_completion_function;
340 | }
341 |
342 | if (!generator)
343 | return NULL;
344 |
345 | array = malloc(512 * sizeof(char *));
346 | if (!array)
347 | return NULL;
348 |
349 | while (num < 511 && (entry = generator(token, state))) {
350 | state = 1;
351 | array[num++] = entry;
352 | }
353 | array[num] = NULL;
354 |
355 | if (!num) {
356 | free(array);
357 | return NULL;
358 | }
359 |
360 | return array;
361 | }
362 |
363 | static char *complete(char *token, int *match)
364 | {
365 | size_t len = 0;
366 | char *word, **words = NULL;
367 | int start, end;
368 |
369 | word = rl_find_token(&len);
370 | if (!word)
371 | goto fallback;
372 |
373 | start = word - rl_line_buffer;
374 | end = start + len;
375 |
376 | word = strndup(word, len);
377 | if (!word)
378 | goto fallback;
379 |
380 | rl_attempted_completion_over = 0;
381 | words = rl_attempted_completion_function(word, start, end);
382 |
383 | if (!rl_attempted_completion_over && !words)
384 | words = rl_completion_matches(word, NULL);
385 |
386 | if (words) {
387 | int i = 0;
388 |
389 | free(word);
390 | word = NULL;
391 |
392 | /* Exactly one match -- finish it off. */
393 | if (words[0] && !words[1]) {
394 | *match = 1;
395 | word = strdup(words[0] + len);
396 | }
397 |
398 | while (words[i])
399 | free(words[i++]);
400 | free(words);
401 |
402 | if (word)
403 | return word;
404 | }
405 |
406 | if (word)
407 | free(word);
408 |
409 | fallback:
410 | return el_filename_complete(token, match);
411 | }
412 |
413 | /*
414 | * First check for editline specific custom completion function, then
415 | * for any GNU Readline compat, then fallback to filename completion.
416 | */
417 | char *rl_complete(char *token, int *match)
418 | {
419 | if (el_complete_func)
420 | return el_complete_func(token, match);
421 |
422 | if (rl_attempted_completion_function)
423 | return complete(token, match);
424 |
425 | return el_filename_complete(token, match);
426 | }
427 |
428 | static rl_list_possib_func_t *el_list_possib_func = NULL;
429 |
430 | /* For compatibility with the Heimdal project. */
431 | rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func)
432 | {
433 | rl_list_possib_func_t *old = el_list_possib_func;
434 | el_list_possib_func = func;
435 | return old;
436 | }
437 |
438 | /* Default possible completions. */
439 | int el_filename_list_possib(char *pathname, char ***av)
440 | {
441 | char *dir;
442 | char *file;
443 | int ac;
444 |
445 | if (SplitPath(pathname, &dir, &file) < 0)
446 | return 0;
447 |
448 | ac = FindMatches(dir, file, av);
449 | free(dir);
450 | free(file);
451 |
452 | return ac;
453 | }
454 |
455 | /* Return all possible completions. */
456 | int rl_list_possib(char *token, char ***av)
457 | {
458 | if (el_list_possib_func)
459 | return el_list_possib_func(token, av);
460 |
461 | return el_filename_list_possib(token, av);
462 | }
463 |
464 |
465 | /**
466 | * Local Variables:
467 | * c-file-style: "k&r"
468 | * c-basic-offset: 4
469 | * End:
470 | */
471 |
--------------------------------------------------------------------------------
/src/editline.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
3 | * All rights reserved.
4 | *
5 | * This software is not subject to any license of the American Telephone
6 | * and Telegraph Company or of the Regents of the University of California.
7 | *
8 | * Permission is granted to anyone to use this software for any purpose on
9 | * any computer system, and to alter it and redistribute it freely, subject
10 | * to the following restrictions:
11 | * 1. The authors are not responsible for the consequences of use of this
12 | * software, no matter how awful, even if they arise from flaws in it.
13 | * 2. The origin of this software must not be misrepresented, either by
14 | * explicit claim or by omission. Since few users ever read sources,
15 | * credits must appear in the documentation.
16 | * 3. Altered versions must be plainly marked as such, and must not be
17 | * misrepresented as being the original software. Since few users
18 | * ever read sources, credits must appear in the documentation.
19 | * 4. This notice may not be removed or altered.
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "editline.h"
28 |
29 | /*
30 | ** Manifest constants.
31 | */
32 | #define SCREEN_COLS 80
33 | #define SCREEN_ROWS 24
34 | #define EL_STDIN 0
35 | #define EL_STDOUT 1
36 | #define NO_ARG (-1)
37 | #define DEL 127
38 | #define SEPS "\"#$&'()*:;<=>?[\\]^`{|}~\n\t "
39 |
40 | /*
41 | ** The type of case-changing to perform.
42 | */
43 | typedef enum {
44 | TOupper, TOlower, TOcapitalize
45 | } el_case_t;
46 |
47 | /*
48 | ** Key to command mapping.
49 | */
50 | typedef struct {
51 | int Key;
52 | el_status_t (*Function)(void);
53 | } el_keymap_t;
54 |
55 | /*
56 | ** Command history structure.
57 | */
58 | typedef struct {
59 | int Size;
60 | int Pos;
61 | char **Lines;
62 | } el_hist_t;
63 |
64 | /* User definable callbacks. */
65 | rl_getc_func_t *rl_getc_function = rl_getc;
66 | rl_hook_func_t *rl_event_hook;
67 | rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
68 | rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal;
69 |
70 | /*
71 | ** Globals.
72 | */
73 | int rl_eof;
74 | int rl_erase;
75 | int rl_intr;
76 | int rl_kill;
77 | int rl_quit;
78 | #ifdef CONFIG_SIGSTOP
79 | int rl_susp;
80 | #endif
81 |
82 | int el_hist_size = 15;
83 | static el_hist_t H = {
84 | .Size = 0,
85 | .Pos = 0,
86 | .Lines = NULL,
87 | };
88 |
89 | static char NILSTR[] = "";
90 | static const char *el_input = NILSTR;
91 | static char *Yanked;
92 | static char *Screen;
93 | static char NEWLINE[]= CRLF;
94 | static char CLEAR[]= "\ec";
95 | static const char *el_term = "dumb";
96 | static int Repeat;
97 | static int old_point;
98 | static int el_push_back;
99 | static int el_pushed;
100 | static int el_intr_pending;
101 | static int el_infd = EL_STDIN;
102 | static int el_outfd = EL_STDOUT;
103 | static el_keymap_t Map[];
104 | static el_keymap_t MetaMap[];
105 | static size_t Length = 0;
106 | static size_t ScreenCount;
107 | static size_t ScreenSize;
108 | static char *backspace = "\b";
109 | static char *old_search = NULL;
110 | static int tty_cols = SCREEN_COLS;
111 | static int tty_rows = SCREEN_ROWS;
112 | static int Searching = 0;
113 | static const char *(*search_move)(void);
114 | static const char *old_prompt = NULL;
115 | static rl_vcpfunc_t *line_handler = NULL;
116 | static char *line_up = "\x1b[A";
117 | static char *line_down = "\x1b[B";
118 | static int prompt_len = 0;
119 |
120 | int el_no_echo = 0; /* e.g., under Emacs */
121 | int el_no_hist = 0;
122 | int rl_point;
123 | int rl_mark;
124 | int rl_end;
125 | int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */
126 | int rl_inhibit_complete = 0;
127 | char *rl_line_buffer = NULL;
128 | static const char *rl_saved_prompt = NULL;
129 | const char *rl_prompt = NULL;
130 | const char *rl_readline_name = NULL; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */
131 | FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */
132 | FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL */
133 |
134 | /* Declarations. */
135 | static char *editinput(int complete);
136 | #ifdef CONFIG_USE_TERMCAP
137 | extern char *tgetstr(const char *, char **);
138 | extern int tgetent(char *, const char *);
139 | extern int tgetnum(const char *);
140 | #endif
141 |
142 | /*
143 | ** Misc. local helper functions.
144 | */
145 | static int is_alpha_num(unsigned char c)
146 | {
147 | if (isalnum(c))
148 | return 1;
149 | if (ISMETA(c))
150 | return 1;
151 | if (ISCTL(c))
152 | return 1;
153 |
154 | return 0;
155 | }
156 |
157 | /*
158 | ** TTY input/output functions.
159 | */
160 |
161 | static void tty_flush(void)
162 | {
163 | ssize_t res;
164 |
165 | if (!ScreenCount)
166 | return;
167 |
168 | if (!el_no_echo) {
169 | res = write(el_outfd, Screen, ScreenCount);
170 | if (res > 0)
171 | ScreenCount = 0;
172 | }
173 | }
174 |
175 | static void tty_put(const char c)
176 | {
177 | if (el_no_echo)
178 | return;
179 |
180 | Screen[ScreenCount] = c;
181 | if (++ScreenCount >= ScreenSize) {
182 | char *ptr;
183 |
184 | ScreenSize += SCREEN_INC;
185 | ptr = realloc(Screen, sizeof(char) * ScreenSize);
186 | if (ptr)
187 | Screen = ptr;
188 | }
189 | }
190 |
191 | static void tty_puts(const char *p)
192 | {
193 | while (*p)
194 | tty_put(*p++);
195 | }
196 |
197 | static void tty_show(unsigned char c)
198 | {
199 | if (c == DEL) {
200 | tty_put('^');
201 | tty_put('?');
202 | } else if (ISCTL(c)) {
203 | tty_put('^');
204 | tty_put(UNCTL(c));
205 | } else if (rl_meta_chars && ISMETA(c)) {
206 | tty_put('M');
207 | tty_put('-');
208 | tty_put(UNMETA(c));
209 | } else {
210 | tty_put(c);
211 | }
212 | }
213 |
214 | static void tty_string(const char *p)
215 | {
216 | int i = rl_point + prompt_len + 1;
217 |
218 | while (*p) {
219 | tty_show(*p++);
220 | if ((i++) % tty_cols == 0) {
221 | tty_put(' ');
222 | tty_put('\b');
223 | }
224 | }
225 | }
226 |
227 | static void tty_push(int c)
228 | {
229 | el_pushed = 1;
230 | el_push_back = c;
231 | }
232 |
233 | int rl_getc(void)
234 | {
235 | int r;
236 | char c;
237 |
238 | do {
239 | r = read(el_infd, &c, 1);
240 | } while (r == -1 && errno == EINTR);
241 |
242 | return r == 1 ? c : EOF;
243 | }
244 |
245 | static int tty_get(void)
246 | {
247 | tty_flush();
248 |
249 | if (el_pushed) {
250 | el_pushed = 0;
251 | return el_push_back;
252 | }
253 |
254 | if (*el_input)
255 | return *el_input++;
256 |
257 | return rl_getc_function();
258 | }
259 |
260 | #define tty_back() tty_puts(backspace)
261 |
262 | static void tty_backn(int n)
263 | {
264 | while (--n >= 0)
265 | tty_back();
266 | }
267 |
268 | static void tty_forwardn(int n)
269 | {
270 | char buf[12];
271 |
272 | snprintf(buf, sizeof(buf), "\x1b[%dC", n);
273 | tty_puts(buf);
274 | }
275 |
276 | static void tty_info(void)
277 | {
278 | rl_reset_terminal(NULL);
279 | }
280 |
281 | /*
282 | ** Glue routines to rl_ttyset()
283 | */
284 | void rl_prep_terminal(int meta_flag)
285 | {
286 | rl_meta_chars = !meta_flag;
287 | rl_ttyset(0);
288 | }
289 |
290 | void rl_deprep_terminal(void)
291 | {
292 | rl_ttyset(1);
293 | }
294 |
295 | /*
296 | ** Print an array of words in columns.
297 | */
298 | void el_print_columns(int ac, char **av)
299 | {
300 | char *p;
301 | int i;
302 | int j;
303 | int k;
304 | int len;
305 | int skip;
306 | int longest;
307 | int cols;
308 | int colwidth;
309 |
310 | /* Find longest name, determine column count from that. */
311 | for (longest = 0, i = 0; i < ac; i++) {
312 | if ((j = strlen((char *)av[i])) > longest)
313 | longest = j;
314 | }
315 |
316 | colwidth = longest + 3;
317 | if (colwidth > tty_cols)
318 | colwidth = tty_cols;
319 | cols = tty_cols / colwidth;
320 |
321 | tty_puts(NEWLINE);
322 | for (skip = ac / cols + 1, i = 0; i < skip; i++) {
323 | for (j = i; j < ac; j += skip) {
324 | for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
325 | tty_put(*p);
326 |
327 | if (j + skip < ac) {
328 | while (++len < colwidth)
329 | tty_put(' ');
330 | }
331 | }
332 |
333 | tty_puts(NEWLINE);
334 | }
335 | }
336 |
337 | static void reposition(int key)
338 | {
339 | int len_with_prompt = prompt_len + rl_end;
340 | int n = len_with_prompt / tty_cols; /* determine the number of lines */
341 | int i = 0;
342 |
343 | tty_put('\r');
344 |
345 | if (n > 0) {
346 | int line;
347 |
348 | /* determine num of current line */
349 | if (key == CTL('A') || key == CTL('E') || key == rl_kill)
350 | line = (prompt_len + old_point) / tty_cols;
351 | else
352 | line = len_with_prompt / tty_cols;
353 |
354 | /* move to end of line(s) */
355 | if (key == CTL('E')) {
356 | int k;
357 |
358 | for (k = line; k < n; k++)
359 | tty_puts(line_down);
360 |
361 | /* determine reminder of last line and redraw only it */
362 | i = rl_point - (len_with_prompt % tty_cols);
363 | } else {
364 | int k;
365 |
366 | /* CTRL-A, CTRL-U, insert (end, middle), remove (end, middle) */
367 | for (k = line; k > 0; k--)
368 | tty_puts(line_up); /* redraw characters until changed data */
369 |
370 | tty_puts(rl_prompt);
371 | }
372 | } else if (n == 0) {
373 | tty_puts(rl_prompt);
374 | }
375 |
376 | for (; i < rl_point; i++) {
377 | tty_show(rl_line_buffer[i]);
378 |
379 | /* move to the next line */
380 | if ((i + prompt_len + 1) % tty_cols == 0)
381 | tty_put('\n');
382 | }
383 | }
384 |
385 | static void left(el_status_t Change)
386 | {
387 | if (rl_point) {
388 | if ((rl_point + prompt_len) % tty_cols == 0) {
389 | tty_puts(line_up);
390 | tty_forwardn(tty_cols);
391 | } else {
392 | tty_back();
393 | }
394 |
395 | if (ISMETA(rl_line_buffer[rl_point - 1])) {
396 | if (rl_meta_chars) {
397 | tty_back();
398 | tty_back();
399 | }
400 | } else if (ISCTL(rl_line_buffer[rl_point - 1])) {
401 | tty_back();
402 | }
403 | }
404 |
405 | if (Change == CSmove)
406 | rl_point--;
407 | }
408 |
409 | static void right(el_status_t Change)
410 | {
411 | if ((rl_point + prompt_len + 1) % tty_cols == 0)
412 | tty_put('\n');
413 | else
414 | tty_show(rl_line_buffer[rl_point]);
415 |
416 | if (Change == CSmove)
417 | rl_point++;
418 | }
419 |
420 | el_status_t el_ring_bell(void)
421 | {
422 | tty_put('\07');
423 | tty_flush();
424 |
425 | return CSstay;
426 | }
427 |
428 | static el_status_t do_macro(int c)
429 | {
430 | char name[4];
431 |
432 | name[0] = '_';
433 | name[1] = c;
434 | name[2] = '_';
435 | name[3] = '\0';
436 |
437 | if ((el_input = (char *)getenv((char *)name)) == NULL) {
438 | el_input = NILSTR;
439 | return el_ring_bell();
440 | }
441 |
442 | return CSstay;
443 | }
444 |
445 | /* Skip forward to start of next word. If @move is set we also move the cursor. */
446 | static el_status_t do_forward(el_status_t move)
447 | {
448 | int i;
449 | char *p;
450 |
451 | i = 0;
452 | do {
453 | p = &rl_line_buffer[rl_point];
454 |
455 | /* Skip leading whitespace, like FSF Readline */
456 | for ( ; rl_point < rl_end && (p[0] == ' ' || !is_alpha_num(p[0])); rl_point++, p++) {
457 | if (move == CSmove)
458 | right(CSstay);
459 | }
460 |
461 | /* Skip to end of word, if inside a word. */
462 | for (; rl_point < rl_end && is_alpha_num(p[0]); rl_point++, p++) {
463 | if (move == CSmove)
464 | right(CSstay);
465 | }
466 |
467 | if (rl_point == rl_end)
468 | break;
469 | } while (++i < Repeat);
470 |
471 | return CSstay;
472 | }
473 |
474 | static el_status_t do_case(el_case_t type)
475 | {
476 | int i;
477 | int end;
478 | int count;
479 | char *p;
480 |
481 | do_forward(CSstay);
482 | if (old_point != rl_point) {
483 | if ((count = rl_point - old_point) < 0)
484 | count = -count;
485 |
486 | rl_point = old_point;
487 | if ((end = rl_point + count) > rl_end)
488 | end = rl_end;
489 |
490 | for (i = rl_point, p = &rl_line_buffer[i]; rl_point < end; p++) {
491 | if ((type == TOupper) || (type == TOcapitalize && rl_point == i)) {
492 | if (islower((unsigned char)(*p)))
493 | *p = toupper((unsigned char)(*p));
494 | } else if (isupper((unsigned char)(*p))) {
495 | *p = tolower((unsigned char)(*p));
496 | }
497 | right(CSmove);
498 | }
499 | }
500 |
501 | return CSstay;
502 | }
503 |
504 | static el_status_t case_down_word(void)
505 | {
506 | return do_case(TOlower);
507 | }
508 |
509 | static el_status_t case_up_word(void)
510 | {
511 | return do_case(TOupper);
512 | }
513 |
514 | static el_status_t case_cap_word(void)
515 | {
516 | return do_case(TOcapitalize);
517 | }
518 |
519 | static void ceol(void)
520 | {
521 | int extras = 0;
522 | int i;
523 | char *p;
524 |
525 | while (rl_point < 0) {
526 | tty_put(' ');
527 | rl_point++;
528 | }
529 |
530 | for (i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) {
531 | if ((i + prompt_len + 1) % tty_cols == 0){
532 | tty_put(' ');
533 | tty_put('\n');
534 | }
535 | else
536 | tty_put(' ');
537 | if (ISMETA(*p)) {
538 | if (rl_meta_chars) {
539 | tty_put(' ');
540 | tty_put(' ');
541 | extras += 2;
542 | }
543 | } else if (ISCTL(*p)) {
544 | tty_put(' ');
545 | extras++;
546 | }
547 | }
548 |
549 | for (i += extras; i > rl_point; i--) {
550 | if ((i + prompt_len) % tty_cols == 0) {
551 | tty_puts(line_up);
552 | tty_forwardn(tty_cols);
553 | } else {
554 | tty_back();
555 | }
556 | }
557 | }
558 |
559 | static void clear_line(void)
560 | {
561 | int n = (rl_point + prompt_len) / tty_cols;
562 | rl_point = -(int)strlen(rl_prompt);
563 |
564 | if (n > 0) {
565 | for(int k = 0; k < n; k++)
566 | tty_puts(line_up);
567 | tty_put('\r');
568 | }
569 | else {
570 | tty_put('\r');
571 | }
572 |
573 | ceol();
574 |
575 | rl_point = 0;
576 | rl_end = 0;
577 | rl_line_buffer[0] = '\0';
578 | }
579 |
580 | static el_status_t insert_string(const char *p)
581 | {
582 | size_t len;
583 | int i;
584 | char *line;
585 | char *q;
586 |
587 | len = strlen(p);
588 | if (rl_end + len >= Length) {
589 | line = malloc(sizeof(char) * (Length + len + MEM_INC));
590 | if (!line)
591 | return CSstay;
592 |
593 | if (Length) {
594 | memcpy(line, rl_line_buffer, Length);
595 | free(rl_line_buffer);
596 | }
597 |
598 | rl_line_buffer = line;
599 | Length += len + MEM_INC;
600 | }
601 |
602 | for (q = &rl_line_buffer[rl_point], i = rl_end - rl_point; --i >= 0; )
603 | q[len + i] = q[i];
604 |
605 | memcpy(&rl_line_buffer[rl_point], p, len);
606 | rl_end += len;
607 | rl_line_buffer[rl_end] = '\0';
608 | tty_string(&rl_line_buffer[rl_point]);
609 | rl_point += len;
610 |
611 | return rl_point == rl_end ? CSstay : CSmove;
612 | }
613 |
614 | int rl_insert_text(const char *text)
615 | {
616 | int mark = rl_point;
617 |
618 | insert_string(text);
619 | ceol();
620 |
621 | return rl_point - mark;
622 | }
623 |
624 | static el_status_t redisplay(int cls)
625 | {
626 | if (cls)
627 | tty_puts(CLEAR);
628 | else
629 | tty_puts("\r\e[K");
630 |
631 | tty_puts(rl_prompt);
632 | rl_point = 0;
633 | tty_string(rl_line_buffer);
634 | rl_point = rl_end;
635 | return CSmove;
636 | }
637 |
638 | static el_status_t refresh(void)
639 | {
640 | return redisplay(1);
641 | }
642 |
643 | int rl_refresh_line(int ignore1 __attribute__((unused)), int ignore2 __attribute__((unused)))
644 | {
645 | redisplay(0);
646 | return 0;
647 | }
648 |
649 | static el_status_t toggle_meta_mode(void)
650 | {
651 | rl_meta_chars = ! rl_meta_chars;
652 | return redisplay(0);
653 | }
654 |
655 | const char *el_next_hist(void)
656 | {
657 | return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
658 | }
659 |
660 | const char *el_prev_hist(void)
661 | {
662 | return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
663 | }
664 |
665 | static el_status_t do_insert_hist(const char *p)
666 | {
667 | if (p == NULL)
668 | return el_ring_bell();
669 |
670 | clear_line();
671 |
672 | rl_point = 0;
673 | reposition(EOF);
674 | rl_end = 0;
675 |
676 | return insert_string(p);
677 | }
678 |
679 | static el_status_t do_hist(const char *(*move)(void))
680 | {
681 | const char *p;
682 | int i = 0;
683 |
684 | do {
685 | if ((p = move()) == NULL)
686 | return el_ring_bell();
687 | } while (++i < Repeat);
688 |
689 | return do_insert_hist(p);
690 | }
691 |
692 | static el_status_t h_next(void)
693 | {
694 | if (el_no_hist)
695 | return CSstay;
696 |
697 | return do_hist(el_next_hist);
698 | }
699 |
700 | static el_status_t h_prev(void)
701 | {
702 | if (el_no_hist)
703 | return CSstay;
704 |
705 | return do_hist(el_prev_hist);
706 | }
707 |
708 | static el_status_t h_first(void)
709 | {
710 | return do_insert_hist(H.Lines[H.Pos = 0]);
711 | }
712 |
713 | static el_status_t h_last(void)
714 | {
715 | return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
716 | }
717 |
718 | /*
719 | ** Return zero if pat appears as a substring in text.
720 | */
721 | static int substrcmp(const char *text, const char *pat, size_t len)
722 | {
723 | char c;
724 |
725 | if ((c = *pat) == '\0')
726 | return *text == '\0';
727 |
728 | for ( ; *text; text++) {
729 | if (*text == c && strncmp(text, pat, len) == 0)
730 | return 0;
731 | }
732 |
733 | return 1;
734 | }
735 |
736 | static const char *search_hist(const char *search, const char *(*move)(void))
737 | {
738 | int len;
739 | int pos;
740 | int (*match)(const char *s1, const char *s2, size_t n);
741 | const char *pat;
742 |
743 | /* Save or get remembered search pattern. */
744 | if (search && *search) {
745 | if (old_search)
746 | free(old_search);
747 | old_search = strdup(search);
748 | } else {
749 | if (old_search == NULL || *old_search == '\0')
750 | return NULL;
751 | search = old_search;
752 | }
753 |
754 | /* Set up pattern-finder. */
755 | if (*search == '^') {
756 | match = strncmp;
757 | pat = search + 1;
758 | } else {
759 | match = substrcmp;
760 | pat = search;
761 | }
762 | len = strlen(pat);
763 |
764 | pos = H.Pos; /* Save H.Pos */
765 | while (move()) {
766 | if (match(H.Lines[H.Pos], pat, len) == 0)
767 | return H.Lines[H.Pos];
768 | }
769 | H.Pos = pos; /* Restore H.Pos */
770 |
771 | return NULL;
772 | }
773 |
774 | static el_status_t h_search_end(const char *p)
775 | {
776 | rl_set_prompt(old_prompt);
777 | Searching = 0;
778 |
779 | if (el_intr_pending > 0) {
780 | el_intr_pending = 0;
781 | clear_line();
782 | return redisplay(0);
783 | }
784 |
785 | p = search_hist(p, search_move);
786 | if (p == NULL) {
787 | el_ring_bell();
788 | clear_line();
789 | return redisplay(0);
790 | }
791 |
792 | return do_insert_hist(p);
793 | }
794 |
795 | static el_status_t h_search(void)
796 | {
797 | if (Searching)
798 | return el_ring_bell();
799 | Searching = 1;
800 |
801 | clear_line();
802 | old_prompt = rl_prompt;
803 | rl_set_prompt("Search: ");
804 | reposition(EOF);
805 |
806 | search_move = Repeat == NO_ARG ? el_prev_hist : el_next_hist;
807 | if (line_handler) {
808 | editinput(0);
809 | return CSstay;
810 | }
811 |
812 | return h_search_end(editinput(1));
813 | }
814 |
815 | static el_status_t fd_char(void)
816 | {
817 | int i = 0;
818 |
819 | do {
820 | if (rl_point >= rl_end)
821 | break;
822 | right(CSmove);
823 | } while (++i < Repeat);
824 | return CSstay;
825 | }
826 |
827 | static void save_yank(int begin, int i)
828 | {
829 | if (Yanked) {
830 | free(Yanked);
831 | Yanked = NULL;
832 | }
833 |
834 | if (i < 1)
835 | return;
836 |
837 | Yanked = malloc(sizeof(char) * (i + 1));
838 | if (Yanked) {
839 | memcpy(Yanked, &rl_line_buffer[begin], i);
840 | Yanked[i] = '\0';
841 | }
842 | }
843 |
844 | static el_status_t delete_string(int count)
845 | {
846 | int i;
847 | char *p;
848 |
849 | if (count <= 0 || rl_end == rl_point)
850 | return el_ring_bell();
851 |
852 | if (count == 1 && rl_point == rl_end - 1) {
853 | /* Optimize common case of delete at end of line. */
854 | rl_end--;
855 | p = &rl_line_buffer[rl_point];
856 | i = 1;
857 | tty_put(' ');
858 | if (ISCTL(*p)) {
859 | i = 2;
860 | tty_put(' ');
861 | } else if (rl_meta_chars && ISMETA(*p)) {
862 | i = 3;
863 | tty_put(' ');
864 | tty_put(' ');
865 | }
866 | tty_backn(i);
867 | *p = '\0';
868 | return CSmove;
869 | }
870 |
871 | if (rl_point + count > rl_end && (count = rl_end - rl_point) <= 0)
872 | return CSstay;
873 |
874 | if (count > 1)
875 | save_yank(rl_point, count);
876 |
877 | for (p = &rl_line_buffer[rl_point], i = rl_end - (rl_point + count) + 1; --i >= 0; p++)
878 | p[0] = p[count];
879 | ceol();
880 |
881 | rl_end -= count;
882 | tty_string(&rl_line_buffer[rl_point]);
883 |
884 | return CSmove;
885 | }
886 |
887 | static el_status_t bk_char(void)
888 | {
889 | int i = 0;
890 |
891 | do {
892 | if (rl_point == 0)
893 | break;
894 | left(CSmove);
895 | } while (++i < Repeat);
896 |
897 | return CSstay;
898 | }
899 |
900 | static el_status_t bk_del_char(void)
901 | {
902 | int i = 0;
903 |
904 | do {
905 | if (rl_point == 0)
906 | break;
907 | left(CSmove);
908 | } while (++i < Repeat);
909 |
910 | return delete_string(i);
911 | }
912 |
913 | static el_status_t kill_line(void)
914 | {
915 | int i;
916 |
917 | if (Repeat != NO_ARG) {
918 | if (Repeat < rl_point) {
919 | i = rl_point;
920 | rl_point = Repeat;
921 | reposition(EOF);
922 | delete_string(i - rl_point);
923 | } else if (Repeat > rl_point) {
924 | right(CSmove);
925 | delete_string(Repeat - rl_point - 1);
926 | }
927 |
928 | return CSmove;
929 | }
930 |
931 | save_yank(rl_point, rl_end - rl_point);
932 | rl_line_buffer[rl_point] = '\0';
933 | ceol();
934 | rl_end = rl_point;
935 |
936 | return CSstay;
937 | }
938 |
939 | static el_status_t insert_char(int c)
940 | {
941 | el_status_t s;
942 | char buff[2];
943 | char *p;
944 | char *q;
945 | int i;
946 |
947 | if (Repeat == NO_ARG || Repeat < 2) {
948 | buff[0] = c;
949 | buff[1] = '\0';
950 |
951 | return insert_string(buff);
952 | }
953 |
954 | p = malloc(sizeof(char) * (Repeat + 1));
955 | if (!p)
956 | return CSstay;
957 |
958 | for (i = Repeat, q = p; --i >= 0; )
959 | *q++ = c;
960 | *q = '\0';
961 | Repeat = 0;
962 | s = insert_string(p);
963 | free(p);
964 |
965 | return s;
966 | }
967 |
968 | static el_status_t beg_line(void)
969 | {
970 | if (rl_point) {
971 | rl_point = 0;
972 | return CSmove;
973 | }
974 |
975 | return CSstay;
976 | }
977 |
978 | static el_status_t end_line(void)
979 | {
980 | if (rl_point != rl_end) {
981 | rl_point = rl_end;
982 | return CSmove;
983 | }
984 |
985 | return CSstay;
986 | }
987 |
988 | static el_status_t del_char(void)
989 | {
990 | return delete_string(Repeat == NO_ARG ? CSeof : Repeat);
991 | }
992 |
993 | el_status_t el_del_char(void)
994 | {
995 | return del_char();
996 | }
997 |
998 | static el_status_t fd_word(void)
999 | {
1000 | return do_forward(CSmove);
1001 | }
1002 |
1003 | static el_status_t bk_word(void)
1004 | {
1005 | int i;
1006 | char *p;
1007 |
1008 | i = 0;
1009 | do {
1010 | for (p = &rl_line_buffer[rl_point]; p > rl_line_buffer && !is_alpha_num(p[-1]); p--)
1011 | left(CSmove);
1012 |
1013 | for (; p > rl_line_buffer && !isblank(p[-1]) && is_alpha_num(p[-1]); p--)
1014 | left(CSmove);
1015 |
1016 | if (rl_point == 0)
1017 | break;
1018 | } while (++i < Repeat);
1019 |
1020 | return CSstay;
1021 | }
1022 |
1023 | static el_status_t meta(void)
1024 | {
1025 | int c;
1026 | el_keymap_t *kp;
1027 |
1028 | if ((c = tty_get()) == EOF)
1029 | return CSeof;
1030 |
1031 | #ifdef CONFIG_ANSI_ARROWS
1032 | /* See: https://en.wikipedia.org/wiki/ANSI_escape_code */
1033 | /* Recognize ANSI escapes for `Meta+Left` and `Meta+Right`. */
1034 | if (c == '\e') {
1035 | switch (tty_get()) {
1036 | case '[':
1037 | {
1038 | switch (tty_get()) {
1039 | /* \e\e[C = Meta+Left */
1040 | case 'C': return fd_word();
1041 | /* \e\e[D = Meta+Right */
1042 | case 'D': return bk_word();
1043 | default:
1044 | break;
1045 | }
1046 |
1047 | return el_ring_bell();
1048 | }
1049 | default:
1050 | break;
1051 | }
1052 |
1053 | return el_ring_bell();
1054 | }
1055 |
1056 | /* Also include VT-100 arrows. */
1057 | if (c == '[' || c == 'O') {
1058 | switch (tty_get()) {
1059 | case EOF: return CSeof;
1060 | case '1':
1061 | {
1062 | char seq[4] = { 0 };
1063 | seq[0] = tty_get();
1064 |
1065 | /* \e[1~ */
1066 | if (seq[0] == '~')
1067 | return beg_line(); /* Home */
1068 |
1069 | for (c = 1; c < 3; c++)
1070 | seq[c] = tty_get();
1071 |
1072 | if (!strncmp(seq, ";5C", 3)
1073 | || !strncmp(seq, ";3C", 3))
1074 | return fd_word(); /* \e[1;5C = Ctrl+Right */
1075 | if (!strncmp(seq, ";5D", 3)
1076 | || !strncmp(seq, ";3D", 3))
1077 | return bk_word(); /* \e[1;5D = Ctrl+Left */
1078 |
1079 | break;
1080 | }
1081 | case '2': tty_get(); return CSstay; /* Insert */
1082 | case '3': tty_get(); return del_char(); /* Delete */
1083 | case '4': tty_get(); return end_line(); /* End */
1084 | case '5': tty_get(); return CSstay; /* PgUp */
1085 | case '6': tty_get(); return CSstay; /* PgDn */
1086 | case '7': tty_get(); return beg_line(); /* Home (urxvt) */
1087 | case '8': tty_get(); return end_line(); /* End (urxvt) */
1088 | case 'A': return h_prev(); /* Up */
1089 | case 'B': return h_next(); /* Down */
1090 | case 'C': return fd_char(); /* Left */
1091 | case 'D': return bk_char(); /* Right */
1092 | case 'F': return end_line(); /* End */
1093 | case 'H': return beg_line(); /* Home */
1094 | default: /* Fall through */
1095 | break;
1096 | }
1097 |
1098 | return el_ring_bell();
1099 | }
1100 | #endif /* CONFIG_ANSI_ARROWS */
1101 |
1102 | if (isdigit(c)) {
1103 | for (Repeat = c - '0'; (c = tty_get()) != EOF && isdigit(c); )
1104 | Repeat = Repeat * 10 + c - '0';
1105 | tty_push(c);
1106 |
1107 | return CSstay;
1108 | }
1109 |
1110 | if (isupper(c))
1111 | return do_macro(c);
1112 |
1113 | for (kp = MetaMap; kp->Function; kp++) {
1114 | if (kp->Key == c)
1115 | return kp->Function();
1116 | }
1117 |
1118 | return el_ring_bell();
1119 | }
1120 |
1121 | static el_status_t emacs(int c)
1122 | {
1123 | el_status_t s;
1124 | el_keymap_t *kp;
1125 |
1126 | /* Save point before interpreting input character 'c'. */
1127 | old_point = rl_point;
1128 |
1129 | if (rl_meta_chars && ISMETA(c)) {
1130 | tty_push(UNMETA(c));
1131 | return meta();
1132 | }
1133 |
1134 | for (kp = Map; kp->Function; kp++) {
1135 | if (kp->Key == c)
1136 | break;
1137 | }
1138 |
1139 | if (kp->Function) {
1140 | s = kp->Function();
1141 | if (s == CSdispatch) /* If Function is inhibited. */
1142 | s = insert_char(c);
1143 | } else {
1144 | s = insert_char(c);
1145 | }
1146 |
1147 | if (!el_pushed) {
1148 | /* No pushback means no repeat count; hacky, but true. */
1149 | Repeat = NO_ARG;
1150 | }
1151 |
1152 | return s;
1153 | }
1154 |
1155 | static el_status_t tty_special(int c)
1156 | {
1157 | el_status_t rc;
1158 |
1159 | #ifdef CONFIG_SIGINT
1160 | if (c == rl_intr) {
1161 | el_intr_pending = SIGINT;
1162 | return CSsignal;
1163 | }
1164 | #endif
1165 | if (c == rl_quit) {
1166 | el_intr_pending = SIGQUIT;
1167 | return CSeof;
1168 | }
1169 | #ifdef CONFIG_SIGSTOP
1170 | if (c == rl_susp) {
1171 | el_intr_pending = SIGTSTP;
1172 | return CSsignal;
1173 | }
1174 | #endif
1175 |
1176 | if (rl_meta_chars && ISMETA(c))
1177 | return CSdispatch;
1178 |
1179 | if (c == rl_erase || c == DEL)
1180 | return bk_del_char();
1181 |
1182 | if (c == rl_kill) {
1183 | Repeat = rl_point;
1184 | rc = bk_del_char();
1185 | Repeat = NO_ARG;
1186 | return rc;
1187 | }
1188 |
1189 | #ifdef CONFIG_EOF
1190 | if (c == rl_eof && rl_point == 0 && rl_end == 0)
1191 | return CSeof;
1192 | #endif
1193 |
1194 | return CSdispatch;
1195 | }
1196 |
1197 | static char *editinput(int complete)
1198 | {
1199 | int c;
1200 |
1201 | do {
1202 | c = tty_get();
1203 | if (c == EOF)
1204 | break;
1205 |
1206 | switch (tty_special(c)) {
1207 | case CSdone:
1208 | return rl_line_buffer;
1209 |
1210 | case CSeof:
1211 | return NULL;
1212 |
1213 | case CSsignal:
1214 | return (char *)"";
1215 |
1216 | case CSmove:
1217 | reposition(c);
1218 | break;
1219 |
1220 | case CSdispatch:
1221 | switch (emacs(c)) {
1222 | case CSdone:
1223 | return rl_line_buffer;
1224 |
1225 | case CSeof:
1226 | return NULL;
1227 |
1228 | case CSsignal:
1229 | return (char *)"";
1230 |
1231 | case CSmove:
1232 | reposition(c);
1233 | break;
1234 |
1235 | case CSdispatch:
1236 | case CSstay:
1237 | break;
1238 | }
1239 | break;
1240 |
1241 | case CSstay:
1242 | break;
1243 | }
1244 | } while (complete);
1245 |
1246 | return NULL;
1247 | }
1248 |
1249 | static void hist_alloc(void)
1250 | {
1251 | if (!H.Lines)
1252 | H.Lines = calloc(1 + el_hist_size, sizeof(char *));
1253 | }
1254 |
1255 | static void hist_add(const char *p)
1256 | {
1257 | int i;
1258 | char *s;
1259 |
1260 | #ifdef CONFIG_UNIQUE_HISTORY
1261 | if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0)
1262 | return;
1263 | #endif
1264 |
1265 | s = strdup(p);
1266 | if (s == NULL)
1267 | return;
1268 |
1269 | if (H.Size <= el_hist_size) {
1270 | H.Lines[H.Size++] = s;
1271 | } else {
1272 | free(H.Lines[0]);
1273 | for (i = 0; i < el_hist_size; i++)
1274 | H.Lines[i] = H.Lines[i + 1];
1275 | H.Lines[i] = s;
1276 | }
1277 | H.Pos = H.Size - 1;
1278 | }
1279 |
1280 | static char *read_redirected(void)
1281 | {
1282 | int size = MEM_INC;
1283 | char *p;
1284 | char *line;
1285 | const char *end;
1286 |
1287 | p = line = malloc(sizeof(char) * size);
1288 | if (!p)
1289 | return NULL;
1290 |
1291 | end = p + size;
1292 | while (1) {
1293 | if (p == end) {
1294 | int oldpos = end - line;
1295 |
1296 | size += MEM_INC;
1297 | p = realloc(line, sizeof(char) * size);
1298 | if (!p) {
1299 | free(line);
1300 | return NULL;
1301 | }
1302 | line = p;
1303 | end = p + size;
1304 |
1305 | p += oldpos; /* Continue where we left off... */
1306 | }
1307 |
1308 | if (read(el_infd, p, 1) <= 0) {
1309 | /* Ignore "incomplete" lines at EOF, just like we do for a tty. */
1310 | free(line);
1311 | return NULL;
1312 | }
1313 |
1314 | if (*p == '\n')
1315 | break;
1316 | p++;
1317 | }
1318 | *p = '\0';
1319 |
1320 | return line;
1321 | }
1322 |
1323 | /* For compatibility with FSF readline. */
1324 | void rl_reset_terminal(const char *terminal_name)
1325 | {
1326 | #ifdef CONFIG_USE_TERMCAP
1327 | char buf[1024];
1328 | char *bp;
1329 | #endif
1330 | #ifdef TIOCGWINSZ
1331 | struct winsize W;
1332 | #endif
1333 |
1334 | if (terminal_name) {
1335 | el_term = terminal_name;
1336 | } else if ((el_term = getenv("TERM")) == NULL) {
1337 | el_term = "dumb";
1338 | }
1339 |
1340 | /* Initialize to faulty values to trigger fallback if nothing else works. */
1341 | tty_cols = tty_rows = -1;
1342 |
1343 | #ifdef CONFIG_USE_TERMCAP
1344 | bp = buf;
1345 | if (-1 != tgetent(buf, el_term)) {
1346 | if ((backspace = tgetstr("le", &bp)) != NULL)
1347 | backspace = strdup(backspace);
1348 | tty_cols = tgetnum("co");
1349 | tty_rows = tgetnum("li");
1350 | }
1351 | /* Make sure to check width & rows and fallback to TIOCGWINSZ if available. */
1352 | #endif
1353 |
1354 | if (tty_cols <= 0 || tty_rows <= 0) {
1355 | #ifdef TIOCGWINSZ
1356 | if (ioctl(el_outfd, TIOCGWINSZ, &W) >= 0 && W.ws_col > 0 && W.ws_row > 0) {
1357 | tty_cols = (int)W.ws_col;
1358 | tty_rows = (int)W.ws_row;
1359 | return;
1360 | }
1361 | #endif
1362 | tty_cols = SCREEN_COLS;
1363 | tty_rows = SCREEN_ROWS;
1364 | }
1365 | }
1366 |
1367 | void rl_set_prompt(const char *prompt)
1368 | {
1369 | if (prompt)
1370 | rl_prompt = prompt;
1371 | prompt_len = strlen(rl_prompt);
1372 | }
1373 |
1374 | void rl_save_prompt(void)
1375 | {
1376 | rl_saved_prompt = rl_prompt;
1377 | }
1378 |
1379 | void rl_restore_prompt(void)
1380 | {
1381 | if (rl_saved_prompt)
1382 | rl_set_prompt(rl_saved_prompt);
1383 | }
1384 |
1385 | void rl_initialize(void)
1386 | {
1387 | if (!rl_prompt)
1388 | rl_set_prompt("? ");
1389 |
1390 | hist_alloc();
1391 |
1392 | /* Setup I/O descriptors */
1393 | if (!rl_instream) el_infd = EL_STDIN;
1394 | else el_infd = fileno(rl_instream);
1395 | if (el_infd < 0) el_infd = EL_STDIN;
1396 | if (!rl_outstream) el_outfd = EL_STDOUT;
1397 | else el_outfd = fileno(rl_outstream);
1398 | if (el_outfd < 0) el_outfd = EL_STDOUT;
1399 | }
1400 |
1401 | void rl_uninitialize(void)
1402 | {
1403 | int i;
1404 |
1405 | /* Uninitialize the history */
1406 | if (H.Lines) {
1407 | for (i = 0; i <= el_hist_size; i++) {
1408 | if (H.Lines[i])
1409 | free(H.Lines[i]);
1410 | H.Lines[i] = NULL;
1411 | }
1412 | free(H.Lines);
1413 | H.Lines = NULL;
1414 | }
1415 | H.Size = 0;
1416 | H.Pos = 0;
1417 |
1418 | if (old_search)
1419 | free(old_search);
1420 | old_search = NULL;
1421 |
1422 | /* Uninitialize the line buffer */
1423 | if (rl_line_buffer)
1424 | free(rl_line_buffer);
1425 | rl_line_buffer = NULL;
1426 | Length = 0;
1427 | }
1428 |
1429 | void rl_clear_message(void)
1430 | {
1431 | /* Nothing to do atm. */
1432 | }
1433 |
1434 | void rl_forced_update_display(void)
1435 | {
1436 | redisplay(0);
1437 | tty_flush();
1438 | }
1439 |
1440 | static int el_prep(const char *prompt)
1441 | {
1442 | rl_initialize();
1443 |
1444 | if (!rl_line_buffer) {
1445 | Length = MEM_INC;
1446 | rl_line_buffer = malloc(sizeof(char) * Length);
1447 | if (!rl_line_buffer)
1448 | return -1;
1449 | }
1450 |
1451 | tty_info();
1452 | rl_prep_term_function(!rl_meta_chars);
1453 | hist_add(NILSTR);
1454 | ScreenSize = SCREEN_INC;
1455 | Screen = malloc(sizeof(char) * ScreenSize);
1456 | if (!Screen)
1457 | return -1;
1458 |
1459 | rl_set_prompt(prompt);
1460 |
1461 | if (el_no_echo) {
1462 | int old = el_no_echo;
1463 |
1464 | el_no_echo = 0;
1465 | tty_puts(rl_prompt);
1466 | tty_flush();
1467 | el_no_echo = old;
1468 | } else {
1469 | tty_puts(rl_prompt);
1470 | }
1471 |
1472 | Repeat = NO_ARG;
1473 | old_point = rl_point = rl_mark = rl_end = 0;
1474 | rl_line_buffer[0] = '\0';
1475 | el_intr_pending = -1;
1476 |
1477 | return 0;
1478 | }
1479 |
1480 | static char *el_deprep(char *line)
1481 | {
1482 | if (line) {
1483 | line = strdup(line);
1484 | tty_puts(NEWLINE);
1485 | tty_flush();
1486 | }
1487 |
1488 | rl_deprep_term_function();
1489 | if (Screen) {
1490 | free(Screen);
1491 | Screen = NULL;
1492 | }
1493 |
1494 | free(H.Lines[--H.Size]);
1495 | H.Lines[H.Size] = NULL;
1496 |
1497 | /* Add to history, unless no-echo or no-history mode ... */
1498 | if (!el_no_echo && !el_no_hist) {
1499 | if (line != NULL && *line != '\0')
1500 | hist_add(line);
1501 | }
1502 |
1503 | if (el_intr_pending > 0) {
1504 | int signo = el_intr_pending;
1505 |
1506 | el_intr_pending = 0;
1507 | kill(getpid(), signo);
1508 | }
1509 |
1510 | return line;
1511 | }
1512 |
1513 | void rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *lhandler)
1514 | {
1515 | if (!lhandler)
1516 | return;
1517 | line_handler = lhandler;
1518 |
1519 | /*
1520 | * Any error from el_prep() is handled by the lhandler callbck as
1521 | * soon as the user calls rl_callback_read_char().
1522 | */
1523 | el_prep(prompt);
1524 | tty_flush();
1525 | }
1526 |
1527 | /*
1528 | * Reads one character at a time, when a complete line has been received
1529 | * the lhandler from rl_callback_handler_install() is called with the
1530 | * line as argument.
1531 | *
1532 | * If the callback returns the terminal is prepped for reading a new
1533 | * line.
1534 | *
1535 | * If any error occurs, either in the _install() phase, or while reading
1536 | * one character, this function restores the terminal and calls lhandler
1537 | * with a NULL argument.
1538 | */
1539 | void rl_callback_read_char(void)
1540 | {
1541 | char *line;
1542 |
1543 | if (!line_handler) {
1544 | errno = EINVAL;
1545 | return;
1546 | }
1547 |
1548 | /*
1549 | * Check if rl_callback_handler_install() failed
1550 | * This is the only point where we can tell user
1551 | */
1552 | if (!Screen || !rl_line_buffer) {
1553 | errno = ENOMEM;
1554 | line_handler(el_deprep(NULL));
1555 | return;
1556 | }
1557 |
1558 | line = editinput(0);
1559 | if (line) {
1560 | char *l;
1561 |
1562 | if (Searching) {
1563 | h_search_end(line);
1564 | tty_flush();
1565 | return;
1566 | }
1567 |
1568 | l = el_deprep(line);
1569 | line_handler(l);
1570 |
1571 | if (el_prep(rl_prompt))
1572 | line_handler(NULL);
1573 | }
1574 | tty_flush();
1575 | }
1576 |
1577 | void rl_callback_handler_remove(void)
1578 | {
1579 | if (!line_handler)
1580 | return;
1581 |
1582 | el_deprep(NULL);
1583 | line_handler = NULL;
1584 | }
1585 |
1586 | char *readline(const char *prompt)
1587 | {
1588 | /* Unless called by the user already. */
1589 | rl_initialize();
1590 |
1591 | if (!isatty(el_infd)) {
1592 | tty_flush();
1593 |
1594 | return read_redirected();
1595 | }
1596 |
1597 | if (el_prep(prompt))
1598 | return NULL;
1599 |
1600 | return el_deprep(editinput(1));
1601 | }
1602 |
1603 | /*
1604 | * Even though readline() itself adds history automatically, the user
1605 | * can also add lines. This is for compatibility with GNU Readline.
1606 | */
1607 | void add_history(const char *p)
1608 | {
1609 | if (p == NULL || *p == '\0')
1610 | return;
1611 |
1612 | hist_add(p);
1613 | }
1614 |
1615 |
1616 | int read_history(const char *filename)
1617 | {
1618 | FILE *fp;
1619 | char buf[SCREEN_INC];
1620 |
1621 | hist_alloc();
1622 |
1623 | fp = fopen(filename, "r");
1624 | if (!fp)
1625 | return EOF;
1626 |
1627 | H.Size = 0;
1628 | while (H.Size < el_hist_size) {
1629 | if (!fgets(buf, SCREEN_INC, fp))
1630 | break;
1631 |
1632 | buf[strlen(buf) - 1] = 0; /* Remove '\n' */
1633 | add_history(buf);
1634 | }
1635 |
1636 | return fclose(fp);
1637 | }
1638 |
1639 | int write_history(const char *filename)
1640 | {
1641 | FILE *fp;
1642 | int i = 0;
1643 |
1644 | hist_alloc();
1645 |
1646 | fp = fopen(filename, "w");
1647 | if (!fp)
1648 | return EOF;
1649 |
1650 | while (i < H.Size)
1651 | fprintf(fp, "%s\n", H.Lines[i++]);
1652 |
1653 | return fclose(fp);
1654 | }
1655 |
1656 | /*
1657 | ** Move back to the beginning of the current word and return an
1658 | ** allocated copy of it.
1659 | */
1660 | char *el_find_word(void)
1661 | {
1662 | char *p, *q;
1663 | char *word;
1664 | size_t len;
1665 |
1666 | p = &rl_line_buffer[rl_point];
1667 | while (p > rl_line_buffer) {
1668 | p--;
1669 | if (p > rl_line_buffer && p[-1] == '\\') {
1670 | p--;
1671 | } else {
1672 | if (strchr(SEPS, (char) *p) != NULL) {
1673 | p++;
1674 | break;
1675 | }
1676 | }
1677 | }
1678 |
1679 | len = rl_point - (p - rl_line_buffer) + 1;
1680 | word = malloc(sizeof(char) * len);
1681 | if (!word)
1682 | return NULL;
1683 |
1684 | q = word;
1685 | while (p < &rl_line_buffer[rl_point]) {
1686 | if (*p == '\\') {
1687 | if (++p == &rl_line_buffer[rl_point])
1688 | break;
1689 | }
1690 | *q++ = *p++;
1691 | }
1692 | *q = '\0';
1693 |
1694 | return word;
1695 | }
1696 |
1697 | static el_status_t c_possible(void)
1698 | {
1699 | char **av;
1700 | char *word;
1701 | int ac;
1702 |
1703 | word = el_find_word();
1704 | ac = rl_list_possib(word, &av);
1705 | if (word)
1706 | free(word);
1707 | if (ac) {
1708 | el_print_columns(ac, av);
1709 | while (--ac >= 0)
1710 | free(av[ac]);
1711 | free(av);
1712 |
1713 | return CSmove;
1714 | }
1715 |
1716 | return el_ring_bell();
1717 | }
1718 |
1719 | static el_status_t c_complete(void)
1720 | {
1721 | char *p, *q;
1722 | char *word, *string;
1723 | size_t len;
1724 | int unique;
1725 | el_status_t s = CSdone;
1726 |
1727 | if (rl_inhibit_complete)
1728 | return CSdispatch;
1729 |
1730 | word = el_find_word();
1731 | p = rl_complete(word, &unique);
1732 | if (word)
1733 | free(word);
1734 | if (p) {
1735 | len = strlen(p);
1736 | word = p;
1737 |
1738 | string = q = malloc(sizeof(char) * (2 * len + 1));
1739 | if (!string) {
1740 | free(word);
1741 | return CSstay;
1742 | }
1743 |
1744 | while (*p) {
1745 | if ((*p < ' ' || strchr(SEPS, *p) != NULL)
1746 | && (!unique || p[1] != 0)) {
1747 | *q++ = '\\';
1748 | }
1749 | *q++ = *p++;
1750 | }
1751 | *q = '\0';
1752 | free(word);
1753 |
1754 | if (len > 0) {
1755 | s = insert_string(string);
1756 | #ifdef CONFIG_TERMINAL_BELL
1757 | if (!unique)
1758 | el_ring_bell();
1759 | #endif
1760 | }
1761 | free(string);
1762 |
1763 | if (len > 0)
1764 | return s;
1765 | }
1766 |
1767 | return c_possible();
1768 | }
1769 |
1770 | static el_status_t accept_line(void)
1771 | {
1772 | rl_line_buffer[rl_end] = '\0';
1773 | return CSdone;
1774 | }
1775 |
1776 | static el_status_t transpose(void)
1777 | {
1778 | char c;
1779 |
1780 | if (rl_point) {
1781 | if (rl_point == rl_end)
1782 | left(CSmove);
1783 | c = rl_line_buffer[rl_point - 1];
1784 | left(CSstay);
1785 | rl_line_buffer[rl_point - 1] = rl_line_buffer[rl_point];
1786 | tty_show(rl_line_buffer[rl_point - 1]);
1787 | rl_line_buffer[rl_point++] = c;
1788 | tty_show(c);
1789 | }
1790 |
1791 | return CSstay;
1792 | }
1793 |
1794 | static el_status_t quote(void)
1795 | {
1796 | int c;
1797 |
1798 | return (c = tty_get()) == EOF ? CSeof : insert_char((int)c);
1799 | }
1800 |
1801 | static el_status_t mk_set(void)
1802 | {
1803 | rl_mark = rl_point;
1804 | return CSstay;
1805 | }
1806 |
1807 | static el_status_t exchange(void)
1808 | {
1809 | int c;
1810 |
1811 | if ((c = tty_get()) != CTL('X'))
1812 | return c == EOF ? CSeof : el_ring_bell();
1813 |
1814 | if ((c = rl_mark) <= rl_end) {
1815 | rl_mark = rl_point;
1816 | rl_point = c;
1817 | return CSmove;
1818 | }
1819 |
1820 | return CSstay;
1821 | }
1822 |
1823 | static el_status_t yank(void)
1824 | {
1825 | if (Yanked && *Yanked)
1826 | return insert_string(Yanked);
1827 |
1828 | return CSstay;
1829 | }
1830 |
1831 | static el_status_t copy_region(void)
1832 | {
1833 | if (rl_mark > rl_end)
1834 | return el_ring_bell();
1835 |
1836 | if (rl_point > rl_mark)
1837 | save_yank(rl_mark, rl_point - rl_mark);
1838 | else
1839 | save_yank(rl_point, rl_mark - rl_point);
1840 |
1841 | return CSstay;
1842 | }
1843 |
1844 | static el_status_t move_to_char(void)
1845 | {
1846 | int i, c;
1847 | char *p;
1848 |
1849 | if ((c = tty_get()) == EOF)
1850 | return CSeof;
1851 |
1852 | for (i = rl_point + 1, p = &rl_line_buffer[i]; i < rl_end; i++, p++) {
1853 | if (*p == c) {
1854 | rl_point = i;
1855 | return CSmove;
1856 | }
1857 | }
1858 |
1859 | return CSstay;
1860 | }
1861 |
1862 | static el_status_t fd_kill_word(void)
1863 | {
1864 | int i;
1865 |
1866 | do_forward(CSstay);
1867 | if (old_point != rl_point) {
1868 | i = rl_point - old_point - 1;
1869 | rl_point = old_point;
1870 | return delete_string(i);
1871 | }
1872 |
1873 | return CSstay;
1874 | }
1875 |
1876 | static el_status_t bk_kill_word(void)
1877 | {
1878 | bk_word();
1879 | if (old_point != rl_point)
1880 | return delete_string(old_point - rl_point);
1881 |
1882 | return CSstay;
1883 | }
1884 |
1885 | static int argify(char *line, char ***avp)
1886 | {
1887 | char *c;
1888 | char **p;
1889 | char **arg;
1890 | int ac;
1891 | int i;
1892 |
1893 | i = MEM_INC;
1894 | *avp = p = malloc(sizeof(char *) * i);
1895 | if (!p)
1896 | return 0;
1897 |
1898 | for (c = line; isspace((unsigned char)(*c)); c++)
1899 | continue;
1900 |
1901 | if (*c == '\n' || *c == '\0')
1902 | return 0;
1903 |
1904 | for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1905 | if (!isspace((unsigned char)(*c))) {
1906 | c++;
1907 | continue;
1908 | }
1909 |
1910 | *c++ = '\0';
1911 | if (*c && *c != '\n') {
1912 | if (ac + 1 == i) {
1913 | arg = malloc(sizeof(char *) * (i + MEM_INC));
1914 | if (!arg) {
1915 | p[ac] = NULL;
1916 | return ac;
1917 | }
1918 |
1919 | memcpy(arg, p, i * sizeof(char *));
1920 | i += MEM_INC;
1921 | free(p);
1922 | *avp = p = arg;
1923 | }
1924 | p[ac++] = c;
1925 | }
1926 | }
1927 |
1928 | *c = '\0';
1929 | p[ac] = NULL;
1930 |
1931 | return ac;
1932 | }
1933 |
1934 | static el_status_t last_argument(void)
1935 | {
1936 | char **av = NULL;
1937 | char *p;
1938 | el_status_t s;
1939 | int ac;
1940 |
1941 | if (H.Size == 1 || (p = (char *)H.Lines[H.Size - 2]) == NULL)
1942 | return el_ring_bell();
1943 |
1944 | p = strdup(p);
1945 | if (!p)
1946 | return CSstay;
1947 |
1948 | ac = argify(p, &av);
1949 | if (Repeat != NO_ARG)
1950 | s = Repeat < ac ? insert_string(av[Repeat]) : el_ring_bell();
1951 | else
1952 | s = ac ? insert_string(av[ac - 1]) : CSstay;
1953 |
1954 | if (av)
1955 | free(av);
1956 | free(p);
1957 |
1958 | return s;
1959 | }
1960 |
1961 | static el_keymap_t Map[64] = {
1962 | { CTL('@'), mk_set },
1963 | { CTL('A'), beg_line },
1964 | { CTL('B'), bk_char },
1965 | { CTL('D'), del_char },
1966 | { CTL('E'), end_line },
1967 | { CTL('F'), fd_char },
1968 | { CTL('G'), el_ring_bell },
1969 | { CTL('H'), bk_del_char },
1970 | { CTL('I'), c_complete },
1971 | { CTL('J'), accept_line },
1972 | { CTL('K'), kill_line },
1973 | { CTL('L'), refresh },
1974 | { CTL('M'), accept_line },
1975 | { CTL('N'), h_next },
1976 | { CTL('O'), el_ring_bell },
1977 | { CTL('P'), h_prev },
1978 | { CTL('Q'), el_ring_bell },
1979 | { CTL('R'), h_search },
1980 | { CTL('S'), el_ring_bell },
1981 | { CTL('T'), transpose },
1982 | { CTL('U'), el_ring_bell },
1983 | { CTL('V'), quote },
1984 | { CTL('W'), bk_kill_word },
1985 | { CTL('X'), exchange },
1986 | { CTL('Y'), yank },
1987 | { CTL('Z'), el_ring_bell },
1988 | { CTL('['), meta },
1989 | { CTL(']'), move_to_char },
1990 | { CTL('^'), el_ring_bell },
1991 | { CTL('_'), el_ring_bell },
1992 | { 0, NULL }
1993 | };
1994 |
1995 | static el_keymap_t MetaMap[64]= {
1996 | { CTL('H'), bk_kill_word },
1997 | { DEL, bk_kill_word },
1998 | { ' ', mk_set },
1999 | { '.', last_argument },
2000 | { '<', h_first },
2001 | { '>', h_last },
2002 | { '?', c_possible },
2003 | { 'b', bk_word },
2004 | { 'c', case_cap_word },
2005 | { 'd', fd_kill_word },
2006 | { 'f', fd_word },
2007 | { 'l', case_down_word },
2008 | { 'm', toggle_meta_mode },
2009 | { 'u', case_up_word },
2010 | { 'y', yank },
2011 | { 'w', copy_region },
2012 | { 0, NULL }
2013 | };
2014 |
2015 | static size_t find_key_in_map(int key, el_keymap_t map[], size_t mapsz)
2016 | {
2017 | size_t i;
2018 |
2019 | for (i = 0; i < mapsz && map[i].Function; i++) {
2020 | if (map[i].Key == key)
2021 | return i;
2022 | }
2023 |
2024 | if (i < mapsz)
2025 | return i;
2026 |
2027 | return mapsz;
2028 | }
2029 |
2030 | static el_status_t el_bind_key_in_map(int key, el_keymap_func_t function, el_keymap_t map[], size_t mapsz)
2031 | {
2032 | size_t creat, pos = find_key_in_map(key, map, mapsz);
2033 |
2034 | /* Must check that pos is not the next to last array position,
2035 | * otherwise we will write out-of-bounds to terminate the list. */
2036 | if (pos + 1 >= mapsz) {
2037 | errno = ENOMEM;
2038 | return CSeof;
2039 | }
2040 |
2041 | /* Add at end, create new? */
2042 | creat = map[pos].Function == NULL;
2043 |
2044 | /* A new key so have to add it to end */
2045 | map[pos].Key = key;
2046 | map[pos].Function = function;
2047 |
2048 | /* Terminate list */
2049 | if (creat) {
2050 | map[pos + 1].Key = 0;
2051 | map[pos + 1].Function = NULL;
2052 | }
2053 |
2054 | return CSdone;
2055 | }
2056 |
2057 | el_status_t el_bind_key(int key, el_keymap_func_t function)
2058 | {
2059 | return el_bind_key_in_map(key, function, Map, NELEMS(Map));
2060 | }
2061 |
2062 | el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function)
2063 | {
2064 | return el_bind_key_in_map(key, function, MetaMap, NELEMS(MetaMap));
2065 | }
2066 |
2067 | rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *func)
2068 | {
2069 | rl_getc_func_t *old = rl_getc_function;
2070 | rl_getc_function = func;
2071 | return old;
2072 | }
2073 |
2074 | /**
2075 | * Local Variables:
2076 | * c-file-style: "k&r"
2077 | * c-basic-offset: 4
2078 | * End:
2079 | */
2080 |
--------------------------------------------------------------------------------
/src/editline.h:
--------------------------------------------------------------------------------
1 | /* Internal header file for editline library.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 |
23 | #ifndef EDITLINE_PRIVATE_H_
24 | #define EDITLINE_PRIVATE_H_
25 |
26 | #include
27 | #include
28 | #ifdef HAVE_MALLOC_H
29 | #include
30 | #endif
31 | #ifdef HAVE_STDLIB_H
32 | #include
33 | #endif
34 | #ifdef HAVE_STRING_H
35 | #include
36 | #endif
37 | #ifdef HAVE_DIRENT_H
38 | #include
39 | #endif
40 | #ifdef HAVE_SIGNAL_H
41 | #include
42 | #endif
43 | #ifdef SYS_UNIX
44 | #include "unix.h"
45 | #endif
46 | #ifdef SYS_OS9
47 | #include "os9.h"
48 | #endif
49 | /* The following two are for TIOCGWINSZ */
50 | #ifdef HAVE_TERMIOS_H
51 | # include
52 | #endif
53 | #ifdef GWINSZ_IN_SYS_IOCTL
54 | # include
55 | #endif
56 |
57 | #define MEM_INC 64
58 | #define SCREEN_INC 256
59 |
60 | /* From The Practice of Programming, by Kernighan and Pike */
61 | #ifndef NELEMS
62 | #define NELEMS(array) (sizeof(array) / sizeof(array[0]))
63 | #endif
64 |
65 | /*
66 | ** Variables and routines internal to this package.
67 | */
68 | extern int rl_eof;
69 | extern int rl_erase;
70 | extern int rl_intr;
71 | extern int rl_kill;
72 | extern int rl_quit;
73 | #ifdef CONFIG_SIGSTOP
74 | extern int rl_susp;
75 | #endif
76 | void rl_ttyset(int Reset);
77 | void rl_add_slash(char *path, char *p);
78 | char *rl_complete(char *token, int *match);
79 | int rl_list_possib(char *token, char ***av);
80 |
81 | #ifndef HAVE_STDLIB_H
82 | extern char *getenv(const char *name);
83 | extern char *malloc(size_t size);
84 | extern char *realloc(void *ptr, size_t size);
85 | extern char *memcpy(void *dest, const void *src, size_t n);
86 | extern char *strcat(char *dest, const char *src);
87 | extern char *strchr(const char *s, int c);
88 | extern char *strrchr(const char *s, int c);
89 | extern char *strcpy(char *dest, const char *src);
90 | extern char *strdup(const char *s);
91 | extern int strcmp(const char *s1, const char *s2);
92 | extern int strlen(const char *s);
93 | extern int strncmp(const char *s1, const char *s2, size_t n);
94 | #endif/* !HAVE_STDLIB_H */
95 |
96 | #ifndef HAVE_STRDUP
97 | extern char *strdup(const char *s);
98 | #endif
99 |
100 | #include "../include/editline.h"
101 | #endif /* EDITLINE_PRIVATE_H_ */
102 |
--------------------------------------------------------------------------------
/src/os9.h:
--------------------------------------------------------------------------------
1 | /* Editline system header file for OS-9 (on 68k).
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 |
23 | #define CRLF "\r\l"
24 |
25 | #include
26 | typedef struct direct DIRENTRY;
27 |
--------------------------------------------------------------------------------
/src/sysos9.c:
--------------------------------------------------------------------------------
1 | /* OS-9 (on 68k) system-dependant routines for editline library.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 | #include "editline.h"
23 | #include
24 | #include
25 |
26 | void rl_ttyset(int Reset)
27 | {
28 | static struct sgbuf old;
29 | struct sgbuf new;
30 |
31 | if (Reset == 0) {
32 | _gs_opt(0, &old);
33 | _gs_opt(0, &new);
34 | new.sg_backsp = 0; new.sg_delete = 0; new.sg_echo = 0;
35 | new.sg_alf = 0; new.sg_nulls = 0; new.sg_pause = 0;
36 | new.sg_page = 0; new.sg_bspch = 0; new.sg_dlnch = 0;
37 | new.sg_eorch = 0; new.sg_eofch = 0; new.sg_rlnch = 0;
38 | new.sg_dulnch = 0; new.sg_psch = 0; new.sg_kbich = 0;
39 | new.sg_kbach = 0; new.sg_bsech = 0; new.sg_bellch = 0;
40 | new.sg_xon = 0; new.sg_xoff = 0; new.sg_tabcr = 0;
41 | new.sg_tabsiz = 0;
42 | _ss_opt(0, &new);
43 | rl_erase = old.sg_bspch;
44 | rl_kill = old.sg_dlnch;
45 | rl_eof = old.sg_eofch;
46 | rl_intr = old.sg_kbich;
47 | rl_quit = -1;
48 | }
49 | else {
50 | _ss_opt(0, &old);
51 | }
52 | }
53 |
54 | void rl_add_slash(char *path, char *p)
55 | {
56 | strcat(p, access(path, S_IREAD | S_IFDIR) ? " " : "/");
57 | }
58 |
59 | /**
60 | * Local Variables:
61 | * c-file-style: "k&r"
62 | * c-basic-offset: 4
63 | * End:
64 | */
65 |
--------------------------------------------------------------------------------
/src/sysunix.c:
--------------------------------------------------------------------------------
1 | /* Unix system-dependant routines for editline library.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 |
23 | #include
24 | #include "editline.h"
25 |
26 | #ifndef HAVE_TCGETATTR
27 | /* Wrapper for ioctl syscalls to restart on signal */
28 | static int ioctl_wrap(int fd, int req, void *arg)
29 | {
30 | int result, retries = 3;
31 |
32 | while (-1 == (result = ioctl(fd, req, arg)) && retries > 0) {
33 | retries--;
34 |
35 | if (EINTR == errno)
36 | continue;
37 |
38 | break;
39 | }
40 |
41 | return result;
42 | }
43 | #endif
44 |
45 | /* Prefer termios over the others since it is likely the most portable. */
46 | #if defined(HAVE_TCGETATTR)
47 | #include
48 |
49 | /* Wrapper for tcgetattr */
50 | static int getattr(int fd, struct termios *arg)
51 | {
52 | int result, retries = 3;
53 |
54 | while (-1 == (result = tcgetattr(fd, arg)) && retries > 0) {
55 | retries--;
56 |
57 | if (EINTR == errno)
58 | continue;
59 |
60 | break;
61 | }
62 |
63 | return result;
64 | }
65 |
66 | /* Wrapper for tcgetattr */
67 | static int setattr(int fd, int opt, const struct termios *arg)
68 | {
69 | int result, retries = 3;
70 |
71 | while (-1 == (result = tcsetattr(fd, opt, arg)) && retries > 0) {
72 | retries--;
73 |
74 | if (EINTR == errno)
75 | continue;
76 |
77 | break;
78 | }
79 |
80 | return result;
81 | }
82 |
83 | void rl_ttyset(int Reset)
84 | {
85 | static struct termios old;
86 | struct termios new;
87 |
88 | if (!Reset) {
89 | if (-1 == getattr(0, &old))
90 | perror("Failed tcgetattr()");
91 |
92 | rl_erase = old.c_cc[VERASE];
93 | rl_kill = old.c_cc[VKILL];
94 | rl_eof = old.c_cc[VEOF];
95 | rl_intr = old.c_cc[VINTR];
96 | rl_quit = old.c_cc[VQUIT];
97 | #ifdef CONFIG_SIGSTOP
98 | rl_susp = old.c_cc[VSUSP];
99 | #endif
100 |
101 | new = old;
102 | new.c_lflag &= ~(ECHO | ICANON | ISIG);
103 | new.c_iflag &= ~INPCK;
104 | if (rl_meta_chars)
105 | new.c_iflag |= ISTRIP;
106 | else
107 | new.c_iflag &= ~ISTRIP;
108 | new.c_cc[VMIN] = 1;
109 | new.c_cc[VTIME] = 0;
110 | if (-1 == setattr(0, TCSADRAIN, &new))
111 | perror("Failed tcsetattr(TCSADRAIN)");
112 | } else {
113 | if (-1 == setattr(0, TCSADRAIN, &old))
114 | perror("Failed tcsetattr(TCSADRAIN)");
115 | }
116 | }
117 |
118 | #elif defined(HAVE_TERMIO_H)
119 | #include
120 |
121 | void rl_ttyset(int Reset)
122 | {
123 | static struct termio old;
124 | struct termio new;
125 |
126 | if (!Reset) {
127 | if (-1 == ioctl_wrap(0, TCGETA, &old))
128 | perror("Failed ioctl(TCGETA)");
129 |
130 | rl_erase = old.c_cc[VERASE];
131 | rl_kill = old.c_cc[VKILL];
132 | rl_eof = old.c_cc[VEOF];
133 | rl_intr = old.c_cc[VINTR];
134 | rl_quit = old.c_cc[VQUIT];
135 | #ifdef CONFIG_SIGSTOP
136 | rl_susp = old.c_cc[VSUSP];
137 | #endif
138 |
139 | new = old;
140 | new.c_lflag &= ~(ECHO | ICANON | ISIG);
141 | new.c_iflag &= ~INPCK;
142 | if (rl_meta_chars)
143 | new.c_iflag |= ISTRIP;
144 | else
145 | new.c_iflag &= ~ISTRIP;
146 |
147 | new.c_cc[VMIN] = 1;
148 | new.c_cc[VTIME] = 0;
149 | if (-1 == ioctl_wrap(0, TCSETAW, &new))
150 | perror("Failed ioctl(TCSETAW)");
151 | } else {
152 | if (-1 == ioctl_wrap(0, TCSETAW, &old))
153 | perror("Failed ioctl(TCSETAW)");
154 | }
155 | }
156 |
157 | #elif defined(HAVE_SGTTY_H)
158 | #include
159 |
160 | void rl_ttyset(int Reset)
161 | {
162 | static struct sgttyb old_sgttyb;
163 | static struct tchars old_tchars;
164 | struct sgttyb new_sgttyb;
165 | struct tchars new_tchars;
166 | #ifdef CONFIG_SIGSTOP
167 | struct ltchars old_ltchars;
168 | #endif
169 |
170 | if (!Reset) {
171 | if (-1 == ioctl_wrap(0, TIOCGETP, &old_sgttyb))
172 | perror("Failed TIOCGETP");
173 |
174 | rl_erase = old_sgttyb.sg_erase;
175 | rl_kill = old_sgttyb.sg_kill;
176 |
177 | if (-1 == ioctl_wrap(0, TIOCGETC, &old_tchars))
178 | perror("Failed TIOCGETC");
179 |
180 | rl_eof = old_tchars.t_eofc;
181 | rl_intr = old_tchars.t_intrc;
182 | rl_quit = old_tchars.t_quitc;
183 |
184 | #ifdef CONFIG_SIGSTOP
185 | if (-1 == ioctl_wrap(0, TIOCGLTC, &old_ltchars))
186 | perror("Failed TIOCGLTC");
187 |
188 | rl_susp = old_ltchars.t_suspc;
189 | #endif
190 |
191 | new_sgttyb = old_sgttyb;
192 | new_sgttyb.sg_flags &= ~ECHO;
193 | new_sgttyb.sg_flags |= RAW;
194 | if (rl_meta_chars)
195 | new_sgttyb.sg_flags &= ~PASS8;
196 | else
197 | new_sgttyb.sg_flags |= PASS8;
198 |
199 | if (-1 == ioctl_wrap(0, TIOCSETP, &new_sgttyb))
200 | perror("Failed TIOCSETP");
201 |
202 | new_tchars = old_tchars;
203 | new_tchars.t_intrc = -1;
204 | new_tchars.t_quitc = -1;
205 | if (-1 == ioctl_wrap(0, TIOCSETC, &new_tchars))
206 | perror("Failed TIOCSETC");
207 | } else {
208 | if (-1 == ioctl_wrap(0, TIOCSETP, &old_sgttyb))
209 | perror("Failed TIOCSETP");
210 |
211 | if (-1 == ioctl_wrap(0, TIOCSETC, &old_tchars))
212 | perror("Failed TIOCSETC");
213 | }
214 | }
215 | #else /* Neither HAVE_SGTTY_H, HAVE_TERMIO_H or HAVE_TCGETATTR */
216 | #error Unsupported platform, missing tcgetattr(), termio.h and sgtty.h
217 | #endif /* Neither HAVE_SGTTY_H, HAVE_TERMIO_H or HAVE_TCGETATTR */
218 |
219 | #ifndef HAVE_STRDUP
220 | /* Return an allocated copy of a string. */
221 | char *strdup(const char *s)
222 | {
223 | size_t len;
224 | char *ptr;
225 |
226 | if (!s)
227 | return NULL;
228 |
229 | len = strlen(s) + 1;
230 | ptr = malloc(len);
231 | if (ptr)
232 | return memcpy(ptr, s, len);
233 |
234 | return NULL;
235 | }
236 | #endif
237 |
238 | void rl_add_slash(char *path, char *p)
239 | {
240 | struct stat Sb;
241 |
242 | if (stat(path, &Sb) >= 0)
243 | strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " ");
244 | }
245 |
246 | /**
247 | * Local Variables:
248 | * c-file-style: "k&r"
249 | * c-basic-offset: 4
250 | * End:
251 | */
252 |
--------------------------------------------------------------------------------
/src/unix.h:
--------------------------------------------------------------------------------
1 | /* Editline system header file for Unix.
2 | *
3 | * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
4 | * All rights reserved.
5 | *
6 | * This software is not subject to any license of the American Telephone
7 | * and Telegraph Company or of the Regents of the University of California.
8 | *
9 | * Permission is granted to anyone to use this software for any purpose on
10 | * any computer system, and to alter it and redistribute it freely, subject
11 | * to the following restrictions:
12 | * 1. The authors are not responsible for the consequences of use of this
13 | * software, no matter how awful, even if they arise from flaws in it.
14 | * 2. The origin of this software must not be misrepresented, either by
15 | * explicit claim or by omission. Since few users ever read sources,
16 | * credits must appear in the documentation.
17 | * 3. Altered versions must be plainly marked as such, and must not be
18 | * misrepresented as being the original software. Since few users
19 | * ever read sources, credits must appear in the documentation.
20 | * 4. This notice may not be removed or altered.
21 | */
22 |
23 | #ifndef EDITLINE_UNIX_H_
24 | #define EDITLINE_UNIX_H_
25 |
26 | #define CRLF "\r\n"
27 | #define FORWARD STATIC
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | #include
34 | typedef struct dirent DIRENTRY;
35 |
36 | #endif /* EDITLINE_UNIX_H_ */
37 |
--------------------------------------------------------------------------------