2008-04-03 Chris Johns <chrisj@rtems.org>

* libfs/src/nfsclient/src/librtemsNfs.h,
	libfs/src/nfsclient/src/nfs.c: Remove CEXP references. CEXP is
	external to RTEMS and even if in the cpukit it should not cross
	reference in this way.
	* libmisc/shell/shell_getchar.c: New. Taken from the monitor.
	* libmisc/Makefile.am: Add shell_getchar.c and clean up a little
	in the shell area.
	* libmisc/shell/shell.c, libmisc/shell/shell.h: Add line editting
	support.
This commit is contained in:
Chris Johns
2008-04-03 03:13:24 +00:00
parent ffd1050791
commit ea90df234a
7 changed files with 652 additions and 128 deletions

View File

@@ -1,3 +1,15 @@
2008-04-03 Chris Johns <chrisj@rtems.org>
* libfs/src/nfsclient/src/librtemsNfs.h,
libfs/src/nfsclient/src/nfs.c: Remove CEXP references. CEXP is
external to RTEMS and even if in the cpukit it should not cross
reference in this way.
* libmisc/shell/shell_getchar.c: New. Taken from the monitor.
* libmisc/Makefile.am: Add shell_getchar.c and clean up a little
in the shell area.
* libmisc/shell/shell.c, libmisc/shell/shell.h: Add line editting
support.
2008-03-29 Chris Johns <chrisj@rtems.org>
* librpc/include/rpc/clnt.h: Added the missing __BEGIN_DECLS as

View File

@@ -70,11 +70,6 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef HAVE_CEXP_H
#include <cexpHelp.h>
#endif
/* RPCIO driver interface.
* If you need RPCIO for other purposes than NFS
* you may want to include <rpcio.h>

View File

@@ -68,17 +68,11 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <nfs_prot.h>
#include <mount_prot.h>
#include "rpcio.h"
#ifdef HAVE_CEXP_H
#include <cexpHelp.h>
#endif
/* Configurable parameters */
/* Estimated average length of a filename (including terminating 0).

View File

@@ -71,16 +71,16 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \
shell/main_echo.c shell/main_exit.c shell/main_help.c shell/main_id.c \
shell/main_logoff.c shell/main_ls.c shell/main_mallocinfo.c \
shell/main_mdump.c shell/main_medit.c shell/main_mfill.c \
shell/main_mkdir.c shell/main_mount.c $(shell_mount_fs) \
shell/main_mkdir.c shell/main_mount.c \
shell/main_mount_msdos.c shell/main_mmove.c shell/main_msdosfmt.c \
shell/main_mwdump.c shell/main_perioduse.c shell/main_pwd.c \
shell/main_rm.c shell/main_rmdir.c shell/main_sleep.c \
shell/main_stackuse.c shell/main_tty.c shell/main_umask.c \
shell/main_unmount.c shell/main_blksync.c shell/main_whoami.c \
shell/shell.c shell/shell_cmdset.c shell/shellconfig.c shell/shellconfig.h \
shell/shell.h shell/shell_makeargs.c shell/str2int.c shell/write_file.c \
shell/utils-cp.c shell/err.c shell/errx.c shell/verr.c shell/verrx.c \
shell/vwarn.c shell/vwarnx.c shell/warn.c shell/warnx.c \
shell/shell.c shell/shell_cmdset.c shell/shell_getchar.c shell/shellconfig.c \
shell/shellconfig.h shell/shell.h shell/shell_makeargs.c shell/str2int.c \
shell/write_file.c shell/utils-cp.c shell/err.c shell/errx.c shell/verr.c \
shell/verrx.c shell/vwarn.c shell/vwarnx.c shell/warn.c shell/warnx.c \
shell/fts.c shell/print_heapinfo.c shell/main_wkspaceinfo.c \
shell/shell_script.c
if LIBNETWORKING

View File

@@ -79,6 +79,286 @@ rtems_shell_env_t *rtems_shell_init_env(
/*
* Get a line of user input with modest features
*/
int rtems_shell_line_editor(
char *cmds[],
int count,
int size,
const char *prompt,
FILE *in,
FILE *out
)
{
unsigned int extended_key;
char c;
int col;
int last_col;
int output;
char line[size];
char new_line[size];
int up;
int cmd = -1;
int inserting = 1;
output = (out && isatty(fileno(in)));
col = last_col = 0;
tcdrain(fileno(in));
if (out)
tcdrain(fileno(out));
if (output && prompt)
fprintf(out, "\r%s", prompt);
line[0] = 0;
new_line[0] = 0;
for (;;) {
if (output)
fflush(out);
extended_key = rtems_shell_getchar(in);
if (extended_key == EOF)
return -2;
c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
/*
* Make the extended_key usable as a boolean.
*/
extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
up = 0;
if (extended_key)
{
switch (c)
{
case RTEMS_SHELL_KEYS_END:
if (output)
fprintf(out,line + col);
col = (int) strlen (line);
break;
case RTEMS_SHELL_KEYS_HOME:
if (output) {
if (prompt)
fprintf(out,"\r%s", prompt);
}
col = 0;
break;
case RTEMS_SHELL_KEYS_LARROW:
if (col > 0)
{
col--;
if (output)
fputc('\b', out);
}
break;
case RTEMS_SHELL_KEYS_RARROW:
if ((col < size) && (line[col] != '\0'))
{
if (output)
fprintf(out, "%c", line[col]);
col++;
}
break;
case RTEMS_SHELL_KEYS_UARROW:
if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) {
if (output)
fputc('\x7', out);
break;
}
up = 1;
/* drop through */
case RTEMS_SHELL_KEYS_DARROW:
{
int last_cmd = cmd;
int clen = strlen (line);
if (prompt)
clen += strlen(prompt);
if (up) {
cmd++;
} else {
if (cmd < 0) {
if (output)
fprintf(out, "\x7");
break;
}
else
cmd--;
}
if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0))
memcpy (new_line, line, size);
if (cmd < 0)
memcpy (line, new_line, size);
else
memcpy (line, cmds[cmd], size);
col = strlen (line);
if (output) {
fprintf(out,"\r%*c", clen, ' ');
fprintf(out,"\r%s%s", prompt, line);
}
else {
if (output)
fputc('\x7', out);
}
}
break;
case RTEMS_SHELL_KEYS_DEL:
if (line[col] != '\0')
{
int end;
int bs;
strcpy (&line[col], &line[col + 1]);
if (output) {
fprintf(out,"\r%s%s ", prompt, line);
end = (int) strlen (line);
for (bs = 0; bs < ((end - col) + 1); bs++)
fputc('\b', out);
}
}
break;
case RTEMS_SHELL_KEYS_INS:
inserting = inserting ? 0 : 1;
break;
}
}
else
{
switch (c)
{
case 1:/*Control-a*/
if (output) {
if (prompt)
fprintf(out,"\r%s", prompt);
}
col = 0;
break;
case 5:/*Control-e*/
if (output)
fprintf(out,line + col);
col = (int) strlen (line);
break;
case 11:/*Control-k*/
if (line[col]) {
if (output) {
int end = strlen(line);
int bs;
fprintf(out,"%*c", end - col, ' ');
for (bs = 0; bs < (end - col); bs++)
fputc('\b', out);
}
line[col] = '\0';
}
break;
case 0x04:/*Control-d*/
if (strlen(line))
break;
case EOF:
if (output)
fputc(out, '\n');
return -2;
case '\f':
if (output) {
int end;
int bs;
fputc('\f',out);
fprintf(out,"\r%s%s", prompt, line);
end = (int) strlen (line);
for (bs = 0; bs < (end - col); bs++)
fputc('\b', out);
}
break;
case '\b':
case '\x7e':
case '\x7f':
if (col > 0)
{
int bs;
col--;
strcpy (line + col, line + col + 1);
if (output) {
fprintf(out,"\b%s \b", line + col);
for (bs = 0; bs < ((int) strlen (line) - col); bs++)
fputc('\b', out);
}
}
break;
case '\n':
case '\r':
{
/*
* Process the command.
*/
if (output)
fprintf(out,"\n");
/*
* Only process the command if we have a command and it is not
* repeated in the history.
*/
if (strlen(line) == 0) {
cmd = -1;
} else {
if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) {
if (count > 1)
memmove(cmds[1], cmds[0], (count - 1) * size);
memmove (cmds[0], line, size);
cmd = 0;
}
}
}
return cmd;
default:
if ((col < (size - 1)) && (c >= ' ') && (c <= 'z')) {
int end = strlen (line);
if (inserting && (col < end) && (end < size)) {
int ch, bs;
for (ch = end + 1; ch > col; ch--)
line[ch] = line[ch - 1];
if (output) {
fprintf(out, line + col);
for (bs = 0; bs < (end - col + 1); bs++)
fputc('\b', out);
}
}
line[col++] = c;
if (col > end)
line[col] = '\0';
if (output)
fputc(c, out);
}
break;
}
}
}
return -2;
}
int rtems_shell_scanline(
char *line,
int size,
@@ -104,16 +384,8 @@ int rtems_shell_scanline(
line[col] = 0;
c = fgetc(in);
switch (c) {
case 0x04:/*Control-d*/
if (col)
break;
case EOF:
return 0;
case '\f':
if (doEcho)
fputc('\f',out);
case 0x03:/*Control-C*/
line[0] = 0;
case '\n':
case '\r':
if (doEcho)
@@ -363,19 +635,39 @@ rtems_task rtems_shell_task(rtems_task_argument task_argument)
rtems_task_delete( RTEMS_SELF );
}
#define RTEMS_SHELL_MAXIMUM_ARGUMENTS 128
void rtems_shell_get_prompt(
rtems_shell_env_t *shell_env,
char *prompt,
int size)
{
char curdir[256];
/* XXX: show_prompt user adjustable */
getcwd(curdir,sizeof(curdir));
snprintf(prompt, size - 1, "%s%s[%s] %c ",
((shell_env->taskname) ? shell_env->taskname : ""),
((shell_env->taskname) ? " " : ""),
curdir,
geteuid()?'$':'#');
}
#define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128)
#define RTEMS_SHELL_CMD_SIZE (128)
#define RTEMS_SHELL_CMD_COUNT (32)
#define RTEMS_SHELL_PROMPT_SIZE (128)
rtems_boolean rtems_shell_main_loop(
rtems_shell_env_t *shell_env_arg
)
)
{
rtems_shell_env_t *shell_env;
rtems_shell_cmd_t *shell_cmd;
rtems_status_code sc;
struct termios term;
char curdir[256];
char cmd[256];
char last_cmd[256]; /* to repeat 'r' */
char *prompt = NULL;
int cmd;
int cmd_count = 1; /* assume a script and so only 1 command line */
char *cmds[RTEMS_SHELL_CMD_COUNT];
int argc;
char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
rtems_boolean result = TRUE;
@@ -384,6 +676,8 @@ rtems_boolean rtems_shell_main_loop(
FILE *stdinToClose = NULL;
FILE *stdoutToClose = NULL;
memset(cmds, 0, sizeof(cmds));
rtems_shell_initialize_command_set();
shell_env =
@@ -404,8 +698,8 @@ rtems_boolean rtems_shell_main_loop(
setuid(0);
setgid(0);
rtems_current_user_env->euid =
rtems_current_user_env->egid = 0;
rtems_current_user_env->euid = rtems_current_user_env->egid = 0;
fileno(stdout);
@@ -460,12 +754,33 @@ rtems_boolean rtems_shell_main_loop(
"shell:cannot set terminal attributes(%s)\n",shell_env->devname);
}
}
cmd_count = RTEMS_SHELL_CMD_COUNT;
prompt = malloc(RTEMS_SHELL_PROMPT_SIZE);
if (!prompt)
fprintf(stderr,
"shell:cannot allocate prompt memory\n");
}
setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/
rtems_shell_initialize_command_set();
/*
* Allocate the command line buffers.
*/
cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE);
if (!cmds[0]) {
fprintf(stderr, "no memory for command line buffers\n" );
}
else {
memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
for (cmd = 1; cmd < cmd_count; cmd++) {
cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE;
}
do {
/* Set again root user and root filesystem, side effect of set_priv..*/
sc = rtems_libio_set_private_env();
@@ -476,8 +791,7 @@ rtems_boolean rtems_shell_main_loop(
}
if (input_file || !rtems_shell_login(stdin,stdout)) {
const char *c;
strcpy(last_cmd,"");
strcpy(cmd,"");
memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
if (!input_file) {
rtems_shell_cat_file(stdout,"/etc/motd");
fprintf(stdout, "\n"
@@ -485,28 +799,34 @@ rtems_boolean rtems_shell_main_loop(
__DATE__". 'help' to list commands.\n",
shell_env->devname);
}
chdir("/"); /* XXX: chdir to getpwent homedir */
shell_env->exit_shell = FALSE;
for (;;) {
int cmd;
/* Prompt section */
if (!input_file) {
/* XXX: show_prompt user adjustable */
getcwd(curdir,sizeof(curdir));
fprintf(stdout, "%s%s[%s] %c ",
((shell_env->taskname) ? shell_env->taskname : ""),
((shell_env->taskname) ? " " : ""),
curdir,
geteuid()?'$':'#');
if (prompt) {
rtems_shell_get_prompt(shell_env, prompt,
RTEMS_SHELL_PROMPT_SIZE);
}
/* getcmd section */
if (!rtems_shell_scanline(cmd,sizeof(cmd),stdin,stdout)) {
cmd = rtems_shell_line_editor(cmds, cmd_count,
RTEMS_SHELL_CMD_SIZE, prompt,
stdin, stdout);
if (cmd == -1)
continue; /* empty line */
if (cmd == -2)
break; /*EOF*/
}
line++;
/* evaluate cmd section */
c = cmd;
c = cmds[cmd];
while (*c) {
if (!isblank(*c))
break;
@@ -517,23 +837,16 @@ rtems_boolean rtems_shell_main_loop(
continue;
if (*c == '#') { /* comment character */
cmd[0] = 0;
cmds[cmd][0] = 0;
continue;
}
if (!strcmp(cmd,"e")) { /* edit last command */
strcpy(cmd,last_cmd);
continue;
} else if (!strcmp(cmd,"r")) { /* repeat last command */
strcpy(cmd,last_cmd);
} else if (!strcmp(cmd,"bye") || !strcmp(cmd,"exit")) {
if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
fprintf(stdout, "Shell exiting\n" );
break;
} else if (!strcmp(cmd,"shutdown")) { /* exit application */
} else if (!strcmp(cmds[cmd],"shutdown")) { /* exit application */
fprintf(stdout, "System shutting down at user request\n" );
exit(0);
} else if (!strcmp(cmd,"")) { /* only for get a new prompt */
strcpy(last_cmd,cmd);
}
/* exec cmd section */
@@ -543,28 +856,31 @@ rtems_boolean rtems_shell_main_loop(
* Run in a new shell task background. (unix &)
* Resuming. A little bash.
*/
if (!rtems_shell_make_args(cmd, &argc, argv,
if (!rtems_shell_make_args(cmds[cmd], &argc, argv,
RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
shell_cmd = rtems_shell_lookup_cmd(argv[0]);
if ( argv[0] == NULL ) {
shell_env->errorlevel = -1;
} else if ( shell_cmd == NULL ) {
shell_env->errorlevel = rtems_shell_script_file( argc, argv );
shell_env->errorlevel = rtems_shell_script_file(argc, argv);
} else {
shell_env->errorlevel = shell_cmd->command(argc, argv);
}
}
/* end exec cmd section */
/* end exec cmd section */
if (shell_env->exit_shell)
break;
strcpy(last_cmd, cmd);
cmd[0] = 0;
}
fflush( stdout );
fflush( stderr );
}
} while (result && shell_env->forever);
free (cmds[0]);
}
if ( stdinToClose )
fclose( stdinToClose );
if ( stdoutToClose )

View File

@@ -29,6 +29,31 @@
extern "C" {
#endif
/*
* Some key labels to define special keys.
*/
#define RTEMS_SHELL_KEYS_EXTENDED (0x8000)
#define RTEMS_SHELL_KEYS_NORMAL_MASK (0x00ff)
#define RTEMS_SHELL_KEYS_INS (0)
#define RTEMS_SHELL_KEYS_DEL (1)
#define RTEMS_SHELL_KEYS_UARROW (2)
#define RTEMS_SHELL_KEYS_DARROW (3)
#define RTEMS_SHELL_KEYS_LARROW (4)
#define RTEMS_SHELL_KEYS_RARROW (5)
#define RTEMS_SHELL_KEYS_HOME (6)
#define RTEMS_SHELL_KEYS_END (7)
#define RTEMS_SHELL_KEYS_F1 (8)
#define RTEMS_SHELL_KEYS_F2 (9)
#define RTEMS_SHELL_KEYS_F3 (10)
#define RTEMS_SHELL_KEYS_F4 (11)
#define RTEMS_SHELL_KEYS_F5 (12)
#define RTEMS_SHELL_KEYS_F6 (13)
#define RTEMS_SHELL_KEYS_F7 (14)
#define RTEMS_SHELL_KEYS_F8 (15)
#define RTEMS_SHELL_KEYS_F9 (16)
#define RTEMS_SHELL_KEYS_F10 (17)
typedef int (*rtems_shell_command_t)(int argc,char * argv[]);
struct rtems_shell_cmd_tt;
@@ -48,6 +73,12 @@ typedef struct {
char *alias;
} rtems_shell_alias_t;
/*
* The return value has RTEMS_SHELL_KEYS_EXTENDED set if the key
* is extended, ie a special key.
*/
unsigned int rtems_shell_getchar(FILE *in);
rtems_shell_cmd_t * rtems_shell_lookup_cmd(char * cmd);
rtems_shell_cmd_t *rtems_shell_add_cmd_struct(

View File

@@ -0,0 +1,176 @@
/*
*
* Handle keys for the shell.
*
* Author:
*
* Chris Johns (chrisj@rtems.org)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <time.h>
#include <rtems.h>
#include <rtems/error.h>
#include <rtems/system.h>
#include <rtems/shell.h>
#include <rtems/shellconfig.h>
#include "internal.h"
/*
* Taken from the monitor code.
*/
/*
* Translation tables. Not sure if this is the best way to
* handle this, how-ever I wish to avoid the overhead of
* including a more complete and standard environment such
* as ncurses.
*/
struct translation_table
{
char expecting;
struct translation_table *branch;
unsigned int key;
};
static struct translation_table trans_one[] =
{
{ '\x7e', 0, RTEMS_SHELL_KEYS_HOME },
{ 0, 0, 0 }
};
static struct translation_table trans_two[] =
{
{ '~', 0, RTEMS_SHELL_KEYS_INS },
{ 0, 0, 0 }
};
static struct translation_table trans_three[] =
{
{ '~', 0, RTEMS_SHELL_KEYS_DEL },
{ 0, 0, 0 }
};
static struct translation_table trans_tab_csi[] =
{
{ '1', trans_one, 0 },
{ '2', trans_two, 0 },
{ '3', trans_three, 0 },
{ 'A', 0, RTEMS_SHELL_KEYS_UARROW },
{ 'B', 0, RTEMS_SHELL_KEYS_DARROW },
{ 'D', 0, RTEMS_SHELL_KEYS_LARROW },
{ 'C', 0, RTEMS_SHELL_KEYS_RARROW },
{ 'F', 0, RTEMS_SHELL_KEYS_END },
{ 'H', 0, RTEMS_SHELL_KEYS_HOME },
{ 0, 0, 0 }
};
static struct translation_table trans_tab_O[] =
{
{ '1', 0, RTEMS_SHELL_KEYS_F1 },
{ '2', 0, RTEMS_SHELL_KEYS_F2 },
{ '3', 0, RTEMS_SHELL_KEYS_F3 },
{ '4', 0, RTEMS_SHELL_KEYS_F4 },
{ '5', 0, RTEMS_SHELL_KEYS_F5 },
{ '6', 0, RTEMS_SHELL_KEYS_F6 },
{ '7', 0, RTEMS_SHELL_KEYS_F7 },
{ '8', 0, RTEMS_SHELL_KEYS_F8 },
{ '9', 0, RTEMS_SHELL_KEYS_F9 },
{ ':', 0, RTEMS_SHELL_KEYS_F10 },
{ 'F', 0, RTEMS_SHELL_KEYS_END },
{ 'P', 0, RTEMS_SHELL_KEYS_F1 },
{ 'Q', 0, RTEMS_SHELL_KEYS_F2 },
{ 'R', 0, RTEMS_SHELL_KEYS_F3 },
{ 'S', 0, RTEMS_SHELL_KEYS_F4 },
{ 'T', 0, RTEMS_SHELL_KEYS_F5 },
{ 'U', 0, RTEMS_SHELL_KEYS_F6 },
{ 'V', 0, RTEMS_SHELL_KEYS_F7 },
{ 'W', 0, RTEMS_SHELL_KEYS_F8 },
{ 'X', 0, RTEMS_SHELL_KEYS_F9 },
{ 'Y', 0, RTEMS_SHELL_KEYS_F10 },
{ 0, 0, 0 }
};
static struct translation_table trans_tab[] =
{
{ '[', trans_tab_csi, 0 }, /* CSI command sequences */
{ 'O', trans_tab_O, 0 }, /* O are the fuction keys */
{ 0, 0, 0 }
};
/*
* Perform a basic tranlation for some ANSI/VT100 key codes.
* This code could do with a timeout on the ESC as it is
* now lost from the input stream. It is not* used by the
* line editor below so considiered not worth the effort.
*/
unsigned int
rtems_shell_getchar (FILE *in)
{
struct translation_table *translation = 0;
for (;;)
{
char c = fgetc (in);
if (c == EOF)
return EOF;
if (c == 27)
translation = trans_tab;
else
{
/*
* If no translation happing just pass through
* and return the key.
*/
if (translation)
{
/*
* Scan the current table for the key, and if found
* see if this key is a fork. If so follow it and
* wait else return the extended key.
*/
int index = 0;
int branched = 0;
while ((translation[index].expecting != '\0') ||
(translation[index].key != '\0'))
{
if (translation[index].expecting == c)
{
/*
* A branch is take if more keys are to come.
*/
if (translation[index].branch == 0)
return RTEMS_SHELL_KEYS_EXTENDED | translation[index].key;
else
{
translation = translation[index].branch;
branched = 1;
break;
}
}
index++;
}
/*
* Who knows what these keys are, just drop them.
*/
if (!branched)
translation = 0;
}
else
return c;
}
}
}