diff -ruN Ngraph-6.3.18-src/Makefile Ngraph-6.3.18-readline-src/Makefile
--- Ngraph-6.3.18-src/Makefile	2003-02-16 21:46:30.000000000 +0900
+++ Ngraph-6.3.18-readline-src/Makefile	2003-02-18 21:09:23.000000000 +0900
@@ -11,16 +11,16 @@
 # Linux + Open Motif 2.1 [dynamic link]
 #
 CC = gcc
-CCOPTION = -O2 -m486
+CCOPTION = -O2 -m486 -Wall
 MAKE = make
 AR = ar
 RANLIB = ranlib
 STRIP = strip
-DEFS = -DJAPANESE
-PLATFORM  = '"for X11 [Linux(glibc2) + Open Motif]"'
+DEFS = -DJAPANESE -DREADLINE
+PLATFORM  = '"for X11 [Linux(glibc2) + Open Motif + readline]"'
 X11INCLUDE = -I/usr/X11R6/include
 STATICLINK =
-X11LIB = -L/usr/X11R6/lib -lm -lXm -lXext -lXt -lXp -lX11 -lICE -lSM
+X11LIB = -L/usr/X11R6/lib -lm -lXm -lXext -lXt -lXp -lX11 -lICE -lSM -lreadline -ltermcap
 #
 #
 ###############################################################################
diff -ruN Ngraph-6.3.18-src/Ngraph.ini Ngraph-6.3.18-readline-src/Ngraph.ini
--- Ngraph-6.3.18-src/Ngraph.ini	2003-02-16 21:46:30.000000000 +0900
+++ Ngraph-6.3.18-readline-src/Ngraph.ini	2003-02-17 21:10:44.000000000 +0900
@@ -1,6 +1,7 @@
 [Ngraph]
 terminal=xterm -e INSTALLDIR/terminal
 alloc_console=0
+history_size=100
 
 [x11menu]
 framex=0
diff -ruN Ngraph-6.3.18-src/src/shell.c Ngraph-6.3.18-readline-src/src/shell.c
--- Ngraph-6.3.18-src/src/shell.c	2003-02-16 21:46:33.000000000 +0900
+++ Ngraph-6.3.18-readline-src/src/shell.c	2003-02-17 21:00:12.000000000 +0900
@@ -133,6 +133,14 @@
 #include <fcntl.h>
 #include <signal.h>
 #ifndef WINDOWS
+
+#ifdef READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+static char *Prompt;
+char *readline(char *);
+#endif
+
 #include <sys/wait.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
@@ -265,12 +273,45 @@
   char buf[2];
   int byte;
   struct itimerval tval;
+#ifdef READLINE
+  static char *str_ptr = NULL, *line_str = NULL;
+#endif
 
   if (nisatty(nshell->fd)) {
     shellevloop(SIGALRM);
+#ifdef READLINE
+    if(str_ptr == NULL){
+      str_ptr = line_str = readline(Prompt);
+      if(str_ptr == NULL){
+	byte = 0;
+      }else if(strlen(str_ptr) > 0) {
+	int pos;
+	for(pos = history_length; pos >= 0; pos--){
+	  if((pos = history_search_pos(str_ptr, -1, pos)) >= 0 &&
+	     strcmp(history_get(pos+history_base)->line, str_ptr) == 0){
+	    remove_history(pos);
+	    break;
+	  }
+	}
+	add_history(str_ptr);
+      }
+    }
+    if(str_ptr != NULL){
+      if(*line_str == '\0'){
+	free(str_ptr);
+	str_ptr = line_str = NULL;
+	buf[0] = '\0';
+	byte = 1;
+      }else{
+	buf[0] = *line_str++;
+	byte = 1;
+      }
+    }
+#else
     do {
       byte=read(nshell->fd,buf,1);
     } while (byte<0);
+#endif
     tval.it_interval.tv_sec=0;
     tval.it_interval.tv_usec=0;
     tval.it_value.tv_sec=0;
@@ -1087,7 +1128,11 @@
       if (nisatty(nshell->fd)) {
         if ((cmd==NULL) && (cmdroot==NULL)) prompt=getval(nshell,"PS1");
         else prompt=getval(nshell,"PS2");
+#ifdef READLINE
+	Prompt = prompt;
+#else
         if (prompt!=NULL) printfconsole("%.256s",prompt);
+#endif
       }
       do {
         ch=shget(nshell);
diff -ruN Ngraph-6.3.18-src/x11/main.c Ngraph-6.3.18-readline-src/x11/main.c
--- Ngraph-6.3.18-src/x11/main.c	2003-02-16 21:46:33.000000000 +0900
+++ Ngraph-6.3.18-readline-src/x11/main.c	2003-02-17 21:00:12.000000000 +0900
@@ -73,6 +73,18 @@
 #include "nstring.h"
 #include "config.h"
 
+#ifdef READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#include "shell.h"
+#include "ox11menu.h"
+#include <assert.h>
+static char **attempt_shell_completion (char *text, int start, int end);
+#define HIST_SIZE 100
+#define HIST_FILE ".ngraph_history"
+#endif
+
+
 #define TRUE  1
 #define FALSE 0
 
@@ -357,6 +369,10 @@
   int allocnow,allocconsole;
   struct narray iarray;
   char *arg;
+#ifdef READLINE
+  int history_size = HIST_SIZE;
+  char *history_file;
+#endif
 
   mainenviron=environ;
 
@@ -455,6 +471,15 @@
           else allocconsole=TRUE;
         }
         memfree(f1);
+#ifdef READLINE
+      } else if (strcmp(tok,"history_size")==0) {
+        f1=getitok2(&s2,&len," \t,");
+        val=strtol(f1,&endptr,10);
+        if (endptr[0]=='\0' && val > 0) {
+	  history_size = val;
+        }
+        memfree(f1);
+#endif
       } else if (strcmp(tok,"terminal")==0) {
         terminal=getitok2(&s2,&len,"");
       }
@@ -464,6 +489,20 @@
     closeconfig(fp);
   }
 
+#ifdef READLINE
+  rl_readline_name = "ngraph";
+  rl_completer_word_break_characters = " \t\n\"'@><;|&({}`";
+  rl_attempted_completion_function = (CPPFunction *)attempt_shell_completion;
+  rl_completion_entry_function = (Function *)NULL;
+  history_file = malloc(sizeof(char) * (strlen(homedir) + strlen(HIST_FILE) + 2));
+  if(history_file != NULL){
+    sprintf(history_file, "%s/%s", homedir, HIST_FILE);
+    read_history (history_file);
+  }
+  using_history ();
+  stifle_history (history_size);
+#endif
+
   putstderr=putconsole;
   printfstderr=printfconsole;
   inputyn=inputynconsole;
@@ -529,8 +568,527 @@
     memfree(loginshell);
     if (getobj(sys,"login_shell",0,0,NULL,&loginshell)) exit(1);
   } while (loginshell!=NULL);
+#ifdef READLINE
+  if(history_file != NULL){
+    write_history (history_file);
+  }
+#endif
   if (consoleac && (consolepid!=-1)) nfreeconsole();
   memfree(terminal);
   delobj(getobject("system"),0);
   return 0;
 }
+
+#ifdef READLINE
+struct mylist{
+  struct mylist *next;
+  int len;
+  char str[1];
+};
+
+static char **obj_name_matching(char *text);
+static char *obj_member_completion_function(char *text, int state);
+static char *obj_name_completion_function(char *text, int state);
+static char *my_completion_function(char *text, int state, char **func(char *));
+static char *command_word_completion_function (char *hint_text, int state);
+static char **cmd_name_matching(char *text);
+static char **get_obj_member_list(struct objlist *objcur, char *member);
+static char **get_obj_enum_list(struct objlist *objcur, char *member, char *val);
+static char **get_obj_bool_list(struct objlist *objcur, char *member, char *val);
+static char **get_obj_font_list(struct objlist *objcur, char *member, char *val);
+static int get_obj_num(void);
+static struct mylist *mylist_add(struct mylist *parent, const char *text);
+static struct mylist *mylist_cat(struct mylist *list_top, struct mylist *list);
+static void mylist_free(struct mylist *list);
+static int mylist_num(const struct mylist *list);
+static struct mylist *get_file_list(const char *path, int type, int mode);
+static struct mylist *get_exec_file_list(void);
+static int my_sprintf(char **str, char *format, ...);
+
+static char **attempt_shell_completion (char *text, int start, int end)
+{
+  char **matches = NULL;
+  int in_command_position, ti;
+  char *command_separator_chars = ";|(`";
+
+  ti = start - 1;
+  while ((ti > -1) && (whitespace (rl_line_buffer[ti])))
+    ti--;
+
+  in_command_position = 0;
+  if(ti < 0){
+    in_command_position++;
+  }else if(strchr(command_separator_chars, rl_line_buffer[ti])){
+    in_command_position++;
+  }
+
+  if(!matches && in_command_position)
+    matches = completion_matches(text, command_word_completion_function);
+ 
+  if(!matches)
+    matches = completion_matches(text, obj_name_completion_function);
+
+  if(!matches)
+    matches = completion_matches(text, obj_member_completion_function);
+
+  return matches;
+}
+
+static char *obj_member_completion_function(char *text, int state)
+{
+  static char **list = (char **)NULL;
+  static int list_index = 0, first_char_loc;
+  struct objlist *objcur;
+
+  /* If we don't have any state, make some. */
+  if(!state){
+    static char *obj, *instances, *member, *val;
+
+    if(list)
+      free (list);
+
+    list = (char **)NULL;
+
+    first_char_loc = 0;
+
+    if((obj = strdup(text)) == NULL)
+      return NULL;
+
+    if((instances = strchr(obj, ':')) && (member = strchr(instances + 1, ':'))){
+      *instances = *member = '\0';
+      instances++;
+      member++;
+    }else{
+      free(obj);
+      return NULL;
+    }
+
+    objcur = getobject(obj);
+    if(objcur == NULL){
+      free(obj);
+      return NULL;
+    }
+
+    if((val = strchr(member, '=')) != NULL){
+      *val = '\0';
+      val++;
+      first_char_loc = val - obj;
+      list = get_obj_enum_list(objcur, member, val);
+
+      if(list == NULL)
+	list = get_obj_bool_list(objcur, member, val);
+
+      if(list == NULL)
+	list = get_obj_font_list(objcur, member, val);
+    }else{
+      first_char_loc = member - obj;
+      list = get_obj_member_list(objcur, member);
+    }
+
+    list_index = 0;
+    free(obj);
+  }
+
+  if(list && list[list_index]){
+    char *t;
+
+    if((t = malloc (first_char_loc + strlen (list[list_index]) + 1)) == NULL)
+      return NULL;
+
+    sprintf(t, "%.*s%s", first_char_loc, text, list[list_index]);
+    list_index++;
+    return (t);
+  }else{
+    return ((char *)NULL);
+  }
+}
+
+static char **get_obj_member_list(struct objlist *objcur, char *member)
+{
+  char **list = (char **)NULL;
+  int i, j, len;
+
+  if((list = malloc(sizeof(*list) * (chkobjfieldnum(objcur) + 1))) == NULL)
+    return NULL;
+
+  len = strlen(member);
+  j = 0;
+  for(i = 0; i < chkobjfieldnum(objcur); i++){
+    if(strncmp(chkobjfieldname(objcur,i), member, len) == 0){
+      list[j++] = chkobjfieldname(objcur,i);
+    }
+  }
+  list[j] = NULL;
+  return list;
+}
+
+static char **get_obj_enum_list(struct objlist *objcur, char *member, char *val)
+{
+  char **list = (char **)NULL, **enumlist;
+  int i, j, len;
+
+  if(chkobjfieldtype(objcur, member) != NENUM)
+    return NULL;
+
+  enumlist = (char **)chkobjarglist(objcur, member);
+  for(i = 0; enumlist[i] != NULL; i++);
+
+  if((list = malloc((sizeof(*list)) * (i + 1))) == NULL)
+    return NULL;
+
+  len = strlen(val);
+  j = 0;
+  for(i = 0; enumlist[i] != NULL; i++){
+    if(strncmp(enumlist[i], val, len) == 0){
+      list[j++] = enumlist[i];
+    }
+  }
+  list[j] = NULL;
+
+  return list;
+}
+
+static char **get_obj_bool_list(struct objlist *objcur, char *member, char *val)
+{
+  char **list = (char **)NULL;
+  static char *boollist[] = {"true", "false", NULL};
+  int i, j, len;
+
+  if(chkobjfieldtype(objcur, member) != NBOOL)
+    return NULL;
+
+  if((list = malloc(sizeof(boollist))) == NULL)
+    return NULL;
+
+  len = strlen(val);
+  j = 0;
+  for(i = 0; boollist[i] != NULL; i++){
+    if(strncmp(boollist[i], val, len) == 0){
+      list[j++] = boollist[i];
+    }
+  }
+  list[j] = NULL;
+
+  return list;
+}
+
+static char **get_obj_font_list(struct objlist *objcur, char *member, char *val)
+{
+  char **list = (char **)NULL;
+  struct fontmap *fontmap;
+  int i, j, len, twobyte;
+
+  if(mxlocal == NULL)
+    return NULL;
+
+  if(mxlocal->fontmaproot == NULL)
+    return NULL;
+
+  if(chkobjfieldtype(objcur, member) != NSTR)
+    return NULL;
+
+  if(strstr(member, "font") == NULL)
+    return NULL;
+
+  for(i = 0, fontmap = mxlocal->fontmaproot; fontmap != NULL; fontmap = fontmap->next, i++);
+
+  if((list = malloc((sizeof(*list)) * (i + 1))) == NULL)
+    return NULL;
+
+  if(strstr(member, "jfont") != NULL)
+    twobyte = TRUE;
+  else
+    twobyte = FALSE;
+
+  len = strlen(val);
+  j = 0;
+  for(fontmap = mxlocal->fontmaproot; fontmap != NULL; fontmap = fontmap->next){
+    if((fontmap->twobyte == twobyte) && (strncmp(fontmap->fontalias, val, len) == 0)){
+      list[j++] = fontmap->fontalias;
+    }
+  }
+  list[j] = NULL;
+  return list;
+}
+
+static char *command_word_completion_function (char *text, int state)
+{
+  return my_completion_function(text, state, cmd_name_matching);
+}
+
+static char *obj_name_completion_function(char *text, int state)
+{
+  return my_completion_function(text, state, obj_name_matching);
+}
+
+static char *my_completion_function(char *text, int state, char **func(char *))
+{
+  static char **list = (char **)NULL;
+  static int list_index = 0;
+  static int first_char_loc;
+
+  /* If we don't have any state, make some. */
+  if(!state){
+    if (list)
+      free (list);
+
+    list = (char **)NULL;
+
+    first_char_loc = 0;
+
+    list = func(&text[first_char_loc]);
+    list_index = 0;
+  }
+
+  if(list && list[list_index]){
+    char *t = strdup(list[list_index]);
+    if(t == NULL)
+      return NULL;
+
+    list_index++;
+    return t;
+  }else
+    return NULL;
+}
+
+static int get_obj_num(void)
+{
+  static int num = 0;
+  if(num == 0){
+    struct objlist *objcur;
+    for(objcur = chkobjroot(); objcur != NULL; objcur = objcur->next)
+      num++;
+  }
+
+  return num;
+}
+
+static char **obj_name_matching(char *text)
+{
+  int j, text_len;
+  struct objlist *objcur;
+  char **list;
+
+  list = malloc((get_obj_num() + 1) * sizeof(*list));
+
+  if(list == NULL)
+    return NULL;
+
+  text_len = strlen(text);
+  j = 0;
+
+  for(objcur = chkobjroot(); objcur != NULL; objcur=objcur->next){
+    if(strncmp(objcur->name, text, text_len) == 0)
+      list[j++] = objcur->name;
+  }
+
+  if(j == 0){
+    free(list);
+    list = NULL;
+  }else{
+    list[j] = NULL;
+  }
+
+  assert(j < get_obj_num()+1);
+  return list;
+}
+
+static char **cmd_name_matching(char *text)
+{
+  int i, j, text_len, file_len;
+  struct objlist *objcur;
+  char **list;
+  struct mylist *file_list = NULL, *file_list_cur = NULL;
+
+  file_list = get_exec_file_list();
+  file_len = mylist_num(file_list);
+
+  list = malloc((CMDNUM + CPCMDNUM + get_obj_num() + file_len +1) * sizeof(*list));
+
+  if(list == NULL)
+    return NULL;
+
+  text_len = strlen(text);
+  j = 0;
+
+  for(file_list_cur = file_list; file_list_cur != NULL; file_list_cur = file_list_cur->next){
+    if(strncmp(file_list_cur->str, text, text_len) == 0){
+      list[j++] = file_list_cur->str;
+    }
+  }
+
+  for(i = 0; i < CMDNUM; i++){
+    if(strncmp(cmdtable[i].name, text, text_len) == 0){
+      list[j++] = cmdtable[i].name;
+    }
+  }
+
+  for(i = 0; i < CPCMDNUM; i++){
+    if(strncmp(cpcmdtable[i], text, text_len) == 0){
+      list[j++] = cpcmdtable[i];
+    }
+  }
+
+  for(objcur = chkobjroot(); objcur != NULL; objcur=objcur->next){
+    if(strncmp(objcur->name, text, text_len) == 0)
+      list[j++] = objcur->name;
+  }
+
+  if(j == 0){
+    free(list);
+    list = NULL;
+  }else{
+    list[j] = NULL;
+  }
+
+  assert(j < CMDNUM + CPCMDNUM + get_obj_num() + file_len + 1);
+  return list;
+}
+
+struct mylist *get_exec_file_list(void)
+{
+  char *path, *path_env, *next_ptr, *path_ptr;
+  static struct mylist *list = NULL, *list_next = NULL;
+
+  if(list != NULL){
+    return list;
+    /*
+      mylist_free(list);
+      list = NULL;
+    */
+  }
+
+  if((path_env = getenv("PATH")) == NULL)
+    return NULL;
+
+  if((path = path_ptr = strdup(path_env)) == NULL)
+    return NULL;
+
+  while((next_ptr = strchr(path_ptr, ':')) != NULL){
+    *next_ptr = '\0';
+    next_ptr++;
+
+    list_next = get_file_list(path_ptr ,S_IFREG, S_IXUSR);
+    list = mylist_cat(list, list_next);
+    path_ptr = next_ptr;
+  }
+  free(path);
+  return list;
+}
+
+static struct mylist *get_file_list(const char *path, int type, int mode)
+{
+  DIR *dir;
+  struct dirent *ent;
+  struct stat statbuf;
+  struct mylist *list = NULL, *list_next = list;
+  char *full_path_name;
+
+  if((dir = opendir(path)) == NULL){
+    return NULL;
+  }
+  while((ent = readdir(dir)) != NULL){
+    if(my_sprintf(&full_path_name, "%s/%s", path, ent->d_name) < 0){
+      if(list != NULL)
+	mylist_free(list);
+      list = NULL;
+      break;
+    }
+    stat(full_path_name, &statbuf);
+    if((statbuf.st_mode & type) && (statbuf.st_mode & mode)){
+      list_next = mylist_add(list_next, ent->d_name);
+      if(list == NULL)
+	list = list_next;
+    }
+  }
+
+  closedir(dir);
+
+  return list;
+}
+
+#define BUF_UNIT   256
+
+static int my_sprintf(char **str, char *format, ...)
+{
+  va_list arg;
+  static int buf_size = BUF_UNIT;
+  static char *buf = NULL;
+  int len;
+
+  if(buf == NULL && (buf = malloc(buf_size)) == NULL){
+      return -1;
+  }
+
+  va_start(arg, format);
+  len = vsnprintf(buf, buf_size, format, arg) + 1;
+  va_end(arg);
+  if(len > buf_size){
+    char *tmp;
+    buf_size = (len / BUF_UNIT + 1) * BUF_UNIT;
+    if((tmp = realloc(buf, buf_size)) == NULL){
+      return -1;
+    }
+    buf=tmp;
+    va_start(arg, format);
+    len = vsnprintf(buf, buf_size, format, arg) + 1;
+    va_end(arg);
+  }
+  *str = buf;
+  return len;
+}
+
+static struct mylist *mylist_add(struct mylist *parent, const char *text)
+{
+  struct mylist *list;
+  int len;
+
+  len = strlen(text) + 1;
+  if((list = malloc(sizeof(struct mylist) + len)) == NULL)
+    return NULL;
+
+  memcpy(list->str, text, len);
+  list->next = NULL;
+  list->len = len;
+  if(parent != NULL)
+    parent->next = list;
+
+  return list;
+}
+    
+static void mylist_free(struct mylist *list)
+{
+  struct mylist *tmp;
+  while(list != NULL){
+    tmp = list->next;
+    free(list);
+    list = tmp;
+  }
+}
+
+static int mylist_num(const struct mylist *list)
+{
+  int num = 0;
+  while(list != NULL){
+    num++;
+    list = list->next;
+  }
+  return num;
+}
+
+static struct mylist *mylist_cat(struct mylist *list_top, struct mylist *list)
+{
+  struct mylist *list_ptr;
+
+  if(list_top == NULL)
+    return list;
+
+  list_ptr =list_top;
+  while(list_ptr->next != NULL)
+    list_ptr = list_ptr->next;
+
+  list_ptr->next = list;
+  return list_top;
+}
+
+#endif
