diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV
index d63f19fc8..efe2560e0 100644
--- a/configure/CONFIG_SITE_ENV
+++ b/configure/CONFIG_SITE_ENV
@@ -57,8 +57,11 @@ EPICS_TS_NTP_INET=
# Prompt string
# IOCSH_HISTSIZE
# Number of lines of command history to keep.
+# IOCSH_HISTEDIT_DISABLE
+# Prevents use of readline or equivalent if defined.
IOCSH_PS1="epics> "
IOCSH_HISTSIZE=50
+IOCSH_HISTEDIT_DISABLE=
# Log Server:
# EPICS_IOC_LOG_INET
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index b2e5fdc65..2a91b73c0 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -20,6 +20,17 @@
-->
+
Refactoring of epicsReadline
+
+The epicsReadline code has been reorganized to allow the commandline history
+editor to be disabled at runtime. The EPICS_COMMANDLINE_LIBRARY build setting
+still selects the preferred editor, but the new IOCSH_HISTEDIT_DISABLE
+environment variable can be set at runtime to disable history editing and make
+the IOC or other program use the basic editor instead. This is useful when
+starting and controlling an IOC from another program through its stdin and
+stdout streams since history editors often insert invisible escape codes into
+the stdout stream, making it hard to parse.
+
Callback subsystem API
Added a new macro callbackGetPriority(prio, callback) to the
diff --git a/src/libCom/env/envDefs.h b/src/libCom/env/envDefs.h
index b2a594f44..c5b947d57 100644
--- a/src/libCom/env/envDefs.h
+++ b/src/libCom/env/envDefs.h
@@ -69,6 +69,7 @@ epicsShareExtern const ENV_PARAM EPICS_CMD_PROTO_PORT;
epicsShareExtern const ENV_PARAM EPICS_AR_PORT;
epicsShareExtern const ENV_PARAM IOCSH_PS1;
epicsShareExtern const ENV_PARAM IOCSH_HISTSIZE;
+epicsShareExtern const ENV_PARAM IOCSH_HISTEDIT_DISABLE;
epicsShareExtern const ENV_PARAM *env_param_list[];
diff --git a/src/libCom/osi/epicsReadline.c b/src/libCom/osi/epicsReadline.c
new file mode 100644
index 000000000..7cc569014
--- /dev/null
+++ b/src/libCom/osi/epicsReadline.c
@@ -0,0 +1,149 @@
+/*************************************************************************\
+* Copyright (c) 2002 The University of Saskatchewan
+* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/* $Revision-Id$ */
+/* Author: Eric Norum Date: 12DEC2001 */
+
+#include
+#include
+#include
+
+#define epicsExportSharedSymbols
+#include "envDefs.h"
+#include "epicsReadline.h"
+
+#define EPICS_COMMANDLINE_LIBRARY_EPICS 0
+#define EPICS_COMMANDLINE_LIBRARY_LIBTECLA 1
+#define EPICS_COMMANDLINE_LIBRARY_READLINE 2
+#define EPICS_COMMANDLINE_LIBRARY_READLINE_CURSES 2
+#define EPICS_COMMANDLINE_LIBRARY_READLINE_NCURSES 2
+
+#ifndef EPICS_COMMANDLINE_LIBRARY
+# define EPICS_COMMANDLINE_LIBRARY EPICS_COMMANDLINE_LIBRARY_EPICS
+#endif
+
+struct osdContext;
+struct readlineContext {
+ FILE *in;
+ char *line;
+ struct osdContext *osd;
+};
+
+static void osdReadlineBegin(struct readlineContext *);
+static char * osdReadline(const char *prompt, struct readlineContext *);
+static void osdReadlineEnd(struct readlineContext *);
+
+#if EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_EPICS
+
+static void osdReadlineBegin(struct readlineContext * c) {}
+static char * osdReadline(const char *prompt, struct readlineContext * c) { return NULL; }
+static void osdReadlineEnd(struct readlineContext * c) {}
+
+#else
+
+# if EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_READLINE
+# include "gnuReadline.c"
+# else
+# include "osdReadline.c"
+# endif
+
+#endif
+
+/*
+ * Create a command-line context
+ */
+void * epicsShareAPI
+epicsReadlineBegin(FILE *in)
+{
+ struct readlineContext *readlineContext = malloc(sizeof *readlineContext);
+
+ if (readlineContext) {
+ readlineContext->in = in;
+ readlineContext->line = NULL;
+ if (!envGetConfigParamPtr(&IOCSH_HISTEDIT_DISABLE))
+ osdReadlineBegin(readlineContext);
+ }
+ return readlineContext;
+}
+
+/*
+ * Read a line of input
+ */
+char * epicsShareAPI
+epicsReadline (const char *prompt, void *context)
+{
+ struct readlineContext *readlineContext = context;
+ FILE *in;
+ char *line;
+ int c; /* char is unsigned on some archs, EOF is -ve */
+ int linelen = 0;
+ int linesize = 50;
+
+ if (readlineContext->osd)
+ return osdReadline(prompt, readlineContext);
+
+ free(readlineContext->line);
+ readlineContext->line = NULL;
+ if ((in = readlineContext->in) == NULL) {
+ in = stdin;
+ if (prompt) {
+ fputs(prompt, stdout);
+ fflush(stdout);
+ }
+ }
+ line = (char *)malloc(linesize);
+ if (line == NULL) {
+ printf("Out of memory!\n");
+ return NULL;
+ }
+ while ((c = getc(in)) != '\n') {
+ if (c == EOF) {
+ if (ferror(in)) {
+ if ((errno == EINTR) || (errno == EPIPE)) {
+ clearerr(in);
+ continue;
+ }
+ }
+ free (line);
+ return NULL;
+ }
+ if ((linelen + 1) >= linesize) {
+ char *cp;
+
+ linesize += 50;
+ cp = (char *)realloc(line, linesize);
+ if (cp == NULL) {
+ printf("Out of memory!\n");
+ free(line);
+ return NULL;
+ }
+ line = cp;
+ }
+ line[linelen++] = c;
+ }
+ line[linelen] = '\0';
+ readlineContext->line = line;
+ return line;
+}
+
+/*
+ * Destroy a command-line context
+ */
+void epicsShareAPI
+epicsReadlineEnd (void *context)
+{
+ if (context) {
+ struct readlineContext *readlineContext = context;
+
+ if (readlineContext->osd)
+ osdReadlineEnd(readlineContext);
+ else
+ free(readlineContext->line);
+ free(readlineContext);
+ }
+}
+
diff --git a/src/libCom/osi/os/default/epicsReadline.h b/src/libCom/osi/epicsReadline.h
similarity index 66%
rename from src/libCom/osi/os/default/epicsReadline.h
rename to src/libCom/osi/epicsReadline.h
index f6ddf2791..1d0e8b761 100644
--- a/src/libCom/osi/os/default/epicsReadline.h
+++ b/src/libCom/osi/epicsReadline.h
@@ -1,14 +1,13 @@
/*************************************************************************\
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-#ifndef _EPICS_READLINE_H
-#define _EPICS_READLINE_H
+#ifndef INC_epicsReadline_H
+#define INC_epicsReadline_H
#ifdef __cplusplus
extern "C" {
@@ -25,4 +24,4 @@ epicsShareFunc void epicsShareAPI epicsReadlineEnd (void *context);
}
#endif
-#endif /* _EPICS_READLINE_H */
+#endif /* INC_epicsReadline_H */
diff --git a/src/libCom/osi/os/RTEMS/osdReadline.c b/src/libCom/osi/os/RTEMS/osdReadline.c
new file mode 100644
index 000000000..6f1e6732c
--- /dev/null
+++ b/src/libCom/osi/os/RTEMS/osdReadline.c
@@ -0,0 +1,70 @@
+/*************************************************************************\
+* Copyright (c) 2002 The University of Saskatchewan
+* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/* $Revision-Id$ */
+/* Author: Eric Norum Date: 12DEC2001 */
+
+/*
+ * This file is included by epicsReadline.c which has already included the
+ * headers stdio.h, stdlib.h, errno.h, envDefs.h and epicsReadline.h
+ */
+
+#include
+#include
+
+struct osdContext {};
+
+/*
+ * Create a command-line context
+ */
+static void
+osdReadlineBegin (struct readlineContext *context)
+{
+ GetLine *gl;
+ long i = 50;
+
+ envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
+ if (i < 0)
+ i = 0;
+
+ gl = new_GetLine(200, i * 40);
+ if (gl) {
+ context->osd = (struct osdContext *) gl;
+ if (context->in)
+ gl_change_terminal(gl, context->in, stdout, NULL);
+ }
+}
+
+/*
+ * Read a line of input
+ */
+static char *
+osdReadline (const char *prompt, struct readlineContext *context)
+{
+ GetLine *gl = (GetLine *) context->osd;
+ char *line;
+
+ line = gl_get_line(gl, prompt ? prompt : "", NULL, -1);
+ if (line) {
+ char *nl = strchr(line, '\n');
+
+ if (nl)
+ *nl = '\0';
+ return line;
+}
+
+/*
+ * Destroy a command-line context
+ */
+static void
+osdReadlineEnd(struct readlineContext *context)
+{
+ GetLine *gl = (GetLine *) context->osd;
+
+ del_GetLine(gl);
+}
+
diff --git a/src/libCom/osi/os/default/epicsReadline.c b/src/libCom/osi/os/default/epicsReadline.c
deleted file mode 100644
index 6c442e376..000000000
--- a/src/libCom/osi/os/default/epicsReadline.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*************************************************************************\
-* Copyright (c) 2002 The University of Saskatchewan
-* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
-* National Laboratory.
-* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
-\*************************************************************************/
-/* $Revision-Id$ */
-/* Author: Eric Norum Date: 12DEC2001 */
-
-#include
-#include
-#include
-
-#define epicsExportSharedSymbols
-#include "envDefs.h"
-#include "epicsReadline.h"
-
-#define EPICS_COMMANDLINE_LIBRARY_EPICS 0
-#define EPICS_COMMANDLINE_LIBRARY_LIBTECLA 1
-#define EPICS_COMMANDLINE_LIBRARY_READLINE 2
-#define EPICS_COMMANDLINE_LIBRARY_READLINE_CURSES 2
-#define EPICS_COMMANDLINE_LIBRARY_READLINE_NCURSES 2
-
-#ifndef EPICS_COMMANDLINE_LIBRARY
-#define EPICS_COMMANDLINE_LIBRARY EPICS_COMMANDLINE_LIBRARY_EPICS
-#endif
-
-
-
-#if EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_LIBTECLA
-#include
-#include
-
-/*
- * Create a command-line context
- */
-void * epicsShareAPI
-epicsReadlineBegin (FILE *in)
-{
- GetLine *gl;
- long i = 50;
-
- envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
- if (i < 0) i = 0;
- gl = new_GetLine(200, i * 40);
- if ((gl != NULL) && (in != NULL))
- gl_change_terminal(gl, in, stdout, NULL);
- return gl;
-}
-
-/*
- * Read a line of input
- */
-char * epicsShareAPI
-epicsReadline (const char *prompt, void *context)
-{
- char *line;
- char *nl;
-
- line = gl_get_line(context, prompt ? prompt : "", NULL, -1);
- if ((line != NULL) && ((nl = strchr(line, '\n')) != NULL))
- *nl = '\0';
- return line;
-}
-
-/*
- * Destroy a command-line context
- */
-void epicsShareAPI
-epicsReadlineEnd(void *context)
-{
- del_GetLine(context);
-}
-
-
-#elif EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_READLINE
-
-#include
-#include
-
-struct readlineContext {
- FILE *in;
- char *line;
-};
-
-/*
- * Create a command-line context
- */
-void * epicsShareAPI
-epicsReadlineBegin(FILE *in)
-{
- struct readlineContext *readlineContext;
-
- readlineContext = malloc(sizeof *readlineContext);
- if (readlineContext != NULL) {
- readlineContext->in = in;
- readlineContext->line = NULL;
- if (in == NULL) {
- long i = 50;
-
- envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
- if (i < 0) i = 0;
- stifle_history (i);
- rl_bind_key ('\t', rl_insert);
- }
- }
- return readlineContext;
-}
-
-/*
- * Read a line of input
- */
-char * epicsShareAPI
-epicsReadline (const char *prompt, void *context)
-{
- struct readlineContext *readlineContext = context;
-
- int c; /* char is unsigned on some archs, EOF is -ve */
- char *line = NULL;
- int linelen = 0;
- int linesize = 50;
-
- free (readlineContext->line);
- readlineContext->line = NULL;
- if (readlineContext->in == NULL) {
- line = readline (prompt);
- }
- else {
- line = (char *)malloc (linesize * sizeof *line);
- if (line == NULL) {
- printf ("Out of memory!\n");
- return NULL;
- }
- if (prompt) {
- fputs (prompt, stdout);
- fflush (stdout);
- }
- while ((c = getc (readlineContext->in)) != '\n') {
- if (c == EOF) {
- free (line);
- line = NULL;
- break;
- }
- if ((linelen + 1) >= linesize) {
- char *cp;
-
- linesize += 50;
- cp = (char *)realloc (line, linesize * sizeof *line);
- if (cp == NULL) {
- printf ("Out of memory!\n");
- free (line);
- line = NULL;
- break;
- }
- line = cp;
- }
- line[linelen++] = c;
- }
- if (line)
- line[linelen] = '\0';
- }
- readlineContext->line = line;
- if (line && line[0] != '\0')
- add_history (line);
- return line;
-}
-
-/*
- * Destroy a command-line context
- */
-void epicsShareAPI
-epicsReadlineEnd (void *context)
-{
- struct readlineContext *readlineContext = context;
-
- if (readlineContext) {
- free(readlineContext->line);
- free(readlineContext);
- }
-}
-
-
-#elif EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_EPICS
-
-#if defined(vxWorks)
-
-#include
-#include
-#define LEDLIB_LINESIZE 1000
-
-#ifndef _WRS_VXWORKS_MAJOR
-typedef int LED_ID;
-#endif
-
-struct readlineContext {
- LED_ID ledId;
- char line[LEDLIB_LINESIZE];
- FILE *in;
-};
-
-/*
- * Create a command-line context
- */
-void * epicsShareAPI
-epicsReadlineBegin(FILE *in)
-{
- struct readlineContext *readlineContext;
-
- readlineContext = malloc(sizeof *readlineContext);
- if (readlineContext != NULL) {
- readlineContext->ledId = (LED_ID) ERROR;
- readlineContext->in = in;
- if (in == NULL) {
- long i = 50;
-
- envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
- if (i < 1) i = 1;
- readlineContext->ledId = ledOpen(fileno(stdin), fileno(stdout), i);
- if (readlineContext->ledId == (LED_ID) ERROR) {
- readlineContext->in = stdin;
- printf("Warning -- Unabled to allocate space for command-line history.\n");
- printf("Warning -- Command-line editting disabled.\n");
- }
- }
- }
- return readlineContext;
-}
-
-/*
- * Read a line of input
- */
-char * epicsShareAPI
-epicsReadline (const char *prompt, void *context)
-{
- struct readlineContext *readlineContext = context;
- int i;
-
- if (prompt) {
- fputs(prompt, stdout);
- fflush(stdout);
- }
- if (readlineContext->ledId != (LED_ID) ERROR) {
- i = ledRead(readlineContext->ledId, readlineContext->line, LEDLIB_LINESIZE-1);
- if (i < 0)
- return NULL;
- }
- else {
- if (fgets(readlineContext->line, LEDLIB_LINESIZE, readlineContext->in) == NULL)
- return NULL;
- i = strlen(readlineContext->line);
- }
- if ((i >= 1) && (readlineContext->line[i-1] == '\n'))
- readlineContext->line[i-1] = '\0';
- else
- readlineContext->line[i] = '\0';
- return readlineContext->line;
-}
-
-/*
- * Destroy a command-line context
- */
-void epicsShareAPI
-epicsReadlineEnd (void *context)
-{
- struct readlineContext *readlineContext = context;
-
- if (readlineContext) {
- if (readlineContext->ledId != (LED_ID) ERROR)
- ledClose(readlineContext->ledId);
- free(readlineContext);
- }
-}
-
-#else /* !vxWorks */
-
-struct readlineContext {
- FILE *in;
- char *line;
-};
-
-/*
- * Create a command-line context
- */
-void * epicsShareAPI
-epicsReadlineBegin(FILE *in)
-{
- struct readlineContext *readlineContext;
-
- readlineContext = malloc(sizeof *readlineContext);
- if (readlineContext != NULL) {
- readlineContext->in = in;
- readlineContext->line = NULL;
- }
- return readlineContext;
-}
-
-/*
- * Read a line of input
- */
-char * epicsShareAPI
-epicsReadline (const char *prompt, void *context)
-{
- struct readlineContext *readlineContext = context;
-
- int c; /* char is unsigned on some archs, EOF is -ve */
- char *line = NULL;
- int linelen = 0;
- int linesize = 50;
- FILE *in;
-
- free (readlineContext->line);
- readlineContext->line = NULL;
- if ((in = readlineContext->in) == NULL) {
- in = stdin;
- if (prompt != NULL) {
- fputs (prompt, stdout);
- fflush (stdout);
- }
- }
- line = (char *)malloc (linesize * sizeof *line);
- if (line == NULL) {
- printf ("Out of memory!\n");
- return NULL;
- }
- while ((c = getc (in)) != '\n') {
- if (c == EOF) {
- if (ferror(in)) {
- if ((errno == EINTR) || (errno == EPIPE)) {
- clearerr(in);
- continue;
- }
- }
- free (line);
- return NULL;
- }
- if ((linelen + 1) >= linesize) {
- char *cp;
-
- linesize += 50;
- cp = (char *)realloc (line, linesize * sizeof *line);
- if (cp == NULL) {
- printf ("Out of memory!\n");
- free (line);
- return NULL;
- }
- line = cp;
- }
- line[linelen++] = c;
- }
- line[linelen] = '\0';
- readlineContext->line = line;
- return line;
-}
-
-/*
- * Destroy a command-line context
- */
-void epicsShareAPI
-epicsReadlineEnd (void *context)
-{
- struct readlineContext *readlineContext = context;
-
- if (readlineContext) {
- free(readlineContext->line);
- free(readlineContext);
- }
-}
-
-#endif /* !vxWorks */
-
-#else
-
-# error "Unsupported EPICS_COMMANDLINE_LIBRARY"
-
-#endif
diff --git a/src/libCom/osi/os/default/gnuReadline.c b/src/libCom/osi/os/default/gnuReadline.c
new file mode 100644
index 000000000..d24589e77
--- /dev/null
+++ b/src/libCom/osi/os/default/gnuReadline.c
@@ -0,0 +1,106 @@
+/*************************************************************************\
+* Copyright (c) 2002 The University of Saskatchewan
+* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/* $Revision-Id$ */
+/* Author: Eric Norum Date: 12DEC2001 */
+
+/*
+ * This file is included by epicsReadline.c which has already included the
+ * headers stdio.h, stdlib.h, errno.h, envDefs.h and epicsReadline.h
+ */
+
+#include
+#include
+
+struct osdContext {} present;
+
+/*
+ * Create a command-line context
+ */
+static void
+osdReadlineBegin(struct readlineContext *context)
+{
+ context->osd = &present;
+ if (context->in == NULL) {
+ long i = 50;
+
+ envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
+ if (i < 0)
+ i = 0;
+ stifle_history(i);
+ rl_bind_key('\t', rl_insert);
+ }
+}
+
+/*
+ * Read a line of input
+ */
+static char *
+osdReadline (const char *prompt, struct readlineContext *context)
+{
+ char *line;
+
+ free(context->line);
+ context->line = NULL;
+ if (context->in == NULL) {
+ line = readline(prompt);
+ }
+ else {
+ int c; /* char is unsigned on some archs; EOF is -ve */
+ int linelen = 0;
+ int linesize = 50;
+
+ line = malloc(linesize);
+ if (line == NULL) {
+ printf("Out of memory!\n");
+ return NULL;
+ }
+ if (prompt) {
+ fputs(prompt, stdout);
+ fflush(stdout);
+ }
+ while ((c = getc(context->in)) != '\n') {
+ if (c == EOF) {
+ free(line);
+ line = NULL;
+ break;
+ }
+ if ((linelen + 1) >= linesize) {
+ char *cp;
+
+ linesize += 50;
+ cp = (char *)realloc(line, linesize);
+ if (cp == NULL) {
+ printf ("Out of memory!\n");
+ free(line);
+ line = NULL;
+ break;
+ }
+ line = cp;
+ }
+ line[linelen++] = c;
+ }
+ if (line)
+ line[linelen] = '\0';
+ }
+ context->line = line;
+ if (line && *line)
+ add_history(line);
+ return line;
+}
+
+/*
+ * Destroy a command-line context
+ */
+static void
+osdReadlineEnd (struct readlineContext *context)
+{
+ if (context->osd) {
+ free(context->line);
+ }
+}
+
diff --git a/src/libCom/osi/os/vxWorks/osdReadline.c b/src/libCom/osi/os/vxWorks/osdReadline.c
new file mode 100644
index 000000000..e0208893e
--- /dev/null
+++ b/src/libCom/osi/os/vxWorks/osdReadline.c
@@ -0,0 +1,101 @@
+/*************************************************************************\
+* Copyright (c) 2002 The University of Saskatchewan
+* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/* $Revision-Id$ */
+/* Author: Eric Norum Date: 12DEC2001 */
+
+/*
+ * This file is included by epicsReadline.c which has already included the
+ * headers stdio.h, stdlib.h, errno.h, envDefs.h and epicsReadline.h
+ */
+
+#include
+#include
+
+/* FIXME: Remove line-lenth limitation */
+#define LEDLIB_LINESIZE 1000
+
+#ifndef _WRS_VXWORKS_MAJOR
+typedef int LED_ID;
+#endif
+
+struct osdContext {
+ LED_ID ledId;
+ char line[LEDLIB_LINESIZE];
+};
+
+/*
+ * Create a command-line context
+ */
+static void
+osdReadlineBegin(struct readlineContext *context)
+{
+ struct osdContext osd = malloc(sizeof *osd);
+
+ if (osd != NULL) {
+ osd->ledId = (LED_ID) ERROR;
+ if (context->in == NULL) {
+ long i = 50;
+
+ envGetLongConfigParam(&IOCSH_HISTSIZE, &i);
+ if (i < 1)
+ i = 1;
+
+ osd->ledId = ledOpen(fileno(stdin), fileno(stdout), i);
+ if (osd->ledId == (LED_ID) ERROR) {
+ context->in = stdin;
+ printf("Warning -- Unabled to allocate space for command-line history.\n");
+ printf("Warning -- Command-line editting disabled.\n");
+ }
+ }
+ context->osd = osd;
+ }
+}
+
+/*
+ * Read a line of input
+ */
+static char *
+osdReadline (const char *prompt, struct readlineContext *context)
+{
+ struct osdContext *osd = context->osd;
+ int i;
+
+ if (prompt) {
+ fputs(prompt, stdout);
+ fflush(stdout);
+ }
+ if (osd->ledId != (LED_ID) ERROR) {
+ i = ledRead(osd->ledId, osd->line, LEDLIB_LINESIZE-1);
+ if (i < 0)
+ return NULL;
+ }
+ else {
+ if (fgets(osd->line, LEDLIB_LINESIZE, context->in) == NULL)
+ return NULL;
+ i = strlen(osd->line);
+ }
+ if ((i >= 1) && (osd->line[i-1] == '\n'))
+ osd->line[i-1] = '\0';
+ else
+ osd->line[i] = '\0';
+ return osd->line;
+}
+
+/*
+ * Destroy a command-line context
+ */
+static void
+osdReadlineEnd (struct readlineContext *context)
+{
+ LED_ID ledId = context->osd->ledId;
+
+ if (ledId != (LED_ID) ERROR)
+ ledClose(ledId);
+ free(context->osd);
+}
+