libCom: epicsReadline refactoring

This commit is contained in:
Andrew Johnson
2015-06-29 17:45:18 -05:00
parent 155017bf09
commit 3a54e97758
9 changed files with 447 additions and 383 deletions
+3
View File
@@ -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
+11
View File
@@ -20,6 +20,17 @@
-->
<h3>Refactoring of epicsReadline</h3>
<p>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 <tt>IOCSH_HISTEDIT_DISABLE</tt>
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.</p>
<h3>Callback subsystem API</h3>
<p>Added a new macro <tt>callbackGetPriority(prio, callback)</tt> to the
+1
View File
@@ -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[];
+149
View File
@@ -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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#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);
}
}
@@ -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 */
+70
View File
@@ -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 <string.h>
#include <libtecla.h>
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);
}
-376
View File
@@ -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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#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 <libtecla.h>
#include <string.h>
/*
* 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 <readline/readline.h>
#include <readline/history.h>
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 <string.h>
#include <ledLib.h>
#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
+106
View File
@@ -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 <readline/readline.h>
#include <readline/history.h>
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);
}
}
+101
View File
@@ -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 <string.h>
#include <ledLib.h>
/* 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);
}