s11n.net
s11nlite::save(Anything, Anywhere);
Project powered by:
SourceForge.net
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.