Save Your Data, man!
Project powered by:
|
ACHTUNG: this code is no longer maintained. Please visit http://www.thrysoee.dk/editline/ for the latest (as of late 2011) editline code.
libeditline
A BSD-licensed replacement for GNU Readline
Disclaimer: forked code
This release of libeditline is a fork of the release available via:
http://sourceforge.net/projects/libedit
It was (apparently) originally written by Christos Zoulas.
Some info about the libedit library can be found
here.
In December 2005 i found what appears to be an official release
here. Another
C++ wrapper for GNU Readline can be found
Sergey Satsky's site, and has
support for Readline custom completers (this library does not
support those).
Before i say anything about this code, i want to explain...
Why a fork!?!?!?
What is a "fork"? It's this metal eating utensil, normally
unfamiliar to hackers... no, sorry, wrong web page...
It's when someone takes software and releases a variant of it,
as opposed to submitting his changes back through the
mainstream releases (which, as may be the case, may not be actively
maintained any longer).
A fork normally represents the last-ditch approach
to releasing software (or changes to others' software) when the
maintainers of the original software cannot be found, have dropped
off the net, are not willing to incorporate changes which one
really wants included in the mainstream releases, or
any number of similar reasons. In other words, it happens when
one coder really wants to hack someone else's code, but that
someone else cannot be found, is unresponsive, no longer
maintains the project, and similar cases.
Forking is, in Open Source circles, generally considered taboo,
or at least poor manners or an act of last resort.
While it is technically completely kosher
and well within the bounds of Open Source licenses, it is normally
avoided for a number of reasons, logistical, technological,
psychological, sociological and philosphical.
i am invoking the "last-ditch" clause of the taboo, in regards
to libeditline, because:
- The original project appears, sadly enough, to have been
abandoned. The authors left no email addresses in their source code,
no README file, no web site, etc.
- The project on Sourceforge is hosted by someone other than the original authors,
he hasn't made a release some 3.5 years, has no code in the CVS tree, and so far
attempts to contact him have failed. (However, the fact that some 1500 people
have downloaded the sources from the SF project show that this code is something
people want!)
- This code fills a massive niche which i've needed to fill for a long time (3+ years),
and it's not readily available in an overall-useful form on the web.
i'm gonna get a LOT of use out of it, and want it readily available (and readily hackable!). :)
- i've made a significant number of changes to it, and don't have an originating project
i can submit them back to.
- Googling for libedit brings up remarkably little - mostly people talking
about it, but nobody hosting a copy of it or information about using it. (i personally
found it by accident via a link in the PHP documentation for its Readline extension.)
- It's good, useful code
(at least, it was before my changes ;),
apparently has no home, and deserves some evangelism!
- It is the only known implementation of a readline-like library which
does not fall under a restrictive license
(yes, the GPL is restrictive),
and it would be a damned shame to see it fall between the cracks of the internet, so to say.
- As a C++ coder, i need this code and, as a license holder, i'm gonna exercise my rights . ;)
- And, lastly: as a user of a library, if the mainstream code base isn't readily
available/hackable, it's time to
Use the Fork, Luke! (Sorry, it had to be said. ;)
And so i've adopted a forked copy. (And i hope that any Open Source developers
can respect and understand my reasons for forking. :/)
If someone is aware of a maintained, "original" copy of these sources, please
let me know so i can
get in touch with the maintainers! i'm perfectly willing to follow a mainstream
copy, assuming there actually is one.
That said, i am perfectly willing to take over maintenance of the "official"
tree if i can get in touch with an "official" person to take over the project
from (i'm still trying to find someone). If that does indeed happen, this will
become the "official" home for libeditline. Until then, please consider this
to be an unofficial, forked copy which i intend to take in its own direction.
With that out of the way...
Getting it...
You can download the sources
from the downloads page.
Significant changes from the original libedit
If you coincidentally have used the original libedit code, please be
aware of the following significant changes:
- The readline-compatibility-mode header has been renamed from readline.h to editline.h,
for reasons explained in the README.
- The library name has changed from libedit to libeditline, for reasons also explained
in the README.
- The tree, as shipped, compiles the lib as C++, not C, because i only link it against C++ code and the
sources don't have the extern "C" blocks which they need. Forcing it to compile as C++ is a workaround
so i can link against C++ client apps.
- el_gets() no longer returns a trailing newline, even when not in readline-compatibility mode.
The old behaviour was, IMO, brain-dead, intrusive on client code (who always had to remove the newline
or work around it), and counter to every convention known to computer science
(with the exception of perl's while(<>){...}, and that doesn't count because the first command
in such a loop is normally chomp, to remove the newline!).
- There have been a huge number of (char *) to (const char *) changes, to help clarify pointer
ownership on function parameters and return values, and to ease an eventual port to std::string.
- In readline-compat mode, builtin functions are now swallowed by the readline compatibility layer, executed via libeditline but
not propagated back to the client (there is no need for them to see them, IMO). Even though the client app will
not see these events/inputs, they are added to the command history, for usability reasons (this also coincidentally
helps keep the history in sync with client-side history management).
- Builtin commands now all have a prefix of "el-", for reasons explained in the ChangeLog.
- Builtin functions may now be added from the client-side, via el_register_builtin(), and clients
can query the list via el_builtin_by_name() and el_builtins_list().
- Some of my changes (e.g., builtin function handling) are implemented in C++, not C, to simplify
some code by using, e.g., standard containers. i have avoided using "complex" C++ features (e.g., templates) which might
cause problems for older compilers - in theory the C++-related changes will even work on gcc 2.95.x
(but this is untested/unproven). Also, so far i have used only C-aware data types in the public APIs
(though this might change in the future).
- i'm slowly adding documentation to the API (which i've largely had to decode, due to non-existent, ambiguous, or
simply non-informative docs from the original authors). There is a man page, but it's quite incomplete,
and doesn't currently cover any of the mutilations i've done on the API.
- Replaced the several of the #defines with more descriptive/usable names. e.g., the 3
macros public, private and protected were changed, for obvious reasons, by adding a
prefix of el_ to each. (i still cannot BELIEVE someone defined those as macros!)
- Default editing mode is now emacs, not vi :). (Sorry, guys! Deal with it!)
- In readline compat mode, you can call el_readline_el() to get el's internal EditLine object
which is used for readline compatibility mode. This means you may directly customize it using the el API, which wasn't
possible using the original release.
(That resulted in some 120k of diffs in the first 30 hours of hacking!)
The full list of changes is in the ChangeLog.
Caveats and known problems
- Has little usable test/sample code. The test app which shipped with the original tree
(now under ./test/test.c) is quite buggy, apparently due to its internal handling
of continued lines. It sorely misrepresents the core lib as being buggy (which does not
appear to be the case at all).
- Emacs-style incremental searches work a bit differently than in emacs/readline: you've
got to play around with them a bit to figure out how it works (but it
does work).
Porting from GNU Readline, mini-HOWTO
- See editline.h for the full list of "compatibility functions". Most commonly-used
readline functions are emulated there, including the history-related API.
- Change #include <[readline/]readline.h> to #include <[editline/]editline.h>.
If you have included history.h, remove it - those are covered by editline.h.
If you don't use any of readline's signal-handling functions (like the SIGWINCH stuff) then you're done!
- If you use readline's signal handling functions, comment them out, #if them out of existence,
or otherwise get rid of them - you won't need them any more.
- Link against -leditline -lncurses (curses is used by both readline and editline, by
the way).
That's all there is to it! Working with the "native" editline API is a bit more complex, and
currently has no comprehensive documentation, but it is demonstrated quite clearly in
test/test.c (see above disclaimer) and in the function el_init().
You can use the function el_readline_el() to get the internal EditLine object
used by compatibility mode, to customize it further.
As a final tip:
s11n.net's readline_cpp library provides an OO interface which
is compatible with GNU readline, editline and plain old stdin, using whatever is available to it.
If your clients use that class instead of directly using readline's API they can get the
basic readline/history functions without having to know if they're using readline, editline or stdin
(which one is used is determined via readline_cpp's configure script). Aside from maintenance
benefits, this also gives more licensing leeway: clients of readline_cpp must only be
GPLd if readline_cpp is built with GNU readline support.
Hacking editline
Overall, hacking the source tree is remarkably simple. Going in, i expected only to
port the tree to another build platform (not GNU autotools, i mean), and be done
with it. After looking over the code i found how easy it was to tweak, and just kept
on doing so...
The code is fairly well laid-out, though some of the header/impl cross-overs are a bit
convoluted (but not unduly so). Start out in el.h and work your way out
from there.
The CVS tree is available via
the s11n CVS tree on Sourceforge,
in the editline repository. If you'd like write access,
please send me some code changes (to prove that you need write access) and your
Sourceforge account name, and i'll get you added to the project.
Potential TODOs
Some things i'd eventually like to do (or see done) with editline's code:
- More C++!!! i want to port most of it away from ([const] char *) to std::string,
at the very least. There's a LOT of stdup()ing going on in the code, and that makes
me nervous. This is a major undertaking, however, and will probably require a day or three
of Zen Coding Session(s). The relative cleanliness and modularity of the underlying code should ease
this port significantly, though.
- Write an OO wrapper for the editline type, eventually completely replacing the
current struct with an OO class.
- Improve the "readline compatible tab completion handler" a bit. It
isn't quite as compatible as i'd like (try entering
/bin/[TAB][TAB]), but all in all it's quite okay.
|