commit 27c900d6ae9cd0dcf4bc97bc9b8c1882e40ccfa8
parent 3202133256713848312dddefba2250a6803bfec6
Author: Toby Goodwin <toby@paccrat.org>
Date: Fri, 15 May 2015 19:36:55 +0100
snapshot from cvs: 2005-03-03
Diffstat:
M | Makefile.am | | | 14 | ++++++-------- |
M | builtins.c | | | 2 | +- |
M | configure.ac | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | edit-gnu.c | | | 92 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
M | edit-null.c | | | 59 | +++++++++++------------------------------------------------ |
M | hash.c | | | 11 | ----------- |
M | heredoc.c | | | 2 | +- |
M | input.c | | | 84 | +++++++++++++++++++++++++++++-------------------------------------------------- |
M | lex.c | | | 10 | +++++----- |
M | rc.1 | | | 9 | ++++++++- |
M | rc.h | | | 35 | +---------------------------------- |
M | signal.c | | | 19 | +++++++------------ |
M | var.c | | | 8 | ++++---- |
M | which.c | | | 20 | +++++++++++++++++++- |
14 files changed, 227 insertions(+), 229 deletions(-)
diff --git a/Makefile.am b/Makefile.am
@@ -1,5 +1,7 @@
## Process this file with automake to produce Makefile.in
+EDIT=@EDIT@
+
if AMC_HISTORY
man_MANS = rc.1 history.1
HISTORY = history
@@ -11,10 +13,6 @@ if AMC_NO_HASHBANG
EXECVE = execve.o
endif
-if AMC_READLINE
-READLINE = readline.o
-endif
-
if AMC_RESTART
SYSTEM = system-bsd.o
else
@@ -26,12 +24,12 @@ noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY)
rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c
-EXTRA_rc_SOURCES = addon.c execve.c readline.c system.c system-bsd.c
+EXTRA_rc_SOURCES = addon.c edit-bsd.c edit-gnu.c edit-null.c execve.c system.c system-bsd.c
-rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM)
-rc_LDADD = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM)
+rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM)
+rc_LDADD = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM)
-noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h
+noinst_HEADERS = edit.h getgroups.h input.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h
BUILT_SOURCES = sigmsgs.c
diff --git a/builtins.c b/builtins.c
@@ -395,8 +395,8 @@ extern void b_dot(char **av) {
return;
}
starassign(*av, av+1, TRUE);
- pushfd(fd);
interactive = i;
+ pushfd(fd);
star.name = "*";
except(eVarstack, star, &e);
doit(TRUE);
diff --git a/configure.ac b/configure.ac
@@ -6,9 +6,9 @@ AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE", [Release date])
dnl Automake stuff.
dnl Use this one for snapshots...
-dnl AM_INIT_AUTOMAKE(rc, 1.7s`echo $RELDATE |sed 's/-//g'`)
+AM_INIT_AUTOMAKE(rc, 1.7s`echo $RELDATE |sed 's/-//g'`)
dnl ...and this one for releases
-AM_INIT_AUTOMAKE(rc, 1.7.1)
+dnl AM_INIT_AUTOMAKE(rc, 1.7.1)
AM_CONFIG_HEADER(config.h)
@@ -90,7 +90,7 @@ no) RC_SYS_MKNOD_FIFO ;;
esac
dnl Now handle arguments.
-AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin],
+AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include `echo' as a builtin],
test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO, 1, [Define to 1 to include `echo' as a builtin.]),
AC_DEFINE(RC_ECHO))
@@ -104,7 +104,7 @@ AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment
AC_ARG_ENABLE(def-interp,
[ --enable-def-interp=/bin/foo
- Use /bin/foo as default interpreter [/bin/sh]],
+ Use /bin/foo as default interpreter [[/bin/sh]]],
[
case "$enableval" in
no)
@@ -120,8 +120,8 @@ AC_ARG_ENABLE(def-interp,
AC_ARG_ENABLE(def-path,
[ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\"
- Default path [All of these that exist
- (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]],
+ Default path [[All of these that exist
+ (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]]],
[
case "$enableval" in
no|yes) ;;
@@ -156,7 +156,7 @@ AC_ARG_WITH(history,
AM_CONDITIONAL(AMC_HISTORY, test "$rc_history" = yes)
-AC_ARG_WITH(addon, [ --with-addon[=foo.c] Extra builtins, from addon.c by default ],[
+AC_ARG_WITH(addon, [ --with-addon[[=foo.c]] Extra builtins, from addon.c by default ],[
case "$withval" in
yes) ADDON=addon.o ;;
no) ADDON='' ;;
@@ -170,32 +170,69 @@ esac
AC_SUBST(ADDON)
-AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing],
- AC_CHECK_LIB(edit, readline,
- AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit",
- AC_MSG_ERROR(editline library not found)))
+EDIT=edit-null.o
+AC_ARG_WITH(edit, [ --with-edit=(bsd,edit,gnu,vrl) Command line editing library], [
+ case $withval in
+ yes)
+ AC_MSG_ERROR(must specify which library)
+ # might consider searching
+ ;;
+ bsd)
+ EDIT=edit-bsd.o
+ RC_LIB_TGETENT
+ AC_CHECK_LIB(edit, el_init, [
+ LIBS="$LIBS -ledit $rc_lib_tgetent"
+ ], AC_MSG_ERROR(editline library not found), $rc_lib_tgetent)
+ ;;
+ gnu)
+ EDIT=edit-gnu.o
+ RC_LIB_TGETENT
+ AC_CHECK_LIB(readline, readline, [
+ LIBS="$LIBS -lreadline $rc_lib_tgetent"
+ ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent)
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <readline/readline.h>
+ ], [
+ rl_catch_signals = 0;
+ ], [], AC_MSG_ERROR(readline >= 4.0 not found))
+ ;;
+ no|null)
+ ;;
+ edit|vrl)
+ EDIT=edit-$withval.o
+ ;;
+ *)
+ AC_MSG_ERROR(unknown editing library $withval)
+ ;;
+ esac
+])
+AC_SUBST(EDIT)
+dnl AC_CHECK_LIB(edit, readline,
+dnl AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit",
+dnl AC_MSG_ERROR(editline library not found)))
-if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then
- RC_LIB_TGETENT
-fi
+dnl if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then
+dnl RC_LIB_TGETENT
+dnl fi
-AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing],
- AC_CHECK_LIB(vrl, readline,
- AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent",
- AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent))
+dnl AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing],
+dnl AC_CHECK_LIB(vrl, readline,
+dnl AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent",
+dnl AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent))
dnl There are (at least) two incompatible versions of readline, and we
dnl need to know which one we are using. We don't support readline 2.0.
-AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [
- AC_CHECK_LIB(readline, readline, [
- AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.])
- LIBS="$LIBS -lreadline $rc_lib_tgetent"
- AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent)
- ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent)
-])
-AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set)
+dnl AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [
+dnl AC_CHECK_LIB(readline, readline, [
+dnl AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.])
+dnl LIBS="$LIBS -lreadline $rc_lib_tgetent"
+dnl AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent)
+dnl ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent)
+dnl ])
+dnl AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set)
dnl For some reason CPPFLAGS doesn't get propagated.
-AC_SUBST(CPPFLAGS)
+dnl AC_SUBST(CPPFLAGS)
AC_OUTPUT(Makefile)
diff --git a/edit-gnu.c b/edit-gnu.c
@@ -1,38 +1,84 @@
#include "rc.h"
+#include <errno.h>
#include <stdio.h>
#include <readline/readline.h>
+#include <readline/history.h>
-#include "jbwrap.h"
+#include "edit.h"
-struct Jbwrap rl_buf;
-volatile sig_atomic_t rl_active;
+bool editing = 1;
+
+struct cookie {
+ char *buffer;
+};
+
+void *edit_begin(int fd) {
+ List *hist;
+ struct cookie *c;
-void edit_init(void *ignored) {
rl_catch_signals = 0;
+
+ hist = varlookup("history");
+ if (hist != NULL)
+ if (read_history(hist->w) != 0 && errno != ENOENT) /* ignore if missing */
+ uerror(hist->w);
+
+ c = ealloc(sizeof *c);
+ c->buffer = NULL;
+ return c;
}
-char *edit_getline(void *ignored, char *prompt) {
- char *r = NULL;
- int s;
-
- if ((s = sigsetjmp(rl_buf.j, 1)) == 0) {
- rl_active = TRUE;
- r = readline(prompt);
- } else {
- rl_free_line_state();
- rl_cleanup_after_signal();
- rl_active = FALSE;
- rc_raise(eError);
- }
+static void edit_catcher(int sig) {
+ write(2, "\n", 1);
+ rc_raise(eError);
+}
+
+static char *prompt;
+
+char *edit_alloc(void *cookie, int *count) {
+ struct cookie *c = cookie;
+ void (*oldint)(int), (*oldquit)(int);
+
+ oldint = sys_signal(SIGINT, edit_catcher);
+ oldquit = sys_signal(SIGQUIT, edit_catcher);
+
+ c->buffer = readline(prompt);
- if (r) {
- r = erealloc(r, strlen(r) + 2); /* 1 for \n + 1 for \0 */
- strcat(r, "\n");
+ sys_signal(SIGINT, oldint);
+ sys_signal(SIGQUIT, oldquit);
+
+ if (c->buffer) {
+ *count = strlen(c->buffer);
+ if (*count)
+ add_history(c->buffer);
+ c->buffer[*count] = '\n';
+ ++*count; /* include the \n */
}
- return r;
+ return c->buffer;
+}
+
+void edit_prompt(void *cookie, char *pr) {
+ prompt = pr;
+}
+
+void edit_free(void *cookie) {
+ struct cookie *c = cookie;
+
+ efree(c->buffer);
+ /* Set c->buffer to NULL, allowing us to "overfree" it. This
+ is a bit of a kludge, but it's otherwise hard to deal with
+ the case where a signal causes an early return from
+ readline. */
+ c->buffer = NULL;
+}
+
+void edit_end(void *cookie) {
+ struct cookie *c = cookie;
+
+ efree(c);
}
-void edit_free(void *ignored, void *buffer) {
- efree(buffer);
+void edit_reset(void *cookie) {
+ rl_reset_terminal(NULL);
}
diff --git a/edit-null.c b/edit-null.c
@@ -8,65 +8,28 @@
bool editing = 0;
-void *edit_init(int fd) {
- /* this function deliberately left blank */
+void *edit_begin(int fd) {
+ assert(0); /* should never be called */
return NULL;
}
char *edit_alloc(void *cookie, int *count) {
- char *buf;
- int size, used;
- ssize_t r;
-
- used = 0;
- size = 1;
- buf = ealloc(size + 1); /* leave room for terminating \0 */
- do {
- if (used >= size) { /* >= leaves room for terminating \0 */
- size = size * 2;
- buf = erealloc(buf, size);
- }
- do {
- r = rc_read(0, buf + used, size - used);
- sigchk();
- if (r == -1)
- switch (errno) {
- case EAGAIN:
- if (!makeblocking(0))
- panic("not O_NONBLOCK");
- errno = EINTR;
- break;
- case EIO:
- if (makesamepgrp(0))
- errno = EINTR;
- else
- errno = EIO;
- break;
- }
- } while (r < 0 && errno == EINTR);
-
- if (r == 0)
- return NULL;
-
- used += r;
- buf[used] = '\0';
- } while (strchr(buf, '\n') == NULL);
-
- *count = used;
- if (used)
- return buf;
- else
- return NULL;
+ assert(0); /* should never be called */
+ return NULL;
}
void edit_prompt(void *cookie, char *prompt) {
- fprint(2, "%s", prompt);
+ assert(0); /* should never be called */
}
void edit_free(void *buffer) {
- efree(buffer);
+ assert(0); /* should never be called */
}
void edit_end(void *cookie) {
- /* this function deliberately left blank */
+ assert(0); /* should never be called */
+}
+
+void edit_reset(void *cookie) {
+ assert(0); /* should never be called */
}
diff --git a/hash.c b/hash.c
@@ -315,14 +315,3 @@ extern void whatare_all_vars(bool showfn, bool showvar) {
if (fp[i].name != NULL && fp[i].name != dead)
prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
}
-
-/* fake getenv() for readline() follows: */
-
-#if EDITLINE || READLINE
-extern char *getenv(const char *name) {
- List *s;
- if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL)
- return NULL;
- return s->w;
-}
-#endif
diff --git a/heredoc.c b/heredoc.c
@@ -42,7 +42,7 @@ static char *readheredoc(char *eof) {
bufend = &buf[bufsize]; \
}
for (;;) {
- print_prompt2();
+ nextline();
for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
;
if (*s == '\0' && (c == '\n' || c == EOF)) {
diff --git a/input.c b/input.c
@@ -8,31 +8,28 @@
#include "input.h"
#include "jbwrap.h"
-/*
- NB: character unget is supported for up to two characters, but NOT
- in the case of EOF. Since EOF does not fit in a char, it is easiest
- to support only one unget of EOF.
-*/
+/* How many characters can we unget? */
+enum { UNGETSIZE = 2 };
typedef enum inputtype {
iFd, iString, iEdit
} inputtype;
typedef struct Input {
- bool saved, eofread;
+ bool saved;
inputtype t;
- int fd, index, read, lineno, last;
+ int fd, index, read, ungetcount, lineno, last;
char *ibuf;
void *cookie;
+ int ungetbuf[UNGETSIZE];
int (*gchar)(void);
- void (*ugchar)(int);
} Input;
#define BUFSIZE ((size_t) 256)
static char *inbuf;
static size_t istacksize, chars_out, chars_in;
-static bool eofread = FALSE, save_lineno = TRUE;
+static bool save_lineno = TRUE;
static Input *istack, *itop;
int lastchar;
@@ -40,24 +37,15 @@ int lastchar;
static char *prompt, *prompt2;
extern void ugchar(int c) {
- if (c == EOF)
- eofread = TRUE;
- else
- (*istack->ugchar)(c);
-}
-
-static void fdstringugchar(int c) {
- assert(chars_out);
- inbuf[--chars_out] = c;
+ assert(istack->ungetcount < UNGETSIZE);
+ istack->ungetbuf[istack->ungetcount++] = c;
}
extern int gchar() {
int c;
- if (eofread) {
- eofread = FALSE;
- return lastchar = EOF;
- }
+ if (istack->ungetcount)
+ return lastchar = istack->ungetbuf[--istack->ungetcount];
while ((c = (*istack->gchar)()) == '\0')
pr_error("warning: null character ignored", 0);
@@ -65,6 +53,7 @@ extern int gchar() {
return c;
}
+
/* get the next character from a string. */
static int stringgchar() {
@@ -82,7 +71,7 @@ static void history() {
return;
for (a = 0; a < chars_in; a++) {
- char c = inbuf[a+2];
+ char c = inbuf[a];
/* skip empty lines and comments */
if (c == '#' || c == '\n')
@@ -92,11 +81,10 @@ static void history() {
if (c != ' ' && c != '\t') {
char *name = hist->w;
int fd = rc_open(name, rAppend);
- if (fd < 0) {
+ if (fd < 0)
uerror(name);
- varrm(name, TRUE);
- } else {
- writeall(fd, inbuf + 2, chars_in);
+ else {
+ writeall(fd, inbuf, chars_in);
close(fd);
}
break;
@@ -104,13 +92,14 @@ static void history() {
}
}
+
/* read a character from a file descriptor */
static int fdgchar() {
- if (chars_out >= chars_in + 2) { /* replenish empty buffer */
+ if (chars_out >= chars_in) { /* replenish empty buffer */
ssize_t r;
do {
- r = rc_read(istack->fd, inbuf + 2, BUFSIZE);
+ r = rc_read(istack->fd, inbuf, BUFSIZE);
sigchk();
if (r == -1)
switch (errno) {
@@ -134,31 +123,18 @@ static int fdgchar() {
chars_in = (size_t) r;
if (chars_in == 0)
return lastchar = EOF;
- chars_out = 2;
+ chars_out = 0;
if (dashvee)
- writeall(2, inbuf + 2, chars_in);
+ writeall(2, inbuf, chars_in);
history();
}
return lastchar = inbuf[chars_out++];
}
-enum { UNGETSIZE = 2 };
-static int ungetbuf[UNGETSIZE];
-static int ungetcount = 0;
-
-static void editugchar(int c) {
- fprint(2, "in editugchar, with c = %d and ungetcount = %d\n", c, ungetcount);
- assert(ungetcount < UNGETSIZE);
- ungetbuf[ungetcount++] = c;
-}
-
/* read a character from a line-editing file descriptor */
static int editgchar() {
- if (ungetcount)
- return lastchar = ungetbuf[--ungetcount];
-
if (chars_out >= chars_in) { /* replenish empty buffer */
edit_free(istack->cookie);
inbuf = edit_alloc(istack->cookie, &chars_in);
@@ -182,11 +158,12 @@ void termchange(void) {
edit_reset(istack->cookie);
}
+
/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
extern void initinput() {
istack = itop = ealloc(istacksize = 256 * sizeof (Input));
- istack->eofread = TRUE;
+ ugchar(EOF);
}
/* push an input source onto the stack. set up a new input buffer, and set gchar() */
@@ -199,15 +176,15 @@ static void pushcommon() {
istack->lineno = lineno;
istack->saved = save_lineno;
istack->last = lastchar;
- istack->eofread = eofread;
istack++;
idiff = istack - itop;
if (idiff >= istacksize / sizeof (Input)) {
itop = erealloc(itop, istacksize *= 2);
istack = itop + idiff;
}
- chars_out = 2;
+ chars_out = 0;
chars_in = 0;
+ istack->ungetcount = 0;
}
extern void pushfd(int fd) {
@@ -218,13 +195,11 @@ extern void pushfd(int fd) {
if (editing && interactive && isatty(fd)) {
istack->t = iEdit;
istack->gchar = editgchar;
- istack->ugchar = editugchar;
istack->cookie = edit_begin(fd);
} else {
istack->t = iFd;
istack->gchar = fdgchar;
- istack->ugchar = fdstringugchar;
- inbuf = ealloc(BUFSIZE + 2);
+ inbuf = ealloc(BUFSIZE);
}
}
@@ -232,15 +207,15 @@ extern void pushstring(char **a, bool save) {
pushcommon();
istack->t = iString;
save_lineno = save;
- inbuf = mprint("..%A", a);
+ inbuf = mprint("%A", a);
istack->gchar = stringgchar;
- istack->ugchar = fdstringugchar;
if (save_lineno)
lineno = 1;
else
--lineno;
}
+
/* remove an input source from the stack. restore associated variables etc. */
extern void popinput() {
@@ -251,7 +226,6 @@ extern void popinput() {
efree(inbuf);
--istack;
lastchar = istack->last;
- eofread = istack->eofread;
inbuf = istack->ibuf;
chars_out = istack->index;
chars_in = istack->read;
@@ -262,6 +236,7 @@ extern void popinput() {
save_lineno = istack->saved;
}
+
/* flush input characters upto newline. Used by scanerror() */
extern void skiptonl() {
@@ -274,6 +249,7 @@ extern void skiptonl() {
ugchar(c);
}
+
/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
extern Node *doit(bool clobberexecit) {
@@ -367,6 +343,8 @@ extern void closefds() {
}
}
+/* print (or set) prompt(2) */
+
extern void nextline() {
lineno++;
if (interactive) {
diff --git a/lex.c b/lex.c
@@ -99,8 +99,8 @@ extern int yylex() {
meta = (dollar ? dnw : nw);
dollar = FALSE;
if (newline) {
- --lineno; /* slight space optimization; print_prompt2() always increments lineno */
- print_prompt2();
+ --lineno; /* slight space optimization; nextline() always increments lineno */
+ nextline();
newline = FALSE;
}
top: while ((c = gchar()) == ' ' || c == '\t')
@@ -120,7 +120,7 @@ top: while ((c = gchar()) == ' ' || c == '\t')
} while ((c = gchar()) != EOF && !meta[(unsigned char) c]);
while (c == '\\') {
if ((c = gchar()) == '\n') {
- print_prompt2();
+ nextline();
c = ' '; /* Pretend a space was read */
break;
} else {
@@ -198,7 +198,7 @@ top: while ((c = gchar()) == ' ' || c == '\t')
while ((c = gchar()) != '\'' || (c = gchar()) == '\'') {
buf[i++] = c;
if (c == '\n')
- print_prompt2();
+ nextline();
if (c == EOF) {
w = NW;
scanerror("eof in quoted string");
@@ -215,7 +215,7 @@ top: while ((c = gchar()) == ' ' || c == '\t')
return WORD;
case '\\':
if ((c = gchar()) == '\n') {
- print_prompt2();
+ nextline();
goto top; /* Pretend it was just another space. */
}
ugchar(c);
diff --git a/rc.1 b/rc.1
@@ -2056,8 +2056,15 @@ The
.Cr limit
builtin silently ignores extra arguments.
.PP
+Backquote substitution never produces empty strings - multiple
+consecutive occurrences of the separator are treated the same as a
+single occurrence.
+.Ds
+.Cr "ifs=! { x = `{echo -n a!!b}; whatis x }"
+.Cr "x=(a b) # NOT x=(a '' b)"
+.PP
Bug reports should be mailed to
-.Cr "<tjg@star.le.ac.uk>" .
+.Cr "<tjg@ast.cam.ac.uk>" .
.SH INCOMPATIBILITIES
Here is a list of features which distinguish this incarnation of
.I rc
diff --git a/rc.h b/rc.h
@@ -46,10 +46,6 @@ typedef enum bool {
FALSE, TRUE
} bool;
-typedef enum inputtype {
- iFd, iString
-} inputtype;
-
typedef enum redirtype {
rFrom, rCreate, rAppend, rHeredoc, rHerestring
} redirtype;
@@ -326,38 +322,8 @@ extern int yyparse(void);
extern void initparse(void);
/* readline */
-
-#if READLINE
-
-/* Including the real readline .h files is too complicated, so we just
-declare what we actually use. */
-
-extern void add_history(char *);
-extern char *readline(char *);
-extern int rl_clear_signals(void);
-extern int rl_pending_input;
-extern int rl_reset_terminal(char *);
-
-#if READLINE_OLD
-extern void rl_clean_up_for_exit(void);
-extern void rl_deprep_terminal(void);
-#else
-extern void _rl_clean_up_for_exit(void);
-extern void (*rl_deprep_term_function)(void);
-#endif
-
-extern char *rc_readline(char *);
-
extern volatile sig_atomic_t rl_active;
extern struct Jbwrap rl_buf;
-#endif
-
-#if EDITLINE
-extern char *readline(char *);
-extern void add_history(char *);
-#define rc_readline readline
-#endif
-
/* redir.c */
extern void doredirs(void);
@@ -368,6 +334,7 @@ extern void initsignal(void);
extern void catcher(int);
extern void sigchk(void);
extern void (*rc_signal(int, void (*)(int)))(int);
+extern void (*sys_signal(int, void (*)(int)))(int);
extern void (*sighandlers[])(int);
diff --git a/signal.c b/signal.c
@@ -9,7 +9,7 @@
#include "jbwrap.h"
#if HAVE_SIGACTION
-static void (*sys_signal(int signum, void (*handler)(int)))(int) {
+void (*sys_signal(int signum, void (*handler)(int)))(int) {
struct sigaction new, old;
new.sa_handler = handler;
@@ -19,7 +19,9 @@ static void (*sys_signal(int signum, void (*handler)(int)))(int) {
return old.sa_handler;
}
#else
-#define sys_signal(sig, func) (signal((sig), (func)))
+void (*sys_signal(int signum, void (*handler)(int)))(int) {
+ return signal(signum, handler);
+}
#endif
void (*sighandlers[NUMOFSIGNALS])(int);
@@ -33,11 +35,6 @@ extern void catcher(int s) {
}
sys_signal(s, catcher);
-#if READLINE
- if (rl_active)
- siglongjmp(rl_buf.j, s);
-#endif /* READLINE */
-
#if HAVE_RESTARTABLE_SYSCALLS
if (slow) {
siglongjmp(slowbuf.j, s);
@@ -73,13 +70,11 @@ extern void (*rc_signal(int s, void (*h)(int)))(int) {
void (*old)(int);
sigchk();
old = sighandlers[s];
- if (h == SIG_DFL || h == SIG_IGN) {
- sighandlers[s] = h;
+ sighandlers[s] = h;
+ if (h == SIG_DFL || h == SIG_IGN)
sys_signal(s, h);
- } else {
- sighandlers[s] = h;
+ else
sys_signal(s, catcher);
- }
return old;
}
diff --git a/var.c b/var.c
@@ -2,6 +2,8 @@
#include "rc.h"
+#include "input.h"
+
static void colonassign(char *, List *, bool);
static void listassign(char *, List *, bool);
static int hasalias(char *);
@@ -19,10 +21,8 @@ extern void varassign(char *name, List *def, bool stack) {
new->def = newdef;
new->extdef = NULL;
set_exportable(name, TRUE);
-#if READLINE
- if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP")))
- rl_reset_terminal(NULL);
-#endif
+ if (streq(name, "TERM") || streq(name, "TERMCAP"))
+ termchange();
}
/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
diff --git a/which.c b/which.c
@@ -70,6 +70,24 @@ static bool rc_access(char *path, bool verbose) {
return FALSE;
}
+static char *protect(char *in) {
+ char *out = ealloc(strlen(in) * 2 + 1);
+
+ int i;
+ int p = 0;
+
+ for (i = 0; i < strlen(in); ++i) {
+ if (isprint(in[i])) {
+ out[p++] = in[i];
+ ++p;
+ } else {
+ out[p++] = '\\';
+ out[p++] = '?';
+ }
+ }
+ return out; /* XXXX */
+}
+
/* return a full pathname by searching $path, and by checking the status of the file */
extern char *which(char *name, bool verbose) {
@@ -120,6 +138,6 @@ extern char *which(char *name, bool verbose) {
return test;
}
if (verbose)
- fprint(2, "%s not found\n", name);
+ fprint(2, "rc: cannot find `%s'\n", protect(name));
return NULL;
}