[submodule "src/libuv"]
path = src/libuv
url = git://github.com/graydon/libuv.git
-[submodule "src/linenoise"]
- path = src/linenoise
- url = git://github.com/antirez/linenoise.git
CFG_RUSTC_FLAGS := $(RUSTFLAGS)
CFG_GCCISH_CFLAGS :=
-CFG_GCCISH_CXXFLAGS :=
CFG_GCCISH_LINK_FLAGS :=
ifdef CFG_DISABLE_OPTIMIZE
TSREQ$(1)_T_$(2)_H_$(3) = \
$$(HSREQ$(1)_H_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUNTIME) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a \
- $$(TLIB$(1)_T_$(2)_H_$(3))/liblinenoise.a
+ $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
# Prerequisites for complete stageN targets
SREQ$(1)_T_$(2)_H_$(3) = \
$(SREQ3_T_$(target)_H_$(CFG_HOST_TRIPLE)))
FUZZ := $(HBIN2_H_$(CFG_HOST_TRIPLE))/fuzzer$(X)
CARGO := $(HBIN2_H_$(CFG_HOST_TRIPLE))/cargo$(X)
-RUSTI := $(HBIN2_H_$(CFG_HOST_TRIPLE))/rusti$(X)
RUSTDOC := $(HBIN2_H_$(CFG_HOST_TRIPLE))/rustdoc$(X)
+RUSTI := $(HBIN2_H_$(CFG_HOST_TRIPLE))/rusti$(X)
all: rustc $(GENERATED) docs $(FUZZ) $(CARGO) $(RUSTDOC) $(RUSTI)
include $(CFG_SRC_DIR)mk/stage0.mk
include $(CFG_SRC_DIR)mk/rt.mk
include $(CFG_SRC_DIR)mk/rustllvm.mk
-include $(CFG_SRC_DIR)mk/linenoise.mk
include $(CFG_SRC_DIR)mk/tools.mk
include $(CFG_SRC_DIR)mk/docs.mk
include $(CFG_SRC_DIR)mk/llvm.mk
make_dir rustllvm/$t
done
-make_dir linenoise
-for t in $CFG_TARGET_TRIPLES
-do
- make_dir linenoise/$t
-done
-
make_dir rt
for t in $CFG_TARGET_TRIPLES
do
make_dir rt/$t
for i in \
- isaac bigint sync test arch/i386 arch/x86_64 \
+ isaac linenoise bigint sync test arch/i386 arch/x86_64 \
libuv libuv/src/ares libuv/src/eio libuv/src/ev
do
make_dir rt/$t/$i
clean-misc:
@$(call E, cleaning)
- $(Q)find linenoise rustllvm rt $(CFG_HOST_TRIPLE)/test \
+ $(Q)find rustllvm rt $(CFG_HOST_TRIPLE)/test \
-name '*.[odasS]' -o \
-name '*.so' -o \
-name '*.dylib' -o \
-name '*.def' -o \
-name '*.bc' \
| xargs rm -f
- $(Q)find linenoise rustllvm rt $(CFG_HOST_TRIPLE)\
+ $(Q)find rustllvm rt $(CFG_HOST_TRIPLE)\
-name '*.dSYM' \
| xargs rm -Rf
$(Q)rm -f $(RUNTIME_OBJS) $(RUNTIME_DEF)
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
- $(Q)rm -f $(LINENOISE_OBJS)
$(Q)rm -Rf $(DOCS)
$(Q)rm -Rf $(GENERATED)
$(Q)rm -f tmp/*.log tmp/*.rc tmp/*.rs
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustc$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/fuzzer$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/cargo$(X)
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME)
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$(X)
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/fuzzer$(X)
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/cargo$(X)
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X)
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X)
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X)
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME)
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM)
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/liblinenoise.a
endef
$(foreach host, $(CFG_TARGET_TRIPLES), \
libcore \
libsyntax \
libstd \
- linenoise \
rt \
rustdoc \
rustllvm \
+++ /dev/null
-######################################################################
-# linenoise - minimalistic readline alternative used by the REPL
-######################################################################
-
-define DEF_LINENOISE_TARGETS
-
-LINENOISE_CS_$(1) := $$(addprefix linenoise/, linenoise.c)
-LINENOISE_OBJS_$(1) := $(LINENOISE_CS_$(1):linenoise/%.c=linenoise/$(1)/%.o)
-
-ALL_OBJ_FILES += $$(LINENOISE_OBJS_$(1))
-
-linenoise/$(1)/liblinenoise.a: $$(LINENOISE_OBJS_$(1))
- @$$(call E, link: $$@)
- $$(Q)ar rcs $$@ $$<
-
-linenoise/$(1)/%.o: linenoise/%.c $$(MKFILE_DEPS)
- @$$(call E, compile: $$@)
- $$(Q)$$(call CFG_COMPILE_C_$(1), $$@,) $$<
-endef
-
-# Instantiate template for all stages
-$(foreach target,$(CFG_TARGET_TRIPLES), \
- $(eval $(call DEF_LINENOISE_TARGETS,$(target))))
# Hack: not sure how to test if a file exists in make other than this
OS_SUPP = $(patsubst %,--suppressions=%,\
- $(wildcard $(CFG_SRC_DIR)src/etc/$(CFG_OSTYPE).supp*))
+ $(wildcard $(CFG_SRC_DIR)src/etc/$(CFG_OSTYPE).supp*))
ifneq ($(findstring mingw,$(CFG_OSTYPE)),)
CFG_WINDOWSY := 1
$$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
$$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
$$(call CFG_INSTALL_NAME,$$(4))
- CFG_COMPILE_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
- $$(CFG_GCCISH_CFLAGS) $$(CFG_CLANG_CFLAGS) \
+ CFG_COMPILE_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
+ $$(CFG_GCCISH_CFLAGS) $$(CFG_CLANG_CFLAGS) \
$$(CFG_GCCISH_CXXFLAGS) \
- $$(CFG_GCCISH_CFLAGS_$$(HOST_$(1))) \
- $$(CFG_CLANG_CFLAGS_$$(HOST_$(1))) \
+ $$(CFG_GCCISH_CFLAGS_$$(HOST_$(1))) \
+ $$(CFG_CLANG_CFLAGS_$$(HOST_$(1))) \
$$(CFG_DEPEND_FLAGS) \
- -c -o $$(1) $$(2)
- CFG_LINK_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
- $$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
- $$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
- $$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
- $$(call CFG_INSTALL_NAME,$$(4))
+ -c -o $$(1) $$(2)
+ CFG_LINK_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
+ $$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
+ $$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
+ $$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
+ $$(call CFG_INSTALL_NAME,$$(4))
endef
$(foreach target,$(CFG_TARGET_TRIPLES), \
$$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
$$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
$$(call CFG_INSTALL_NAME,$$(4))
- CFG_COMPILE_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
- $$(CFG_GCCISH_CFLAGS) \
+ CFG_COMPILE_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
+ $$(CFG_GCCISH_CFLAGS) \
$$(CFG_GCCISH_CXXFLAGS) \
- $$(CFG_GCCISH_CFLAGS_$$(HOST_$(1))) \
- $$(CFG_GCC_CFLAGS) \
- $$(CFG_GCC_CFLAGS_$$(HOST_$(1))) \
+ $$(CFG_GCCISH_CFLAGS_$$(HOST_$(1))) \
+ $$(CFG_GCC_CFLAGS) \
+ $$(CFG_GCC_CFLAGS_$$(HOST_$(1))) \
$$(CFG_DEPEND_FLAGS) \
-c -o $$(1) $$(2)
- CFG_LINK_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
- $$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
- $$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
- $$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
+ CFG_LINK_CXX_$(1) = $$(CFG_GCCISH_CROSS)$$(CXX) \
+ $$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
+ $$(CFG_GCCISH_LINK_FLAGS_$$(HOST_$(1))) \
+ $$(CFG_GCCISH_DEF_FLAG)$$(3) $$(2) \
$$(call CFG_INSTALL_NAME,$$(4))
endef
endef
$(foreach target,$(CFG_TARGET_TRIPLES),\
- $(eval $(call CFG_MAKE_ASSEMBLER,$(target))))
+ $(eval $(call CFG_MAKE_ASSEMBLER,$(target))))
\ No newline at end of file
$(wildcard $(S)src/test/*/*.rs \
$(S)src/test/*/*/*.rs) \
$(wildcard $(S)src/fuzzer/*.rs) \
- $(wildcard $(S)src/cargo/*.rs)
+ $(wildcard $(S)src/cargo/*.rs) \
$(wildcard $(S)src/rusti/*.rs)
PP_INPUTS_FILTERED = $(shell echo $(PP_INPUTS) | xargs grep -L \
# Runtime (C++) library variables
######################################################################
-RUNTIME_CS_$(1) := \
+RUNTIME_CXXS_$(1) := \
rt/sync/timer.cpp \
rt/sync/lock_and_signal.cpp \
rt/sync/rust_thread.cpp \
rt/arch/$$(HOST_$(1))/context.cpp \
rt/arch/$$(HOST_$(1))/gpr.cpp
+RUNTIME_CS_$(1) := rt/linenoise/linenoise.c
+
RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \
rt/arch/$$(HOST_$(1))/ccall.S \
rt/arch/$$(HOST_$(1))/record_sp.S
RUNTIME_DEF_$(1) := rt/rustrt$$(CFG_DEF_SUFFIX)
RUNTIME_INCS_$(1) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
- -I $$(S)src/rt/arch/$$(HOST_$(1)) \
- -I $$(S)src/libuv/include
-RUNTIME_OBJS_$(1) := $$(RUNTIME_CS_$(1):rt/%.cpp=rt/$(1)/%.o) \
+ -I $$(S)src/rt/arch/$$(HOST_$(1)) \
+ -I $$(S)src/rt/linenoise \
+ -I $$(S)src/libuv/include
+RUNTIME_OBJS_$(1) := $$(RUNTIME_CXXS_$(1):rt/%.cpp=rt/$(1)/%.o) \
+ $$(RUNTIME_CS_$(1):rt/%.c=rt/$(1)/%.o) \
$$(RUNTIME_S_$(1):rt/%.S=rt/$(1)/%.o)
ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1))
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
$$(SNAP_DEFINES)) $$<
+rt/$(1)/%.o: rt/%.c $$(MKFILE_DEPS)
+ @$$(call E, compile: $$@)
+ $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
+ $$(SNAP_DEFINES)) $$<
+
rt/$(1)/%.o: rt/%.S $$(MKFILE_DEPS) \
$$(LLVM_CONFIG_$$(CFG_HOST_TRIPLE))
@$$(call E, compile: $$@)
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
-$$(TLIB$(1)_T_$(2)_H_$(3))/liblinenoise.a: \
- linenoise/$(2)/liblinenoise.a
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM): \
rustllvm/$(2)/$$(CFG_RUSTLLVM)
@$$(call E, cp: $$@)
check-stage$(1)-T-$(2)-H-$(3)-bench \
check-stage$(1)-T-$(2)-H-$(3)-pretty \
check-stage$(1)-T-$(2)-H-$(3)-rustdoc \
- check-stage$(1)-T-$(2)-H-$(3)-rusti \
+ check-stage$(1)-T-$(2)-H-$(3)-rusti \
check-stage$(1)-T-$(2)-H-$(3)-cargo \
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial \
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi \
$$(Q)$$(call CFG_RUN_TEST,$$<,$(2),$(3)) $$(TESTARGS) \
--logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-rusti.log
+
# Rules for the cargo test runner
$(3)/test/cargotest.stage$(1)-$(2)$$(X): \
check-stage$(1)-H-all-rustdoc: \
$$(foreach target,$$(CFG_TARGET_TRIPLES), \
check-stage$(1)-H-$$(target)-rustdoc)
-check-stage$(1)-H-all-rusti: \
- $$(foreach target,$$(CFG_TARGET_TRIPLES), \
- check-stage$(1)-H-$$(target)-rusti)
check-stage$(1)-H-all-cargo: \
$$(foreach target,$$(CFG_TARGET_TRIPLES), \
check-stage$(1)-H-$$(target)-cargo)
check-stage$(1)-pretty-bench: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-pretty-bench
check-stage$(1)-pretty-pretty: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-pretty-pretty
check-stage$(1)-rustdoc: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-rustdoc
-check-stage$(1)-rusti: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-rusti
check-stage$(1)-cargo: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-cargo
check-stage$(1)-doc-tutorial: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial
check-stage$(1)-doc-tutorial-ffi: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-ffi
CARGO_CRATE := $(S)src/cargo/cargo.rc
CARGO_INPUTS := $(wildcard $(S)src/cargo/*rs)
-# Rusti, the JIT REPL
-RUSTI_CRATE := $(S)src/rusti/rusti.rc
-RUSTI_INPUTS := $(wildcard $(S)src/rusti/*rs)
-
# Rustdoc, the documentation tool
RUSTDOC_CRATE := $(S)src/rustdoc/rustdoc.rc
RUSTDOC_INPUTS := $(wildcard $(S)src/rustdoc/*.rs)
+# Rusti, the JIT REPL
+RUSTI_CRATE := $(S)src/rusti/rusti.rc
+RUSTI_INPUTS := $(wildcard $(S)src/rusti/*.rs)
+
# FIXME: These are only built for the host arch. Eventually we'll
# have tools that need to built for other targets.
define TOOLS_STAGE_N
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
-$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X): \
- $$(RUSTI_CRATE) $$(RUSTI_INPUTS) \
+$$(HBIN$(2)_H_$(4))/cargo$$(X): \
+ $$(TBIN$(1)_T_$(4)_H_$(3))/cargo$$(X) \
+ $$(HSREQ$(2)_H_$(4))
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
+
+$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X): \
+ $$(RUSTDOC_CRATE) $$(RUSTDOC_INPUTS) \
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_CORELIB) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_STDLIB) \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
-$$(HBIN$(2)_H_$(4))/cargo$$(X): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/cargo$$(X) \
- $$(HSREQ$(2)_H_$(4))
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(HBIN$(2)_H_$(4))/rusti$$(X): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X) \
+$$(HBIN$(2)_H_$(4))/rustdoc$$(X): \
+ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X) \
$$(HSREQ$(2)_H_$(4))
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
-$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X): \
- $$(RUSTDOC_CRATE) $$(RUSTDOC_INPUTS) \
+$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X): \
+ $$(RUSTI_CRATE) $$(RUSTI_INPUTS) \
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_CORELIB) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_STDLIB) \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
-$$(HBIN$(2)_H_$(4))/rustdoc$$(X): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X) \
+$$(HBIN$(2)_H_$(4))/rusti$$(X): \
+ $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X) \
$$(HSREQ$(2)_H_$(4))
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
cargo/ The package manager
-rusti/ The JIT REPL
+rusti/ The JIT REPL
rustdoc/ The Rust API documentation tool
rustllvm/ LLVM support code
-linenoise\ Minimalistic libreadline alternative
-
fuzzer/ A collection of fuzz testers
etc/ Scripts, editor support, misc
pub mod inst;
}
pub mod result;
-pub mod rl;
pub mod to_str;
pub mod to_bytes;
pub mod from_str;
+++ /dev/null
-use libc::{c_char, c_int};
-
-#[link_args = "-Llinenoise"]
-#[link_name = "linenoise"]
-#[abi = "cdecl"]
-extern mod linenoise {
- #[legacy_exports];
- fn linenoise(prompt: *c_char) -> *c_char;
- fn linenoiseHistoryAdd(line: *c_char) -> c_int;
- fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
- fn linenoiseHistorySave(file: *c_char) -> c_int;
- fn linenoiseHistoryLoad(file: *c_char) -> c_int;
- fn linenoiseSetCompletionCallback(callback: *u8);
- fn linenoiseAddCompletion(completions: *(), line: *c_char);
- fn linenoiseClearScreen();
-}
-
-/// Add a line to history
-pub fn add_history(line: ~str) -> bool {
- do str::as_c_str(line) |buf| {
- linenoise::linenoiseHistoryAdd(buf) == 1 as c_int
- }
-}
-
-/// Set the maximum amount of lines stored
-pub fn set_history_max_len(len: int) -> bool {
- linenoise::linenoiseHistorySetMaxLen(len as c_int) == 1 as c_int
-}
-
-/// Save line history to a file
-pub fn save_history(file: ~str) -> bool {
- do str::as_c_str(file) |buf| {
- linenoise::linenoiseHistorySave(buf) == 1 as c_int
- }
-}
-
-/// Load line history from a file
-pub fn load_history(file: ~str) -> bool {
- do str::as_c_str(file) |buf| {
- linenoise::linenoiseHistoryLoad(buf) == 1 as c_int
- }
-}
-
-/// Print out a prompt and then wait for input and return it
-pub fn read(prompt: ~str) -> Option<~str> {
- do str::as_c_str(prompt) |buf| unsafe {
- let line = linenoise::linenoise(buf);
-
- if line.is_null() { None }
- else { Some(str::raw::from_c_str(line)) }
- }
-}
-
-/// Clear the screen
-pub fn clear() {
- linenoise::linenoiseClearScreen();
-}
-
-pub type CompletionCb = fn~(~str, fn(~str));
-
-fn complete_key(_v: @CompletionCb) {}
-
-/// Bind to the main completion callback
-pub fn complete(cb: CompletionCb) unsafe {
- task::local_data::local_data_set(complete_key, @(move cb));
-
- extern fn callback(line: *c_char, completions: *()) unsafe {
- let cb = copy *task::local_data::local_data_get(complete_key).get();
-
- do cb(str::raw::from_c_str(line)) |suggestion| {
- do str::as_c_str(suggestion) |buf| {
- linenoise::linenoiseAddCompletion(completions, buf);
- }
- }
- }
-
- linenoise::linenoiseSetCompletionCallback(callback);
-}
+++ /dev/null
-Subproject commit 8c9b481281ba401f6baf45bc9ca9fc940b59405f
--- /dev/null
+/* linenoise.c -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ * http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Switch to gets() if $TERM is something we can't support.
+ * - Filter bogus Ctrl+<char> combinations.
+ * - Win32 support
+ *
+ * Bloat:
+ * - Completion?
+ * - History search like Ctrl+r in readline?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * with three sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * CHA (Cursor Horizontal Absolute)
+ * Sequence: ESC [ n G
+ * Effect: moves cursor to column n
+ *
+ * EL (Erase Line)
+ * Sequence: ESC [ n K
+ * Effect: if n is 0 or missing, clear from cursor to end of line
+ * Effect: if n is 1, clear from beginning of line to cursor
+ * Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ * Sequence: ESC [ n C
+ * Effect: moves cursor forward of n chars
+ *
+ * The following are used to clear the screen: ESC [ H ESC [ 2 J
+ * This is actually composed of two sequences:
+ *
+ * cursorhome
+ * Sequence: ESC [ H
+ * Effect: moves the cursor to upper left corner
+ *
+ * ED2 (Clear entire screen)
+ * Sequence: ESC [ 2 J
+ * Effect: clear the whole screen
+ *
+ */
+
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "linenoise.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+static char *unsupported_term[] = {"dumb","cons25",NULL};
+static linenoiseCompletionCallback *completionCallback = NULL;
+
+static struct termios orig_termios; /* in order to restore at exit */
+static int rawmode = 0; /* for atexit() function to check if restore is needed*/
+static int atexit_registered = 0; /* register atexit just 1 time */
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+char **history = NULL;
+
+static void linenoiseAtExit(void);
+int linenoiseHistoryAdd(const char *line);
+
+static int isUnsupportedTerm(void) {
+ char *term = getenv("TERM");
+ int j;
+
+ if (term == NULL) return 0;
+ for (j = 0; unsupported_term[j]; j++)
+ if (!strcasecmp(term,unsupported_term[j])) return 1;
+ return 0;
+}
+
+static void freeHistory(void) {
+ if (history) {
+ int j;
+
+ for (j = 0; j < history_len; j++)
+ free(history[j]);
+ free(history);
+ }
+}
+
+static int enableRawMode(int fd) {
+ struct termios raw;
+
+ if (!isatty(STDIN_FILENO)) goto fatal;
+ if (!atexit_registered) {
+ atexit(linenoiseAtExit);
+ atexit_registered = 1;
+ }
+ if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
+
+ raw = orig_termios; /* modify the original mode */
+ /* input modes: no break, no CR to NL, no parity check, no strip char,
+ * no start/stop output control. */
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ /* output modes - disable post processing */
+ raw.c_oflag &= ~(OPOST);
+ /* control modes - set 8 bit chars */
+ raw.c_cflag |= (CS8);
+ /* local modes - choing off, canonical off, no extended functions,
+ * no signal chars (^Z,^C) */
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ /* control chars - set return condition: min number of bytes and timer.
+ * We want read to return every single byte, without timeout. */
+ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+ /* put terminal in raw mode after flushing */
+ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
+ rawmode = 1;
+ return 0;
+
+fatal:
+ errno = ENOTTY;
+ return -1;
+}
+
+static void disableRawMode(int fd) {
+ /* Don't even check the return value as it's too late. */
+ if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
+ rawmode = 0;
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+ disableRawMode(STDIN_FILENO);
+ freeHistory();
+}
+
+static int getColumns(void) {
+ struct winsize ws;
+
+ if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80;
+ return ws.ws_col;
+}
+
+static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) {
+ char seq[64];
+ size_t plen = strlen(prompt);
+
+ while((plen+pos) >= cols) {
+ buf++;
+ len--;
+ pos--;
+ }
+ while (plen+len > cols) {
+ len--;
+ }
+
+ /* Cursor to left edge */
+ snprintf(seq,64,"\x1b[0G");
+ if (write(fd,seq,strlen(seq)) == -1) return;
+ /* Write the prompt and the current buffer content */
+ if (write(fd,prompt,strlen(prompt)) == -1) return;
+ if (write(fd,buf,len) == -1) return;
+ /* Erase to right */
+ snprintf(seq,64,"\x1b[0K");
+ if (write(fd,seq,strlen(seq)) == -1) return;
+ /* Move cursor to original position. */
+ snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
+ if (write(fd,seq,strlen(seq)) == -1) return;
+}
+
+static void beep() {
+ fprintf(stderr, "\x7");
+ fflush(stderr);
+}
+
+static void freeCompletions(linenoiseCompletions *lc) {
+ size_t i;
+ for (i = 0; i < lc->len; i++)
+ free(lc->cvec[i]);
+ if (lc->cvec != NULL)
+ free(lc->cvec);
+}
+
+static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) {
+ linenoiseCompletions lc = { 0, NULL };
+ int nread, nwritten;
+ char c = 0;
+
+ completionCallback(buf,&lc);
+ if (lc.len == 0) {
+ beep();
+ } else {
+ size_t stop = 0, i = 0;
+ size_t clen;
+
+ while(!stop) {
+ /* Show completion or original buffer */
+ if (i < lc.len) {
+ clen = strlen(lc.cvec[i]);
+ refreshLine(fd,prompt,lc.cvec[i],clen,clen,cols);
+ } else {
+ refreshLine(fd,prompt,buf,*len,*pos,cols);
+ }
+
+ nread = read(fd,&c,1);
+ if (nread <= 0) {
+ freeCompletions(&lc);
+ return -1;
+ }
+
+ switch(c) {
+ case 9: /* tab */
+ i = (i+1) % (lc.len+1);
+ if (i == lc.len) beep();
+ break;
+ case 27: /* escape */
+ /* Re-show original buffer */
+ if (i < lc.len) {
+ refreshLine(fd,prompt,buf,*len,*pos,cols);
+ }
+ stop = 1;
+ break;
+ default:
+ /* Update buffer and return */
+ if (i < lc.len) {
+ nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]);
+ *len = *pos = nwritten;
+ }
+ stop = 1;
+ break;
+ }
+ }
+ }
+
+ freeCompletions(&lc);
+ return c; /* Return last read character */
+}
+
+void linenoiseClearScreen(void) {
+ if (write(STDIN_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+ /* nothing to do, just to avoid warning. */
+ }
+}
+
+static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) {
+ size_t plen = strlen(prompt);
+ size_t pos = 0;
+ size_t len = 0;
+ size_t cols = getColumns();
+ int history_index = 0;
+ size_t old_pos;
+ size_t diff;
+
+ buf[0] = '\0';
+ buflen--; /* Make sure there is always space for the nulterm */
+
+ /* The latest history entry is always our current buffer, that
+ * initially is just an empty string. */
+ linenoiseHistoryAdd("");
+
+ if (write(fd,prompt,plen) == -1) return -1;
+ while(1) {
+ char c;
+ int nread;
+ char seq[2], seq2[2];
+
+ nread = read(fd,&c,1);
+ if (nread <= 0) return len;
+
+ /* Only autocomplete when the callback is set. It returns < 0 when
+ * there was an error reading from fd. Otherwise it will return the
+ * character that should be handled next. */
+ if (c == 9 && completionCallback != NULL) {
+ c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
+ /* Return on errors */
+ if (c < 0) return len;
+ /* Read next character when 0 */
+ if (c == 0) continue;
+ }
+
+ switch(c) {
+ case 13: /* enter */
+ history_len--;
+ free(history[history_len]);
+ return (int)len;
+ case 3: /* ctrl-c */
+ errno = EAGAIN;
+ return -1;
+ case 127: /* backspace */
+ case 8: /* ctrl-h */
+ if (pos > 0 && len > 0) {
+ memmove(buf+pos-1,buf+pos,len-pos);
+ pos--;
+ len--;
+ buf[len] = '\0';
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ break;
+ case 4: /* ctrl-d, remove char at right of cursor */
+ if (len > 1 && pos < (len-1)) {
+ memmove(buf+pos,buf+pos+1,len-pos);
+ len--;
+ buf[len] = '\0';
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ } else if (len == 0) {
+ history_len--;
+ free(history[history_len]);
+ return -1;
+ }
+ break;
+ case 20: /* ctrl-t */
+ if (pos > 0 && pos < len) {
+ int aux = buf[pos-1];
+ buf[pos-1] = buf[pos];
+ buf[pos] = aux;
+ if (pos != len-1) pos++;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ break;
+ case 2: /* ctrl-b */
+ goto left_arrow;
+ case 6: /* ctrl-f */
+ goto right_arrow;
+ case 16: /* ctrl-p */
+ seq[1] = 65;
+ goto up_down_arrow;
+ case 14: /* ctrl-n */
+ seq[1] = 66;
+ goto up_down_arrow;
+ break;
+ case 27: /* escape sequence */
+ if (read(fd,seq,2) == -1) break;
+ if (seq[0] == 91 && seq[1] == 68) {
+left_arrow:
+ /* left arrow */
+ if (pos > 0) {
+ pos--;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ } else if (seq[0] == 91 && seq[1] == 67) {
+right_arrow:
+ /* right arrow */
+ if (pos != len) {
+ pos++;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ } else if (seq[0] == 91 && (seq[1] == 65 || seq[1] == 66)) {
+up_down_arrow:
+ /* up and down arrow: history */
+ if (history_len > 1) {
+ /* Update the current history entry before to
+ * overwrite it with tne next one. */
+ free(history[history_len-1-history_index]);
+ history[history_len-1-history_index] = strdup(buf);
+ /* Show the new entry */
+ history_index += (seq[1] == 65) ? 1 : -1;
+ if (history_index < 0) {
+ history_index = 0;
+ break;
+ } else if (history_index >= history_len) {
+ history_index = history_len-1;
+ break;
+ }
+ strncpy(buf,history[history_len-1-history_index],buflen);
+ buf[buflen] = '\0';
+ len = pos = strlen(buf);
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ } else if (seq[0] == 91 && seq[1] > 48 && seq[1] < 55) {
+ /* extended escape */
+ if (read(fd,seq2,2) == -1) break;
+ if (seq[1] == 51 && seq2[0] == 126) {
+ /* delete */
+ if (len > 0 && pos < len) {
+ memmove(buf+pos,buf+pos+1,len-pos-1);
+ len--;
+ buf[len] = '\0';
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ }
+ }
+ break;
+ default:
+ if (len < buflen) {
+ if (len == pos) {
+ buf[pos] = c;
+ pos++;
+ len++;
+ buf[len] = '\0';
+ if (plen+len < cols) {
+ /* Avoid a full update of the line in the
+ * trivial case. */
+ if (write(fd,&c,1) == -1) return -1;
+ } else {
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ } else {
+ memmove(buf+pos+1,buf+pos,len-pos);
+ buf[pos] = c;
+ len++;
+ pos++;
+ buf[len] = '\0';
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ }
+ }
+ break;
+ case 21: /* Ctrl+u, delete the whole line. */
+ buf[0] = '\0';
+ pos = len = 0;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 11: /* Ctrl+k, delete from current to end of line. */
+ buf[pos] = '\0';
+ len = pos;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 1: /* Ctrl+a, go to the start of the line */
+ pos = 0;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 5: /* ctrl+e, go to the end of the line */
+ pos = len;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 12: /* ctrl+l, clear screen */
+ linenoiseClearScreen();
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ case 23: /* ctrl+w, delete previous word */
+ old_pos = pos;
+ while (pos > 0 && buf[pos-1] == ' ')
+ pos--;
+ while (pos > 0 && buf[pos-1] != ' ')
+ pos--;
+ diff = old_pos - pos;
+ memmove(&buf[pos], &buf[old_pos], len-old_pos+1);
+ len -= diff;
+ refreshLine(fd,prompt,buf,len,pos,cols);
+ break;
+ }
+ }
+ return len;
+}
+
+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
+ int fd = STDIN_FILENO;
+ int count;
+
+ if (buflen == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!isatty(STDIN_FILENO)) {
+ if (fgets(buf, buflen, stdin) == NULL) return -1;
+ count = strlen(buf);
+ if (count && buf[count-1] == '\n') {
+ count--;
+ buf[count] = '\0';
+ }
+ } else {
+ if (enableRawMode(fd) == -1) return -1;
+ count = linenoisePrompt(fd, buf, buflen, prompt);
+ disableRawMode(fd);
+ printf("\n");
+ }
+ return count;
+}
+
+char *linenoise(const char *prompt) {
+ char buf[LINENOISE_MAX_LINE];
+ int count;
+
+ if (isUnsupportedTerm()) {
+ size_t len;
+
+ printf("%s",prompt);
+ fflush(stdout);
+ if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
+ len = strlen(buf);
+ while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
+ len--;
+ buf[len] = '\0';
+ }
+ return strdup(buf);
+ } else {
+ count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
+ if (count == -1) return NULL;
+ return strdup(buf);
+ }
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+ completionCallback = fn;
+}
+
+void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
+ size_t len = strlen(str);
+ char *copy = malloc(len+1);
+ memcpy(copy,str,len+1);
+ lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+ lc->cvec[lc->len++] = copy;
+}
+
+/* Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+ char *linecopy;
+
+ if (history_max_len == 0) return 0;
+ if (history == NULL) {
+ history = malloc(sizeof(char*)*history_max_len);
+ if (history == NULL) return 0;
+ memset(history,0,(sizeof(char*)*history_max_len));
+ }
+ linecopy = strdup(line);
+ if (!linecopy) return 0;
+ if (history_len == history_max_len) {
+ free(history[0]);
+ memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+ history_len--;
+ }
+ history[history_len] = linecopy;
+ history_len++;
+ return 1;
+}
+
+int linenoiseHistorySetMaxLen(int len) {
+ char **new;
+
+ if (len < 1) return 0;
+ if (history) {
+ int tocopy = history_len;
+
+ new = malloc(sizeof(char*)*len);
+ if (new == NULL) return 0;
+ if (len < tocopy) tocopy = len;
+ memcpy(new,history+(history_max_len-tocopy), sizeof(char*)*tocopy);
+ free(history);
+ history = new;
+ }
+ history_max_len = len;
+ if (history_len > history_max_len)
+ history_len = history_max_len;
+ return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(char *filename) {
+ FILE *fp = fopen(filename,"w");
+ int j;
+
+ if (fp == NULL) return -1;
+ for (j = 0; j < history_len; j++)
+ fprintf(fp,"%s\n",history[j]);
+ fclose(fp);
+ return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(char *filename) {
+ FILE *fp = fopen(filename,"r");
+ char buf[LINENOISE_MAX_LINE];
+
+ if (fp == NULL) return -1;
+
+ while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+ char *p;
+
+ p = strchr(buf,'\r');
+ if (!p) p = strchr(buf,'\n');
+ if (p) *p = '\0';
+ linenoiseHistoryAdd(buf);
+ }
+ fclose(fp);
+ return 0;
+}
--- /dev/null
+/* linenoise.h -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+typedef struct linenoiseCompletions {
+ size_t len;
+ char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, char *);
+
+char *linenoise(const char *prompt);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(char *filename);
+int linenoiseHistoryLoad(char *filename);
+void linenoiseClearScreen(void);
+
+#endif /* __LINENOISE_H */
\ No newline at end of file
tinfl_decompress_mem_to_heap
rust_annihilate_box
rust_gc_metadata
+linenoise
+linenoiseSetCompletionCallback
+linenoiseAddCompletion
+linenoiseHistoryAdd
+linenoiseHistorySetMaxLen
+linenoiseHistorySave
+linenoiseHistoryLoad
+linenoiseClearScreen
--- /dev/null
+use libc::{c_char, c_int};
+
+extern mod rustrt {
+ #[legacy_exports];
+ fn linenoise(prompt: *c_char) -> *c_char;
+ fn linenoiseHistoryAdd(line: *c_char) -> c_int;
+ fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
+ fn linenoiseHistorySave(file: *c_char) -> c_int;
+ fn linenoiseHistoryLoad(file: *c_char) -> c_int;
+ fn linenoiseSetCompletionCallback(callback: *u8);
+ fn linenoiseAddCompletion(completions: *(), line: *c_char);
+ fn linenoiseClearScreen();
+}
+
+/// Add a line to history
+pub fn add_history(line: ~str) -> bool {
+ do str::as_c_str(line) |buf| {
+ rustrt::linenoiseHistoryAdd(buf) == 1 as c_int
+ }
+}
+
+/// Set the maximum amount of lines stored
+pub fn set_history_max_len(len: int) -> bool {
+ rustrt::linenoiseHistorySetMaxLen(len as c_int) == 1 as c_int
+}
+
+/// Save line history to a file
+pub fn save_history(file: ~str) -> bool {
+ do str::as_c_str(file) |buf| {
+ rustrt::linenoiseHistorySave(buf) == 1 as c_int
+ }
+}
+
+/// Load line history from a file
+pub fn load_history(file: ~str) -> bool {
+ do str::as_c_str(file) |buf| {
+ rustrt::linenoiseHistoryLoad(buf) == 1 as c_int
+ }
+}
+
+/// Print out a prompt and then wait for input and return it
+pub fn read(prompt: ~str) -> Option<~str> {
+ do str::as_c_str(prompt) |buf| unsafe {
+ let line = rustrt::linenoise(buf);
+
+ if line.is_null() { None }
+ else { Some(str::raw::from_c_str(line)) }
+ }
+}
+
+/// Clear the screen
+pub fn clear() {
+ rustrt::linenoiseClearScreen();
+}
+
+pub type CompletionCb = fn~(~str, fn(~str));
+
+fn complete_key(_v: @CompletionCb) {}
+
+/// Bind to the main completion callback
+pub fn complete(cb: CompletionCb) unsafe {
+ task::local_data::local_data_set(complete_key, @(move cb));
+
+ extern fn callback(line: *c_char, completions: *()) unsafe {
+ let cb = copy *task::local_data::local_data_get(complete_key).get();
+
+ do cb(str::raw::from_c_str(line)) |suggestion| {
+ do str::as_c_str(suggestion) |buf| {
+ rustrt::linenoiseAddCompletion(completions, buf);
+ }
+ }
+ }
+
+ rustrt::linenoiseSetCompletionCallback(callback);
+}
\ No newline at end of file
#[allow(vecs_implicitly_copyable,
non_implicitly_copyable_typarams)];
-#[allow(non_camel_case_types)];
-#[allow(deprecated_mode)];
-#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
use core::*;
use io::{ReaderUtil, WriterUtil};
-use std::c_vec;
use rustc::back;
use rustc::driver::{driver, session};
use rustc::front;
use syntax::ast_util::*;
use parse::token;
use print::{pp, pprust};
+
+mod rl;
#[legacy_exports];
#[allow(ctypes)];
-#[allow(deprecated_mode)];
-#[allow(deprecated_pattern)];
#[allow(heap_memory)];
#[allow(implicit_copies)];
#[allow(managed_heap_memory)];
extern mod std;
-fn print<T>(result: T) {
+fn print<T>(+result: T) {
io::println(fmt!("%?", result));
}