Index: cpukit/libmisc/shell/.cvsignore
===================================================================
--- cpukit/libmisc/shell/.cvsignore	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/.cvsignore	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
Index: cpukit/libmisc/shell/Makefile.am
===================================================================
--- cpukit/libmisc/shell/Makefile.am	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/Makefile.am	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,44 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+include_rtemsdir = $(includedir)/rtems
+
+LIBNAME = libshell-tmp
+LIB = $(ARCH)/$(LIBNAME).a
+
+C_FILES = cmds.c shell.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+include_rtems_HEADERS = shell.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+$(PROJECT_INCLUDE)/rtems:
+	@$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+	$(INSTALL_DATA) $< $@
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(LIB): $(OBJS)
+	$(make-library)
+
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems \
+    $(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/rtems/%)
+
+all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) $(LIB)
+
+.PRECIOUS: $(LIB)
+
+EXTRA_DIST = README shell.c cmds.c shell.h
+
+include $(top_srcdir)/../../../automake/local.am
Index: cpukit/libmisc/shell/README
===================================================================
--- cpukit/libmisc/shell/README	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/README	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,28 @@
+#
+#  $Id$
+#
+
+This directory contains a shell user extension
+primary features:
+
+   + create a user shell terminal task.
+
+This code has not been extensively tested.  It is provided as a tool
+for RTEMS users to open more shell terminal.
+Suggestions and comments are appreciated.
+
+NOTES:
+
+1.  printf() & getchar() works but you can't use 
+    0,1,2 like fildes. You need to use fileno(stdin),fileno(stdout),...
+    
+2.  You only need a termios dev to start a new session, add your new commands
+    and enjoy it.
+
+
+
+FUTURE:
+
+1.  Adding new commands in cmds.c to give file manegement to shell.
+
+2.  Create a telnetd daemon. (pseudo-terminal needed)
Index: cpukit/libmisc/shell/cmds.c
===================================================================
--- cpukit/libmisc/shell/cmds.c	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/cmds.c	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,479 @@
+/*
+ * Author: Fernando RUIZ CASAS
+ *
+ *  Work: fernando.ruiz@ctv.es
+ *  Home: correo@fernando-ruiz.com
+ *
+ * This file is inspired in rtems_monitor & Chris John MyRightBoot
+ * 
+ * But I want to make it more user friendly
+ * A 'monitor' command is added to adapt the call rtems monitor commands
+ * at my call procedure
+ * 
+ * MINIX date.c is adapted to run here. Like a exercise only....
+ *
+ * TODO: A lot of improvements of course. 
+ *      cat, cp, rm, mv, ...
+ *      hexdump,
+ *      
+ *      More? Say me it, please...
+ *      
+ *      The BSP Specific are not welcome here.
+ *      
+ * C&S welcome...
+ *
+ *  $Id$
+ */
+
+#undef  __STRICT_ANSI__ /* fileno() */
+#include <stdio.h>
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#include <rtems.h>
+#include <rtems/monitor.h>
+#include <rtems/score/tod.h>
+
+#include <imfs.h>
+#include <rtems/shell.h>
+
+/* ----------------------------------------------- *
+  - str to int "0xaffe" "0b010010" "0123" "192939"
+ * ----------------------------------------------- */
+int str2int(char * s) {
+ int sign=1;	
+ int base=10;
+ int value=0;
+ int digit;
+ if (!s) return 0;
+ if (*s) {
+  if (*s=='-') {
+   sign=-1;
+   s++;
+   if (!*s) return 0;
+  };
+  if (*s=='0') {
+   s++;
+   switch(*s) {
+    case 'x':
+    case 'X':s++;
+ 	     base=16;
+	     break;
+    case 'b':
+    case 'B':s++;
+	     base=2;
+	     break;
+    default :base=8;
+	     break;
+   }
+  }; 
+  while (*s) {
+   switch(*s) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':digit=*s-'0';
+ 	     break;
+    case 'A':	   
+    case 'B':	   
+    case 'C':	   
+    case 'D':	   
+    case 'E':	   
+    case 'F':digit=*s-'A'+10;
+	     break;
+    case 'a':	   
+    case 'b':	   
+    case 'c':	   
+    case 'd':	   
+    case 'e':	   
+    case 'f':digit=*s-'a'+10;
+	     break;
+    default:return value*sign;	     
+   };
+   if (digit>base) return value*sign;
+   value=value*base+digit;
+   s++;
+  };
+ };
+ return value*sign;	
+}
+/*----------------------------------------------------------------------------*
+ * RAM MEMORY COMMANDS
+ *----------------------------------------------------------------------------*/
+
+#define mdump_adr (current_shell_env->mdump_adr)  /* static value */
+
+int main_mdump(int argc,char * argv[]) {
+ unsigned char n,m,max=0;
+ int adr=mdump_adr;
+ unsigned char * pb;
+ if (argc>1) adr=str2int(argv[1]);
+ if (argc>2) max=str2int(argv[2]);
+ max/=16;
+ if (!max) max=20;
+ for (m=0;m<max;m++) {
+  printf("0x%08X ",adr);
+  pb=(unsigned char*) adr;
+  for (n=0;n<16;n++)
+   printf("%02X%c",pb[n],n==7?'-':' ');
+  for (n=0;n<16;n++) {
+   printf("%c",isprint(pb[n])?pb[n]:'.');
+  };
+  printf("\n");
+  adr+=16;
+ };
+ mdump_adr=adr;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+int main_mwdump(int argc,char * argv[]) {
+ unsigned char n,m,max=0;
+ int adr=mdump_adr;
+ unsigned short * pw;
+ if (argc>1) adr=str2int(argv[1]);
+ if (argc>2) max=str2int(argv[2]);
+ max/=16;
+ if (!max) max=20;
+ for (m=0;m<max;m++) {
+  printf("0x%08X ",adr);
+  pw=(unsigned short*) adr;
+  for (n=0;n<8;n++)
+   printf("%02X %02X%c",pw[n]/0x100,pw[n]%0x100,n==3?'-':' ');
+  for (n=0;n<8;n++) {
+   printf("%c",isprint(pw[n]/0x100)?pw[n]/0x100:'.');
+   printf("%c",isprint(pw[n]%0x100)?pw[n]%0x100:'.');
+  };
+  printf("\n");
+  adr+=16;
+ };
+ mdump_adr=adr;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+int main_medit(int argc,char * argv[]) {
+ unsigned char * pb;
+ int n,i;
+ if (argc<3) {
+  printf("too few arguments\n");
+  return 0;
+ };
+ pb=(unsigned char*)str2int(argv[1]);
+ i=2;
+ n=0;
+ while (i<=argc) {
+  pb[n++]=str2int(argv[i++])%0x100;
+ }
+ mdump_adr=(int)pb;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+int main_mfill(int argc,char * argv[]) {
+ int  adr;
+ int  size;
+ unsigned char value;
+ if (argc<4) {
+  printf("too few arguments\n");
+  return 0;
+ };
+ adr  =str2int(argv[1]);
+ size =str2int(argv[2]);
+ value=str2int(argv[3])%0x100;
+ memset((unsigned char*)adr,size,value);
+ mdump_adr=adr;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+int main_mmove(int argc,char * argv[]) {
+ int  src;
+ int  dst;
+ int  size;
+ if (argc<4) {
+  printf("too few arguments\n");
+  return 0;
+ };
+ dst  =str2int(argv[1]);
+ src  =str2int(argv[2]);
+ size =str2int(argv[3]);
+ memcpy((unsigned char*)dst,(unsigned char*)src,size);
+ mdump_adr=dst;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+#ifdef MALLOC_STATS  /* /rtems/s/src/lib/libc/malloc.c */
+int main_malloc_dump(int argc,char * argv[]) {
+ void malloc_dump(void); 
+ malloc_dump();	
+ return 0;
+}
+#endif
+/*----------------------------------------------------------------------------
+ * Reset. Assumes that the watchdog is present.
+ *----------------------------------------------------------------------------*/
+int main_reset (int argc, char **argv)
+{
+  rtems_interrupt_level level;
+  printf ("Waiting for watchdog ... ");
+  tcdrain(fileno(stdout));
+
+  rtems_interrupt_disable (level);
+  for (;;) 
+      ;
+  return 0;
+}
+/*----------------------------------------------------------------------------
+ * Alias. make an alias
+ *----------------------------------------------------------------------------*/
+int main_alias (int argc, char **argv)
+{
+ if (argc<3) {
+  printf("too few arguments\n");
+  return 1;
+ };
+ if (!shell_alias_cmd(argv[1],argv[2])) {
+  printf("unable to make an alias(%s,%s)\n",argv[1],argv[2]);
+ };
+ return 0;
+}  
+/*-----------------------------------------------------------*  	
+ * Directory commands
+ *-----------------------------------------------------------*/
+int main_ls(int argc, char *argv[])
+{
+   char * fname;
+   DIR                 *dirp;
+   struct dirent       *dp;
+   struct stat         stat_buf;
+   char   sbuf[256];
+   char   nbuf[1024];
+   int  n,size;
+
+   fname=".";
+   if (argc>1) fname=argv[1];
+
+   if ((dirp = opendir(fname)) == NULL)
+   {
+      printf("%s: No such file or directory.\n", fname);
+      return errno;
+   }
+   n=0;
+   size=0;
+   while ((dp = readdir(dirp)) != NULL)
+   {
+      strcpy(nbuf,fname);
+      if (nbuf[strlen(nbuf)-1]!='/') strcat(nbuf,"/");
+      strcat(nbuf,dp->d_name); /* always the fullpathname. Avoid ftpd problem.*/
+      if (stat(nbuf, &stat_buf) == 0)
+      { /* AWFUL buts works...*/
+	 strftime(sbuf,sizeof(sbuf)-1,"%b %d %H:%M",gmtime(&stat_buf.st_atime));     
+         printf("%c%c%c%c%c%c%c%c%c%c %3d rtems  rtems  %11d %s %s%c\n",
+                 (S_ISLNK(stat_buf.st_mode)?('l'):
+                    (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
+                 (stat_buf.st_mode & S_IRUSR)?('r'):('-'),
+                 (stat_buf.st_mode & S_IWUSR)?('w'):('-'),
+                 (stat_buf.st_mode & S_IXUSR)?('x'):('-'),
+                 (stat_buf.st_mode & S_IRGRP)?('r'):('-'),
+                 (stat_buf.st_mode & S_IWGRP)?('w'):('-'),
+                 (stat_buf.st_mode & S_IXGRP)?('x'):('-'),
+                 (stat_buf.st_mode & S_IROTH)?('r'):('-'),
+                 (stat_buf.st_mode & S_IWOTH)?('w'):('-'),
+                 (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
+                 (int)stat_buf.st_nlink,
+                 (int)stat_buf.st_size,
+		 sbuf,
+                 dp->d_name,
+                 S_ISDIR(stat_buf.st_mode)?'/':' ');
+	 n++;
+	 size+=stat_buf.st_size;
+      }
+   }
+   printf("%d files %d bytes occupied\n",n,size);
+   closedir(dirp);
+   return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_pwd (int argc, char *argv[]) {
+   char dir[1024];
+   getcwd(dir,1024);
+   printf("%s\n",dir);
+   return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_chdir (int argc, char *argv[]) {
+   char *dir;
+   dir="/";
+   if (argc>1) dir=argv[1];
+   if (chdir(dir)) {
+    printf("chdir to '%s' failed:%s\n",dir,strerror(errno));
+    return errno;
+   }; 
+   return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_mkdir (int argc, char *argv[]) {
+   char *dir;
+   dir=NULL;
+   if (argc>1) dir=argv[1];
+   if (mkdir(dir,S_IRWXU|S_IRWXG|S_IRWXO)) {
+     printf("mkdir '%s' failed:%s\n",dir,strerror(errno));
+   };  
+   return errno;
+}
+/*-----------------------------------------------------------*/  	
+int main_rmdir (int argc, char *argv[])
+{
+   char *dir;
+   dir=NULL;
+   if (argc>1) dir=argv[1];
+   if (rmdir(dir)) printf("rmdir '%s' failed:%s\n",dir,strerror(errno));
+   return errno;
+}
+/*-----------------------------------------------------------*/  	
+int main_chroot(int argc,char * argv[]) {
+ char * new_root="/";
+ if (argc==2) new_root=argv[1];
+ if (chroot(new_root)<0) {
+  printf("error %s:chroot(%s);\n",strerror(errno),new_root);
+  return -1;
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*/  	
+/* date - print or set time and date		Author: Jan Looyen */
+/* MINIX 1.5 GPL'ed */
+
+
+#define	MIN	60L		/* # seconds in a minute */
+#define	HOUR	(60 * MIN)	/* # seconds in an hour */
+#define	DAY	(24 * HOUR)	/* # seconds in a day */
+#define	YEAR	(365 * DAY)	/* # seconds in a year */
+
+static int conv(unsigned32 *value,char **ptr,unsigned32 max) 
+{
+  int buf;
+  *ptr -= 2;
+  buf = atoi(*ptr);
+  **ptr = 0;
+  if (buf < 0 || buf > max) {
+   fprintf(stderr, "Date: bad conversion\n");
+   return 0;
+  }; 
+  *value=buf;
+  return 1;
+}
+
+static int set_time(char *t) 
+{
+  rtems_time_of_day tod;	
+  FILE * rtc;
+  char *tp;
+  int len;
+  if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&tod)!=RTEMS_SUCCESSFUL) 
+	  memset(&tod,0,sizeof(tod));
+  len = strlen(t);
+  if (len != 12 && len != 10 && len != 6 && len != 4) return 0;
+  tp = t;
+  while (*tp)
+   if (!isdigit(*tp++)) {
+    fprintf(stderr, "date: bad conversion\n");
+    return 0;
+   };
+  if (len == 6 || len == 12) 
+   if (!conv(&tod.second,&tp, 59)) return 0;
+  if (!conv(&tod.minute,&tp, 59)) return 0;
+  if (!conv(&tod.hour,&tp, 23)) return 0;
+  if (len == 12 || len == 10) {
+   if (!conv(&tod.year,&tp, 99)) return 0;
+   tod.year+=1900;
+   if (tod.year<TOD_BASE_YEAR) tod.year+=100;
+   if (!conv(&tod.day   ,&tp, 31)) return 0;
+   if (!conv(&tod.month ,&tp, 12)) return 0;
+  }
+  if (!_TOD_Validate(&tod)) {
+    fprintf(stderr, "Invalid date value\n");
+  } else {
+   rtems_clock_set(&tod);	  
+   rtems_clock_get(RTEMS_CLOCK_GET_TOD,&tod);	  
+   rtc=fopen("/dev/rtc","r+");
+   if (rtc) {
+    fwrite(&tod,sizeof(tod),1,rtc);
+    fclose(rtc);
+   };
+  };
+  return 1;
+}
+
+int main_date(int argc,char *argv[]) 
+{
+  time_t t;
+  if (argc == 2) set_time(argv[1]);
+  time(&t);
+  printf("%s", ctime(&t));
+  return 0;
+}
+/*-----------------------------------------------------------*  	
+ * with this you can call at all the rtems monitor commands.
+ * Not all work fine but you can show the rtems status and more.
+ *-----------------------------------------------------------*/  	
+int main_monitor(int argc,char * argv[]) {
+ rtems_monitor_command_entry_t *command;
+ extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+ rtems_task_ident(RTEMS_SELF,0,&rtems_monitor_task_id);
+ rtems_monitor_node = rtems_get_node(rtems_monitor_task_id);
+ rtems_monitor_default_node = rtems_monitor_node;
+ if ((command=rtems_monitor_command_lookup(rtems_monitor_commands,argc,argv)))
+  command->command_function(argc, argv, command->command_arg, 0);
+ return 0;
+}
+/*-----------------------------------------------------------*/  	
+void register_cmds(void) {
+  rtems_monitor_command_entry_t *command;
+  extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+  /* dir[ectories] topic */
+  shell_add_cmd  ("ls"    ,"dir","ls [dir]     # list files in the directory" ,main_ls   );
+  shell_add_cmd  ("chdir" ,"dir","chdir [dir]  # change the current directory",main_chdir);
+  shell_add_cmd  ("rmdir" ,"dir","rmdir  dir   # remove directory"            ,main_rmdir);
+  shell_add_cmd  ("mkdir" ,"dir","mkdir  dir   # make a directory"            ,main_mkdir);
+  shell_add_cmd  ("pwd"   ,"dir","pwd          # print work directory"        ,main_pwd  );
+  shell_add_cmd  ("chroot","dir","chroot [dir] # change the root directory"   ,main_chroot);
+
+  shell_alias_cmd("ls"    ,"dir");
+  shell_alias_cmd("chdir" ,"cd");
+
+  /* misc. topic */
+  shell_add_cmd  ("date" ,"misc","date [[MMDDYY]hhmm[ss]]"                    ,main_date);
+  shell_add_cmd  ("reset","misc","reset the BSP"                              ,main_reset);
+  shell_add_cmd  ("alias","misc","alias old new"                              ,main_alias);
+
+  /* memory topic */
+  shell_add_cmd  ("mdump","mem"  ,"mdump [adr [size]]"           ,main_mdump);
+  shell_add_cmd  ("wdump","mem"  ,"wdump [adr [size]]"           ,main_mwdump);
+  shell_add_cmd  ("medit","mem"  ,"medit adr value [value ...]"  ,main_medit);
+  shell_add_cmd  ("mfill","mem"  ,"mfill adr size value"         ,main_mfill);
+  shell_add_cmd  ("mmove","mem"  ,"mmove dst src size"           ,main_mmove);
+#ifdef MALLOC_STATS  /* /rtems/s/src/lib/libc/malloc.c */
+  shell_add_cmd  ("malloc","mem","mem  show memory malloc'ed"                 ,main_mem);
+#endif  
+  /* monitor topic */
+  command=rtems_monitor_commands;
+  while (command) {
+   shell_add_cmd(command->command,"monitor",
+                 command->usage  ,main_monitor);
+   command=command->next;
+  };
+}
+/*-----------------------------------------------------------*/  	
Index: cpukit/libmisc/shell/shell.c
===================================================================
--- cpukit/libmisc/shell/shell.c	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/shell.c	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,470 @@
+/*
+ *
+ *  Instantatiate a new terminal shell.
+ *
+ *  Author: 
+ *
+ *   WORK: fernando.ruiz@ctv.es 
+ *   HOME: correo@fernando-ruiz.com
+ *
+ *   Thanks at:
+ *    Chris John
+ *
+ *  $Id$
+ */
+
+#undef  __STRICT_ANSI__  /* fileno() */
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h> 
+
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <rtems/shell.h>
+/* ----------------------------------------------- *
+ * This is a stupidity but is cute.
+ * ----------------------------------------------- */
+rtems_unsigned32 new_rtems_name(char * rtems_name) {
+	static char b[5];
+	sprintf(b,"%-4.4s",rtems_name);
+	return rtems_build_name(b[0],b[1],b[2],b[3]);
+}
+/* **************************************************************
+ * common linked list of shell commands.
+ * Because the help report is very long
+ * I have a topic for each command.
+ * Help list the topics
+ * help [topic] list the commands for the topic
+ * help [command] help for the command
+ * Can you see help rtems monitor report?
+ * ************************************************************** */
+
+struct shell_topic_tt;
+typedef struct shell_topic_tt shell_topic_t;
+
+struct shell_topic_tt {
+	char * topic;
+	shell_topic_t * next;
+};
+
+
+static shell_cmd_t   * shell_first_cmd;
+static shell_topic_t * shell_first_topic;
+/* ----------------------------------------------- *
+ * Using Chain I can reuse the rtems code. 
+ * I am more comfortable with this, sorry.
+ * ----------------------------------------------- */
+shell_topic_t * shell_lookup_topic(char * topic) {
+  shell_topic_t * shell_topic;
+  shell_topic=shell_first_topic;
+  while (shell_topic) {
+   if (!strcmp(shell_topic->topic,topic)) return shell_topic;
+   shell_topic=shell_topic->next;
+  };
+  return (shell_topic_t *) NULL;
+}
+/* ----------------------------------------------- */
+shell_topic_t * shell_add_topic(char * topic) {
+ shell_topic_t * current,*aux;
+ if (!shell_first_topic) {
+  aux=malloc(sizeof(shell_topic_t));	
+  aux->topic=topic;
+  aux->next=(shell_topic_t*)NULL;
+  return shell_first_topic=aux;
+ } else {
+  current=shell_first_topic;
+  if (!strcmp(topic,current->topic)) return current;
+  while (current->next) {
+   if (!strcmp(topic,current->next->topic)) return current->next;
+   current=current->next;
+  }; 
+  aux=malloc(sizeof(shell_topic_t));	
+  aux->topic=topic;
+  aux->next=(shell_topic_t*)NULL;
+  current->next=aux;
+  return aux;
+ };
+}
+/* ----------------------------------------------- */
+shell_cmd_t * shell_lookup_cmd(char * cmd) {
+  shell_cmd_t * shell_cmd;
+  shell_cmd=shell_first_cmd;
+  while (shell_cmd) {
+   if (!strcmp(shell_cmd->name,cmd)) return shell_cmd;
+   shell_cmd=shell_cmd->next;
+  };
+  return (shell_cmd_t *) NULL;
+}
+/* ----------------------------------------------- */
+shell_cmd_t * shell_add_cmd(char * cmd,
+		      char * topic,
+		      char * usage,
+                      shell_command_t command) {
+  int shell_help(int argc,char * argv[]);
+  shell_cmd_t * shell_cmd,*shell_pvt;
+  if (!shell_first_cmd) {
+   shell_first_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
+   shell_first_cmd->name   ="help";
+   shell_first_cmd->topic  ="help";
+   shell_first_cmd->usage  ="help [topic] # list of usage of commands";
+   shell_first_cmd->command=shell_help;
+   shell_first_cmd->alias  =(shell_cmd_t *) NULL;
+   shell_first_cmd->next   =(shell_cmd_t *) NULL;
+   shell_add_topic(shell_first_cmd->topic);
+   register_cmds();
+  };
+  if (!cmd)     return (shell_cmd_t *) NULL;
+  if (!command) return (shell_cmd_t *) NULL;
+  shell_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
+  shell_cmd->name   =cmd;
+  shell_cmd->topic  =topic;
+  shell_cmd->usage  =usage;
+  shell_cmd->command=command;
+  shell_cmd->alias  =(shell_cmd_t *) NULL;
+  shell_cmd->next   =(shell_cmd_t *) NULL;
+  shell_add_topic(shell_cmd->topic);
+  shell_pvt=shell_first_cmd;
+  while (shell_pvt->next) shell_pvt=shell_pvt->next;
+  return shell_pvt->next=shell_cmd;
+}
+/* ----------------------------------------------- *
+ * you can make an alias for every command.
+ * ----------------------------------------------- */
+shell_cmd_t * shell_alias_cmd(char * cmd, char * alias) {
+  shell_cmd_t * shell_cmd,* shell_aux;
+  shell_aux=(shell_cmd_t *) NULL;
+  if (alias) {
+   if ((shell_aux=shell_lookup_cmd(alias))!=NULL) {
+    return NULL;
+   };
+   if ((shell_cmd=shell_lookup_cmd(cmd))!=NULL) {
+    shell_aux=shell_add_cmd(alias,shell_cmd->topic,
+		            shell_cmd->usage,shell_cmd->command);
+    if (shell_aux) shell_aux->alias=shell_cmd;
+   };
+  };
+  return shell_aux;
+}
+/* ----------------------------------------------- *
+ * Poor but enough..
+ * TODO: Redirection capture. "" evaluate, ... C&S welcome.
+ * ----------------------------------------------- */
+int shell_make_args(char * cmd,
+		 int  * pargc,
+		 char * argv[]) {
+  int argc=0;
+  while ((cmd=strtok(cmd," \t\r\n"))!=NULL) {
+    argv[argc++]=cmd;
+    cmd=(char*)NULL;
+   };
+  argv[argc]=(char*)NULL;
+  return *pargc=argc;
+}
+/* ----------------------------------------------- *
+ * show the help for one command.
+ * ----------------------------------------------- */
+int shell_help_cmd(shell_cmd_t * shell_cmd) {
+  char * pc;
+  int    col,line;
+  printf("%-10.10s -",shell_cmd->name);
+  col=12;
+  line=1;
+  if (shell_cmd->alias) {
+   printf("is an <alias> for command '%s'",shell_cmd->alias->name);
+  } else 
+  if (shell_cmd->usage) {
+   pc=shell_cmd->usage;
+   while (*pc) {
+    switch(*pc) {
+     case '\r':break;
+     case '\n':putchar('\n');
+               col=0;
+               break;
+     default  :putchar(*pc);
+               col++;
+               break;
+    };
+    pc++;	    
+    if(col>78) { /* What daring... 78?*/
+     if (*pc) {
+      putchar('\n');
+      col=0;
+     };
+    };
+    if (!col && *pc) {
+      printf("            ");
+      col=12;line++;
+    };  
+   };
+  };
+  puts("");
+  return line;
+}
+/* ----------------------------------------------- *
+ * show the help. The first command implemented.
+ * Can you see the header of routine? Known?
+ * The same with all the commands....
+ * ----------------------------------------------- */
+int shell_help(int argc,char * argv[]) {
+  int col,line,arg;	
+  shell_topic_t *topic;
+  shell_cmd_t * shell_cmd=shell_first_cmd;
+  if (argc<2) {
+   printf("help: TOPIC? The topics are\n");	  
+   topic=shell_first_topic;
+   col=0;
+   while (topic) {
+    if (!col){
+     col=printf("   %s",topic->topic);
+    } else {
+     if ((col+strlen(topic->topic)+2)>78){
+      printf("\n");
+      col=printf("   %s",topic->topic);
+     } else {
+      col+=printf(", %s",topic->topic);
+     }; 
+    };
+    topic=topic->next;
+   };
+   printf("\n");
+   return 1;
+  };
+  line=0;
+  for (arg=1;arg<argc;arg++) {
+   if (line>16) {
+    printf("Press any key to continue...");getchar();
+    printf("\n");
+    line=0;
+   };
+   topic=shell_lookup_topic(argv[arg]);
+   if (!topic){
+    if ((shell_cmd=shell_lookup_cmd(argv[arg]))==NULL) {
+     printf("help: topic or cmd '%s' not found. Try <help> alone for a list\n",argv[arg]);
+     line++;
+    } else {
+     line+=shell_help_cmd(shell_cmd);
+    }
+    continue;
+   };
+   printf("help: list for the topic '%s'\n",argv[arg]);
+   line++;
+   while (shell_cmd) {
+    if (!strcmp(topic->topic,shell_cmd->topic)) 
+     line+=shell_help_cmd(shell_cmd);
+    if (line>16) {
+     printf("Press any key to continue...");getchar();
+     printf("\n");
+     line=0;
+    };
+    shell_cmd=shell_cmd->next;
+   };
+  }; 
+  puts("");
+  return 0;
+}
+/* ----------------------------------------------- *
+ * TODO:Change to bash readline() better.
+ * ----------------------------------------------- */
+int shell_scanline(char * line,int size,FILE * in,FILE * out) {
+  int c,col;
+  col=0;
+  for (;;) {
+   line[col]=0;	  
+   c=fgetc(in);
+   switch (c) {
+    case EOF :return 0;
+    case '\r':if (out) fputc('\n',out);
+	      return 1;
+    case '\b':if (col) {
+	       if (out) {
+	        fputc('\b',out);
+	        fputc(' ',out);
+	        fputc('\b',out);
+	       };
+	       col--;
+	      } else {
+	       if (out) fputc('\a',out);
+	      };
+	      break;
+    default  :if (!iscntrl(c)) {
+		if (col<size-1) {
+		 line[col++]=c;	
+	         if (out) fputc(c,out);
+		} else {
+	          if (out) fputc('\a',out);
+		};
+	      } else {
+	        if (out) fputc('\a',out);
+	      };
+	      break;
+   };
+  };
+}
+/* ----------------------------------------------- *
+ * - The shell TASK                               
+ * Poor but enough..
+ * TODO: Redirection. Tty Signals. ENVVARs. Shell language.
+ * ----------------------------------------------- */
+shell_env_t global_shell_env ,
+          * current_shell_env=&global_shell_env; 
+
+extern char **environ;	  
+
+rtems_task shell_shell(rtems_task_argument task_argument) {
+
+  shell_env_t * shell_env =(shell_env_t*) task_argument;
+  shell_cmd_t * shell_cmd;
+
+  rtems_status_code sc;
+
+  struct termios term;	
+  char * devname;
+  char * curdir;
+
+  char cmd[256];
+  char last_cmd[256]; /* to repeat 'r' */
+  int  argc;
+  char * argv[128];
+
+  sc=rtems_libio_set_private_env();
+  if (sc!=RTEMS_SUCCESSFUL) {
+   rtems_error(sc,"rtems_libio_set_private_env():");	 
+   printk("rtems_libio_set_private_env():%d",sc);	 
+   rtems_task_delete(RTEMS_SELF);
+  }; 
+
+  sc=rtems_task_variable_add(RTEMS_SELF,(void*)&current_shell_env,free);
+  if (sc!=RTEMS_SUCCESSFUL) {
+   rtems_error(sc,"rtems_task_variable_add():");	 
+   printk("rtems_task_variable_add():%d",sc);	 
+   rtems_task_delete(RTEMS_SELF);
+  }; 
+
+  current_shell_env=shell_env; /* Set the task var */
+
+  devname=shell_env->devname;
+
+  stdin =fopen(devname,"r+");
+    
+  if (!stdin) {
+   fprintf(stderr,"shell:unable to open stdin.%s:%s\n",devname,strerror(errno));
+   printk("shell:unable to open stdin.(%s)",strerror(errno));	 
+   rtems_task_delete(RTEMS_SELF);
+  };
+  setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
+  /* make a raw terminal,Linux MANuals */
+  if (tcgetattr (fileno(stdin), &term)>=0) {
+   term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+   term.c_oflag &= ~OPOST;
+   term.c_oflag |= (OPOST|ONLCR);
+   term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+   term.c_cflag  = CLOCAL | CREAD |(shell_env->tcflag);
+   term.c_cc[VMIN]  = 1;
+   term.c_cc[VTIME] = 0;
+   if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
+     fprintf(stderr,"shell:cannot set terminal attributes(%s)\n",devname);
+   };
+   stdout=fopen(devname,"r+");
+   if (!stdout) {
+    fprintf(stderr,"shell:unable to open stdout.%s:%s\n",devname,strerror(errno));
+   };
+   stderr=fopen(devname,"r+");
+   if (!stderr) {
+    printf("shell:unable to open stderr.%s:%s\n",devname,strerror(errno));
+   };
+   /* when the future user environment runs ok
+    * a freopen() reopens the terminals. Now this don't work
+    * (sorry but you can't use because FILENO_STDIN!=0. Better fileno(stdin))
+    */
+  };
+  shell_add_cmd(NULL,NULL,NULL,NULL); /* init the chain list*/
+  strcpy(cmd,"");
+  printf("\n"
+         "RTEMS-SHELL:%s. "__DATE__". 'help' to list commands.\n",devname);
+  curdir=malloc(1024); 
+  chdir("/");
+  for (;;) {
+   /* Prompt section */	  
+   /* XXX: show_prompt user adjustable */
+   getcwd(curdir,1024);
+   printf("%s [%s] # ",devname,curdir);
+   /* getcmd section */	  
+   if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) {
+    printf("shell:unable scanline(%s)\n",devname);	
+    break;
+   };
+   /* evaluate cmd section */	  
+   if (!strcmp(cmd,"r")) {  /* repeat last command, forced, not automatic */
+    strcpy(cmd,last_cmd);
+   } else 
+   if (strcmp(cmd,"")) { /* only for get a new prompt */
+    strcpy(last_cmd,cmd);
+   }; 
+   /* exec cmd section */	  
+   /* TODO: 
+    *  To avoid user crash catch the signals. 
+    *  Open a new stdio files with posibility of redirection *
+    *  Run in a new shell task background. (unix &)
+    *  Resuming. A little bash.
+    */	  
+   if (shell_make_args(cmd,&argc,argv)) {
+    if ((shell_cmd=shell_lookup_cmd(argv[0]))!=NULL) {
+     current_shell_env->errorlevel=shell_cmd->command(argc,argv);
+    } else {
+     printf("shell:%s command not found\n",argv[0]);
+     current_shell_env->errorlevel=-1;
+    };
+   };
+   /* end exec cmd section */	  
+  };
+  free(curdir);
+  rtems_task_delete(RTEMS_SELF);
+}
+/* ----------------------------------------------- */
+rtems_status_code   shell_init (char * task_name,
+				rtems_unsigned32    task_stacksize,
+				rtems_task_priority task_priority,
+				char * devname,
+				tcflag_t tcflag) {
+ rtems_id task_id;
+ rtems_status_code sc;
+ shell_env_t * shell_env;
+ sc=rtems_task_create(new_rtems_name(task_name),
+ 		     task_priority,
+		     task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE,
+		     (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR,
+		     RTEMS_DEFAULT_ATTRIBUTES,
+		     &task_id);
+ if (sc!=RTEMS_SUCCESSFUL) {
+  rtems_error(sc,"creating task %s in shell_init()",task_name);	 
+  return sc;
+ }; 
+ shell_env=malloc(sizeof(shell_env_t));
+ if (!shell_env) {
+  rtems_task_delete(task_id);
+  sc=RTEMS_NO_MEMORY;	 
+  rtems_error(sc,"allocating shell_env %s in shell_init()",task_name);	 
+  return sc;
+ };
+ if (global_shell_env.magic!=new_rtems_name("SENV")) {
+  global_shell_env.magic   =new_rtems_name("SENV");
+  global_shell_env.devname ="/dev/console";
+  global_shell_env.taskname="GLOBAL";
+  global_shell_env.tcflag   =0;
+ }; 
+ shell_env->magic   =global_shell_env.magic; 
+ shell_env->devname =devname;
+ shell_env->taskname=task_name;
+ shell_env->tcflag  =tcflag;
+ return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env);
+}
+/* ----------------------------------------------- */
+
Index: cpukit/libmisc/shell/shell.h
===================================================================
--- cpukit/libmisc/shell/shell.h	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
+++ cpukit/libmisc/shell/shell.h	(revision dd74e612f1ffe208ad1e20f28ac4da3f08764879)
@@ -0,0 +1,72 @@
+/*
+ *  $Id$
+ */
+
+#ifndef __SHELL_H__
+#define __SHELL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif	
+
+#include <rtems.h>	
+#include <stdio.h>	
+#include <termios.h>	
+
+typedef int (*shell_command_t)(int argc,char * argv[]);
+
+struct shell_cmd_tt ;
+typedef struct shell_cmd_tt shell_cmd_t;
+
+struct shell_cmd_tt {
+ char * name;
+ char * usage;
+ char * topic;
+ shell_command_t command;
+ shell_cmd_t * alias;
+ shell_cmd_t * next;
+};
+
+rtems_unsigned32 new_rtems_name(char * rtems_name);
+shell_cmd_t * shell_lookup_cmd(char * cmd);
+shell_cmd_t * shell_add_cmd(char * cmd,
+                            char * topic,
+                            char * usage,
+                            shell_command_t command);
+shell_cmd_t * shell_alias_cmd(char * cmd, char * alias);
+
+int shell_make_args(char * cmd,
+                    int  * pargc,
+                    char * argv[]);
+
+typedef struct  {
+  rtems_name magic; /* 'S','E','N','V': Shell Environment */	
+  char * devname;
+  char * taskname;
+  tcflag_t tcflag;
+  /* user extensions */
+  int  errorlevel;
+  int  mdump_adr;
+} shell_env_t;
+
+int shell_scanline(char * line,int size,FILE * in,FILE * out) ;
+	
+rtems_status_code shell_init(char * task_name      ,
+                              rtems_unsigned32    task_stacksize,/*0 default*/
+		              rtems_task_priority task_priority ,
+                              char * devname      ,
+			      tcflag_t tcflag     );
+
+extern shell_env_t global_shell_env,
+                *  current_shell_env;
+/*--------*/
+/* cmds.c */ 
+/*--------*/
+int str2int(char * s);
+void register_cmds(void);
+ 
+#ifdef __cplusplus
+}
+#endif	
+
+#endif
