]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Sat, 21 Dec 2002 19:58:08 +0000 (19:58 +0000)
committernobody <>
Sat, 21 Dec 2002 19:58:08 +0000 (19:58 +0000)
'carlton_dictionary-branch'.

Cherrypick from master 2002-12-21 19:58:07 UTC Mark Kettenis <kettenis@gnu.org> '* osabi.c: Include "gdb_assert.h" and "gdb_string.h".':
    bfd/bfdio.c
    bfd/bfdwin.c
    config/accross.m4
    gdb/hppa-hpux-tdep.c
    gdb/m68k-tdep.h
    gdb/m68klinux-tdep.c
    gdb/mi/mi-cmd-env.c
    gdb/mips-tdep.h
    gdb/testsuite/gdb.base/store.c
    gdb/testsuite/gdb.base/store.exp
    libiberty/make-relative-prefix.c
    readline/compat.c
    readline/doc/history.0
    readline/doc/history.3
    readline/examples/readlinebuf.h
    readline/examples/rlcat.c
    readline/mbutil.c
    readline/misc.c
    readline/rlmbutil.h
    readline/rltypedefs.h
    readline/support/wcwidth.c
    readline/text.c

22 files changed:
bfd/bfdio.c [new file with mode: 0644]
bfd/bfdwin.c [new file with mode: 0644]
config/accross.m4 [new file with mode: 0644]
gdb/hppa-hpux-tdep.c [new file with mode: 0644]
gdb/m68k-tdep.h [new file with mode: 0644]
gdb/m68klinux-tdep.c [new file with mode: 0644]
gdb/mi/mi-cmd-env.c [new file with mode: 0644]
gdb/mips-tdep.h [new file with mode: 0644]
gdb/testsuite/gdb.base/store.c [new file with mode: 0644]
gdb/testsuite/gdb.base/store.exp [new file with mode: 0644]
libiberty/make-relative-prefix.c [new file with mode: 0644]
readline/compat.c [new file with mode: 0644]
readline/doc/history.0 [new file with mode: 0644]
readline/doc/history.3 [new file with mode: 0644]
readline/examples/readlinebuf.h [new file with mode: 0644]
readline/examples/rlcat.c [new file with mode: 0644]
readline/mbutil.c [new file with mode: 0644]
readline/misc.c [new file with mode: 0644]
readline/rlmbutil.h [new file with mode: 0644]
readline/rltypedefs.h [new file with mode: 0644]
readline/support/wcwidth.c [new file with mode: 0644]
readline/text.c [new file with mode: 0644]

diff --git a/bfd/bfdio.c b/bfd/bfdio.c
new file mode 100644 (file)
index 0000000..3229316
--- /dev/null
@@ -0,0 +1,436 @@
+/* Low-level I/O routines for BFDs.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002 Free Software Foundation, Inc.
+   Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sysdep.h"
+
+#include "bfd.h"
+#include "libbfd.h"
+
+#include <limits.h>
+
+#ifndef S_IXUSR
+#define S_IXUSR 0100    /* Execute by owner.  */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010    /* Execute by group.  */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001    /* Execute by others.  */
+#endif
+
+/* Note that archive entries don't have streams; they share their parent's.
+   This allows someone to play with the iostream behind BFD's back.
+
+   Also, note that the origin pointer points to the beginning of a file's
+   contents (0 for non-archive elements).  For archive entries this is the
+   first octet in the file, NOT the beginning of the archive header.  */
+
+static size_t real_read PARAMS ((PTR where, size_t a, size_t b, FILE *file));
+static size_t
+real_read (where, a, b, file)
+     PTR where;
+     size_t a;
+     size_t b;
+     FILE *file;
+{
+  /* FIXME - this looks like an optimization, but it's really to cover
+     up for a feature of some OSs (not solaris - sigh) that
+     ld/pe-dll.c takes advantage of (apparently) when it creates BFDs
+     internally and tries to link against them.  BFD seems to be smart
+     enough to realize there are no symbol records in the "file" that
+     doesn't exist but attempts to read them anyway.  On Solaris,
+     attempting to read zero bytes from a NULL file results in a core
+     dump, but on other platforms it just returns zero bytes read.
+     This makes it to something reasonable. - DJ */
+  if (a == 0 || b == 0)
+    return 0;
+
+
+#if defined (__VAX) && defined (VMS)
+  /* Apparently fread on Vax VMS does not keep the record length
+     information.  */
+  return read (fileno (file), where, a * b);
+#else
+  return fread (where, a, b, file);
+#endif
+}
+
+/* Return value is amount read.  */
+
+bfd_size_type
+bfd_bread (ptr, size, abfd)
+     PTR ptr;
+     bfd_size_type size;
+     bfd *abfd;
+{
+  size_t nread;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    {
+      struct bfd_in_memory *bim;
+      bfd_size_type get;
+
+      bim = (struct bfd_in_memory *) abfd->iostream;
+      get = size;
+      if (abfd->where + get > bim->size)
+       {
+         if (bim->size < (bfd_size_type) abfd->where)
+           get = 0;
+         else
+           get = bim->size - abfd->where;
+         bfd_set_error (bfd_error_file_truncated);
+       }
+      memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
+      abfd->where += get;
+      return get;
+    }
+
+  nread = real_read (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
+  if (nread != (size_t) -1)
+    abfd->where += nread;
+
+  /* Set bfd_error if we did not read as much data as we expected.
+
+     If the read failed due to an error set the bfd_error_system_call,
+     else set bfd_error_file_truncated.
+
+     A BFD backend may wish to override bfd_error_file_truncated to
+     provide something more useful (eg. no_symbols or wrong_format).  */
+  if (nread != size)
+    {
+      if (ferror (bfd_cache_lookup (abfd)))
+       bfd_set_error (bfd_error_system_call);
+      else
+       bfd_set_error (bfd_error_file_truncated);
+    }
+
+  return nread;
+}
+
+bfd_size_type
+bfd_bwrite (ptr, size, abfd)
+     const PTR ptr;
+     bfd_size_type size;
+     bfd *abfd;
+{
+  size_t nwrote;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    {
+      struct bfd_in_memory *bim = (struct bfd_in_memory *) (abfd->iostream);
+      size = (size_t) size;
+      if (abfd->where + size > bim->size)
+       {
+         bfd_size_type newsize, oldsize;
+
+         oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
+         bim->size = abfd->where + size;
+         /* Round up to cut down on memory fragmentation */
+         newsize = (bim->size + 127) & ~(bfd_size_type) 127;
+         if (newsize > oldsize)
+           {
+             bim->buffer = (bfd_byte *) bfd_realloc (bim->buffer, newsize);
+             if (bim->buffer == 0)
+               {
+                 bim->size = 0;
+                 return 0;
+               }
+           }
+       }
+      memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
+      abfd->where += size;
+      return size;
+    }
+
+  nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
+  if (nwrote != (size_t) -1)
+    abfd->where += nwrote;
+  if (nwrote != size)
+    {
+#ifdef ENOSPC
+      errno = ENOSPC;
+#endif
+      bfd_set_error (bfd_error_system_call);
+    }
+  return nwrote;
+}
+
+bfd_vma
+bfd_tell (abfd)
+     bfd *abfd;
+{
+  file_ptr ptr;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    return abfd->where;
+
+  ptr = ftell (bfd_cache_lookup (abfd));
+
+  if (abfd->my_archive)
+    ptr -= abfd->origin;
+  abfd->where = ptr;
+  return ptr;
+}
+
+int
+bfd_flush (abfd)
+     bfd *abfd;
+{
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    return 0;
+  return fflush (bfd_cache_lookup(abfd));
+}
+
+/* Returns 0 for success, negative value for failure (in which case
+   bfd_get_error can retrieve the error code).  */
+int
+bfd_stat (abfd, statbuf)
+     bfd *abfd;
+     struct stat *statbuf;
+{
+  FILE *f;
+  int result;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    abort ();
+
+  f = bfd_cache_lookup (abfd);
+  if (f == NULL)
+    {
+      bfd_set_error (bfd_error_system_call);
+      return -1;
+    }
+  result = fstat (fileno (f), statbuf);
+  if (result < 0)
+    bfd_set_error (bfd_error_system_call);
+  return result;
+}
+
+/* Returns 0 for success, nonzero for failure (in which case bfd_get_error
+   can retrieve the error code).  */
+
+int
+bfd_seek (abfd, position, direction)
+     bfd *abfd;
+     file_ptr position;
+     int direction;
+{
+  int result;
+  FILE *f;
+  long file_position;
+  /* For the time being, a BFD may not seek to it's end.  The problem
+     is that we don't easily have a way to recognize the end of an
+     element in an archive.  */
+
+  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
+
+  if (direction == SEEK_CUR && position == 0)
+    return 0;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    {
+      struct bfd_in_memory *bim;
+
+      bim = (struct bfd_in_memory *) abfd->iostream;
+
+      if (direction == SEEK_SET)
+       abfd->where = position;
+      else
+       abfd->where += position;
+
+      if (abfd->where > bim->size)
+       {
+         if ((abfd->direction == write_direction) ||
+             (abfd->direction == both_direction))
+           {
+             bfd_size_type newsize, oldsize;
+             oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
+             bim->size = abfd->where;
+             /* Round up to cut down on memory fragmentation */
+             newsize = (bim->size + 127) & ~(bfd_size_type) 127;
+             if (newsize > oldsize)
+               {
+                 bim->buffer = (bfd_byte *) bfd_realloc (bim->buffer, newsize);
+                 if (bim->buffer == 0)
+                   {
+                     bim->size = 0;
+                     return -1;
+                   }
+               }
+           }
+         else
+           {
+             abfd->where = bim->size;
+             bfd_set_error (bfd_error_file_truncated);
+             return -1;
+           }
+       }
+      return 0;
+    }
+
+  if (abfd->format != bfd_archive && abfd->my_archive == 0)
+    {
+#if 0
+      /* Explanation for this code: I'm only about 95+% sure that the above
+        conditions are sufficient and that all i/o calls are properly
+        adjusting the `where' field.  So this is sort of an `assert'
+        that the `where' field is correct.  If we can go a while without
+        tripping the abort, we can probably safely disable this code,
+        so that the real optimizations happen.  */
+      file_ptr where_am_i_now;
+      where_am_i_now = ftell (bfd_cache_lookup (abfd));
+      if (abfd->my_archive)
+       where_am_i_now -= abfd->origin;
+      if (where_am_i_now != abfd->where)
+       abort ();
+#endif
+      if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
+       return 0;
+    }
+  else
+    {
+      /* We need something smarter to optimize access to archives.
+        Currently, anything inside an archive is read via the file
+        handle for the archive.  Which means that a bfd_seek on one
+        component affects the `current position' in the archive, as
+        well as in any other component.
+
+        It might be sufficient to put a spike through the cache
+        abstraction, and look to the archive for the file position,
+        but I think we should try for something cleaner.
+
+        In the meantime, no optimization for archives.  */
+    }
+
+  f = bfd_cache_lookup (abfd);
+  file_position = position;
+  if (direction == SEEK_SET && abfd->my_archive != NULL)
+    file_position += abfd->origin;
+
+  result = fseek (f, file_position, direction);
+  if (result != 0)
+    {
+      int hold_errno = errno;
+
+      /* Force redetermination of `where' field.  */
+      bfd_tell (abfd);
+
+      /* An EINVAL error probably means that the file offset was
+         absurd.  */
+      if (hold_errno == EINVAL)
+       bfd_set_error (bfd_error_file_truncated);
+      else
+       {
+         bfd_set_error (bfd_error_system_call);
+         errno = hold_errno;
+       }
+    }
+  else
+    {
+      /* Adjust `where' field.  */
+      if (direction == SEEK_SET)
+       abfd->where = position;
+      else
+       abfd->where += position;
+    }
+  return result;
+}
+
+/*
+FUNCTION
+       bfd_get_mtime
+
+SYNOPSIS
+       long bfd_get_mtime(bfd *abfd);
+
+DESCRIPTION
+       Return the file modification time (as read from the file system, or
+       from the archive header for archive members).
+
+*/
+
+long
+bfd_get_mtime (abfd)
+     bfd *abfd;
+{
+  FILE *fp;
+  struct stat buf;
+
+  if (abfd->mtime_set)
+    return abfd->mtime;
+
+  fp = bfd_cache_lookup (abfd);
+  if (0 != fstat (fileno (fp), &buf))
+    return 0;
+
+  abfd->mtime = buf.st_mtime;          /* Save value in case anyone wants it */
+  return buf.st_mtime;
+}
+
+/*
+FUNCTION
+       bfd_get_size
+
+SYNOPSIS
+       long bfd_get_size(bfd *abfd);
+
+DESCRIPTION
+       Return the file size (as read from file system) for the file
+       associated with BFD @var{abfd}.
+
+       The initial motivation for, and use of, this routine is not
+       so we can get the exact size of the object the BFD applies to, since
+       that might not be generally possible (archive members for example).
+       It would be ideal if someone could eventually modify
+       it so that such results were guaranteed.
+
+       Instead, we want to ask questions like "is this NNN byte sized
+       object I'm about to try read from file offset YYY reasonable?"
+       As as example of where we might do this, some object formats
+       use string tables for which the first <<sizeof (long)>> bytes of the
+       table contain the size of the table itself, including the size bytes.
+       If an application tries to read what it thinks is one of these
+       string tables, without some way to validate the size, and for
+       some reason the size is wrong (byte swapping error, wrong location
+       for the string table, etc.), the only clue is likely to be a read
+       error when it tries to read the table, or a "virtual memory
+       exhausted" error when it tries to allocate 15 bazillon bytes
+       of space for the 15 bazillon byte table it is about to read.
+       This function at least allows us to answer the quesion, "is the
+       size reasonable?".
+*/
+
+long
+bfd_get_size (abfd)
+     bfd *abfd;
+{
+  FILE *fp;
+  struct stat buf;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    return ((struct bfd_in_memory *) abfd->iostream)->size;
+
+  fp = bfd_cache_lookup (abfd);
+  if (0 != fstat (fileno (fp), & buf))
+    return 0;
+
+  return buf.st_size;
+}
diff --git a/bfd/bfdwin.c b/bfd/bfdwin.c
new file mode 100644 (file)
index 0000000..442a8a4
--- /dev/null
@@ -0,0 +1,255 @@
+/* Support for memory-mapped windows into a BFD.
+   Copyright 1995, 1996, 2001, 2002 Free Software Foundation, Inc.
+   Written by Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sysdep.h"
+
+#include "bfd.h"
+#include "libbfd.h"
+
+/* Currently, if USE_MMAP is undefined, none if the window stuff is
+   used.  Okay, so it's mis-named.  At least the command-line option
+   "--without-mmap" is more obvious than "--without-windows" or some
+   such.  */
+
+#ifdef USE_MMAP
+
+#undef HAVE_MPROTECT /* code's not tested yet */
+
+#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
+#include <sys/mman.h>
+#endif
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+static int debug_windows;
+
+/* The idea behind the next and refcount fields is that one mapped
+   region can suffice for multiple read-only windows or multiple
+   non-overlapping read-write windows.  It's not implemented yet
+   though.  */
+
+/*
+INTERNAL_DEFINITION
+
+.struct _bfd_window_internal {
+.  struct _bfd_window_internal *next;
+.  PTR data;
+.  bfd_size_type size;
+.  int refcount : 31;          {* should be enough...  *}
+.  unsigned mapped : 1;                {* 1 = mmap, 0 = malloc *}
+.};
+*/
+
+void
+bfd_init_window (windowp)
+     bfd_window *windowp;
+{
+  windowp->data = 0;
+  windowp->i = 0;
+  windowp->size = 0;
+}
+
+void
+bfd_free_window (windowp)
+     bfd_window *windowp;
+{
+  bfd_window_internal *i = windowp->i;
+  windowp->i = 0;
+  windowp->data = 0;
+  if (i == 0)
+    return;
+  i->refcount--;
+  if (debug_windows)
+    fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n",
+            windowp, windowp->data, windowp->size, windowp->i);
+  if (i->refcount != 0)
+    return;
+
+  if (i->mapped)
+    {
+#ifdef HAVE_MMAP
+      munmap (i->data, i->size);
+      goto no_free;
+#else
+      abort ();
+#endif
+    }
+#ifdef HAVE_MPROTECT
+  mprotect (i->data, i->size, PROT_READ | PROT_WRITE);
+#endif
+  free (i->data);
+#ifdef HAVE_MMAP
+ no_free:
+#endif
+  i->data = 0;
+  /* There should be no more references to i at this point.  */
+  free (i);
+}
+
+static int ok_to_map = 1;
+
+bfd_boolean
+bfd_get_file_window (abfd, offset, size, windowp, writable)
+     bfd *abfd;
+     file_ptr offset;
+     bfd_size_type size;
+     bfd_window *windowp;
+     bfd_boolean writable;
+{
+  static size_t pagesize;
+  bfd_window_internal *i = windowp->i;
+  bfd_size_type size_to_alloc = size;
+
+  if (debug_windows)
+    fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)",
+            abfd, (long) offset, (long) size,
+            windowp, windowp->data, (unsigned long) windowp->size,
+            windowp->i, writable);
+
+  /* Make sure we know the page size, so we can be friendly to mmap.  */
+  if (pagesize == 0)
+    pagesize = getpagesize ();
+  if (pagesize == 0)
+    abort ();
+
+  if (i == 0)
+    {
+      i = ((bfd_window_internal *)
+          bfd_zmalloc ((bfd_size_type) sizeof (bfd_window_internal)));
+      windowp->i = i;
+      if (i == 0)
+       return FALSE;
+      i->data = 0;
+    }
+#ifdef HAVE_MMAP
+  if (ok_to_map
+      && (i->data == 0 || i->mapped == 1)
+      && (abfd->flags & BFD_IN_MEMORY) == 0)
+    {
+      file_ptr file_offset, offset2;
+      size_t real_size;
+      int fd;
+      FILE *f;
+
+      /* Find the real file and the real offset into it.  */
+      while (abfd->my_archive != NULL)
+       {
+         offset += abfd->origin;
+         abfd = abfd->my_archive;
+       }
+      f = bfd_cache_lookup (abfd);
+      fd = fileno (f);
+
+      /* Compute offsets and size for mmap and for the user's data.  */
+      offset2 = offset % pagesize;
+      if (offset2 < 0)
+       abort ();
+      file_offset = offset - offset2;
+      real_size = offset + size - file_offset;
+      real_size = real_size + pagesize - 1;
+      real_size -= real_size % pagesize;
+
+      /* If we're re-using a memory region, make sure it's big enough.  */
+      if (i->data && i->size < size)
+       {
+         munmap (i->data, i->size);
+         i->data = 0;
+       }
+      i->data = mmap (i->data, real_size,
+                     writable ? PROT_WRITE | PROT_READ : PROT_READ,
+                     (writable
+                      ? MAP_FILE | MAP_PRIVATE
+                      : MAP_FILE | MAP_SHARED),
+                     fd, file_offset);
+      if (i->data == (PTR) -1)
+       {
+         /* An error happened.  Report it, or try using malloc, or
+            something.  */
+         bfd_set_error (bfd_error_system_call);
+         i->data = 0;
+         windowp->data = 0;
+         if (debug_windows)
+           fprintf (stderr, "\t\tmmap failed!\n");
+         return FALSE;
+       }
+      if (debug_windows)
+       fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
+                (long) real_size, i->data, (long) offset2);
+      i->size = real_size;
+      windowp->data = (PTR) ((bfd_byte *) i->data + offset2);
+      windowp->size = size;
+      i->mapped = 1;
+      return TRUE;
+    }
+  else if (debug_windows)
+    {
+      if (ok_to_map)
+       fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
+                (unsigned long) i->data, (int) i->mapped);
+      else
+       fprintf (stderr, _("not mapping: env var not set\n"));
+    }
+#else
+  ok_to_map = 0;
+#endif
+
+#ifdef HAVE_MPROTECT
+  if (!writable)
+    {
+      size_to_alloc += pagesize - 1;
+      size_to_alloc -= size_to_alloc % pagesize;
+    }
+#endif
+  if (debug_windows)
+    fprintf (stderr, "\n\t%s(%6ld)",
+            i->data ? "realloc" : " malloc", (long) size_to_alloc);
+  i->data = (PTR) bfd_realloc (i->data, size_to_alloc);
+  if (debug_windows)
+    fprintf (stderr, "\t-> %p\n", i->data);
+  i->refcount = 1;
+  if (i->data == NULL)
+    {
+      if (size_to_alloc == 0)
+       return TRUE;
+      return FALSE;
+    }
+  if (bfd_seek (abfd, offset, SEEK_SET) != 0)
+    return FALSE;
+  i->size = bfd_bread (i->data, size, abfd);
+  if (i->size != size)
+    return FALSE;
+  i->mapped = 0;
+#ifdef HAVE_MPROTECT
+  if (!writable)
+    {
+      if (debug_windows)
+       fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
+                (long) i->size);
+      mprotect (i->data, i->size, PROT_READ);
+    }
+#endif
+  windowp->data = i->data;
+  windowp->size = i->size;
+  return TRUE;
+}
+
+#endif /* USE_MMAP */
diff --git a/config/accross.m4 b/config/accross.m4
new file mode 100644 (file)
index 0000000..a4cebf6
--- /dev/null
@@ -0,0 +1,98 @@
+AC_DEFUN([AC_COMPILE_CHECK_SIZEOF],
+[changequote(<<, >>)dnl
+dnl The name to #define.
+define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
+dnl The cache variable name.
+define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
+changequote([, ])dnl
+AC_MSG_CHECKING(size of $1)
+AC_CACHE_VAL(AC_CV_NAME,
+[for ac_size in 4 8 1 2 16 12 $2 ; do # List sizes in rough order of prevalence.
+  AC_TRY_COMPILE([#include "confdefs.h"
+#include <sys/types.h>
+$2
+], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size)
+  if test x$AC_CV_NAME != x ; then break; fi
+done
+])
+if test x$AC_CV_NAME = x ; then
+  AC_MSG_ERROR([cannot determine a size for $1])
+fi
+AC_MSG_RESULT($AC_CV_NAME)
+AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1])
+undefine([AC_TYPE_NAME])dnl
+undefine([AC_CV_NAME])dnl
+])
+
+AC_DEFUN([AC_C_BIGENDIAN_CROSS],
+[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian,
+[ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif], [# It does; now see whether it defined to BIG_ENDIAN or not.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)])
+if test $ac_cv_c_bigendian = unknown; then
+AC_TRY_RUN([main () {
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes,
+[ echo $ac_n "cross-compiling... " 2>&AC_FD_MSG ])
+fi])
+if test $ac_cv_c_bigendian = unknown; then
+AC_MSG_CHECKING(to probe for byte ordering)
+[
+cat >conftest.c <<EOF
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii() { char* s = (char*) ascii_mm; s = (char*) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic() { char* s = (char*) ebcdic_mm; s = (char*) ebcdic_ii; }
+int main() { _ascii (); _ebcdic (); return 0; }
+EOF
+] if test -f conftest.c ; then
+     if ${CC-cc} ${CFLAGS} conftest.c -o conftest.o && test -f conftest.o ; then
+        if test `grep -l BIGenDianSyS conftest.o` ; then
+           echo $ac_n ' big endian probe OK, ' 1>&AC_FD_MSG
+           ac_cv_c_bigendian=yes
+        fi
+        if test `grep -l LiTTleEnDian conftest.o` ; then
+           echo $ac_n ' little endian probe OK, ' 1>&AC_FD_MSG
+           if test $ac_cv_c_bigendian = yes ; then
+            ac_cv_c_bigendian=unknown;
+           else
+            ac_cv_c_bigendian=no
+           fi
+        fi
+        echo $ac_n 'guessing bigendian ...  ' >&AC_FD_MSG
+     fi
+  fi
+AC_MSG_RESULT($ac_cv_c_bigendian)
+fi
+if test $ac_cv_c_bigendian = yes; then
+  AC_DEFINE(WORDS_BIGENDIAN, 1, [whether byteorder is bigendian])
+  AC_DEFINE(HOST_WORDS_BIG_ENDIAN, 1,
+  [Define if the host machine stores words of multi-word integers in
+   big-endian order.])
+  BYTEORDER=4321
+else
+  BYTEORDER=1234
+fi
+AC_DEFINE_UNQUOTED(BYTEORDER, $BYTEORDER, [1234 = LIL_ENDIAN, 4321 = BIGENDIAN])
+if test $ac_cv_c_bigendian = unknown; then
+  AC_MSG_ERROR(unknown endianess - sorry, please pre-set ac_cv_c_bigendian)
+fi
+])
diff --git a/gdb/hppa-hpux-tdep.c b/gdb/hppa-hpux-tdep.c
new file mode 100644 (file)
index 0000000..37e6ccb
--- /dev/null
@@ -0,0 +1,45 @@
+/* Target-dependent code for HPUX running on PA-RISC, for GDB.
+   Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "osabi.h"
+
+/* Forward declarations.  */
+extern void _initialize_hppa_hpux_tdep (void);
+extern initialize_file_ftype _initialize_hppa_hpux_tdep;
+
+static void
+hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+}
+
+static void
+hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+}
+
+void
+_initialize_hppa_hpux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_SOM,
+                          hppa_hpux_som_init_abi);
+  gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_ELF,
+                          hppa_hpux_elf_init_abi);
+}
diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h
new file mode 100644 (file)
index 0000000..8da568e
--- /dev/null
@@ -0,0 +1,47 @@
+/* Common target dependent code for the Motorola 68000 series.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef M68K_TDEP_H
+#define M68K_TDEP_H
+
+/* Register numbers of various important registers.
+   Note that some of these values are "real" register numbers,
+   and correspond to the general registers of the machine,
+   and some are "phony" register numbers which are too large
+   to be actual register numbers as far as the user is concerned
+   but do serve to get the desired values when passed to read_register.  */
+
+enum
+{
+  M68K_D0_REGNUM = 0,
+  M68K_A0_REGNUM = 8,
+  M68K_A1_REGNUM = 9,
+  M68K_FP_REGNUM = 14,         /* Contains address of executing stack frame */
+  M68K_SP_REGNUM = 15,         /* Contains address of top of stack */
+  M68K_PS_REGNUM = 16,         /* Contains processor status */
+  M68K_PC_REGNUM = 17,         /* Contains program counter */
+  M68K_FP0_REGNUM = 18,                /* Floating point register 0 */
+  M68K_FPC_REGNUM = 26,                /* 68881 control register */
+  M68K_FPS_REGNUM = 27,                /* 68881 status register */
+  M68K_FPI_REGNUM = 28
+};
+
+#endif /* M68K_TDEP_H */
diff --git a/gdb/m68klinux-tdep.c b/gdb/m68klinux-tdep.c
new file mode 100644 (file)
index 0000000..afd2d2d
--- /dev/null
@@ -0,0 +1,126 @@
+/* Motorola m68k target-dependent support for GNU/Linux.
+
+   Copyright 1996, 1998, 2000, 2001, 2002 Free Software Foundation,
+   Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+
+\f
+/* Check whether insn1 and insn2 are parts of a signal trampoline.  */
+
+#define IS_SIGTRAMP(insn1, insn2)                                      \
+  (/* addaw #20,sp; moveq #119,d0; trap #0 */                          \
+   (insn1 == 0xdefc0014 && insn2 == 0x70774e40)                                \
+   /* moveq #119,d0; trap #0 */                                                \
+   || insn1 == 0x70774e40)
+
+#define IS_RT_SIGTRAMP(insn1, insn2)                                   \
+  (/* movel #173,d0; trap #0 */                                                \
+   (insn1 == 0x203c0000 && insn2 == 0x00ad4e40)                                \
+   /* moveq #82,d0; notb d0; trap #0 */                                        \
+   || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40))
+
+/* Return non-zero if PC points into the signal trampoline.  For the sake
+   of m68k_linux_frame_saved_pc we also distinguish between non-RT and RT
+   signal trampolines.  */
+
+int
+m68k_linux_in_sigtramp (CORE_ADDR pc)
+{
+  CORE_ADDR sp;
+  char buf[12];
+  unsigned long insn0, insn1, insn2;
+
+  if (read_memory_nobpt (pc - 4, buf, sizeof (buf)))
+    return 0;
+  insn1 = extract_unsigned_integer (buf + 4, 4);
+  insn2 = extract_unsigned_integer (buf + 8, 4);
+  if (IS_SIGTRAMP (insn1, insn2))
+    return 1;
+  if (IS_RT_SIGTRAMP (insn1, insn2))
+    return 2;
+
+  insn0 = extract_unsigned_integer (buf, 4);
+  if (IS_SIGTRAMP (insn0, insn1))
+    return 1;
+  if (IS_RT_SIGTRAMP (insn0, insn1))
+    return 2;
+
+  insn0 = (insn0 << 16) | (insn1 >> 16);
+  insn1 = (insn1 << 16) | (insn2 >> 16);
+  if (IS_SIGTRAMP (insn0, insn1))
+    return 1;
+  if (IS_RT_SIGTRAMP (insn0, insn1))
+    return 2;
+
+  return 0;
+}
+
+/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
+#define SIGCONTEXT_PC_OFFSET 26
+
+/* Offset to saved PC in ucontext, from <asm/ucontext.h>.  */
+#define UCONTEXT_PC_OFFSET 88
+
+/* Get saved user PC for sigtramp from sigcontext or ucontext.  */
+
+static CORE_ADDR
+m68k_linux_sigtramp_saved_pc (struct frame_info *frame)
+{
+  CORE_ADDR sigcontext_addr;
+  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+  int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+  int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
+
+  /* Get sigcontext address, it is the third parameter on the stack.  */
+  if (frame->next)
+    sigcontext_addr
+      = read_memory_unsigned_integer (FRAME_ARGS_ADDRESS (frame->next)
+                                     + FRAME_ARGS_SKIP
+                                     + sigcontext_offs,
+                                     ptrbytes);
+  else
+    sigcontext_addr
+      = read_memory_unsigned_integer (read_register (SP_REGNUM)
+                                     + sigcontext_offs,
+                                     ptrbytes);
+
+  /* Don't cause a memory_error when accessing sigcontext in case the
+     stack layout has changed or the stack is corrupt.  */
+  if (m68k_linux_in_sigtramp (frame->pc) == 2)
+    target_read_memory (sigcontext_addr + UCONTEXT_PC_OFFSET, buf, ptrbytes);
+  else
+    target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
+  return extract_unsigned_integer (buf, ptrbytes);
+}
+
+/* Return the saved program counter for FRAME.  */
+
+CORE_ADDR
+m68k_linux_frame_saved_pc (struct frame_info *frame)
+{
+  if (get_frame_type (frame) == SIGTRAMP_FRAME)
+    return m68k_linux_sigtramp_saved_pc (frame);
+
+  return read_memory_unsigned_integer (frame->frame + 4, 4);
+}
diff --git a/gdb/mi/mi-cmd-env.c b/gdb/mi/mi-cmd-env.c
new file mode 100644 (file)
index 0000000..104a73b
--- /dev/null
@@ -0,0 +1,254 @@
+/* MI Command Set - environment commands.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Red Hat Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include "defs.h"
+#include "inferior.h"
+#include "value.h"
+#include "mi-out.h"
+#include "mi-cmds.h"
+#include "mi-getopt.h"
+#include "symtab.h"
+#include "target.h"
+#include "environ.h"
+#include "command.h"
+#include "ui-out.h"
+#include "top.h"
+
+static void env_cli_command (const char *cli, char *args);
+static void env_mod_path (char *dirname, char **which_path);
+extern void _initialize_mi_cmd_env (void);
+
+static const char path_var_name[] = "PATH";
+static char *orig_path = NULL;
+
+/* The following is copied from mi-main.c so for m1 and below we
+   can perform old behavior and use cli commands.  */
+static void
+env_execute_cli_command (const char *cli, char *args)
+{
+  if (cli != 0)
+    {
+      struct cleanup *old_cleanups;
+      char *run;
+      xasprintf (&run, cli, args);
+      old_cleanups = make_cleanup (xfree, run);
+      execute_command ( /*ui */ run, 0 /*from_tty */ );
+      do_cleanups (old_cleanups);
+      return;
+    }
+}
+
+
+/* Print working directory.  */
+enum mi_cmd_result
+mi_cmd_env_pwd (char *command, char **argv, int argc)
+{
+  if (argc > 0)
+    error ("mi_cmd_env_pwd: No arguments required");
+          
+  if (mi_version (uiout) < 2)
+    {
+      env_execute_cli_command ("pwd", NULL);
+      return MI_CMD_DONE;
+    }
+     
+  /* Otherwise the mi level is 2 or higher.  */
+
+  getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+  ui_out_field_string (uiout, "cwd", gdb_dirbuf);
+
+  return MI_CMD_DONE;
+}
+
+/* Change working directory.  */
+enum mi_cmd_result
+mi_cmd_env_cd (char *command, char **argv, int argc)
+{
+  if (argc == 0 || argc > 1)
+    error ("mi_cmd_env_cd: Usage DIRECTORY");
+          
+  env_execute_cli_command ("cd %s", argv[0]);
+
+  return MI_CMD_DONE;
+}
+
+static void
+env_mod_path (char *dirname, char **which_path)
+{
+  if (dirname == 0 || dirname[0] == '\0')
+    return;
+
+  /* Call add_path with last arg 0 to indicate not to parse for 
+     separator characters.  */
+  add_path (dirname, which_path, 0);
+}
+
+/* Add one or more directories to start of executable search path.  */
+enum mi_cmd_result
+mi_cmd_env_path (char *command, char **argv, int argc)
+{
+  char *exec_path;
+  char *env;
+  int reset = 0;
+  int optind = 0;
+  int i;
+  char *optarg;
+  enum opt
+    {
+      RESET_OPT
+    };
+  static struct mi_opt opts[] =
+  {
+    {"r", RESET_OPT, 0},
+    0
+  };
+
+  dont_repeat ();
+
+  if (mi_version (uiout) < 2)
+    {
+      for (i = argc - 1; i >= 0; --i)
+       env_execute_cli_command ("path %s", argv[i]);
+      return MI_CMD_DONE;
+    }
+
+  /* Otherwise the mi level is 2 or higher.  */
+  while (1)
+    {
+      int opt = mi_getopt ("mi_cmd_env_path", argc, argv, opts,
+                           &optind, &optarg);
+      if (opt < 0)
+        break;
+      switch ((enum opt) opt)
+        {
+        case RESET_OPT:
+          reset = 1;
+          break;
+        }
+    }
+  argv += optind;
+  argc -= optind;
+
+
+  if (reset)
+    {
+      /* Reset implies resetting to original path first.  */
+      exec_path = xstrdup (orig_path);
+    }
+  else
+    {
+      /* Otherwise, get current path to modify.  */
+      env = get_in_environ (inferior_environ, path_var_name);
+
+      /* Can be null if path is not set.  */
+      if (!env)
+        env = "";
+      exec_path = xstrdup (env);
+    }
+
+  for (i = argc - 1; i >= 0; --i)
+    env_mod_path (argv[i], &exec_path);
+
+  set_in_environ (inferior_environ, path_var_name, exec_path);
+  xfree (exec_path);
+  env = get_in_environ (inferior_environ, path_var_name);
+  ui_out_field_string (uiout, "path", env);
+
+  return MI_CMD_DONE;
+}
+
+/* Add zero or more directories to the front of the source path.  */
+enum mi_cmd_result
+mi_cmd_env_dir (char *command, char **argv, int argc)
+{
+  int i;
+  int optind = 0;
+  int reset = 0;
+  char *optarg;
+  enum opt
+    {
+      RESET_OPT
+    };
+  static struct mi_opt opts[] =
+  {
+    {"r", RESET_OPT, 0},
+    0
+  };
+
+  dont_repeat ();
+
+  if (mi_version (uiout) < 2)
+    {
+      for (i = argc - 1; i >= 0; --i)
+       env_execute_cli_command ("dir %s", argv[i]);
+      return MI_CMD_DONE;
+    }
+
+  /* Otherwise mi level is 2 or higher.  */
+  while (1)
+    {
+      int opt = mi_getopt ("mi_cmd_env_dir", argc, argv, opts,
+                           &optind, &optarg);
+      if (opt < 0)
+        break;
+      switch ((enum opt) opt)
+        {
+        case RESET_OPT:
+          reset = 1;
+          break;
+        }
+    }
+  argv += optind;
+  argc -= optind;
+
+  if (reset)
+    {
+      /* Reset means setting to default path first.  */
+      xfree (source_path);
+      init_source_path ();
+    }
+
+  for (i = argc - 1; i >= 0; --i)
+    env_mod_path (argv[i], &source_path);
+  init_last_source_visited ();
+
+  ui_out_field_string (uiout, "source-path", source_path);
+  forget_cached_source_info ();
+
+  return MI_CMD_DONE;
+}
+
+void 
+_initialize_mi_cmd_env (void)
+{
+  char *env;
+
+  /* We want original execution path to reset to, if desired later.  */
+  env = get_in_environ (inferior_environ, path_var_name);
+
+  /* Can be null if path is not set.  */
+  if (!env)
+    env = "";
+  orig_path = xstrdup (env);
+}
diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h
new file mode 100644 (file)
index 0000000..92202e2
--- /dev/null
@@ -0,0 +1,41 @@
+/* Target-dependent header for the MIPS architecture, for GDB, the GNU Debugger.
+
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef MIPS_TDEP_H
+#define MIPS_TDEP_H
+
+/* All the possible MIPS ABIs. */
+enum mips_abi
+  {
+    MIPS_ABI_UNKNOWN = 0,
+    MIPS_ABI_N32,
+    MIPS_ABI_O32,
+    MIPS_ABI_N64,
+    MIPS_ABI_O64,
+    MIPS_ABI_EABI32,
+    MIPS_ABI_EABI64,
+    MIPS_ABI_LAST
+  };
+
+/* Return the MIPS ABI associated with GDBARCH.  */
+enum mips_abi mips_abi (struct gdbarch *gdbarch);
+
+#endif /* MIPS_TDEP_H */
diff --git a/gdb/testsuite/gdb.base/store.c b/gdb/testsuite/gdb.base/store.c
new file mode 100644 (file)
index 0000000..802945f
--- /dev/null
@@ -0,0 +1,255 @@
+/* Check that GDB can correctly update a value, living in a register,
+   in the target.  This pretty much relies on the compiler taking heed
+   of requests for values to be stored in registers.  */
+
+/* NOTE: carlton/2002-12-05: These functions were all static, but for
+   whatever reason that caused GCC 3.1 to optimize away some of the
+   function calls within main even when no optimization flags were
+   passed.  */
+
+char
+add_char (register char u, register char v)
+{
+  return u + v;
+}
+
+short
+add_short (register short u, register short v)
+{
+  return u + v;
+}
+
+int
+add_int (register int u, register int v)
+{
+  return u + v;
+}
+
+long
+add_long (register long u, register long v)
+{
+  return u + v;
+}
+
+float
+add_float (register float u, register float v)
+{
+  return u + v;
+}
+
+double
+add_double (register double u, register double v)
+{
+  return u + v;
+}
+
+/* */
+
+char
+wack_char (register char u, register char v)
+{
+  register char l = u;
+  l = add_char (l, v);
+  return l;
+}
+
+short
+wack_short (register short u, register short v)
+{
+  register short l = u;
+  l = add_short (l, v);
+  return l;
+}
+
+int
+wack_int (register int u, register int v)
+{
+  register int l = u;
+  l = add_int (l, v);
+  return l;
+}
+
+long
+wack_long (register long u, register long v)
+{
+  register long l = u;
+  l = add_long (l, v);
+  return l;
+}
+
+float
+wack_float (register float u, register float v)
+{
+  register float l = u;
+  l = add_float (l, v);
+  return l;
+}
+
+double
+wack_double (register double u, register double v)
+{
+  register double l = u;
+  l = add_double (l, v);
+  return l;
+}
+
+struct s_1 { short s[1]; } z_1, s_1;
+struct s_2 { short s[2]; } z_2, s_2;
+struct s_3 { short s[3]; } z_3, s_3;
+struct s_4 { short s[4]; } z_4, s_4;
+
+struct s_1
+add_struct_1 (struct s_1 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+struct s_2
+add_struct_2 (struct s_2 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+struct s_3
+add_struct_3 (struct s_3 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+struct s_4
+add_struct_4 (struct s_4 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+struct s_1
+wack_struct_1 (void)
+{
+  int i; register struct s_1 u = z_1;
+  for (i = 0; i < sizeof (s_1) / sizeof (s_1.s[0]); i++) { s_1.s[i] = i + 1; }
+  u = add_struct_1 (u);
+  return u;
+}
+
+struct s_2
+wack_struct_2 (void)
+{
+  int i; register struct s_2 u = z_2;
+  for (i = 0; i < sizeof (s_2) / sizeof (s_2.s[0]); i++) { s_2.s[i] = i + 1; }
+  u = add_struct_2 (u);
+  return u;
+}
+
+struct s_3
+wack_struct_3 (void)
+{
+  int i; register struct s_3 u = z_3;
+  for (i = 0; i < sizeof (s_3) / sizeof (s_3.s[0]); i++) { s_3.s[i] = i + 1; }
+  u = add_struct_3 (u);
+  return u;
+}
+
+struct s_4
+wack_struct_4 (void)
+{
+  int i; register struct s_4 u = z_4;
+  for (i = 0; i < sizeof (s_4) / sizeof (s_4.s[0]); i++) { s_4.s[i] = i + 1; }
+  u = add_struct_4 (u);
+  return u;
+}
+
+/* */
+
+struct f_1 {unsigned i:1;unsigned j:1;unsigned k:1; } f_1 = {1,1,1}, F_1;
+struct f_2 {unsigned i:2;unsigned j:2;unsigned k:2; } f_2 = {1,1,1}, F_2;
+struct f_3 {unsigned i:3;unsigned j:3;unsigned k:3; } f_3 = {1,1,1}, F_3;
+struct f_4 {unsigned i:4;unsigned j:4;unsigned k:4; } f_4 = {1,1,1}, F_4;
+
+struct f_1
+wack_field_1 (void)
+{
+  register struct f_1 u = f_1;
+  return u;
+}
+
+struct f_2
+wack_field_2 (void)
+{
+  register struct f_2 u = f_2;
+  return u;
+}
+
+struct f_3
+wack_field_3 (void)
+{
+  register struct f_3 u = f_3;
+  return u;
+}
+
+struct f_4
+wack_field_4 (void)
+{
+  register struct f_4 u = f_4;
+  return u;
+}
+
+/* */
+
+int
+main ()
+{
+  /* These calls are for current frame test.  */
+  wack_char (1, 2);
+  wack_short (1, 2);
+  wack_int (1, 2);
+  wack_long (1, 2);
+  wack_float (1, 2);
+  wack_double (1, 2);
+
+  /* These calls are for up frame.  */
+  wack_char (1, 2);
+  wack_short (1, 2);
+  wack_int (1, 2);
+  wack_long (1, 2);
+  wack_float (1, 2);
+  wack_double (1, 2);
+
+  /* These calls are for current frame test.  */
+  wack_struct_1 ();
+  wack_struct_2 ();
+  wack_struct_3 ();
+  wack_struct_4 ();
+  
+  /* These calls are for up frame.  */
+  wack_struct_1 ();
+  wack_struct_2 ();
+  wack_struct_3 ();
+  wack_struct_4 ();
+  
+  wack_field_1 ();
+  wack_field_2 ();
+  wack_field_3 ();
+  wack_field_4 ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/store.exp b/gdb/testsuite/gdb.base/store.exp
new file mode 100644 (file)
index 0000000..64a8749
--- /dev/null
@@ -0,0 +1,171 @@
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+if $tracelevel {
+    strace $tracelevel
+}
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "store"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile}] {
+    return -1;
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+#
+# set it up at a breakpoint so we can play with the variable values
+#
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+#
+
+proc check_set { t old new add } {
+    global gdb_prompt
+    gdb_test "tbreak wack_${t}"
+    gdb_test "continue" "register ${t} l = u;" "continue set ${t}"
+    gdb_test "next" "l = add_${t} .l, v.;" "next ${t}"
+    gdb_test "print l" " = ${old}" "print old ${t}"
+    gdb_test "set variable l = 4"
+    gdb_test "print l" " = ${new}" "print new ${t}"
+    gdb_test "next" "return l;"
+    gdb_test "print l" " = ${add}" "print add ${t}"
+}
+
+check_set "char" "1 ..001." "4 ..004." "6 ..006."
+check_set "short" "1" "4" "6"
+check_set "int" "1" "4" "6"
+check_set "long" "1" "4" "6"
+check_set "float" "1" "4" "6"
+check_set "double" "1" "4" "6"
+
+#
+
+proc up_set { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak add_${t}"
+    gdb_test "continue" "return u . v;" "continue up ${t}"
+    gdb_test "up" "l = add_${t} .l, v.;" "up ${t}"
+    gdb_test "print l" " = ${old}" "print old up ${t}"
+    gdb_test "set variable l = 4"
+    gdb_test "print l" " = ${new}" "print new up ${t}"
+}
+
+up_set "char" "1 ..001." "4 ..004."
+up_set "short" "1" "4"
+up_set "int" "1" "4"
+up_set "long" "1" "4"
+up_set "float" "1" "4"
+up_set "double" "1" "4"
+
+#
+
+proc check_struct { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak wack_struct_${t}"
+    gdb_test "continue" "int i; register struct s_${t} u = z_${t};" \
+           "continue set struct ${t}"
+    gdb_test "next 2" "add_struct_${t} .u.;"
+    gdb_test "print u" " = ${old}" "old check struct ${t}"
+    gdb_test "set variable u = s_${t}"
+    gdb_test "print u" " = ${new}" "new check struct ${t}"
+}
+
+check_struct "1" "{s = {0}}" "{s = {1}}"
+check_struct "2" "{s = {0, 0}}" "{s = {1, 2}}"
+check_struct "3" "{s = {0, 0, 0}}" "{s = {1, 2, 3}}"
+check_struct "4" "{s = {0, 0, 0, 0}}" "{s = {1, 2, 3, 4}}"
+
+proc up_struct { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak add_struct_${t}"
+    gdb_test "continue" "for .i = 0; i < sizeof .s. / sizeof .s.s.0..; i..." \
+           "continue up struct ${t}"
+    gdb_test "up" "u = add_struct_${t} .u.;" "up struct ${t}"
+    gdb_test "print u" " = ${old}" "old up struct ${t}"
+    gdb_test "set variable u = s_${t}"
+    gdb_test "print u" " = ${new}" "new up struct ${t}"
+}
+
+up_struct "1" "{s = {0}}" "{s = {1}}"
+up_struct "2" "{s = {0, 0}}" "{s = {1, 2}}"
+up_struct "3" "{s = {0, 0, 0}}" "{s = {1, 2, 3}}"
+up_struct "4" "{s = {0, 0, 0, 0}}" "{s = {1, 2, 3, 4}}"
+
+#
+
+proc check_field { t } {
+    global gdb_prompt
+    gdb_test "tbreak wack_field_${t}"
+    gdb_test "continue" "register struct f_${t} u = f_${t};" \
+           "continue field ${t}"
+    gdb_test "next" "return u;" "next field ${t}"
+
+    gdb_test "print u" " = {i = 1, j = 1, k = 1}" "old field ${t}"
+    gdb_test "set variable u = F_${t}"
+    gdb_test "print u" " = {i = 0, j = 0, k = 0}" "new field ${t}"
+
+    gdb_test "set variable u = F_${t}, u.i = f_${t}.i"
+    gdb_test "print u" " = {i = 1, j = 0, k = 0}" "f_${t}.i"
+
+    gdb_test "set variable u = F_${t}, u.j = f_${t}.j"
+    gdb_test "print u" " = {i = 0, j = 1, k = 0}" "f_${t}.j"
+
+    gdb_test "set variable u = F_${t}, u.k = f_${t}.k"
+    gdb_test "print u" " = {i = 0, j = 0, k = 1}" "f_${t}.k"
+
+    gdb_test "set variable u = f_${t}, u.i = F_${t}.i"
+    gdb_test "print u" " = {i = 0, j = 1, k = 1}" "F_${t}.i"
+
+    gdb_test "set variable u = f_${t}, u.j = F_${t}.j"
+    gdb_test "print u" " = {i = 1, j = 0, k = 1}" "F_${t}.j"
+
+    gdb_test "set variable u = f_${t}, u.k = F_${t}.k"
+    gdb_test "print u" " = {i = 1, j = 1, k = 0}" "F_${t}.k"
+
+}
+
+check_field 1
+check_field 2
+check_field 3
+check_field 4
+
+#
+
+# WANTED: A fairly portable way of convincing the compiler to split a
+# value across memory and registers.
+
diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c
new file mode 100644 (file)
index 0000000..c208cdc
--- /dev/null
@@ -0,0 +1,389 @@
+/* Relative (relocatable) prefix support.
+   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of libiberty.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/*
+
+@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix})
+
+Given three strings @var{progname}, @var{bin_prefix}, @var{prefix}, return a string
+that gets to @var{prefix} starting with the directory portion of @var{progname} and
+a relative pathname of the difference between @var{bin_prefix} and @var{prefix}.
+
+For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, @var{prefix}
+is @code{/alpha/beta/gamma/omega/}, and @var{progname} is @code{/red/green/blue/gcc},
+then this function will return @code{/red/green/blue/../../omega/}.
+
+The return value is normally allocated via @code{malloc}.  If no relative prefix
+can be found, return @code{NULL}.
+
+@end deftypefn
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#endif
+
+#ifndef DIR_SEPARATOR
+#  define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) \
+    || defined (__DJGPP__) || defined (__OS2__)
+#  define HAVE_DOS_BASED_FILE_SYSTEM
+#  define HAVE_HOST_EXECUTABLE_SUFFIX
+#  define HOST_EXECUTABLE_SUFFIX ".exe"
+#  ifndef DIR_SEPARATOR_2 
+#    define DIR_SEPARATOR_2 '\\'
+#  endif
+#  define PATH_SEPARATOR ';'
+#else
+#  define PATH_SEPARATOR ':'
+#endif
+
+#ifndef DIR_SEPARATOR_2
+#  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else
+#  define IS_DIR_SEPARATOR(ch) \
+       (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif
+
+#define DIR_UP ".."
+
+static char *save_string PARAMS ((const char *, int));
+static char **split_directories        PARAMS ((const char *, int *));
+static void free_split_directories PARAMS ((char **));
+
+static char *
+save_string (s, len)
+     const char *s;
+     int len;
+{
+  char *result = malloc (len + 1);
+
+  memcpy (result, s, len);
+  result[len] = 0;
+  return result;
+}
+
+/* Split a filename into component directories.  */
+
+static char **
+split_directories (name, ptr_num_dirs)
+     const char *name;
+     int *ptr_num_dirs;
+{
+  int num_dirs = 0;
+  char **dirs;
+  const char *p, *q;
+  int ch;
+
+  /* Count the number of directories.  Special case MSDOS disk names as part
+     of the initial directory.  */
+  p = name;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
+    {
+      p += 3;
+      num_dirs++;
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
+  while ((ch = *p++) != '\0')
+    {
+      if (IS_DIR_SEPARATOR (ch))
+       {
+         num_dirs++;
+         while (IS_DIR_SEPARATOR (*p))
+           p++;
+       }
+    }
+
+  dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
+  if (dirs == NULL)
+    return NULL;
+
+  /* Now copy the directory parts.  */
+  num_dirs = 0;
+  p = name;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
+    {
+      dirs[num_dirs++] = save_string (p, 3);
+      if (dirs[num_dirs - 1] == NULL)
+       {
+         free (dirs);
+         return NULL;
+       }
+      p += 3;
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
+  q = p;
+  while ((ch = *p++) != '\0')
+    {
+      if (IS_DIR_SEPARATOR (ch))
+       {
+         while (IS_DIR_SEPARATOR (*p))
+           p++;
+
+         dirs[num_dirs++] = save_string (q, p - q);
+         if (dirs[num_dirs - 1] == NULL)
+           {
+             dirs[num_dirs] = NULL;
+             free_split_directories (dirs);
+             return NULL;
+           }
+         q = p;
+       }
+    }
+
+  if (p - 1 - q > 0)
+    dirs[num_dirs++] = save_string (q, p - 1 - q);
+  dirs[num_dirs] = NULL;
+
+  if (dirs[num_dirs - 1] == NULL)
+    {
+      free_split_directories (dirs);
+      return NULL;
+    }
+
+  if (ptr_num_dirs)
+    *ptr_num_dirs = num_dirs;
+  return dirs;
+}
+
+/* Release storage held by split directories.  */
+
+static void
+free_split_directories (dirs)
+     char **dirs;
+{
+  int i = 0;
+
+  while (dirs[i] != NULL)
+    free (dirs[i++]);
+
+  free ((char *) dirs);
+}
+
+/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
+   to PREFIX starting with the directory portion of PROGNAME and a relative
+   pathname of the difference between BIN_PREFIX and PREFIX.
+
+   For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
+   /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
+   function will return /red/green/blue/../../omega/.
+
+   If no relative prefix can be found, return NULL.  */
+
+char *
+make_relative_prefix (progname, bin_prefix, prefix)
+     const char *progname;
+     const char *bin_prefix;
+     const char *prefix;
+{
+  char **prog_dirs, **bin_dirs, **prefix_dirs;
+  int prog_num, bin_num, prefix_num;
+  int i, n, common;
+  int needed_len;
+  char *ret, *ptr;
+
+  if (progname == NULL || bin_prefix == NULL || prefix == NULL)
+    return NULL;
+
+  prog_dirs = split_directories (progname, &prog_num);
+  bin_dirs = split_directories (bin_prefix, &bin_num);
+  if (bin_dirs == NULL || prog_dirs == NULL)
+    return NULL;
+
+  /* If there is no full pathname, try to find the program by checking in each
+     of the directories specified in the PATH environment variable.  */
+  if (prog_num == 1)
+    {
+      char *temp;
+
+      temp = getenv ("PATH");
+      if (temp)
+       {
+         char *startp, *endp, *nstore;
+         size_t prefixlen = strlen (temp) + 1;
+         if (prefixlen < 2)
+           prefixlen = 2;
+
+         nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
+
+         startp = endp = temp;
+         while (1)
+           {
+             if (*endp == PATH_SEPARATOR || *endp == 0)
+               {
+                 if (endp == startp)
+                   {
+                     nstore[0] = '.';
+                     nstore[1] = DIR_SEPARATOR;
+                     nstore[2] = '\0';
+                   }
+                 else
+                   {
+                     strncpy (nstore, startp, endp - startp);
+                     if (! IS_DIR_SEPARATOR (endp[-1]))
+                       {
+                         nstore[endp - startp] = DIR_SEPARATOR;
+                         nstore[endp - startp + 1] = 0;
+                       }
+                     else
+                       nstore[endp - startp] = 0;
+                   }
+                 strcat (nstore, progname);
+                 if (! access (nstore, X_OK)
+#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
+                      || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
+#endif
+                     )
+                   {
+                     free_split_directories (prog_dirs);
+                     progname = nstore;
+                     prog_dirs = split_directories (progname, &prog_num);
+                     if (prog_dirs == NULL)
+                       {
+                         free_split_directories (bin_dirs);
+                         return NULL;
+                       }
+                     break;
+                   }
+
+                 if (*endp == 0)
+                   break;
+                 endp = startp = endp + 1;
+               }
+             else
+               endp++;
+           }
+       }
+    }
+
+  /* Remove the program name from comparison of directory names.  */
+  prog_num--;
+
+  /* If we are still installed in the standard location, we don't need to
+     specify relative directories.  Also, if argv[0] still doesn't contain
+     any directory specifiers after the search above, then there is not much
+     we can do.  */
+  if (prog_num == bin_num)
+    {
+      for (i = 0; i < bin_num; i++)
+       {
+         if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
+           break;
+       }
+
+      if (prog_num <= 0 || i == bin_num)
+       {
+         free_split_directories (prog_dirs);
+         free_split_directories (bin_dirs);
+         prog_dirs = bin_dirs = (char **) 0;
+         return NULL;
+       }
+    }
+
+  prefix_dirs = split_directories (prefix, &prefix_num);
+  if (prefix_dirs == NULL)
+    {
+      free_split_directories (prog_dirs);
+      free_split_directories (bin_dirs);
+      return NULL;
+    }
+
+  /* Find how many directories are in common between bin_prefix & prefix.  */
+  n = (prefix_num < bin_num) ? prefix_num : bin_num;
+  for (common = 0; common < n; common++)
+    {
+      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
+       break;
+    }
+
+  /* If there are no common directories, there can be no relative prefix.  */
+  if (common == 0)
+    {
+      free_split_directories (prog_dirs);
+      free_split_directories (bin_dirs);
+      free_split_directories (prefix_dirs);
+      return NULL;
+    }
+
+  /* Two passes: first figure out the size of the result string, and
+     then construct it.  */
+  needed_len = 0;
+  for (i = 0; i < prog_num; i++)
+    needed_len += strlen (prog_dirs[i]);
+  needed_len += sizeof (DIR_UP) * (bin_num - common);
+  for (i = common; i < prefix_num; i++)
+    needed_len += strlen (prefix_dirs[i]);
+  needed_len += 1; /* Trailing NUL.  */
+
+  ret = (char *) malloc (needed_len);
+  if (ret == NULL)
+    return NULL;
+
+  /* Build up the pathnames in argv[0].  */
+  *ret = '\0';
+  for (i = 0; i < prog_num; i++)
+    strcat (ret, prog_dirs[i]);
+
+  /* Now build up the ..'s.  */
+  ptr = ret + strlen(ret);
+  for (i = common; i < bin_num; i++)
+    {
+      strcpy (ptr, DIR_UP);
+      ptr += sizeof (DIR_UP) - 1;
+      *(ptr++) = DIR_SEPARATOR;
+    }
+  *ptr = '\0';
+
+  /* Put in directories to move over to prefix.  */
+  for (i = common; i < prefix_num; i++)
+    strcat (ret, prefix_dirs[i]);
+
+  free_split_directories (prog_dirs);
+  free_split_directories (bin_dirs);
+  free_split_directories (prefix_dirs);
+
+  return ret;
+}
diff --git a/readline/compat.c b/readline/compat.c
new file mode 100644 (file)
index 0000000..a66d210
--- /dev/null
@@ -0,0 +1,113 @@
+/* compat.c -- backwards compatibility functions. */
+
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "rlstdc.h"
+#include "rltypedefs.h"
+
+extern void rl_free_undo_list PARAMS((void));
+extern int rl_maybe_save_line PARAMS((void));
+extern int rl_maybe_unsave_line PARAMS((void));
+extern int rl_maybe_replace_line PARAMS((void));
+
+extern int rl_crlf PARAMS((void));
+extern int rl_ding PARAMS((void));
+extern int rl_alphabetic PARAMS((int));
+
+extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *));
+extern char *rl_username_completion_function PARAMS((const char *, int));
+extern char *rl_filename_completion_function PARAMS((const char *, int));
+
+/* Provide backwards-compatible entry points for old function names. */
+
+void
+free_undo_list ()
+{
+  rl_free_undo_list ();
+}
+
+int
+maybe_replace_line ()
+{
+  return rl_maybe_replace_line ();
+}
+
+int
+maybe_save_line ()
+{
+  return rl_maybe_save_line ();
+}
+
+int
+maybe_unsave_line ()
+{
+  return rl_maybe_unsave_line ();
+}
+
+int
+ding ()
+{
+  return rl_ding ();
+}
+
+int
+crlf ()
+{
+  return rl_crlf ();
+}
+
+int
+alphabetic (c)
+     int c;
+{
+  return rl_alphabetic (c);
+}
+
+char **
+completion_matches (s, f)
+     const char *s;
+     rl_compentry_func_t *f;
+{
+  return rl_completion_matches (s, f);
+}
+
+char *
+username_completion_function (s, i)
+     const char *s;
+     int i;
+{
+  return rl_username_completion_function (s, i);
+}
+
+char *
+filename_completion_function (s, i)
+     const char *s;
+     int i;
+{
+  return rl_filename_completion_function (s, i);
+}
diff --git a/readline/doc/history.0 b/readline/doc/history.0
new file mode 100644 (file)
index 0000000..324c363
--- /dev/null
@@ -0,0 +1,660 @@
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+N\bNA\bAM\bME\bE
+       history - GNU History Library
+
+C\bCO\bOP\bPY\bYR\bRI\bIG\bGH\bHT\bT
+       The  GNU History Library is Copyright (C) 1989-2002 by the
+       Free Software Foundation, Inc.
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       Many programs read input from the user a line at  a  time.
+       The  GNU  History  library  is able to keep track of those
+       lines, associate arbitrary data with each line,  and  uti-
+       lize  information  from  previous  lines  in composing new
+       ones.
+
+
+H\bHI\bIS\bST\bTO\bOR\bRY\bY E\bEX\bXP\bPA\bAN\bNS\bSI\bIO\bON\bN
+       The history library supports a history  expansion  feature
+       that  is identical to the history expansion in b\bba\bas\bsh\bh.\b.  This
+       section describes what syntax features are available.
+
+       History expansions introduce words from the  history  list
+       into  the input stream, making it easy to repeat commands,
+       insert the arguments to a previous command into  the  cur-
+       rent  input  line,  or  fix  errors  in  previous commands
+       quickly.
+
+       History expansion is usually performed immediately after a
+       complete  line is read.  It takes place in two parts.  The
+       first is to determine which line from the history list  to
+       use during substitution.  The second is to select portions
+       of that line for inclusion into the current one.  The line
+       selected  from  the history is the _\be_\bv_\be_\bn_\bt, and the portions
+       of that line that are acted upon are _\bw_\bo_\br_\bd_\bs.  Various _\bm_\bo_\bd_\bi_\b-
+       _\bf_\bi_\be_\br_\bs are available to manipulate the selected words.  The
+       line is broken into words in the same fashion as b\bba\bas\bsh\bh does
+       when  reading input, so that several words that would oth-
+       erwise be separated are  considered  one  word  when  sur-
+       rounded  by  quotes  (see  the description of h\bhi\bis\bst\bto\bor\bry\by_\b_t\bto\bok\bk-\b-
+       e\ben\bni\biz\bze\be(\b()\b) below).  History expansions are introduced by  the
+       appearance  of the history expansion character, which is !\b!
+       by default.  Only backslash  (\\b\)  and  single  quotes  can
+       quote the history expansion character.
+
+   E\bEv\bve\ben\bnt\bt D\bDe\bes\bsi\big\bgn\bna\bat\bto\bor\brs\bs
+       An event designator is a reference to a command line entry
+       in the history list.
+
+       !\b!      Start a history substitution, except when  followed
+              by a b\bbl\bla\ban\bnk\bk, newline, = or (.
+       !\b!_\bn     Refer to command line _\bn.
+       !\b!-\b-_\bn    Refer to the current command line minus _\bn.
+       !\b!!\b!     Refer  to  the previous command.  This is a synonym
+              for `!-1'.
+
+
+
+
+GNU History 4.3          2002 January 31                        1
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       !\b!_\bs_\bt_\br_\bi_\bn_\bg
+              Refer to the  most  recent  command  starting  with
+              _\bs_\bt_\br_\bi_\bn_\bg.
+       !\b!?\b?_\bs_\bt_\br_\bi_\bn_\bg[\b[?\b?]\b]
+              Refer to the most recent command containing _\bs_\bt_\br_\bi_\bn_\bg.
+              The trailing ?\b? may be omitted if _\bs_\bt_\br_\bi_\bn_\bg is followed
+              immediately by a newline.
+       ^\b^_\bs_\bt_\br_\bi_\bn_\bg_\b1^\b^_\bs_\bt_\br_\bi_\bn_\bg_\b2^\b^
+              Quick   substitution.   Repeat  the  last  command,
+              replacing  _\bs_\bt_\br_\bi_\bn_\bg_\b1  with  _\bs_\bt_\br_\bi_\bn_\bg_\b2.   Equivalent  to
+              ``!!:s/_\bs_\bt_\br_\bi_\bn_\bg_\b1/_\bs_\bt_\br_\bi_\bn_\bg_\b2/'' (see M\bMo\bod\bdi\bif\bfi\bie\ber\brs\bs below).
+       !\b!#\b#     The entire command line typed so far.
+
+   W\bWo\bor\brd\bd D\bDe\bes\bsi\big\bgn\bna\bat\bto\bor\brs\bs
+       Word designators are used to select desired words from the
+       event.  A :\b: separates the  event  specification  from  the
+       word designator.  It may be omitted if the word designator
+       begins with a ^\b^, $\b$, *\b*, -\b-, or %\b%.  Words are  numbered  from
+       the  beginning  of  the  line,  with  the first word being
+       denoted by 0 (zero).  Words are inserted into the  current
+       line separated by single spaces.
+
+       0\b0 (\b(z\bze\ber\bro\bo)\b)
+              The  zeroth  word.  For the shell, this is the com-
+              mand word.
+       _\bn      The _\bnth word.
+       ^\b^      The first argument.  That is, word 1.
+       $\b$      The last argument.
+       %\b%      The word matched  by  the  most  recent  `?_\bs_\bt_\br_\bi_\bn_\bg?'
+              search.
+       _\bx-\b-_\by    A range of words; `-_\by' abbreviates `0-_\by'.
+       *\b*      All of the words but the zeroth.  This is a synonym
+              for `_\b1_\b-_\b$'.  It is not an error to use *\b* if there is
+              just  one  word  in  the event; the empty string is
+              returned in that case.
+       x\bx*\b*     Abbreviates _\bx_\b-_\b$.
+       x\bx-\b-     Abbreviates _\bx_\b-_\b$ like x\bx*\b*, but omits the last word.
+
+       If a word designator is supplied without an event specifi-
+       cation, the previous command is used as the event.
+
+   M\bMo\bod\bdi\bif\bfi\bie\ber\brs\bs
+       After  the  optional  word  designator, there may appear a
+       sequence of one or more of the following  modifiers,  each
+       preceded by a `:'.
+
+       h\bh      Remove a trailing file name component, leaving only
+              the head.
+       t\bt      Remove all leading file  name  components,  leaving
+              the tail.
+       r\br      Remove  a trailing suffix of the form _\b._\bx_\bx_\bx, leaving
+              the basename.
+       e\be      Remove all but the trailing suffix.
+       p\bp      Print the new command but do not execute it.
+
+
+
+GNU History 4.3          2002 January 31                        2
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       q\bq      Quote the substituted words, escaping further  sub-
+              stitutions.
+       x\bx      Quote  the  substituted  words as with q\bq, but break
+              into words at b\bbl\bla\ban\bnk\bks\bs and newlines.
+       s\bs/\b/_\bo_\bl_\bd/\b/_\bn_\be_\bw/\b/
+              Substitute _\bn_\be_\bw for the first occurrence of  _\bo_\bl_\bd  in
+              the event line.  Any delimiter can be used in place
+              of /.  The final delimiter is optional if it is the
+              last  character  of  the event line.  The delimiter
+              may be quoted in _\bo_\bl_\bd and _\bn_\be_\bw with  a  single  back-
+              slash.  If & appears in _\bn_\be_\bw, it is replaced by _\bo_\bl_\bd.
+              A single backslash will quote the  &.   If  _\bo_\bl_\bd  is
+              null, it is set to the last _\bo_\bl_\bd substituted, or, if
+              no previous history substitutions took  place,  the
+              last _\bs_\bt_\br_\bi_\bn_\bg in a !\b!?\b?_\bs_\bt_\br_\bi_\bn_\bg[\b[?\b?]\b]  search.
+       &\b&      Repeat the previous substitution.
+       g\bg      Cause  changes  to be applied over the entire event
+              line.  This is used in conjunction with `:\b:s\bs' (e.g.,
+              `:\b:g\bgs\bs/\b/_\bo_\bl_\bd/\b/_\bn_\be_\bw/\b/')  or  `:\b:&\b&'.   If used with `:\b:s\bs', any
+              delimiter can be used in place of /, and the  final
+              delimiter  is  optional if it is the last character
+              of the event line.
+
+P\bPR\bRO\bOG\bGR\bRA\bAM\bMM\bMI\bIN\bNG\bG W\bWI\bIT\bTH\bH H\bHI\bIS\bST\bTO\bOR\bRY\bY F\bFU\bUN\bNC\bCT\bTI\bIO\bON\bNS\bS
+       This section describes how to use the History  library  in
+       other programs.
+
+   I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn t\bto\bo H\bHi\bis\bst\bto\bor\bry\by
+       The  programmer  using  the  History library has available
+       functions for remembering lines on a history list, associ-
+       ating  arbitrary data with a line, removing lines from the
+       list, searching through the list for a line containing  an
+       arbitrary  text  string,  and  referencing any line in the
+       list directly.  In addition, a history _\be_\bx_\bp_\ba_\bn_\bs_\bi_\bo_\bn  function
+       is  available  which provides for a consistent user inter-
+       face across different programs.
+
+       The user using programs written with the  History  library
+       has  the benefit of a consistent user interface with a set
+       of well-known commands for manipulating the text of previ-
+       ous  lines and using that text in new commands.  The basic
+       history manipulation commands are identical to the history
+       substitution provided by b\bba\bas\bsh\bh.
+
+       If  the  programmer  desires,  he  can  use  the  Readline
+       library,  which  includes  some  history  manipulation  by
+       default, and has the added advantage of command line edit-
+       ing.
+
+       Before declaring any functions using any functionality the
+       History  library  provides  in  other code, an application
+       writer should include the file _\b<_\br_\be_\ba_\bd_\bl_\bi_\bn_\be_\b/_\bh_\bi_\bs_\bt_\bo_\br_\by_\b._\bh_\b> in any
+       file  that  uses  the History library's features.  It sup-
+       plies extern declarations for all of the library's  public
+
+
+
+GNU History 4.3          2002 January 31                        3
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       functions  and  variables,  and declares all of the public
+       data structures.
+
+
+   H\bHi\bis\bst\bto\bor\bry\by S\bSt\bto\bor\bra\bag\bge\be
+       The history list is an array of history entries.   A  his-
+       tory entry is declared as follows:
+
+       _\bt_\by_\bp_\be_\bd_\be_\bf _\bv_\bo_\bi_\bd _\b* h\bhi\bis\bst\btd\bda\bat\bta\ba_\b_t\bt;\b;
+
+       typedef struct _hist_entry {
+         char *line;
+         histdata_t data;
+       } HIST_ENTRY;
+
+       The history list itself might therefore be declared as
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b*_\b* t\bth\bhe\be_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_l\bli\bis\bst\bt;\b;
+
+       The  state  of  the History library is encapsulated into a
+       single structure:
+
+       /*
+        * A structure used to pass around the current state of the history.
+        */
+       typedef struct _hist_state {
+         HIST_ENTRY **entries; /* Pointer to the entries themselves. */
+         int offset;           /* The location pointer within this array. */
+         int length;           /* Number of elements within this array. */
+         int size;             /* Number of slots allocated to this array. */
+         int flags;
+       } HISTORY_STATE;
+
+       If the flags member includes H\bHS\bS_\b_S\bST\bTI\bIF\bFL\bLE\bED\bD, the  history  has
+       been stifled.
+
+H\bHi\bis\bst\bto\bor\bry\by F\bFu\bun\bnc\bct\bti\bio\bon\bns\bs
+       This  section describes the calling sequence for the vari-
+       ous functions exported by the GNU History library.
+
+   I\bIn\bni\bit\bti\bia\bal\bli\biz\bzi\bin\bng\bg H\bHi\bis\bst\bto\bor\bry\by a\ban\bnd\bd S\bSt\bta\bat\bte\be M\bMa\ban\bna\bag\bge\bem\bme\ben\bnt\bt
+       This section describes functions used  to  initialize  and
+       manage  the  state of the History library when you want to
+       use the history functions in your program.
+
+       _\bv_\bo_\bi_\bd u\bus\bsi\bin\bng\bg_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Begin a session in which the history  functions  might  be
+       used.  This initializes the interactive variables.
+
+       _\bH_\bI_\bS_\bT_\bO_\bR_\bY_\b__\bS_\bT_\bA_\bT_\bE _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_g\bge\bet\bt_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_s\bst\bta\bat\bte\be (_\bv_\bo_\bi_\bd)
+       Return  a  structure  describing  the current state of the
+       input history.
+
+       _\bv_\bo_\bi_\bd h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bet\bt_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_s\bst\bta\bat\bte\be (_\bH_\bI_\bS_\bT_\bO_\bR_\bY_\b__\bS_\bT_\bA_\bT_\bE _\b*_\bs_\bt_\ba_\bt_\be)
+
+
+
+GNU History 4.3          2002 January 31                        4
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       Set the state of the history list according to _\bs_\bt_\ba_\bt_\be.
+
+
+   H\bHi\bis\bst\bto\bor\bry\by L\bLi\bis\bst\bt M\bMa\ban\bna\bag\bge\bem\bme\ben\bnt\bt
+       These functions manage individual entries on  the  history
+       list, or set parameters managing the list itself.
+
+       _\bv_\bo_\bi_\bd a\bad\bdd\bd_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg)
+       Place  _\bs_\bt_\br_\bi_\bn_\bg at the end of the history list.  The associ-
+       ated data field (if any) is set to N\bNU\bUL\bLL\bL.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* r\bre\bem\bmo\bov\bve\be_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bi_\bn_\bt _\bw_\bh_\bi_\bc_\bh)
+       Remove history entry at offset  _\bw_\bh_\bi_\bc_\bh  from  the  history.
+       The  removed element is returned so you can free the line,
+       data, and containing structure.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* r\bre\bep\bpl\bla\bac\bce\be_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_e\ben\bnt\btr\bry\by (_\bi_\bn_\bt _\bw_\bh_\bi_\bc_\bh_\b, _\bc_\bo_\bn_\bs_\bt  _\bc_\bh_\ba_\br
+       _\b*_\bl_\bi_\bn_\be_\b, _\bh_\bi_\bs_\bt_\bd_\ba_\bt_\ba_\b__\bt _\bd_\ba_\bt_\ba)
+       Make the history entry at offset _\bw_\bh_\bi_\bc_\bh have _\bl_\bi_\bn_\be and _\bd_\ba_\bt_\ba.
+       This returns the old entry so you can dispose of the data.
+       In  the  case  of  an  invalid  _\bw_\bh_\bi_\bc_\bh,  a  N\bNU\bUL\bLL\bL pointer is
+       returned.
+
+       _\bv_\bo_\bi_\bd c\bcl\ble\bea\bar\br_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Clear the history list by deleting all the entries.
+
+       _\bv_\bo_\bi_\bd s\bst\bti\bif\bfl\ble\be_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bi_\bn_\bt _\bm_\ba_\bx)
+       Stifle the history list, remembering  only  the  last  _\bm_\ba_\bx
+       entries.
+
+       _\bi_\bn_\bt u\bun\bns\bst\bti\bif\bfl\ble\be_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Stop  stifling  the history.  This returns the previously-
+       set maximum number of history  entries  (as  set  by  s\bst\bti\bi-\b-
+       f\bfl\ble\be_\b_h\bhi\bis\bst\bto\bor\bry\by(\b()\b)).   history was stifled.  The value is posi-
+       tive if the history was stifled, negative if it wasn't.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_i\bis\bs_\b_s\bst\bti\bif\bfl\ble\bed\bd (_\bv_\bo_\bi_\bd)
+       Returns non-zero if the history is stifled, zero if it  is
+       not.
+
+
+   I\bIn\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn A\bAb\bbo\bou\but\bt t\bth\bhe\be H\bHi\bis\bst\bto\bor\bry\by L\bLi\bis\bst\bt
+       These  functions  return information about the entire his-
+       tory list or individual list entries.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b*_\b* h\bhi\bis\bst\bto\bor\bry\by_\b_l\bli\bis\bst\bt (_\bv_\bo_\bi_\bd)
+       Return a N\bNU\bUL\bLL\bL terminated array of _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY  _\b*  which  is
+       the  current input history.  Element 0 of this list is the
+       beginning of time.  If there is no history, return N\bNU\bUL\bLL\bL.
+
+       _\bi_\bn_\bt w\bwh\bhe\ber\bre\be_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Returns the offset of the current history element.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* c\bcu\bur\brr\bre\ben\bnt\bt_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+
+
+
+GNU History 4.3          2002 January 31                        5
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       Return the history  entry  at  the  current  position,  as
+       determined  by  w\bwh\bhe\ber\bre\be_\b_h\bhi\bis\bst\bto\bor\bry\by(\b()\b).   If  there  is  no entry
+       there, return a N\bNU\bUL\bLL\bL pointer.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_g\bge\bet\bt (_\bi_\bn_\bt _\bo_\bf_\bf_\bs_\be_\bt)
+       Return the history entry at position _\bo_\bf_\bf_\bs_\be_\bt, starting from
+       h\bhi\bis\bst\bto\bor\bry\by_\b_b\bba\bas\bse\be.  If there is no entry there, or if _\bo_\bf_\bf_\bs_\be_\bt is
+       greater than the history length, return a N\bNU\bUL\bLL\bL pointer.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_t\bto\bot\bta\bal\bl_\b_b\bby\byt\bte\bes\bs (_\bv_\bo_\bi_\bd)
+       Return the  number  of  bytes  that  the  primary  history
+       entries  are  using.  This function returns the sum of the
+       lengths of all the lines in the history.
+
+
+   M\bMo\bov\bvi\bin\bng\bg A\bAr\bro\bou\bun\bnd\bd t\bth\bhe\be H\bHi\bis\bst\bto\bor\bry\by L\bLi\bis\bst\bt
+       These functions allow the current index into  the  history
+       list to be set or changed.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bet\bt_\b_p\bpo\bos\bs (_\bi_\bn_\bt _\bp_\bo_\bs)
+       Set  the  current history offset to _\bp_\bo_\bs, an absolute index
+       into the list.  Returns 1 on success, 0  if  _\bp_\bo_\bs  is  less
+       than zero or greater than the number of history entries.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* p\bpr\bre\bev\bvi\bio\bou\bus\bs_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Back up the current history offset to the previous history
+       entry, and return a pointer to that entry.  If there is no
+       previous entry, return a N\bNU\bUL\bLL\bL pointer.
+
+       _\bH_\bI_\bS_\bT_\b__\bE_\bN_\bT_\bR_\bY _\b* n\bne\bex\bxt\bt_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bv_\bo_\bi_\bd)
+       Move  the  current history offset forward to the next his-
+       tory entry, and return the a pointer to  that  entry.   If
+       there is no next entry, return a N\bNU\bUL\bLL\bL pointer.
+
+
+   S\bSe\bea\bar\brc\bch\bhi\bin\bng\bg t\bth\bhe\be H\bHi\bis\bst\bto\bor\bry\by L\bLi\bis\bst\bt
+       These  functions  allow  searching of the history list for
+       entries containing a specific string.   Searching  may  be
+       performed  both forward and backward from the current his-
+       tory position.  The search may be _\ba_\bn_\bc_\bh_\bo_\br_\be_\bd,  meaning  that
+       the  string  must  match  at  the beginning of the history
+       entry.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bea\bar\brc\bch\bh (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg_\b, _\bi_\bn_\bt _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn)
+       Search the history for _\bs_\bt_\br_\bi_\bn_\bg,  starting  at  the  current
+       history  offset.   If  _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn  is less than 0, then the
+       search is through previous entries, otherwise through sub-
+       sequent  entries.   If  _\bs_\bt_\br_\bi_\bn_\bg  is found, then the current
+       history index is set to that history entry, and the  value
+       returned  is  the  offset  in  the line of the entry where
+       _\bs_\bt_\br_\bi_\bn_\bg was found.  Otherwise, nothing is changed, and a -1
+       is returned.
+
+       _\bi_\bn_\bt   h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bea\bar\brc\bch\bh_\b_p\bpr\bre\bef\bfi\bix\bx   (_\bc_\bo_\bn_\bs_\bt   _\bc_\bh_\ba_\br  _\b*_\bs_\bt_\br_\bi_\bn_\bg_\b,  _\bi_\bn_\bt
+
+
+
+GNU History 4.3          2002 January 31                        6
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn)
+       Search the history for _\bs_\bt_\br_\bi_\bn_\bg,  starting  at  the  current
+       history  offset.   The  search is anchored: matching lines
+       must begin with _\bs_\bt_\br_\bi_\bn_\bg.  If _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn is less than 0, then
+       the  search is through previous entries, otherwise through
+       subsequent entries.  If _\bs_\bt_\br_\bi_\bn_\bg is found, then the  current
+       history  index  is set to that entry, and the return value
+       is  0.   Otherwise,  nothing  is  changed,  and  a  -1  is
+       returned.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bea\bar\brc\bch\bh_\b_p\bpo\bos\bs (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg_\b, _\bi_\bn_\bt _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn_\b,
+       _\bi_\bn_\bt _\bp_\bo_\bs)
+       Search for _\bs_\bt_\br_\bi_\bn_\bg in the history list, starting at _\bp_\bo_\bs, an
+       absolute  index  into the list.  If _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn is negative,
+       the search proceeds backward from _\bp_\bo_\bs, otherwise  forward.
+       Returns  the  absolute  index of the history element where
+       _\bs_\bt_\br_\bi_\bn_\bg was found, or -1 otherwise.
+
+
+   M\bMa\ban\bna\bag\bgi\bin\bng\bg t\bth\bhe\be H\bHi\bis\bst\bto\bor\bry\by F\bFi\bil\ble\be
+       The History library can read the history from and write it
+       to  a file.  This section documents the functions for man-
+       aging a history file.
+
+       _\bi_\bn_\bt r\bre\bea\bad\bd_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bf_\bi_\bl_\be_\bn_\ba_\bm_\be)
+       Add the contents of _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be to the history list,  a  line
+       at  a  time.   If _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be is N\bNU\bUL\bLL\bL, then read from _\b~_\b/_\b._\bh_\bi_\bs_\b-
+       _\bt_\bo_\br_\by.  Returns 0 if successful, or e\ber\brr\brn\bno\bo if not.
+
+       _\bi_\bn_\bt r\bre\bea\bad\bd_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_r\bra\ban\bng\bge\be (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br  _\b*_\bf_\bi_\bl_\be_\bn_\ba_\bm_\be_\b,  _\bi_\bn_\bt  _\bf_\br_\bo_\bm_\b,
+       _\bi_\bn_\bt _\bt_\bo)
+       Read  a  range  of lines from _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be, adding them to the
+       history list.  Start reading at line _\bf_\br_\bo_\bm and end  at  _\bt_\bo.
+       If  _\bf_\br_\bo_\bm  is  zero, start at the beginning.  If _\bt_\bo is less
+       than _\bf_\br_\bo_\bm, then read until the end of the file.  If  _\bf_\bi_\bl_\be_\b-
+       _\bn_\ba_\bm_\be  is  N\bNU\bUL\bLL\bL,  then  read from _\b~_\b/_\b._\bh_\bi_\bs_\bt_\bo_\br_\by.  Returns 0 if
+       successful, or e\ber\brr\brn\bno\bo if not.
+
+       _\bi_\bn_\bt w\bwr\bri\bit\bte\be_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bf_\bi_\bl_\be_\bn_\ba_\bm_\be)
+       Write the current history to _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be,  overwriting  _\bf_\bi_\bl_\be_\b-
+       _\bn_\ba_\bm_\be  if  necessary.   If _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be is N\bNU\bUL\bLL\bL, then write the
+       history list to _\b~_\b/_\b._\bh_\bi_\bs_\bt_\bo_\br_\by.   Returns  0  on  success,  or
+       e\ber\brr\brn\bno\bo on a read or write error.
+
+
+       _\bi_\bn_\bt a\bap\bpp\bpe\ben\bnd\bd_\b_h\bhi\bis\bst\bto\bor\bry\by (_\bi_\bn_\bt _\bn_\be_\bl_\be_\bm_\be_\bn_\bt_\bs_\b, _\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bf_\bi_\bl_\be_\bn_\ba_\bm_\be)
+       Append the last _\bn_\be_\bl_\be_\bm_\be_\bn_\bt_\bs of the history list to _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be.
+       If _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be is N\bNU\bUL\bLL\bL, then append to _\b~_\b/_\b._\bh_\bi_\bs_\bt_\bo_\br_\by.  Returns 0
+       on success, or e\ber\brr\brn\bno\bo on a read or write error.
+
+       _\bi_\bn_\bt   h\bhi\bis\bst\bto\bor\bry\by_\b_t\btr\bru\bun\bnc\bca\bat\bte\be_\b_f\bfi\bil\ble\be  (_\bc_\bo_\bn_\bs_\bt  _\bc_\bh_\ba_\br  _\b*_\bf_\bi_\bl_\be_\bn_\ba_\bm_\be_\b,  _\bi_\bn_\bt
+       _\bn_\bl_\bi_\bn_\be_\bs)
+       Truncate the history file _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be, leaving only the  last
+       _\bn_\bl_\bi_\bn_\be_\bs  lines.   If  _\bf_\bi_\bl_\be_\bn_\ba_\bm_\be  is N\bNU\bUL\bLL\bL, then _\b~_\b/_\b._\bh_\bi_\bs_\bt_\bo_\br_\by is
+
+
+
+GNU History 4.3          2002 January 31                        7
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       truncated.  Returns 0 on success, or e\ber\brr\brn\bno\bo on failure.
+
+
+   H\bHi\bis\bst\bto\bor\bry\by E\bEx\bxp\bpa\ban\bns\bsi\bio\bon\bn
+       These functions implement history expansion.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_e\bex\bxp\bpa\ban\bnd\bd (_\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg_\b, _\bc_\bh_\ba_\br _\b*_\b*_\bo_\bu_\bt_\bp_\bu_\bt)
+       Expand _\bs_\bt_\br_\bi_\bn_\bg, placing the result into _\bo_\bu_\bt_\bp_\bu_\bt,  a  pointer
+       to a string.  Returns:
+              0      If no expansions took place (or, if the only
+                     change in the text was the removal of escape
+                     characters  preceding  the history expansion
+                     character);
+              1      if expansions did take place;
+              -1     if there was an error in expansion;
+              2      if the returned line  should  be  displayed,
+                     but not executed, as with the :\b:p\bp modifier.
+       If  an  error ocurred in expansion, then _\bo_\bu_\bt_\bp_\bu_\bt contains a
+       descriptive error message.
+
+       _\bc_\bh_\ba_\br _\b* g\bge\bet\bt_\b_h\bhi\bis\bst\bto\bor\bry\by_\b_e\bev\bve\ben\bnt\bt (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg_\b, _\bi_\bn_\bt _\b*_\bc_\bi_\bn_\bd_\be_\bx_\b,
+       _\bi_\bn_\bt _\bq_\bc_\bh_\ba_\br)
+       Returns  the text of the history event beginning at _\bs_\bt_\br_\bi_\bn_\bg
+       + _\b*_\bc_\bi_\bn_\bd_\be_\bx.  _\b*_\bc_\bi_\bn_\bd_\be_\bx is modified  to  point  to  after  the
+       event  specifier.  At function entry, _\bc_\bi_\bn_\bd_\be_\bx points to the
+       index into _\bs_\bt_\br_\bi_\bn_\bg where the  history  event  specification
+       begins.   _\bq_\bc_\bh_\ba_\br  is a character that is allowed to end the
+       event specification in addition to the  ``normal''  termi-
+       nating characters.
+
+       _\bc_\bh_\ba_\br _\b*_\b* h\bhi\bis\bst\bto\bor\bry\by_\b_t\bto\bok\bke\ben\bni\biz\bze\be (_\bc_\bo_\bn_\bs_\bt _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg)
+       Return  an  array  of tokens parsed out of _\bs_\bt_\br_\bi_\bn_\bg, much as
+       the shell might.  The tokens are split on  the  characters
+       in the h\bhi\bis\bst\bto\bor\bry\by_\b_w\bwo\bor\brd\bd_\b_d\bde\bel\bli\bim\bmi\bit\bte\ber\brs\bs variable, and shell quoting
+       conventions are obeyed.
+
+       _\bc_\bh_\ba_\br _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_a\bar\brg\bg_\b_e\bex\bxt\btr\bra\bac\bct\bt (_\bi_\bn_\bt  _\bf_\bi_\br_\bs_\bt_\b,  _\bi_\bn_\bt  _\bl_\ba_\bs_\bt_\b,  _\bc_\bo_\bn_\bs_\bt
+       _\bc_\bh_\ba_\br _\b*_\bs_\bt_\br_\bi_\bn_\bg)
+       Extract  a  string segment consisting of the _\bf_\bi_\br_\bs_\bt through
+       _\bl_\ba_\bs_\bt arguments present in  _\bs_\bt_\br_\bi_\bn_\bg.   Arguments  are  split
+       using h\bhi\bis\bst\bto\bor\bry\by_\b_t\bto\bok\bke\ben\bni\biz\bze\be(\b()\b).
+
+
+   H\bHi\bis\bst\bto\bor\bry\by V\bVa\bar\bri\bia\bab\bbl\ble\bes\bs
+       This  section  describes  the externally-visible variables
+       exported by the GNU History Library.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_b\bba\bas\bse\be
+       The logical offset of the first entry in the history list.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_l\ble\ben\bng\bgt\bth\bh
+       The  number  of  entries  currently  stored in the history
+       list.
+
+
+
+
+GNU History 4.3          2002 January 31                        8
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_m\bma\bax\bx_\b_e\ben\bnt\btr\bri\bie\bes\bs
+       The maximum number  of  history  entries.   This  must  be
+       changed using s\bst\bti\bif\bfl\ble\be_\b_h\bhi\bis\bst\bto\bor\bry\by(\b()\b).
+
+       _\bc_\bh_\ba_\br h\bhi\bis\bst\bto\bor\bry\by_\b_e\bex\bxp\bpa\ban\bns\bsi\bio\bon\bn_\b_c\bch\bha\bar\br
+       The  character  that  introduces  a  history  event.   The
+       default is !\b!.  Setting this to 0 inhibits  history  expan-
+       sion.
+
+       _\bc_\bh_\ba_\br h\bhi\bis\bst\bto\bor\bry\by_\b_s\bsu\bub\bbs\bst\bt_\b_c\bch\bha\bar\br
+       The  character  that invokes word substitution if found at
+       the start of a line.  The default is ^\b^.
+
+       _\bc_\bh_\ba_\br h\bhi\bis\bst\bto\bor\bry\by_\b_c\bco\bom\bmm\bme\ben\bnt\bt_\b_c\bch\bha\bar\br
+       During tokenization, if this  character  is  seen  as  the
+       first  character  of  a  word,  then it and all subsequent
+       characters up to a newline are ignored,  suppressing  his-
+       tory  expansion  for  the  remainder of the line.  This is
+       disabled by default.
+
+       _\bc_\bh_\ba_\br _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_w\bwo\bor\brd\bd_\b_d\bde\bel\bli\bim\bmi\bit\bte\ber\brs\bs
+       The  characters  that  separate  tokens  for  h\bhi\bis\bst\bto\bor\bry\by_\b_t\bto\bok\bk-\b-
+       e\ben\bni\biz\bze\be(\b()\b).  The default value is "\b" \\b\t\bt\\b\n\bn(\b()\b)<\b<>\b>;\b;&\b&|\b|"\b".
+
+       _\bc_\bh_\ba_\br _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_n\bno\bo_\b_e\bex\bxp\bpa\ban\bnd\bd_\b_c\bch\bha\bar\brs\bs
+       The  list of characters which inhibit history expansion if
+       found immediately following  h\bhi\bis\bst\bto\bor\bry\by_\b_e\bex\bxp\bpa\ban\bns\bsi\bio\bon\bn_\b_c\bch\bha\bar\br.   The
+       default is space, tab, newline, \\b\r\br, and =\b=.
+
+       _\bc_\bh_\ba_\br _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_s\bse\bea\bar\brc\bch\bh_\b_d\bde\bel\bli\bim\bmi\bit\bte\ber\br_\b_c\bch\bha\bar\brs\bs
+       The list of additional characters which can delimit a his-
+       tory search string, in addition to space, tab, _\b: and _\b?  in
+       the case of a substring search.  The default is empty.
+
+       _\bi_\bn_\bt h\bhi\bis\bst\bto\bor\bry\by_\b_q\bqu\buo\bot\bte\bes\bs_\b_i\bin\bnh\bhi\bib\bbi\bit\bt_\b_e\bex\bxp\bpa\ban\bns\bsi\bio\bon\bn
+       If  non-zero,  single-quoted words are not scanned for the
+       history expansion character.  The default value is 0.
+
+       _\br_\bl_\b__\bl_\bi_\bn_\be_\bb_\bu_\bf_\b__\bf_\bu_\bn_\bc_\b__\bt _\b* h\bhi\bis\bst\bto\bor\bry\by_\b_i\bin\bnh\bhi\bib\bbi\bit\bt_\b_e\bex\bxp\bpa\ban\bns\bsi\bio\bon\bn_\b_f\bfu\bun\bnc\bct\bti\bio\bon\bn
+       This should be set to the address of a function that takes
+       two  arguments:  a  c\bch\bha\bar\br  *\b* (_\bs_\bt_\br_\bi_\bn_\bg) and an i\bin\bnt\bt index into
+       that string (_\bi).  It should return a non-zero value if the
+       history expansion starting at _\bs_\bt_\br_\bi_\bn_\bg_\b[_\bi_\b] should not be per-
+       formed; zero if the  expansion  should  be  done.   It  is
+       intended  for  use  by applications like b\bba\bas\bsh\bh that use the
+       history expansion character for additional  purposes.   By
+       default, this variable is set to N\bNU\bUL\bLL\bL.
+
+F\bFI\bIL\bLE\bES\bS
+       _\b~_\b/_\b._\bh_\bi_\bs_\bt_\bo_\br_\by
+              Default filename for reading and writing saved his-
+              tory
+
+
+
+
+
+GNU History 4.3          2002 January 31                        9
+
+
+
+
+
+HISTORY(3)                                             HISTORY(3)
+
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bT_\bh_\be _\bG_\bn_\bu _\bR_\be_\ba_\bd_\bl_\bi_\bn_\be _\bL_\bi_\bb_\br_\ba_\br_\by, Brian Fox and Chet Ramey
+       _\bT_\bh_\be _\bG_\bn_\bu _\bH_\bi_\bs_\bt_\bo_\br_\by _\bL_\bi_\bb_\br_\ba_\br_\by, Brian Fox and Chet Ramey
+       _\bb_\ba_\bs_\bh(1)
+       _\br_\be_\ba_\bd_\bl_\bi_\bn_\be(3)
+
+A\bAU\bUT\bTH\bHO\bOR\bRS\bS
+       Brian Fox, Free Software Foundation
+       bfox@gnu.org
+
+       Chet Ramey, Case Western Reserve University
+       chet@ins.CWRU.Edu
+
+B\bBU\bUG\bG R\bRE\bEP\bPO\bOR\bRT\bTS\bS
+       If you find a bug  in  the  h\bhi\bis\bst\bto\bor\bry\by  library,  you  should
+       report it.  But first, you should make sure that it really
+       is a bug, and that it appears in the latest version of the
+       h\bhi\bis\bst\bto\bor\bry\by library that you have.
+
+       Once  you have determined that a bug actually exists, mail
+       a bug report to _\bb_\bu_\bg_\b-_\br_\be_\ba_\bd_\bl_\bi_\bn_\be@_\bg_\bn_\bu_\b._\bo_\br_\bg.  If you have a  fix,
+       you  are  welcome  to  mail that as well!  Suggestions and
+       `philosophical' bug reports may  be  mailed  to  _\bb_\bu_\bg_\b-_\br_\be_\ba_\bd_\b-
+       _\bl_\bi_\bn_\be@_\bg_\bn_\bu_\b._\bo_\br_\bg   or   posted   to   the   Usenet   newsgroup
+       g\bgn\bnu\bu.\b.b\bba\bas\bsh\bh.\b.b\bbu\bug\bg.
+
+       Comments and  bug  reports  concerning  this  manual  page
+       should be directed to _\bc_\bh_\be_\bt_\b@_\bi_\bn_\bs_\b._\bC_\bW_\bR_\bU_\b._\bE_\bd_\bu.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+GNU History 4.3          2002 January 31                       10
+
+
diff --git a/readline/doc/history.3 b/readline/doc/history.3
new file mode 100644 (file)
index 0000000..ed0cb9f
--- /dev/null
@@ -0,0 +1,640 @@
+.\"
+.\" MAN PAGE COMMENTS to
+.\"
+.\"    Chet Ramey
+.\"    Information Network Services
+.\"    Case Western Reserve University
+.\"    chet@ins.CWRU.Edu
+.\"
+.\"    Last Change: Thu Jan 31 16:08:07 EST 2002
+.\"
+.TH HISTORY 3 "2002 January 31" "GNU History 4.3"
+.\"
+.\" File Name macro.  This used to be `.PN', for Path Name,
+.\" but Sun doesn't seem to like that very much.
+.\"
+.de FN
+\fI\|\\$1\|\fP
+..
+.ds lp \fR\|(\fP
+.ds rp \fR\|)\fP
+.\" FnN return-value fun-name N arguments
+.de Fn1
+\fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3\fP\\*(rp
+.br
+..
+.de Fn2
+.if t \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3,\|\\$4\fP\\*(rp
+.if n \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3, \\$4\fP\\*(rp
+.br
+..
+.de Fn3
+.if t \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3,\|\\$4,\|\\$5\fP\|\\*(rp
+.if n \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3, \\$4, \\$5\fP\\*(rp
+.br
+..
+.de Vb
+\fI\\$1\fP \fB\\$2\fP
+.br
+..
+.SH NAME
+history \- GNU History Library
+.SH COPYRIGHT
+.if t The GNU History Library is Copyright \(co 1989-2002 by the Free Software Foundation, Inc.
+.if n The GNU History Library is Copyright (C) 1989-2002 by the Free Software Foundation, Inc.
+.SH DESCRIPTION
+Many programs read input from the user a line at a time.  The GNU
+History library is able to keep track of those lines, associate arbitrary
+data with each line, and utilize information from previous lines in
+composing new ones. 
+.PP
+.SH "HISTORY EXPANSION"
+.PP
+The history library supports a history expansion feature that
+is identical to the history expansion in
+.BR bash.
+This section describes what syntax features are available.
+.PP
+History expansions introduce words from the history list into
+the input stream, making it easy to repeat commands, insert the
+arguments to a previous command into the current input line, or
+fix errors in previous commands quickly.
+.PP
+History expansion is usually performed immediately after a complete line
+is read.
+It takes place in two parts.
+The first is to determine which line from the history list
+to use during substitution.
+The second is to select portions of that line for inclusion into
+the current one.
+The line selected from the history is the \fIevent\fP,
+and the portions of that line that are acted upon are \fIwords\fP.
+Various \fImodifiers\fP are available to manipulate the selected words.
+The line is broken into words in the same fashion as \fBbash\fP
+does when reading input,
+so that several words that would otherwise be separated 
+are considered one word when surrounded by quotes (see the
+description of \fBhistory_tokenize()\fP below).
+History expansions are introduced by the appearance of the
+history expansion character, which is \^\fB!\fP\^ by default.
+Only backslash (\^\fB\e\fP\^) and single quotes can quote
+the history expansion character.
+.SS Event Designators
+.PP
+An event designator is a reference to a command line entry in the
+history list.
+.PP
+.PD 0
+.TP
+.B !
+Start a history substitution, except when followed by a
+.BR blank ,
+newline, = or (.
+.TP
+.B !\fIn\fR
+Refer to command line
+.IR n .
+.TP
+.B !\-\fIn\fR
+Refer to the current command line minus
+.IR n .
+.TP
+.B !!
+Refer to the previous command.  This is a synonym for `!\-1'.
+.TP
+.B !\fIstring\fR
+Refer to the most recent command starting with 
+.IR string .
+.TP
+.B !?\fIstring\fR\fB[?]\fR
+Refer to the most recent command containing
+.IR string .
+The trailing \fB?\fP may be omitted if
+.I string
+is followed immediately by a newline.
+.TP
+.B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u
+Quick substitution.  Repeat the last command, replacing
+.I string1
+with
+.IR string2 .
+Equivalent to
+``!!:s/\fIstring1\fP/\fIstring2\fP/''
+(see \fBModifiers\fP below).
+.TP
+.B !#
+The entire command line typed so far.
+.PD
+.SS Word Designators
+.PP
+Word designators are used to select desired words from the event.
+A 
+.B :
+separates the event specification from the word designator.
+It may be omitted if the word designator begins with a
+.BR ^ ,
+.BR $ ,
+.BR * ,
+.BR \- ,
+or
+.BR % .
+Words are numbered from the beginning of the line,
+with the first word being denoted by 0 (zero).
+Words are inserted into the current line separated by single spaces.
+.PP
+.PD 0
+.TP
+.B 0 (zero)
+The zeroth word.  For the shell, this is the command
+word.
+.TP
+.I n
+The \fIn\fRth word.
+.TP
+.B ^
+The first argument.  That is, word 1.
+.TP
+.B $
+The last argument.
+.TP
+.B %
+The word matched by the most recent `?\fIstring\fR?' search.
+.TP
+.I x\fB\-\fPy
+A range of words; `\-\fIy\fR' abbreviates `0\-\fIy\fR'.
+.TP
+.B *
+All of the words but the zeroth.  This is a synonym
+for `\fI1\-$\fP'.  It is not an error to use
+.B *
+if there is just one
+word in the event; the empty string is returned in that case.
+.TP
+.B x*
+Abbreviates \fIx\-$\fP.
+.TP
+.B x\-
+Abbreviates \fIx\-$\fP like \fBx*\fP, but omits the last word.
+.PD
+.PP
+If a word designator is supplied without an event specification, the
+previous command is used as the event.
+.SS Modifiers
+.PP
+After the optional word designator, there may appear a sequence of
+one or more of the following modifiers, each preceded by a `:'.
+.PP
+.PD 0
+.PP
+.TP
+.B h
+Remove a trailing file name component, leaving only the head.
+.TP
+.B t
+Remove all leading file name components, leaving the tail.
+.TP
+.B r
+Remove a trailing suffix of the form \fI.xxx\fP, leaving the
+basename.
+.TP
+.B e
+Remove all but the trailing suffix.
+.TP
+.B p
+Print the new command but do not execute it.
+.TP
+.B q
+Quote the substituted words, escaping further substitutions.
+.TP
+.B x
+Quote the substituted words as with
+.BR q ,
+but break into words at
+.B blanks
+and newlines.
+.TP
+.B s/\fIold\fP/\fInew\fP/
+Substitute
+.I new
+for the first occurrence of
+.I old
+in the event line.  Any delimiter can be used in place of /.  The
+final delimiter is optional if it is the last character of the
+event line.  The delimiter may be quoted in
+.I old
+and
+.I new
+with a single backslash.  If & appears in
+.IR new ,
+it is replaced by
+.IR old .
+A single backslash will quote the &.  If
+.I old
+is null, it is set to the last
+.I old
+substituted, or, if no previous history substitutions took place,
+the last
+.I string
+in a
+.B !?\fIstring\fR\fB[?]\fR
+search.
+.TP
+.B &
+Repeat the previous substitution.
+.TP
+.B g
+Cause changes to be applied over the entire event line.  This is
+used in conjunction with `\fB:s\fP' (e.g., `\fB:gs/\fIold\fP/\fInew\fP/\fR')
+or `\fB:&\fP'.  If used with
+`\fB:s\fP', any delimiter can be used
+in place of /, and the final delimiter is optional
+if it is the last character of the event line.
+.PD
+.SH "PROGRAMMING WITH HISTORY FUNCTIONS"
+This section describes how to use the History library in other programs.
+.SS Introduction to History
+.PP
+The programmer using the History library has available functions
+for remembering lines on a history list, associating arbitrary data
+with a line, removing lines from the list, searching through the list
+for a line containing an arbitrary text string, and referencing any line
+in the list directly.  In addition, a history \fIexpansion\fP function
+is available which provides for a consistent user interface across
+different programs.
+.PP
+The user using programs written with the History library has the
+benefit of a consistent user interface with a set of well-known
+commands for manipulating the text of previous lines and using that text
+in new commands.  The basic history manipulation commands are
+identical to
+the history substitution provided by \fBbash\fP.
+.PP
+If the programmer desires, he can use the Readline library, which
+includes some history manipulation by default, and has the added
+advantage of command line editing.
+.PP
+Before declaring any functions using any functionality the History
+library provides in other code, an application writer should include
+the file
+.FN <readline/history.h>
+in any file that uses the
+History library's features.  It supplies extern declarations for all
+of the library's public functions and variables, and declares all of
+the public data structures.
+
+.SS History Storage
+.PP
+The history list is an array of history entries.  A history entry is
+declared as follows:
+.PP
+.Vb "typedef void *" histdata_t;
+.PP
+.nf
+typedef struct _hist_entry {
+  char *line;
+  histdata_t data;
+} HIST_ENTRY;
+.fi
+.PP
+The history list itself might therefore be declared as
+.PP
+.Vb "HIST_ENTRY **" the_history_list;
+.PP
+The state of the History library is encapsulated into a single structure:
+.PP
+.nf
+/*
+ * A structure used to pass around the current state of the history.
+ */
+typedef struct _hist_state {
+  HIST_ENTRY **entries; /* Pointer to the entries themselves. */
+  int offset;           /* The location pointer within this array. */
+  int length;           /* Number of elements within this array. */
+  int size;             /* Number of slots allocated to this array. */
+  int flags;
+} HISTORY_STATE;
+.fi
+.PP
+If the flags member includes \fBHS_STIFLED\fP, the history has been
+stifled.
+.SH "History Functions"
+.PP
+This section describes the calling sequence for the various functions
+exported by the GNU History library.
+.SS Initializing History and State Management
+This section describes functions used to initialize and manage
+the state of the History library when you want to use the history
+functions in your program.
+
+.Fn1 void using_history void
+Begin a session in which the history functions might be used.  This
+initializes the interactive variables.
+
+.Fn1 "HISTORY_STATE *" history_get_history_state void
+Return a structure describing the current state of the input history.
+
+.Fn1 void history_set_history_state "HISTORY_STATE *state"
+Set the state of the history list according to \fIstate\fP.
+
+.SS History List Management
+
+These functions manage individual entries on the history list, or set
+parameters managing the list itself.
+
+.Fn1 void add_history "const char *string"
+Place \fIstring\fP at the end of the history list.  The associated data
+field (if any) is set to \fBNULL\fP.
+
+.Fn1 "HIST_ENTRY *" remove_history "int which"
+Remove history entry at offset \fIwhich\fP from the history.  The
+removed element is returned so you can free the line, data,
+and containing structure.
+
+.Fn3 "HIST_ENTRY *" replace_history_entry "int which" "const char *line" "histdata_t data"
+Make the history entry at offset \fIwhich\fP have \fIline\fP and \fIdata\fP.
+This returns the old entry so you can dispose of the data.  In the case
+of an invalid \fIwhich\fP, a \fBNULL\fP pointer is returned.
+
+.Fn1 void clear_history "void"
+Clear the history list by deleting all the entries.
+
+.Fn1 void stifle_history "int max"
+Stifle the history list, remembering only the last \fImax\fP entries.
+
+.Fn1 int unstifle_history "void"
+Stop stifling the history.  This returns the previously-set
+maximum number of history entries (as set by \fBstifle_history()\fP).
+history was stifled.  The value is positive if the history was
+stifled, negative if it wasn't.
+
+.Fn1 int history_is_stifled "void"
+Returns non-zero if the history is stifled, zero if it is not.
+
+.SS Information About the History List
+
+These functions return information about the entire history list or
+individual list entries.
+
+.Fn1 "HIST_ENTRY **" history_list "void"
+Return a \fBNULL\fP terminated array of \fIHIST_ENTRY *\fP which is the
+current input history.  Element 0 of this list is the beginning of time.
+If there is no history, return \fBNULL\fP.
+
+.Fn1 int where_history "void"
+Returns the offset of the current history element.
+
+.Fn1 "HIST_ENTRY *" current_history "void"
+Return the history entry at the current position, as determined by
+\fBwhere_history()\fP.  If there is no entry there, return a \fBNULL\fP
+pointer.
+
+.Fn1 "HIST_ENTRY *" history_get "int offset"
+Return the history entry at position \fIoffset\fP, starting from
+\fBhistory_base\fP.
+If there is no entry there, or if \fIoffset\fP
+is greater than the history length, return a \fBNULL\fP pointer.
+
+.Fn1 int history_total_bytes "void"
+Return the number of bytes that the primary history entries are using.
+This function returns the sum of the lengths of all the lines in the
+history.
+
+.SS Moving Around the History List
+
+These functions allow the current index into the history list to be
+set or changed.
+
+.Fn1 int history_set_pos "int pos"
+Set the current history offset to \fIpos\fP, an absolute index
+into the list.
+Returns 1 on success, 0 if \fIpos\fP is less than zero or greater
+than the number of history entries.
+
+.Fn1 "HIST_ENTRY *" previous_history "void"
+Back up the current history offset to the previous history entry, and
+return a pointer to that entry.  If there is no previous entry, return
+a \fBNULL\fP pointer.
+
+.Fn1 "HIST_ENTRY *" next_history "void"
+Move the current history offset forward to the next history entry, and
+return the a pointer to that entry.  If there is no next entry, return
+a \fBNULL\fP pointer.
+
+.SS Searching the History List
+
+These functions allow searching of the history list for entries containing
+a specific string.  Searching may be performed both forward and backward
+from the current history position.  The search may be \fIanchored\fP,
+meaning that the string must match at the beginning of the history entry.
+
+.Fn2 int history_search "const char *string" "int direction"
+Search the history for \fIstring\fP, starting at the current history offset.
+If \fIdirection\fP is less than 0, then the search is through
+previous entries, otherwise through subsequent entries.
+If \fIstring\fP is found, then
+the current history index is set to that history entry, and the value
+returned is the offset in the line of the entry where
+\fIstring\fP was found.  Otherwise, nothing is changed, and a -1 is
+returned.
+
+.Fn2 int history_search_prefix "const char *string" "int direction"
+Search the history for \fIstring\fP, starting at the current history
+offset.  The search is anchored: matching lines must begin with
+\fIstring\fP.  If \fIdirection\fP is less than 0, then the search is
+through previous entries, otherwise through subsequent entries.
+If \fIstring\fP is found, then the
+current history index is set to that entry, and the return value is 0. 
+Otherwise, nothing is changed, and a -1 is returned. 
+
+.Fn3 int history_search_pos "const char *string" "int direction" "int pos"
+Search for \fIstring\fP in the history list, starting at \fIpos\fP, an
+absolute index into the list.  If \fIdirection\fP is negative, the search
+proceeds backward from \fIpos\fP, otherwise forward.  Returns the absolute
+index of the history element where \fIstring\fP was found, or -1 otherwise.
+
+.SS Managing the History File
+The History library can read the history from and write it to a file.
+This section documents the functions for managing a history file.
+
+.Fn1 int read_history "const char *filename"
+Add the contents of \fIfilename\fP to the history list, a line at a time.
+If \fIfilename\fP is \fBNULL\fP, then read from \fI~/.history\fP.
+Returns 0 if successful, or \fBerrno\fP if not.
+
+.Fn3 int read_history_range "const char *filename" "int from" "int to"
+Read a range of lines from \fIfilename\fP, adding them to the history list.
+Start reading at line \fIfrom\fP and end at \fIto\fP.
+If \fIfrom\fP is zero, start at the beginning.  If \fIto\fP is less than
+\fIfrom\fP, then read until the end of the file.  If \fIfilename\fP is
+\fBNULL\fP, then read from \fI~/.history\fP.  Returns 0 if successful,
+or \fBerrno\fP if not.
+
+.Fn1 int write_history "const char *filename"
+Write the current history to \fIfilename\fP, overwriting \fIfilename\fP
+if necessary.
+If \fIfilename\fP is \fBNULL\fP, then write the history list to \fI~/.history\fP.
+Returns 0 on success, or \fBerrno\fP on a read or write error.
+
+
+.Fn2 int append_history "int nelements" "const char *filename"
+Append the last \fInelements\fP of the history list to \fIfilename\fP.
+If \fIfilename\fP is \fBNULL\fP, then append to \fI~/.history\fP.
+Returns 0 on success, or \fBerrno\fP on a read or write error.
+
+.Fn2 int history_truncate_file "const char *filename" "int nlines"
+Truncate the history file \fIfilename\fP, leaving only the last
+\fInlines\fP lines.
+If \fIfilename\fP is \fBNULL\fP, then \fI~/.history\fP is truncated.
+Returns 0 on success, or \fBerrno\fP on failure.
+
+.SS History Expansion
+
+These functions implement history expansion.
+
+.Fn2 int history_expand "char *string" "char **output"
+Expand \fIstring\fP, placing the result into \fIoutput\fP, a pointer
+to a string.  Returns:
+.RS
+.PD 0
+.TP
+0
+If no expansions took place (or, if the only change in
+the text was the removal of escape characters preceding the history expansion
+character);
+.TP
+1
+if expansions did take place;
+.TP
+-1
+if there was an error in expansion;
+.TP
+2
+if the returned line should be displayed, but not executed,
+as with the \fB:p\fP modifier.
+.PD
+.RE
+If an error ocurred in expansion, then \fIoutput\fP contains a descriptive
+error message.
+
+.Fn3 "char *" get_history_event "const char *string" "int *cindex" "int qchar"
+Returns the text of the history event beginning at \fIstring\fP +
+\fI*cindex\fP.  \fI*cindex\fP is modified to point to after the event
+specifier.  At function entry, \fIcindex\fP points to the index into
+\fIstring\fP where the history event specification begins.  \fIqchar\fP
+is a character that is allowed to end the event specification in addition
+to the ``normal'' terminating characters.
+
+.Fn1 "char **" history_tokenize "const char *string"
+Return an array of tokens parsed out of \fIstring\fP, much as the
+shell might.
+The tokens are split on the characters in the
+\fBhistory_word_delimiters\fP variable,
+and shell quoting conventions are obeyed.
+
+.Fn3 "char *" history_arg_extract "int first" "int last" "const char *string"
+Extract a string segment consisting of the \fIfirst\fP through \fIlast\fP
+arguments present in \fIstring\fP.  Arguments are split using
+\fBhistory_tokenize()\fP.
+
+.SS History Variables
+
+This section describes the externally-visible variables exported by
+the GNU History Library.
+
+.Vb int history_base
+The logical offset of the first entry in the history list.
+
+.Vb int history_length
+The number of entries currently stored in the history list.
+
+.Vb int history_max_entries
+The maximum number of history entries.  This must be changed using
+\fBstifle_history()\fP.
+
+.Vb char history_expansion_char
+The character that introduces a history event.  The default is \fB!\fP.
+Setting this to 0 inhibits history expansion.
+
+.Vb char history_subst_char
+The character that invokes word substitution if found at the start of
+a line.  The default is \fB^\fP.
+
+.Vb char history_comment_char
+During tokenization, if this character is seen as the first character
+of a word, then it and all subsequent characters up to a newline are
+ignored, suppressing history expansion for the remainder of the line.
+This is disabled by default.
+
+.Vb "char *" history_word_delimiters
+The characters that separate tokens for \fBhistory_tokenize()\fP.
+The default value is \fB"\ \et\en()<>;&|"\fP.
+
+.Vb "char *" history_no_expand_chars
+The list of characters which inhibit history expansion if found immediately
+following \fBhistory_expansion_char\fP.  The default is space, tab, newline,
+\fB\er\fP, and \fB=\fP.
+
+.Vb "char *" history_search_delimiter_chars
+The list of additional characters which can delimit a history search
+string, in addition to space, tab, \fI:\fP and \fI?\fP in the case of
+a substring search.  The default is empty.
+
+.Vb int history_quotes_inhibit_expansion
+If non-zero, single-quoted words are not scanned for the history expansion
+character.  The default value is 0.
+
+.Vb "rl_linebuf_func_t *" history_inhibit_expansion_function
+This should be set to the address of a function that takes two arguments:
+a \fBchar *\fP (\fIstring\fP)
+and an \fBint\fP index into that string (\fIi\fP).
+It should return a non-zero value if the history expansion starting at
+\fIstring[i]\fP should not be performed; zero if the expansion should
+be done.
+It is intended for use by applications like \fBbash\fP that use the history
+expansion character for additional purposes.
+By default, this variable is set to \fBNULL\fP.
+.SH FILES
+.PD 0 
+.TP
+.FN ~/.history
+Default filename for reading and writing saved history
+.PD
+.SH "SEE ALSO"
+.PD 0
+.TP
+\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey
+.TP
+\fIThe Gnu History Library\fP, Brian Fox and Chet Ramey
+.TP
+\fIbash\fP(1)
+.TP
+\fIreadline\fP(3)
+.PD
+.SH AUTHORS
+Brian Fox, Free Software Foundation
+.br
+bfox@gnu.org
+.PP
+Chet Ramey, Case Western Reserve University
+.br
+chet@ins.CWRU.Edu
+.SH BUG REPORTS
+If you find a bug in the
+.B history
+library, you should report it.  But first, you should
+make sure that it really is a bug, and that it appears in the latest
+version of the
+.B history
+library that you have.
+.PP
+Once you have determined that a bug actually exists, mail a
+bug report to \fIbug\-readline\fP@\fIgnu.org\fP.
+If you have a fix, you are welcome to mail that
+as well!  Suggestions and `philosophical' bug reports may be mailed
+to \fPbug-readline\fP@\fIgnu.org\fP or posted to the Usenet
+newsgroup
+.BR gnu.bash.bug .
+.PP
+Comments and bug reports concerning
+this manual page should be directed to
+.IR chet@ins.CWRU.Edu .
diff --git a/readline/examples/readlinebuf.h b/readline/examples/readlinebuf.h
new file mode 100644 (file)
index 0000000..91ef4d6
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * $Revision$
+ * $Date$
+ * $Author$
+ *
+ * Contents: A streambuf which uses the GNU readline library for line I/O
+ * (c) 2001 by Dimitris Vyzovitis [vyzo@media.mit.edu]
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ******************************************************************************/
+
+#ifndef _READLINEBUF_H_
+#define _READLINEBUF_H_
+
+#include <iostream>
+#include <cstring>
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#if (defined __GNUC__) && (__GNUC__ < 3)
+#include <streambuf.h>
+#else
+#include <streambuf>
+using std::streamsize;
+using std::streambuf;
+#endif
+
+class readlinebuf : public streambuf {
+public:
+#if (defined __GNUC__) && (__GNUC__ < 3)
+       typedef char char_type;
+       typedef int int_type;
+       typedef streampos pos_type;
+       typedef streamoff off_type;
+#endif
+       static const int_type eof = EOF; // this is -1
+       static const int_type not_eof = 0;
+
+private:
+       const char* prompt_;
+       bool history_;
+       char* line_;
+       int low_;
+       int high_;
+
+protected:
+               
+       virtual int_type showmanyc() const { return high_ - low_; }
+               
+       virtual streamsize xsgetn( char_type* buf, streamsize n ) {
+               int rd = n > (high_ - low_)? (high_ - low_) : n;
+               memcpy( buf, line_, rd );
+               low_ += rd;
+                       
+               if ( rd < n ) {
+                       low_ = high_ = 0;
+                       free( line_ ); // free( NULL ) is a noop
+                       line_ = readline( prompt_ );
+                       if ( line_ ) {
+                               high_ = strlen( line_ );
+                               if ( history_ && high_ ) add_history( line_ );
+                               rd += xsgetn( buf + rd, n - rd );
+                       }
+               }
+                       
+               return rd; 
+       }
+               
+       virtual int_type underflow() {
+               if ( high_ == low_ ) {
+                       low_ = high_ = 0;
+                       free( line_ ); // free( NULL ) is a noop
+                       line_ = readline( prompt_ );
+                       if ( line_ ) {
+                               high_ = strlen( line_ );
+                               if ( history_ && high_ ) add_history( line_ );
+                       }
+               }
+                       
+               if ( low_ < high_ ) return line_[low_];
+               else return eof;
+       }
+               
+       virtual int_type uflow() {
+               int_type c = underflow();
+               if ( c != eof ) ++low_;
+               return c;
+       }
+               
+       virtual int_type pbackfail( int_type c = eof ) {
+               if ( low_ > 0 ) --low_;
+               else if ( c != eof ) {
+                       if ( high_ > 0 ) {
+                               char* nl = (char*)realloc( line_, high_ + 1 );
+                               if ( nl ) {
+                                       line_ = (char*)memcpy( nl + 1, line_, high_ );
+                                       high_ += 1;
+                                       line_[0] = char( c );
+                               } else return eof;
+                       } else {
+                               assert( !line_ );
+                               line_ = (char*)malloc( sizeof( char ) );
+                               *line_ = char( c );
+                               high_ = 1;
+                       }
+               } else return eof;
+
+               return not_eof;
+       }
+               
+public:
+       readlinebuf( const char* prompt = NULL, bool history = true ) 
+               : prompt_( prompt ), history_( history ),
+                 line_( NULL ), low_( 0 ), high_( 0 ) {
+               setbuf( 0, 0 );
+       }
+               
+               
+};
+
+#endif
diff --git a/readline/examples/rlcat.c b/readline/examples/rlcat.c
new file mode 100644 (file)
index 0000000..176b9f4
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * rlcat - cat(1) using readline
+ *
+ * usage: rlcat
+ */
+
+/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include "posixstat.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#if defined (READLINE_LIBRARY)
+#  include "readline.h"
+#  include "history.h"
+#else
+#  include <readline/readline.h>
+#  include <readline/history.h>
+#endif
+
+extern int optind;
+extern char *optarg;
+
+static int stdcat();
+
+static char *progname;
+static int vflag;
+
+static void
+usage()
+{
+  fprintf (stderr, "%s: usage: %s [-vEVN] [filename]\n", progname, progname);
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *temp;
+  int opt, Vflag, Nflag;
+
+  progname = strrchr(argv[0], '/');
+  if (progname == 0)
+    progname = argv[0];
+  else
+    progname++;
+
+  vflag = Vflag = Nflag = 0;
+  while ((opt = getopt(argc, argv, "vEVN")) != EOF)
+    {
+      switch (opt)
+       {
+       case 'v':
+         vflag = 1;
+         break;
+       case 'V':
+         Vflag = 1;
+         break;
+       case 'E':
+         Vflag = 0;
+         break;
+       case 'N':
+         Nflag = 1;
+         break;
+       default:
+         usage ();
+         exit (2);
+       }
+    }
+
+  argc -= optind;
+  argv += optind;
+
+  if (isatty(0) == 0 || argc || Nflag)
+    return stdcat(argc, argv);
+
+  rl_variable_bind ("editing-mode", Vflag ? "vi" : "emacs");
+  while (temp = readline (""))
+    {
+      if (*temp)
+        add_history (temp);
+      printf ("%s\n", temp);
+    }
+
+  return (ferror (stdout));
+}
+
+static int
+fcopy(fp)
+     FILE *fp;
+{
+  int c;
+  char *x;
+
+  while ((c = getc(fp)) != EOF)
+    {
+      if (vflag && isascii ((unsigned char)c) && isprint((unsigned char)c) == 0)
+       {
+         x = rl_untranslate_keyseq (c);
+         if (fputs (x, stdout) != 0)
+           return 1;
+       }
+      else if (putchar (c) == EOF)
+        return 1;
+    }
+  return (ferror (stdout));
+}
+
+int
+stdcat (argc, argv)
+     int argc;
+     char **argv;
+{
+  int  i, fd, r;
+  char *s;
+  FILE *fp;
+
+  if (argc == 0)
+    return (fcopy(stdin));
+
+  for (i = 0, r = 1; i < argc; i++)
+    {
+      if (*argv[i] == '-' && argv[i][1] == 0)
+       fp = stdin;
+      else
+       {
+         fp = fopen (argv[i], "r");
+         if (fp == 0)
+           {
+             fprintf (stderr, "%s: %s: cannot open: %s\n", progname, argv[i], strerror(errno));
+             continue;
+           }
+        }
+      r = fcopy (fp);
+      if (fp != stdin)
+       fclose(fp);
+    }
+  return r;
+}
diff --git a/readline/mbutil.c b/readline/mbutil.c
new file mode 100644 (file)
index 0000000..50302f0
--- /dev/null
@@ -0,0 +1,337 @@
+/* mbutil.c -- readline multibyte character utility functions */
+
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include "posixjmp.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>     /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+#if defined (TIOCSTAT_IN_SYS_IOCTL)
+#  include <sys/ioctl.h>
+#endif /* TIOCSTAT_IN_SYS_IOCTL */
+
+/* Some standard library routines. */
+#include "readline.h"
+
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+/* Declared here so it can be shared between the readline and history
+   libraries. */
+#if defined (HANDLE_MULTIBYTE)
+int rl_byte_oriented = 0;
+#else
+int rl_byte_oriented = 1;
+#endif
+
+/* **************************************************************** */
+/*                                                                 */
+/*             Multibyte Character Utility Functions               */
+/*                                                                 */
+/* **************************************************************** */
+
+#if defined(HANDLE_MULTIBYTE)
+
+static int
+_rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
+     char *string;
+     int seed, count, find_non_zero;
+{
+  size_t tmp = 0;
+  mbstate_t ps;
+  int point = 0;
+  wchar_t wc;
+
+  memset(&ps, 0, sizeof (mbstate_t));
+  if (seed < 0)
+    seed = 0;
+  if (count <= 0)
+    return seed;
+
+  point = seed + _rl_adjust_point(string, seed, &ps);
+  /* if this is true, means that seed was not pointed character
+     started byte.  So correct the point and consume count */
+  if (seed < point)
+    count --;
+
+  while (count > 0)  
+    {
+      tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps);
+      if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
+       {
+         /* invalid bytes. asume a byte represents a character */
+         point++;
+         count--;
+         /* reset states. */
+         memset(&ps, 0, sizeof(mbstate_t));
+       }
+      else if (tmp == (size_t)0)
+       /* found '\0' char */
+       break;
+      else
+       {
+         /* valid bytes */
+         point += tmp;
+         if (find_non_zero)
+           {
+             if (wcwidth (wc) == 0)
+               continue;
+             else
+               count--;
+           }
+         else
+           count--;
+       }
+    }
+
+  if (find_non_zero)
+    {
+      tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
+      while (wcwidth (wc) == 0)
+       {
+         point += tmp;
+         tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
+         if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2))
+           break;
+       }
+    }
+    return point;
+}
+
+static int
+_rl_find_prev_mbchar_internal (string, seed, find_non_zero)
+     char *string;
+     int seed, find_non_zero;
+{
+  mbstate_t ps;
+  int prev, non_zero_prev, point, length;
+  size_t tmp;
+  wchar_t wc;
+
+  memset(&ps, 0, sizeof(mbstate_t));
+  length = strlen(string);
+  
+  if (seed < 0)
+    return 0;
+  else if (length < seed)
+    return length;
+
+  prev = non_zero_prev = point = 0;
+  while (point < seed)
+    {
+      tmp = mbrtowc (&wc, string + point, length - point, &ps);
+      if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
+       {
+         /* in this case, bytes are invalid or shorted to compose
+            multibyte char, so assume that the first byte represents
+            a single character anyway. */
+         tmp = 1;
+         /* clear the state of the byte sequence, because
+            in this case effect of mbstate is undefined  */
+         memset(&ps, 0, sizeof (mbstate_t));
+       }
+      else if (tmp == 0)
+       break;                  /* Found '\0' char.  Can this happen? */
+      else
+       {
+         if (find_non_zero)
+           {
+             if (wcwidth (wc) != 0)
+               prev = point;
+           }
+         else
+           prev = point;  
+       }
+
+      point += tmp;
+    }
+
+  return prev;
+}
+
+/* return the number of bytes parsed from the multibyte sequence starting
+   at src, if a non-L'\0' wide character was recognized. It returns 0, 
+   if a L'\0' wide character was recognized. It  returns (size_t)(-1), 
+   if an invalid multibyte sequence was encountered. It returns (size_t)(-2) 
+   if it couldn't parse a complete  multibyte character.  */
+int
+_rl_get_char_len (src, ps)
+     char *src;
+     mbstate_t *ps;
+{
+  size_t tmp;
+
+  tmp = mbrlen((const char *)src, (size_t)strlen (src), ps);
+  if (tmp == (size_t)(-2))
+    {
+      /* shorted to compose multibyte char */
+      memset (ps, 0, sizeof(mbstate_t));
+      return -2;
+    }
+  else if (tmp == (size_t)(-1))
+    {
+      /* invalid to compose multibyte char */
+      /* initialize the conversion state */
+      memset (ps, 0, sizeof(mbstate_t));
+      return -1;
+    }
+  else if (tmp == (size_t)0)
+    return 0;
+  else
+    return (int)tmp;
+}
+
+/* compare the specified two characters. If the characters matched,
+   return 1. Otherwise return 0. */
+int
+_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
+     char *buf1, *buf2;
+     mbstate_t *ps1, *ps2;
+     int pos1, pos2;
+{
+  int i, w1, w2;
+
+  if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 || 
+       (w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 ||
+       (w1 != w2) ||
+       (buf1[pos1] != buf2[pos2]))
+    return 0;
+
+  for (i = 1; i < w1; i++)
+    if (buf1[pos1+i] != buf2[pos2+i])
+      return 0;
+
+  return 1;
+}
+
+/* adjust pointed byte and find mbstate of the point of string.
+   adjusted point will be point <= adjusted_point, and returns
+   differences of the byte(adjusted_point - point).
+   if point is invalied (point < 0 || more than string length),
+   it returns -1 */
+int
+_rl_adjust_point(string, point, ps)
+     char *string;
+     int point;
+     mbstate_t *ps;
+{
+  size_t tmp = 0;
+  int length;
+  int pos = 0;
+
+  length = strlen(string);
+  if (point < 0)
+    return -1;
+  if (length < point)
+    return -1;
+  
+  while (pos < point)
+    {
+      tmp = mbrlen (string + pos, length - pos, ps);
+      if((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
+       {
+         /* in this case, bytes are invalid or shorted to compose
+            multibyte char, so assume that the first byte represents
+            a single character anyway. */
+         pos++;
+         /* clear the state of the byte sequence, because
+            in this case effect of mbstate is undefined  */
+         memset (ps, 0, sizeof (mbstate_t));
+       }
+      else
+       pos += tmp;
+    }
+
+  return (pos - point);
+}
+
+int
+_rl_is_mbchar_matched (string, seed, end, mbchar, length)
+     char *string;
+     int seed, end;
+     char *mbchar;
+     int length;
+{
+  int i;
+
+  if ((end - seed) < length)
+    return 0;
+
+  for (i = 0; i < length; i++)
+    if (string[seed + i] != mbchar[i])
+      return 0;
+  return 1;
+}
+#endif /* HANDLE_MULTIBYTE */
+
+/* Find next `count' characters started byte point of the specified seed.
+   If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte
+   characters. */
+#undef _rl_find_next_mbchar
+int
+_rl_find_next_mbchar (string, seed, count, flags)
+     char *string;
+     int seed, count, flags;
+{
+#if defined (HANDLE_MULTIBYTE)
+  return _rl_find_next_mbchar_internal (string, seed, count, flags);
+#else
+  return (seed + count);
+#endif
+}
+
+/* Find previous character started byte point of the specified seed.
+   Returned point will be point <= seed.  If flags is MB_FIND_NONZERO,
+   we look for non-zero-width multibyte characters. */
+#undef _rl_find_prev_mbchar
+int
+_rl_find_prev_mbchar (string, seed, flags)
+     char *string;
+     int seed, flags;
+{
+#if defined (HANDLE_MULTIBYTE)
+  return _rl_find_prev_mbchar_internal (string, seed, flags);
+#else
+  return ((seed == 0) ? seed : seed - 1);
+#endif
+}
diff --git a/readline/misc.c b/readline/misc.c
new file mode 100644 (file)
index 0000000..f3775d3
--- /dev/null
@@ -0,0 +1,496 @@
+/* misc.c -- miscellaneous bindable readline functions. */
+
+/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+#  include <locale.h>
+#endif
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
+static int rl_digit_loop PARAMS((void));
+static void _rl_history_set_point PARAMS((void));
+
+/* Forward declarations used in this file */
+void _rl_free_history_entry PARAMS((HIST_ENTRY *));
+
+/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
+   to preserve the value of rl_point from line to line. */
+int _rl_history_preserve_point = 0;
+
+/* Saved target point for when _rl_history_preserve_point is set.  Special
+   value of -1 means that point is at the end of the line. */
+int _rl_history_saved_point = -1;
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Numeric Arguments                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+static int
+rl_digit_loop ()
+{
+  int key, c, sawminus, sawdigits;
+
+  rl_save_prompt ();
+
+  RL_SETSTATE(RL_STATE_NUMERICARG);
+  sawminus = sawdigits = 0;
+  while (1)
+    {
+      if (rl_numeric_arg > 1000000)
+       {
+         sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
+         rl_ding ();
+         rl_restore_prompt ();
+         rl_clear_message ();
+         RL_UNSETSTATE(RL_STATE_NUMERICARG);
+         return 1;
+       }
+      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
+      RL_SETSTATE(RL_STATE_MOREINPUT);
+      key = c = rl_read_key ();
+      RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+      if (c < 0)
+       {
+         _rl_abort_internal ();
+         return -1;
+       }
+
+      /* If we see a key bound to `universal-argument' after seeing digits,
+        it ends the argument but is otherwise ignored. */
+      if (_rl_keymap[c].type == ISFUNC &&
+         _rl_keymap[c].function == rl_universal_argument)
+       {
+         if (sawdigits == 0)
+           {
+             rl_numeric_arg *= 4;
+             continue;
+           }
+         else
+           {
+             RL_SETSTATE(RL_STATE_MOREINPUT);
+             key = rl_read_key ();
+             RL_UNSETSTATE(RL_STATE_MOREINPUT);
+             rl_restore_prompt ();
+             rl_clear_message ();
+             RL_UNSETSTATE(RL_STATE_NUMERICARG);
+             return (_rl_dispatch (key, _rl_keymap));
+           }
+       }
+
+      c = UNMETA (c);
+
+      if (_rl_digit_p (c))
+       {
+         rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
+         sawdigits = rl_explicit_arg = 1;
+       }
+      else if (c == '-' && rl_explicit_arg == 0)
+       {
+         rl_numeric_arg = sawminus = 1;
+         rl_arg_sign = -1;
+       }
+      else
+       {
+         /* Make M-- command equivalent to M--1 command. */
+         if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
+           rl_explicit_arg = 1;
+         rl_restore_prompt ();
+         rl_clear_message ();
+         RL_UNSETSTATE(RL_STATE_NUMERICARG);
+         return (_rl_dispatch (key, _rl_keymap));
+       }
+    }
+
+  /*NOTREACHED*/
+}
+
+/* Add the current digit to the argument in progress. */
+int
+rl_digit_argument (ignore, key)
+     int ignore, key;
+{
+  rl_execute_next (key);
+  return (rl_digit_loop ());
+}
+
+/* What to do when you abort reading an argument. */
+int
+rl_discard_argument ()
+{
+  rl_ding ();
+  rl_clear_message ();
+  _rl_init_argument ();
+  return 0;
+}
+
+/* Create a default argument. */
+int
+_rl_init_argument ()
+{
+  rl_numeric_arg = rl_arg_sign = 1;
+  rl_explicit_arg = 0;
+  return 0;
+}
+
+/* C-u, universal argument.  Multiply the current argument by 4.
+   Read a key.  If the key has nothing to do with arguments, then
+   dispatch on it.  If the key is the abort character then abort. */
+int
+rl_universal_argument (count, key)
+     int count, key;
+{
+  rl_numeric_arg *= 4;
+  return (rl_digit_loop ());
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Utilities                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* We already have a history library, and that is what we use to control
+   the history features of readline.  This is our local interface to
+   the history mechanism. */
+
+/* While we are editing the history, this is the saved
+   version of the original line. */
+HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
+
+/* Set the history pointer back to the last entry in the history. */
+void
+_rl_start_using_history ()
+{
+  using_history ();
+  if (_rl_saved_line_for_history)
+    _rl_free_history_entry (_rl_saved_line_for_history);
+
+  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Free the contents (and containing structure) of a HIST_ENTRY. */
+void
+_rl_free_history_entry (entry)
+     HIST_ENTRY *entry;
+{
+  if (entry == 0)
+    return;
+  if (entry->line)
+    free (entry->line);
+  free (entry);
+}
+
+/* Perhaps put back the current line if it has changed. */
+int
+rl_maybe_replace_line ()
+{
+  HIST_ENTRY *temp;
+
+  temp = current_history ();
+  /* If the current line has changed, save the changes. */
+  if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
+    {
+      temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
+      free (temp->line);
+      free (temp);
+    }
+  return 0;
+}
+
+/* Restore the _rl_saved_line_for_history if there is one. */
+int
+rl_maybe_unsave_line ()
+{
+  if (_rl_saved_line_for_history)
+    {
+      rl_replace_line (_rl_saved_line_for_history->line, 0);
+      rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
+      _rl_free_history_entry (_rl_saved_line_for_history);
+      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
+      rl_point = rl_end;       /* rl_replace_line sets rl_end */
+    }
+  else
+    rl_ding ();
+  return 0;
+}
+
+/* Save the current line in _rl_saved_line_for_history. */
+int
+rl_maybe_save_line ()
+{
+  if (_rl_saved_line_for_history == 0)
+    {
+      _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+      _rl_saved_line_for_history->line = savestring (rl_line_buffer);
+      _rl_saved_line_for_history->data = (char *)rl_undo_list;
+    }
+  return 0;
+}
+
+int
+_rl_free_saved_history_line ()
+{
+  if (_rl_saved_line_for_history)
+    {
+      _rl_free_history_entry (_rl_saved_line_for_history);
+      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
+    }
+  return 0;
+}
+
+static void
+_rl_history_set_point ()
+{
+  rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
+               ? _rl_history_saved_point
+               : rl_end;
+  if (rl_point > rl_end)
+    rl_point = rl_end;
+
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode)
+    rl_point = 0;
+#endif /* VI_MODE */
+
+  if (rl_editing_mode == emacs_mode)
+    rl_mark = (rl_point == rl_end ? 0 : rl_end);
+}
+
+void
+rl_replace_from_history (entry, flags)
+     HIST_ENTRY *entry;
+     int flags;                        /* currently unused */
+{
+  rl_replace_line (entry->line, 0);
+  rl_undo_list = (UNDO_LIST *)entry->data;
+  rl_point = rl_end;
+  rl_mark = 0;
+
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode)
+    {
+      rl_point = 0;
+      rl_mark = rl_end;
+    }
+#endif
+}  
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Commands                            */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Meta-< goes to the start of the history. */
+int
+rl_beginning_of_history (count, key)
+     int count, key;
+{
+  return (rl_get_previous_history (1 + where_history (), key));
+}
+
+/* Meta-> goes to the end of the history.  (The current line). */
+int
+rl_end_of_history (count, key)
+     int count, key;
+{
+  rl_maybe_replace_line ();
+  using_history ();
+  rl_maybe_unsave_line ();
+  return 0;
+}
+
+/* Move down to the next history line. */
+int
+rl_get_next_history (count, key)
+     int count, key;
+{
+  HIST_ENTRY *temp;
+
+  if (count < 0)
+    return (rl_get_previous_history (-count, key));
+
+  if (count == 0)
+    return 0;
+
+  rl_maybe_replace_line ();
+
+  /* either not saved by rl_newline or at end of line, so set appropriately. */
+  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
+    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
+
+  temp = (HIST_ENTRY *)NULL;
+  while (count)
+    {
+      temp = next_history ();
+      if (!temp)
+       break;
+      --count;
+    }
+
+  if (temp == 0)
+    rl_maybe_unsave_line ();
+  else
+    {
+      rl_replace_from_history (temp, 0);
+      _rl_history_set_point ();
+    }
+  return 0;
+}
+
+/* Get the previous item out of our interactive history, making it the current
+   line.  If there is no previous history, just ding. */
+int
+rl_get_previous_history (count, key)
+     int count, key;
+{
+  HIST_ENTRY *old_temp, *temp;
+
+  if (count < 0)
+    return (rl_get_next_history (-count, key));
+
+  if (count == 0)
+    return 0;
+
+  /* either not saved by rl_newline or at end of line, so set appropriately. */
+  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
+    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
+
+  /* If we don't have a line saved, then save this one. */
+  rl_maybe_save_line ();
+
+  /* If the current line has changed, save the changes. */
+  rl_maybe_replace_line ();
+
+  temp = old_temp = (HIST_ENTRY *)NULL;
+  while (count)
+    {
+      temp = previous_history ();
+      if (temp == 0)
+       break;
+
+      old_temp = temp;
+      --count;
+    }
+
+  /* If there was a large argument, and we moved back to the start of the
+     history, that is not an error.  So use the last value found. */
+  if (!temp && old_temp)
+    temp = old_temp;
+
+  if (temp == 0)
+    rl_ding ();
+  else
+    {
+      rl_replace_from_history (temp, 0);
+      _rl_history_set_point ();
+    }
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                         Editing Modes                           */
+/*                                                                 */
+/* **************************************************************** */
+/* How to toggle back and forth between editing modes. */
+int
+rl_vi_editing_mode (count, key)
+     int count, key;
+{
+#if defined (VI_MODE)
+  _rl_set_insert_mode (RL_IM_INSERT, 1);       /* vi mode ignores insert mode */
+  rl_editing_mode = vi_mode;
+  rl_vi_insertion_mode (1, key);
+#endif /* VI_MODE */
+
+  return 0;
+}
+
+int
+rl_emacs_editing_mode (count, key)
+     int count, key;
+{
+  rl_editing_mode = emacs_mode;
+  _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
+  _rl_keymap = emacs_standard_keymap;
+  return 0;
+}
+
+/* Function for the rest of the library to use to set insert/overwrite mode. */
+void
+_rl_set_insert_mode (im, force)
+     int im, force;
+{
+#ifdef CURSOR_MODE
+  _rl_set_cursor (im, force);
+#endif
+
+  rl_insert_mode = im;
+}
+
+/* Toggle overwrite mode.  A positive explicit argument selects overwrite
+   mode.  A negative or zero explicit argument selects insert mode. */
+int
+rl_overwrite_mode (count, key)
+     int count, key;
+{
+  if (rl_explicit_arg == 0)
+    _rl_set_insert_mode (rl_insert_mode ^ 1, 0);
+  else if (count > 0)
+    _rl_set_insert_mode (RL_IM_OVERWRITE, 0);
+  else
+    _rl_set_insert_mode (RL_IM_INSERT, 0);
+
+  return 0;
+}
diff --git a/readline/rlmbutil.h b/readline/rlmbutil.h
new file mode 100644 (file)
index 0000000..27ca32b
--- /dev/null
@@ -0,0 +1,108 @@
+/* rlmbutil.h -- utility functions for multibyte characters. */
+
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if !defined (_RL_MBUTIL_H_)
+#define _RL_MBUTIL_H_
+
+#include "rlstdc.h"
+
+/************************************************/
+/* check multibyte capability for I18N code     */
+/************************************************/
+
+/* For platforms which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+   /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H)
+#  include <wchar.h>
+#  include <wctype.h>
+#  if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */
+#    define HANDLE_MULTIBYTE      1
+#  endif
+#endif
+
+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
+#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T)
+#  define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0)
+#  define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0)
+#  define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0)
+#  define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
+#  define mbrlen(s, n, ps) (mbrlen) (s, n, 0)
+#  define mbstate_t int
+#endif
+
+/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to
+   handle multibyte chars (some systems define MB_LEN_MAX as 1) */
+#ifdef HANDLE_MULTIBYTE
+#  include <limits.h>
+#  if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16)
+#    undef MB_LEN_MAX
+#  endif
+#  if !defined (MB_LEN_MAX)
+#    define MB_LEN_MAX 16
+#  endif
+#endif
+
+/************************************************/
+/* end of multibyte capability checks for I18N  */
+/************************************************/
+
+/*
+ * Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar:
+ *
+ * MB_FIND_ANY         find any multibyte character
+ * MB_FIND_NONZERO     find a non-zero-width multibyte character
+ */
+
+#define MB_FIND_ANY    0x00
+#define MB_FIND_NONZERO        0x01
+
+extern int _rl_find_prev_mbchar PARAMS((char *, int, int));
+extern int _rl_find_next_mbchar PARAMS((char *, int, int, int));
+
+#ifdef HANDLE_MULTIBYTE
+
+extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *));
+extern int _rl_get_char_len PARAMS((char *, mbstate_t *));
+extern int _rl_adjust_point PARAMS((char *, int, mbstate_t *));
+
+extern int _rl_read_mbchar PARAMS((char *, int));
+extern int _rl_read_mbstring PARAMS((int, char *, int));
+
+extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int));
+
+#else /* !HANDLE_MULTIBYTE */
+
+#undef MB_LEN_MAX
+#undef MB_CUR_MAX
+
+#define MB_LEN_MAX     1
+#define MB_CUR_MAX     1
+
+#define _rl_find_prev_mbchar(b, i, f)          (((i) == 0) ? (i) : ((i) - 1))
+#define _rl_find_next_mbchar(b, i1, i2, f)     ((i1) + (i2))
+
+#endif /* !HANDLE_MULTIBYTE */
+
+extern int rl_byte_oriented;
+
+#endif /* _RL_MBUTIL_H_ */
diff --git a/readline/rltypedefs.h b/readline/rltypedefs.h
new file mode 100644 (file)
index 0000000..f3280e9
--- /dev/null
@@ -0,0 +1,88 @@
+/* rltypedefs.h -- Type declarations for readline functions. */
+
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#ifndef _RL_TYPEDEFS_H_
+#define _RL_TYPEDEFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Old-style */
+
+#if !defined (_FUNCTION_DEF)
+#  define _FUNCTION_DEF
+
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+
+#endif /* _FUNCTION_DEF */
+
+/* New style. */
+
+#if !defined (_RL_FUNCTION_TYPEDEF)
+#  define _RL_FUNCTION_TYPEDEF
+
+/* Bindable functions */
+typedef int rl_command_func_t PARAMS((int, int));
+
+/* Typedefs for the completion system */
+typedef char *rl_compentry_func_t PARAMS((const char *, int));
+typedef char **rl_completion_func_t PARAMS((const char *, int, int));
+
+typedef char *rl_quote_func_t PARAMS((char *, int, char *));
+typedef char *rl_dequote_func_t PARAMS((char *, int));
+
+typedef int rl_compignore_func_t PARAMS((char **));
+
+typedef void rl_compdisp_func_t PARAMS((char **, int, int));
+
+/* Type for input and pre-read hook functions like rl_event_hook */
+typedef int rl_hook_func_t PARAMS((void));
+
+/* Input function type */
+typedef int rl_getc_func_t PARAMS((FILE *));
+
+/* Generic function that takes a character buffer (which could be the readline
+   line buffer) and an index into it (which could be rl_point) and returns
+   an int. */
+typedef int rl_linebuf_func_t PARAMS((char *, int));
+
+/* `Generic' function pointer typedefs */
+typedef int rl_intfunc_t PARAMS((int));
+#define rl_ivoidfunc_t rl_hook_func_t
+typedef int rl_icpfunc_t PARAMS((char *));
+typedef int rl_icppfunc_t PARAMS((char **));
+
+typedef void rl_voidfunc_t PARAMS((void));
+typedef void rl_vintfunc_t PARAMS((int));
+typedef void rl_vcpfunc_t PARAMS((char *));
+typedef void rl_vcppfunc_t PARAMS((char **));
+#endif /* _RL_FUNCTION_TYPEDEF */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RL_TYPEDEFS_H_ */
diff --git a/readline/support/wcwidth.c b/readline/support/wcwidth.c
new file mode 100644 (file)
index 0000000..ace9a3a
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * This is an implementation of wcwidth() and wcswidth() as defined in
+ * "The Single UNIX Specification, Version 2, The Open Group, 1997"
+ * <http://www.UNIX-systems.org/online.html>
+ *
+ * Markus Kuhn -- 2001-09-08 -- public domain
+ */
+
+#include <wchar.h>
+
+struct interval {
+  unsigned short first;
+  unsigned short last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(wchar_t ucs, const struct interval *table, int max) {
+  int min = 0;
+  int mid;
+
+  if (ucs < table[0].first || ucs > table[max].last)
+    return 0;
+  while (max >= min) {
+    mid = (min + max) / 2;
+    if (ucs > table[mid].last)
+      min = mid + 1;
+    else if (ucs < table[mid].first)
+      max = mid - 1;
+    else
+      return 1;
+  }
+
+  return 0;
+}
+
+
+/* The following functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ *    - The null character (U+0000) has a column width of 0.
+ *
+ *    - Other C0/C1 control characters and DEL will lead to a return
+ *      value of -1.
+ *
+ *    - Non-spacing and enclosing combining characters (general
+ *      category code Mn or Me in the Unicode database) have a
+ *      column width of 0.
+ *
+ *    - Other format characters (general category code Cf in the Unicode
+ *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ *      have a column width of 0.
+ *
+ *    - Spacing characters in the East Asian Wide (W) or East Asian
+ *      FullWidth (F) category as defined in Unicode Technical
+ *      Report #11 have a column width of 2.
+ *
+ *    - All remaining characters (including all printable
+ *      ISO 8859-1 and WGL4 characters, Unicode control characters,
+ *      etc.) have a column width of 1.
+ *
+ * This implementation assumes that wchar_t characters are encoded
+ * in ISO 10646.
+ */
+
+int wcwidth(wchar_t ucs)
+{
+  /* sorted list of non-overlapping intervals of non-spacing characters */
+  static const struct interval combining[] = {
+    { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
+    { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
+    { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+    { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
+    { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+    { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+    { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
+    { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
+    { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
+    { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
+    { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
+    { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
+    { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
+    { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
+    { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
+    { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
+    { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
+    { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
+    { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+    { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
+    { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
+    { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
+    { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
+    { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
+    { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
+    { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
+    { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
+    { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
+    { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
+    { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
+    { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
+    { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
+    { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
+    { 0xFFF9, 0xFFFB }
+  };
+
+  /* test for 8-bit control characters */
+  if (ucs == 0)
+    return 0;
+  if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+    return -1;
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, combining,
+              sizeof(combining) / sizeof(struct interval) - 1))
+    return 0;
+
+  /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+  return 1 + 
+    (ucs >= 0x1100 &&
+     (ucs <= 0x115f ||                    /* Hangul Jamo init. consonants */
+      (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
+       ucs != 0x303f) ||                  /* CJK ... Yi */
+      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+      (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
+      (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+      (ucs >= 0x20000 && ucs <= 0x2ffff)));
+}
+
+
+int wcswidth(const wchar_t *pwcs, size_t n)
+{
+  int w, width = 0;
+
+  for (;*pwcs && n-- > 0; pwcs++)
+    if ((w = wcwidth(*pwcs)) < 0)
+      return -1;
+    else
+      width += w;
+
+  return width;
+}
+
+
+/*
+ * The following function is the same as wcwidth(), except that
+ * spacing characters in the East Asian Ambiguous (A) category as
+ * defined in Unicode Technical Report #11 have a column width of 2.
+ * This experimental variant might be useful for users of CJK legacy
+ * encodings who want to migrate to UCS. It is not otherwise
+ * recommended for general use.
+ */
+static int wcwidth_cjk(wchar_t ucs)
+{
+  /* sorted list of non-overlapping intervals of East Asian Ambiguous
+   * characters */
+  static const struct interval ambiguous[] = {
+    { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
+    { 0x00AA, 0x00AA }, { 0x00AD, 0x00AE }, { 0x00B0, 0x00B4 },
+    { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
+    { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
+    { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
+    { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
+    { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
+    { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
+    { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
+    { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
+    { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
+    { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
+    { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
+    { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
+    { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
+    { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
+    { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
+    { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0300, 0x034E },
+    { 0x0360, 0x0362 }, { 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 },
+    { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, { 0x0401, 0x0401 },
+    { 0x0410, 0x044F }, { 0x0451, 0x0451 }, { 0x2010, 0x2010 },
+    { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, { 0x201C, 0x201D },
+    { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, { 0x2030, 0x2030 },
+    { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, { 0x203B, 0x203B },
+    { 0x203E, 0x203E }, { 0x2074, 0x2074 }, { 0x207F, 0x207F },
+    { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, { 0x2103, 0x2103 },
+    { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, { 0x2113, 0x2113 },
+    { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 },
+    { 0x212B, 0x212B }, { 0x2153, 0x2155 }, { 0x215B, 0x215E },
+    { 0x2160, 0x216B }, { 0x2170, 0x2179 }, { 0x2190, 0x2199 },
+    { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 },
+    { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, { 0x2202, 0x2203 },
+    { 0x2207, 0x2208 }, { 0x220B, 0x220B }, { 0x220F, 0x220F },
+    { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, { 0x221A, 0x221A },
+    { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, { 0x2225, 0x2225 },
+    { 0x2227, 0x222C }, { 0x222E, 0x222E }, { 0x2234, 0x2237 },
+    { 0x223C, 0x223D }, { 0x2248, 0x2248 }, { 0x224C, 0x224C },
+    { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, { 0x2264, 0x2267 },
+    { 0x226A, 0x226B }, { 0x226E, 0x226F }, { 0x2282, 0x2283 },
+    { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, { 0x2299, 0x2299 },
+    { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, { 0x2312, 0x2312 },
+    { 0x2329, 0x232A }, { 0x2460, 0x24BF }, { 0x24D0, 0x24E9 },
+    { 0x2500, 0x254B }, { 0x2550, 0x2574 }, { 0x2580, 0x258F },
+    { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 },
+    { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD },
+    { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB },
+    { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF },
+    { 0x2605, 0x2606 }, { 0x2609, 0x2609 }, { 0x260E, 0x260F },
+    { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
+    { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
+    { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
+    { 0x273D, 0x273D }, { 0x3008, 0x300B }, { 0x3014, 0x3015 },
+    { 0x3018, 0x301B }, { 0xFFFD, 0xFFFD }
+  };
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, ambiguous,
+              sizeof(ambiguous) / sizeof(struct interval) - 1))
+    return 2;
+
+  return wcwidth(ucs);
+}
+
+
+int wcswidth_cjk(const wchar_t *pwcs, size_t n)
+{
+  int w, width = 0;
+
+  for (;*pwcs && n-- > 0; pwcs++)
+    if ((w = wcwidth_cjk(*pwcs)) < 0)
+      return -1;
+    else
+      width += w;
+
+  return width;
+}
diff --git a/readline/text.c b/readline/text.c
new file mode 100644 (file)
index 0000000..2a7b724
--- /dev/null
@@ -0,0 +1,1540 @@
+/* text.c -- text handling commands for readline. */
+
+/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
+
+   The GNU Readline Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (at your option) any later version.
+
+   The GNU Readline Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+#  include <locale.h>
+#endif
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+#if defined (__EMX__)
+#  define INCL_DOSPROCESS
+#  include <os2.h>
+#endif /* __EMX__ */
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
+/* Forward declarations. */
+static int rl_change_case PARAMS((int, int));
+static int _rl_char_search PARAMS((int, int, int));
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Insert and Delete                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Insert a string of text into the line at point.  This is the only
+   way that you should do insertion.  _rl_insert_char () calls this
+   function.  Returns the number of characters inserted. */
+int
+rl_insert_text (string)
+     const char *string;
+{
+  register int i, l;
+
+  l = (string && *string) ? strlen (string) : 0;
+  if (l == 0)
+    return 0;
+
+  if (rl_end + l >= rl_line_buffer_len)
+    rl_extend_line_buffer (rl_end + l);
+
+  for (i = rl_end; i >= rl_point; i--)
+    rl_line_buffer[i + l] = rl_line_buffer[i];
+  strncpy (rl_line_buffer + rl_point, string, l);
+
+  /* Remember how to undo this if we aren't undoing something. */
+  if (_rl_doing_an_undo == 0)
+    {
+      /* If possible and desirable, concatenate the undos. */
+      if ((l == 1) &&
+         rl_undo_list &&
+         (rl_undo_list->what == UNDO_INSERT) &&
+         (rl_undo_list->end == rl_point) &&
+         (rl_undo_list->end - rl_undo_list->start < 20))
+       rl_undo_list->end++;
+      else
+       rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
+    }
+  rl_point += l;
+  rl_end += l;
+  rl_line_buffer[rl_end] = '\0';
+  return l;
+}
+
+/* Delete the string between FROM and TO.  FROM is inclusive, TO is not.
+   Returns the number of characters deleted. */
+int
+rl_delete_text (from, to)
+     int from, to;
+{
+  register char *text;
+  register int diff, i;
+
+  /* Fix it if the caller is confused. */
+  if (from > to)
+    SWAP (from, to);
+
+  /* fix boundaries */
+  if (to > rl_end)
+    {
+      to = rl_end;
+      if (from > to)
+       from = to;
+    }
+  if (from < 0)
+    from = 0;
+
+  text = rl_copy_text (from, to);
+
+  /* Some versions of strncpy() can't handle overlapping arguments. */
+  diff = to - from;
+  for (i = from; i < rl_end - diff; i++)
+    rl_line_buffer[i] = rl_line_buffer[i + diff];
+
+  /* Remember how to undo this delete. */
+  if (_rl_doing_an_undo == 0)
+    rl_add_undo (UNDO_DELETE, from, to, text);
+  else
+    free (text);
+
+  rl_end -= diff;
+  rl_line_buffer[rl_end] = '\0';
+  return (diff);
+}
+
+/* Fix up point so that it is within the line boundaries after killing
+   text.  If FIX_MARK_TOO is non-zero, the mark is forced within line
+   boundaries also. */
+
+#define _RL_FIX_POINT(x) \
+       do { \
+       if (x > rl_end) \
+         x = rl_end; \
+       else if (x < 0) \
+         x = 0; \
+       } while (0)
+
+void
+_rl_fix_point (fix_mark_too)
+     int fix_mark_too;
+{
+  _RL_FIX_POINT (rl_point);
+  if (fix_mark_too)
+    _RL_FIX_POINT (rl_mark);
+}
+#undef _RL_FIX_POINT
+
+int
+_rl_replace_text (text, start, end)
+     const char *text;
+     int start, end;
+{
+  int n;
+
+  rl_begin_undo_group ();
+  rl_delete_text (start, end + 1);
+  rl_point = start;
+  n = rl_insert_text (text);
+  rl_end_undo_group ();
+
+  return n;
+}
+
+/* Replace the current line buffer contents with TEXT.  If CLEAR_UNDO is
+   non-zero, we free the current undo list. */
+void
+rl_replace_line (text, clear_undo)
+     const char *text;
+     int clear_undo;
+{
+  int len;
+
+  len = strlen (text);
+  if (len >= rl_line_buffer_len)
+    rl_extend_line_buffer (len);
+  strcpy (rl_line_buffer, text);
+  rl_end = len;
+
+  if (clear_undo)
+    rl_free_undo_list ();
+
+  _rl_fix_point (1);
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Readline character functions                */
+/*                                                                 */
+/* **************************************************************** */
+
+/* This is not a gap editor, just a stupid line input routine.  No hair
+   is involved in writing any of the functions, and none should be. */
+
+/* Note that:
+
+   rl_end is the place in the string that we would place '\0';
+   i.e., it is always safe to place '\0' there.
+
+   rl_point is the place in the string where the cursor is.  Sometimes
+   this is the same as rl_end.
+
+   Any command that is called interactively receives two arguments.
+   The first is a count: the numeric arg pased to this command.
+   The second is the key which invoked this command.
+*/
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Movement Commands                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Note that if you `optimize' the display for these functions, you cannot
+   use said functions in other functions which do not do optimizing display.
+   I.e., you will have to update the data base for rl_redisplay, and you
+   might as well let rl_redisplay do that job. */
+
+/* Move forward COUNT bytes. */
+int
+rl_forward_byte (count, key)
+     int count, key;
+{
+  if (count < 0)
+    return (rl_backward_byte (-count, key));
+
+  if (count > 0)
+    {
+      int end = rl_point + count;
+#if defined (VI_MODE)
+      int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end;
+#else
+      int lend = rl_end;
+#endif
+
+      if (end > lend)
+       {
+         rl_point = lend;
+         rl_ding ();
+       }
+      else
+       rl_point = end;
+    }
+
+  if (rl_end < 0)
+    rl_end = 0;
+
+  return 0;
+}
+
+#if defined (HANDLE_MULTIBYTE)
+/* Move forward COUNT characters. */
+int
+rl_forward_char (count, key)
+     int count, key;
+{
+  int point;
+
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+    return (rl_forward_byte (count, key));
+
+  if (count < 0)
+    return (rl_backward_char (-count, key));
+
+  if (count > 0)
+    {
+      point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
+
+#if defined (VI_MODE)
+      if (rl_end <= point && rl_editing_mode == vi_mode)
+       point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO);
+#endif
+
+      if (rl_point == point)
+       rl_ding ();
+
+      rl_point = point;
+
+      if (rl_end < 0)
+       rl_end = 0;
+    }
+
+  return 0;
+}
+#else /* !HANDLE_MULTIBYTE */
+int
+rl_forward_char (count, key)
+     int count, key;
+{
+  return (rl_forward_byte (count, key));
+}
+#endif /* !HANDLE_MULTIBYTE */
+  
+/* Backwards compatibility. */
+int
+rl_forward (count, key)
+     int count, key;
+{
+  return (rl_forward_char (count, key));
+}
+
+/* Move backward COUNT bytes. */
+int
+rl_backward_byte (count, key)
+     int count, key;
+{
+  if (count < 0)
+    return (rl_forward_byte (-count, key));
+
+  if (count > 0)
+    {
+      if (rl_point < count)
+       {
+         rl_point = 0;
+         rl_ding ();
+       }
+      else
+       rl_point -= count;
+    }
+
+  if (rl_point < 0)
+    rl_point = 0;
+
+  return 0;
+}
+
+#if defined (HANDLE_MULTIBYTE)
+/* Move backward COUNT characters. */
+int
+rl_backward_char (count, key)
+     int count, key;
+{
+  int point;
+
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+    return (rl_backward_byte (count, key));
+
+  if (count < 0)
+    return (rl_forward_char (-count, key));
+
+  if (count > 0)
+    {
+      point = rl_point;
+
+      while (count > 0 && point > 0)
+       {
+         point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO);
+         count--;
+       }
+      if (count > 0)
+       {
+         rl_point = 0;
+         rl_ding ();
+       }
+      else
+        rl_point = point;
+    }
+
+  return 0;
+}
+#else
+int
+rl_backward_char (count, key)
+     int count, key;
+{
+  return (rl_backward_byte (count, key));
+}
+#endif
+
+/* Backwards compatibility. */
+int
+rl_backward (count, key)
+     int count, key;
+{
+  return (rl_backward_char (count, key));
+}
+
+/* Move to the beginning of the line. */
+int
+rl_beg_of_line (count, key)
+     int count, key;
+{
+  rl_point = 0;
+  return 0;
+}
+
+/* Move to the end of the line. */
+int
+rl_end_of_line (count, key)
+     int count, key;
+{
+  rl_point = rl_end;
+  return 0;
+}
+
+/* XXX - these might need changes for multibyte characters */
+/* Move forward a word.  We do what Emacs does. */
+int
+rl_forward_word (count, key)
+     int count, key;
+{
+  int c;
+
+  if (count < 0)
+    return (rl_backward_word (-count, key));
+
+  while (count)
+    {
+      if (rl_point == rl_end)
+       return 0;
+
+      /* If we are not in a word, move forward until we are in one.
+        Then, move forward until we hit a non-alphabetic character. */
+      c = rl_line_buffer[rl_point];
+      if (rl_alphabetic (c) == 0)
+       {
+         while (++rl_point < rl_end)
+           {
+             c = rl_line_buffer[rl_point];
+             if (rl_alphabetic (c))
+               break;
+           }
+       }
+
+      if (rl_point == rl_end)
+       return 0;
+
+      while (++rl_point < rl_end)
+       {
+         c = rl_line_buffer[rl_point];
+         if (rl_alphabetic (c) == 0)
+           break;
+       }
+      --count;
+    }
+
+  return 0;
+}
+
+/* Move backward a word.  We do what Emacs does. */
+int
+rl_backward_word (count, key)
+     int count, key;
+{
+  int c;
+
+  if (count < 0)
+    return (rl_forward_word (-count, key));
+
+  while (count)
+    {
+      if (!rl_point)
+       return 0;
+
+      /* Like rl_forward_word (), except that we look at the characters
+        just before point. */
+
+      c = rl_line_buffer[rl_point - 1];
+      if (rl_alphabetic (c) == 0)
+       {
+         while (--rl_point)
+           {
+             c = rl_line_buffer[rl_point - 1];
+             if (rl_alphabetic (c))
+               break;
+           }
+       }
+
+      while (rl_point)
+       {
+         c = rl_line_buffer[rl_point - 1];
+         if (rl_alphabetic (c) == 0)
+           break;
+         else
+           --rl_point;
+       }
+
+      --count;
+    }
+
+  return 0;
+}
+
+/* Clear the current line.  Numeric argument to C-l does this. */
+int
+rl_refresh_line (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+  int curr_line;
+
+  curr_line = _rl_current_display_line ();
+
+  _rl_move_vert (curr_line);
+  _rl_move_cursor_relative (0, rl_line_buffer);   /* XXX is this right */
+
+  _rl_clear_to_eol (0);                /* arg of 0 means to not use spaces */
+
+  rl_forced_update_display ();
+  rl_display_fixed = 1;
+
+  return 0;
+}
+
+/* C-l typed to a line without quoting clears the screen, and then reprints
+   the prompt and the current input line.  Given a numeric arg, redraw only
+   the current line. */
+int
+rl_clear_screen (count, key)
+     int count, key;
+{
+  if (rl_explicit_arg)
+    {
+      rl_refresh_line (count, key);
+      return 0;
+    }
+
+  _rl_clear_screen ();         /* calls termcap function to clear screen */
+  rl_forced_update_display ();
+  rl_display_fixed = 1;
+
+  return 0;
+}
+
+int
+rl_arrow_keys (count, c)
+     int count, c;
+{
+  int ch;
+
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  ch = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+  switch (_rl_to_upper (ch))
+    {
+    case 'A':
+      rl_get_previous_history (count, ch);
+      break;
+
+    case 'B':
+      rl_get_next_history (count, ch);
+      break;
+
+    case 'C':
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_forward_char (count, ch);
+      else
+       rl_forward_byte (count, ch);
+      break;
+
+    case 'D':
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_backward_char (count, ch);
+      else
+       rl_backward_byte (count, ch);
+      break;
+
+    default:
+      rl_ding ();
+    }
+
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Text commands                               */
+/*                                                                 */
+/* **************************************************************** */
+
+#ifdef HANDLE_MULTIBYTE
+static char pending_bytes[MB_LEN_MAX];
+static int pending_bytes_length = 0;
+static mbstate_t ps = {0};
+#endif
+
+/* Insert the character C at the current location, moving point forward.
+   If C introduces a multibyte sequence, we read the whole sequence and
+   then insert the multibyte char into the line buffer. */
+int
+_rl_insert_char (count, c)
+     int count, c;
+{
+  register int i;
+  char *string;
+#ifdef HANDLE_MULTIBYTE
+  int string_size;
+  char incoming[MB_LEN_MAX + 1];
+  int incoming_length = 0;
+  mbstate_t ps_back;
+  static int stored_count = 0;
+#endif
+
+  if (count <= 0)
+    return 0;
+
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+    {
+      incoming[0] = c;
+      incoming[1] = '\0';
+      incoming_length = 1;
+    }
+  else
+    {
+      wchar_t wc;
+      size_t ret;
+
+      if (stored_count <= 0)
+       stored_count = count;
+      else
+       count = stored_count;
+
+      ps_back = ps;
+      pending_bytes[pending_bytes_length++] = c;
+      ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps);
+
+      if (ret == (size_t)-2)
+       {
+         /* Bytes too short to compose character, try to wait for next byte.
+            Restore the state of the byte sequence, because in this case the
+            effect of mbstate is undefined. */
+         ps = ps_back;
+         return 1;
+       }
+      else if (ret == (size_t)-1)
+       {
+         /* Invalid byte sequence for the current locale.  Treat first byte
+            as a single character. */
+         incoming[0] = pending_bytes[0];
+         incoming[1] = '\0';
+         incoming_length = 1;
+         pending_bytes_length--;
+         memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
+         /* Clear the state of the byte sequence, because in this case the
+            effect of mbstate is undefined. */
+         memset (&ps, 0, sizeof (mbstate_t));
+       }
+      else if (ret == (size_t)0)
+       {
+         incoming[0] = '\0';
+         incoming_length = 0;
+         pending_bytes_length--;
+         /* Clear the state of the byte sequence, because in this case the
+            effect of mbstate is undefined. */
+         memset (&ps, 0, sizeof (mbstate_t));
+       }
+      else
+       {
+         /* We successfully read a single multibyte character. */
+         memcpy (incoming, pending_bytes, pending_bytes_length);
+         incoming[pending_bytes_length] = '\0';
+         incoming_length = pending_bytes_length;
+         pending_bytes_length = 0;
+       }
+    }
+#endif /* HANDLE_MULTIBYTE */
+         
+  /* If we can optimize, then do it.  But don't let people crash
+     readline because of extra large arguments. */
+  if (count > 1 && count <= 1024)
+    {
+#if defined (HANDLE_MULTIBYTE)
+      string_size = count * incoming_length;
+      string = (char *)xmalloc (1 + string_size);
+
+      i = 0;
+      while (i < string_size)
+       {
+         strncpy (string + i, incoming, incoming_length);
+         i += incoming_length;
+       }
+      incoming_length = 0;
+      stored_count = 0;
+#else /* !HANDLE_MULTIBYTE */
+      string = (char *)xmalloc (1 + count);
+
+      for (i = 0; i < count; i++)
+       string[i] = c;
+#endif /* !HANDLE_MULTIBYTE */
+
+      string[i] = '\0';
+      rl_insert_text (string);
+      free (string);
+
+      return 0;
+    }
+
+  if (count > 1024)
+    {
+      int decreaser;
+#if defined (HANDLE_MULTIBYTE)
+      string_size = incoming_length * 1024;
+      string = (char *)xmalloc (1 + string_size);
+
+      i = 0;
+      while (i < string_size)
+       {
+         strncpy (string + i, incoming, incoming_length);
+         i += incoming_length;
+       }
+
+      while (count)
+       {
+         decreaser = (count > 1024) ? 1024 : count;
+         string[decreaser*incoming_length] = '\0';
+         rl_insert_text (string);
+         count -= decreaser;
+       }
+
+      free (string);
+      incoming_length = 0;
+      stored_count = 0;
+#else /* !HANDLE_MULTIBYTE */
+      char str[1024+1];
+
+      for (i = 0; i < 1024; i++)
+       str[i] = c;
+
+      while (count)
+       {
+         decreaser = (count > 1024 ? 1024 : count);
+         str[decreaser] = '\0';
+         rl_insert_text (str);
+         count -= decreaser;
+       }
+#endif /* !HANDLE_MULTIBYTE */
+
+      return 0;
+    }
+
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+    {
+#endif
+      /* We are inserting a single character.
+        If there is pending input, then make a string of all of the
+        pending characters that are bound to rl_insert, and insert
+        them all. */
+      if (_rl_any_typein ())
+       _rl_insert_typein (c);
+      else
+       {
+         /* Inserting a single character. */
+         char str[2];
+
+         str[1] = '\0';
+         str[0] = c;
+         rl_insert_text (str);
+       }
+#if defined (HANDLE_MULTIBYTE)
+    }
+  else
+    {
+      rl_insert_text (incoming);
+      stored_count = 0;
+    }
+#endif
+
+  return 0;
+}
+
+/* Overwrite the character at point (or next COUNT characters) with C.
+   If C introduces a multibyte character sequence, read the entire sequence
+   before starting the overwrite loop. */
+int
+_rl_overwrite_char (count, c)
+     int count, c;
+{
+  int i;
+#if defined (HANDLE_MULTIBYTE)
+  char mbkey[MB_LEN_MAX];
+  int k;
+
+  /* Read an entire multibyte character sequence to insert COUNT times. */
+  if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX);
+#endif
+
+  for (i = 0; i < count; i++)
+    {
+      rl_begin_undo_group ();
+
+      if (rl_point < rl_end)
+       rl_delete (1, c);
+
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_insert_text (mbkey);
+      else
+#endif
+       _rl_insert_char (1, c);
+
+      rl_end_undo_group ();
+    }
+
+  return 0;
+}
+
+int
+rl_insert (count, c)
+     int count, c;
+{
+  return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c)
+                                        : _rl_overwrite_char (count, c));
+}
+
+/* Insert the next typed character verbatim. */
+int
+rl_quoted_insert (count, key)
+     int count, key;
+{
+  int c;
+
+#if defined (HANDLE_SIGNALS)
+  _rl_disable_tty_signals ();
+#endif
+
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  c = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+#if defined (HANDLE_SIGNALS)
+  _rl_restore_tty_signals ();
+#endif
+
+  return (_rl_insert_char (count, c));  
+}
+
+/* Insert a tab character. */
+int
+rl_tab_insert (count, key)
+     int count, key;
+{
+  return (_rl_insert_char (count, '\t'));
+}
+
+/* What to do when a NEWLINE is pressed.  We accept the whole line.
+   KEY is the key that invoked this command.  I guess it could have
+   meaning in the future. */
+int
+rl_newline (count, key)
+     int count, key;
+{
+  rl_done = 1;
+
+  if (_rl_history_preserve_point)
+    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
+
+  RL_SETSTATE(RL_STATE_DONE);
+
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode)
+    {
+      _rl_vi_done_inserting ();
+      _rl_vi_reset_last ();
+    }
+#endif /* VI_MODE */
+
+  /* If we've been asked to erase empty lines, suppress the final update,
+     since _rl_update_final calls rl_crlf(). */
+  if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
+    return 0;
+
+  if (readline_echoing_p)
+    _rl_update_final ();
+  return 0;
+}
+
+/* What to do for some uppercase characters, like meta characters,
+   and some characters appearing in emacs_ctlx_keymap.  This function
+   is just a stub, you bind keys to it and the code in _rl_dispatch ()
+   is special cased. */
+int
+rl_do_lowercase_version (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+  return 0;
+}
+
+/* This is different from what vi does, so the code's not shared.  Emacs
+   rubout in overwrite mode has one oddity:  it replaces a control
+   character that's displayed as two characters (^X) with two spaces. */
+int
+_rl_overwrite_rubout (count, key)
+     int count, key;
+{
+  int opoint;
+  int i, l;
+
+  if (rl_point == 0)
+    {
+      rl_ding ();
+      return 1;
+    }
+
+  opoint = rl_point;
+
+  /* L == number of spaces to insert */
+  for (i = l = 0; i < count; i++)
+    {
+      rl_backward_char (1, key);
+      l += rl_character_len (rl_line_buffer[rl_point], rl_point);      /* not exactly right */
+    }
+
+  rl_begin_undo_group ();
+
+  if (count > 1 || rl_explicit_arg)
+    rl_kill_text (opoint, rl_point);
+  else
+    rl_delete_text (opoint, rl_point);
+
+  /* Emacs puts point at the beginning of the sequence of spaces. */
+  opoint = rl_point;
+  _rl_insert_char (l, ' ');
+  rl_point = opoint;
+
+  rl_end_undo_group ();
+
+  return 0;
+}
+  
+/* Rubout the character behind point. */
+int
+rl_rubout (count, key)
+     int count, key;
+{
+  if (count < 0)
+    return (rl_delete (-count, key));
+
+  if (!rl_point)
+    {
+      rl_ding ();
+      return -1;
+    }
+
+  if (rl_insert_mode == RL_IM_OVERWRITE)
+    return (_rl_overwrite_rubout (count, key));
+
+  return (_rl_rubout_char (count, key));
+}
+
+int
+_rl_rubout_char (count, key)
+     int count, key;
+{
+  int orig_point;
+  unsigned char c;
+
+  /* Duplicated code because this is called from other parts of the library. */
+  if (count < 0)
+    return (rl_delete (-count, key));
+
+  if (rl_point == 0)
+    {
+      rl_ding ();
+      return -1;
+    }
+
+  if (count > 1 || rl_explicit_arg)
+    {
+      orig_point = rl_point;
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_backward_char (count, key);
+      else
+#endif
+        rl_backward_byte (count, key);
+      rl_kill_text (orig_point, rl_point);
+    }
+  else
+    {
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX == 1 || rl_byte_oriented)
+       {
+#endif
+         c = rl_line_buffer[--rl_point];
+         rl_delete_text (rl_point, rl_point + 1);
+#if defined (HANDLE_MULTIBYTE)
+       }
+      else
+       {
+         int orig_point;
+
+         orig_point = rl_point;
+         rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+         c = rl_line_buffer[rl_point];
+         rl_delete_text (rl_point, orig_point);
+       }
+#endif /* HANDLE_MULTIBYTE */
+
+      /* I don't think that the hack for end of line is needed for
+        multibyte chars. */
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX == 1 || rl_byte_oriented)
+#endif
+      if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos)
+       {
+         int l;
+         l = rl_character_len (c, rl_point);
+         _rl_erase_at_end_of_line (l);
+       }
+    }
+
+  return 0;
+}
+
+/* Delete the character under the cursor.  Given a numeric argument,
+   kill that many characters instead. */
+int
+rl_delete (count, key)
+     int count, key;
+{
+  int r;
+
+  if (count < 0)
+    return (_rl_rubout_char (-count, key));
+
+  if (rl_point == rl_end)
+    {
+      rl_ding ();
+      return -1;
+    }
+
+  if (count > 1 || rl_explicit_arg)
+    {
+      int orig_point = rl_point;
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_forward_char (count, key);
+      else
+#endif
+       rl_forward_byte (count, key);
+
+      r = rl_kill_text (orig_point, rl_point);
+      rl_point = orig_point;
+      return r;
+    }
+  else
+    {
+      int new_point;
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
+      else
+       new_point = rl_point + 1;
+       
+      return (rl_delete_text (rl_point, new_point));
+    }
+}
+
+/* Delete the character under the cursor, unless the insertion
+   point is at the end of the line, in which case the character
+   behind the cursor is deleted.  COUNT is obeyed and may be used
+   to delete forward or backward that many characters. */      
+int
+rl_rubout_or_delete (count, key)
+     int count, key;
+{
+  if (rl_end != 0 && rl_point == rl_end)
+    return (_rl_rubout_char (count, key));
+  else
+    return (rl_delete (count, key));
+}  
+
+/* Delete all spaces and tabs around point. */
+int
+rl_delete_horizontal_space (count, ignore)
+     int count, ignore;
+{
+  int start = rl_point;
+
+  while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
+    rl_point--;
+
+  start = rl_point;
+
+  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+    rl_point++;
+
+  if (start != rl_point)
+    {
+      rl_delete_text (start, rl_point);
+      rl_point = start;
+    }
+  return 0;
+}
+
+/* Like the tcsh editing function delete-char-or-list.  The eof character
+   is caught before this is invoked, so this really does the same thing as
+   delete-char-or-list-or-eof, as long as it's bound to the eof character. */
+int
+rl_delete_or_show_completions (count, key)
+     int count, key;
+{
+  if (rl_end != 0 && rl_point == rl_end)
+    return (rl_possible_completions (count, key));
+  else
+    return (rl_delete (count, key));
+}
+
+#ifndef RL_COMMENT_BEGIN_DEFAULT
+#define RL_COMMENT_BEGIN_DEFAULT "#"
+#endif
+
+/* Turn the current line into a comment in shell history.
+   A K*rn shell style function. */
+int
+rl_insert_comment (count, key)
+     int count, key;
+{
+  char *rl_comment_text;
+  int rl_comment_len;
+
+  rl_beg_of_line (1, key);
+  rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT;
+
+  if (rl_explicit_arg == 0)
+    rl_insert_text (rl_comment_text);
+  else
+    {
+      rl_comment_len = strlen (rl_comment_text);
+      if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len))
+       rl_delete_text (rl_point, rl_point + rl_comment_len);
+      else
+       rl_insert_text (rl_comment_text);
+    }
+
+  (*rl_redisplay_function) ();
+  rl_newline (1, '\n');
+
+  return (0);
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Changing Case                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* The three kinds of things that we know how to do. */
+#define UpCase 1
+#define DownCase 2
+#define CapCase 3
+
+/* Uppercase the word at point. */
+int
+rl_upcase_word (count, key)
+     int count, key;
+{
+  return (rl_change_case (count, UpCase));
+}
+
+/* Lowercase the word at point. */
+int
+rl_downcase_word (count, key)
+     int count, key;
+{
+  return (rl_change_case (count, DownCase));
+}
+
+/* Upcase the first letter, downcase the rest. */
+int
+rl_capitalize_word (count, key)
+     int count, key;
+{
+ return (rl_change_case (count, CapCase));
+}
+
+/* The meaty function.
+   Change the case of COUNT words, performing OP on them.
+   OP is one of UpCase, DownCase, or CapCase.
+   If a negative argument is given, leave point where it started,
+   otherwise, leave it where it moves to. */
+static int
+rl_change_case (count, op)
+     int count, op;
+{
+  register int start, end;
+  int inword, c;
+
+  start = rl_point;
+  rl_forward_word (count, 0);
+  end = rl_point;
+
+  if (count < 0)
+    SWAP (start, end);
+
+  /* We are going to modify some text, so let's prepare to undo it. */
+  rl_modifying (start, end);
+
+  for (inword = 0; start < end; start++)
+    {
+      c = rl_line_buffer[start];
+      switch (op)
+       {
+       case UpCase:
+         rl_line_buffer[start] = _rl_to_upper (c);
+         break;
+
+       case DownCase:
+         rl_line_buffer[start] = _rl_to_lower (c);
+         break;
+
+       case CapCase:
+         rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c);
+         inword = rl_alphabetic (rl_line_buffer[start]);
+         break;
+
+       default:
+         rl_ding ();
+         return -1;
+       }
+    }
+  rl_point = end;
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Transposition                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Transpose the words at point.  If point is at the end of the line,
+   transpose the two words before point. */
+int
+rl_transpose_words (count, key)
+     int count, key;
+{
+  char *word1, *word2;
+  int w1_beg, w1_end, w2_beg, w2_end;
+  int orig_point = rl_point;
+
+  if (!count)
+    return 0;
+
+  /* Find the two words. */
+  rl_forward_word (count, key);
+  w2_end = rl_point;
+  rl_backward_word (1, key);
+  w2_beg = rl_point;
+  rl_backward_word (count, key);
+  w1_beg = rl_point;
+  rl_forward_word (1, key);
+  w1_end = rl_point;
+
+  /* Do some check to make sure that there really are two words. */
+  if ((w1_beg == w2_beg) || (w2_beg < w1_end))
+    {
+      rl_ding ();
+      rl_point = orig_point;
+      return -1;
+    }
+
+  /* Get the text of the words. */
+  word1 = rl_copy_text (w1_beg, w1_end);
+  word2 = rl_copy_text (w2_beg, w2_end);
+
+  /* We are about to do many insertions and deletions.  Remember them
+     as one operation. */
+  rl_begin_undo_group ();
+
+  /* Do the stuff at word2 first, so that we don't have to worry
+     about word1 moving. */
+  rl_point = w2_beg;
+  rl_delete_text (w2_beg, w2_end);
+  rl_insert_text (word1);
+
+  rl_point = w1_beg;
+  rl_delete_text (w1_beg, w1_end);
+  rl_insert_text (word2);
+
+  /* This is exactly correct since the text before this point has not
+     changed in length. */
+  rl_point = w2_end;
+
+  /* I think that does it. */
+  rl_end_undo_group ();
+  free (word1);
+  free (word2);
+
+  return 0;
+}
+
+/* Transpose the characters at point.  If point is at the end of the line,
+   then transpose the characters before point. */
+int
+rl_transpose_chars (count, key)
+     int count, key;
+{
+#if defined (HANDLE_MULTIBYTE)
+  char *dummy;
+  int i, prev_point;
+#else
+  char dummy[2];
+#endif
+  int char_length;
+
+  if (count == 0)
+    return 0;
+
+  if (!rl_point || rl_end < 2)
+    {
+      rl_ding ();
+      return -1;
+    }
+
+  rl_begin_undo_group ();
+
+  if (rl_point == rl_end)
+    {
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+      else
+       --rl_point;
+      count = 1;
+    }
+
+#if defined (HANDLE_MULTIBYTE)
+  prev_point = rl_point;
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+  else
+#endif
+    rl_point--;
+
+#if defined (HANDLE_MULTIBYTE)
+  char_length = prev_point - rl_point;
+  dummy = (char *)xmalloc (char_length + 1);
+  for (i = 0; i < char_length; i++)
+    dummy[i] = rl_line_buffer[rl_point + i];
+  dummy[i] = '\0';
+#else
+  dummy[0] = rl_line_buffer[rl_point];
+  dummy[char_length = 1] = '\0';
+#endif
+
+  rl_delete_text (rl_point, rl_point + char_length);
+
+  rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
+
+  _rl_fix_point (0);
+  rl_insert_text (dummy);
+  rl_end_undo_group ();
+
+#if defined (HANDLE_MULTIBYTE)
+  free (dummy);
+#endif
+
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Character Searching                         */
+/*                                                                 */
+/* **************************************************************** */
+
+int
+#if defined (HANDLE_MULTIBYTE)
+_rl_char_search_internal (count, dir, smbchar, len)
+     int count, dir;
+     char *smbchar;
+     int len;
+#else
+_rl_char_search_internal (count, dir, schar)
+     int count, dir, schar;
+#endif
+{
+  int pos, inc;
+#if defined (HANDLE_MULTIBYTE)
+  int prepos;
+#endif
+
+  pos = rl_point;
+  inc = (dir < 0) ? -1 : 1;
+  while (count)
+    {
+      if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
+       {
+         rl_ding ();
+         return -1;
+       }
+
+#if defined (HANDLE_MULTIBYTE)
+      pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
+                     : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
+#else
+      pos += inc;
+#endif
+      do
+       {
+#if defined (HANDLE_MULTIBYTE)
+         if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len))
+#else
+         if (rl_line_buffer[pos] == schar)
+#endif
+           {
+             count--;
+             if (dir < 0)
+               rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
+                                       : pos;
+             else
+               rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)
+                                       : pos;
+             break;
+           }
+#if defined (HANDLE_MULTIBYTE)
+         prepos = pos;
+#endif
+       }
+#if defined (HANDLE_MULTIBYTE)
+      while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos
+                      : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos);
+#else
+      while ((dir < 0) ? pos-- : ++pos < rl_end);
+#endif
+    }
+  return (0);
+}
+
+/* Search COUNT times for a character read from the current input stream.
+   FDIR is the direction to search if COUNT is non-negative; otherwise
+   the search goes in BDIR.  So much is dependent on HANDLE_MULTIBYTE
+   that there are two separate versions of this function. */
+#if defined (HANDLE_MULTIBYTE)
+static int
+_rl_char_search (count, fdir, bdir)
+     int count, fdir, bdir;
+{
+  char mbchar[MB_LEN_MAX];
+  int mb_len;
+
+  mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
+
+  if (count < 0)
+    return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
+  else
+    return (_rl_char_search_internal (count, fdir, mbchar, mb_len));
+}
+#else /* !HANDLE_MULTIBYTE */
+static int
+_rl_char_search (count, fdir, bdir)
+     int count, fdir, bdir;
+{
+  int c;
+
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  c = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+  if (count < 0)
+    return (_rl_char_search_internal (-count, bdir, c));
+  else
+    return (_rl_char_search_internal (count, fdir, c));
+}
+#endif /* !HANDLE_MULTIBYTE */
+
+int
+rl_char_search (count, key)
+     int count, key;
+{
+  return (_rl_char_search (count, FFIND, BFIND));
+}
+
+int
+rl_backward_char_search (count, key)
+     int count, key;
+{
+  return (_rl_char_search (count, BFIND, FFIND));
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                The Mark and the Region.                         */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Set the mark at POSITION. */
+int
+_rl_set_mark_at_pos (position)
+     int position;
+{
+  if (position > rl_end)
+    return -1;
+
+  rl_mark = position;
+  return 0;
+}
+
+/* A bindable command to set the mark. */
+int
+rl_set_mark (count, key)
+     int count, key;
+{
+  return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
+}
+
+/* Exchange the position of mark and point. */
+int
+rl_exchange_point_and_mark (count, key)
+     int count, key;
+{
+  if (rl_mark > rl_end)
+    rl_mark = -1;
+
+  if (rl_mark == -1)
+    {
+      rl_ding ();
+      return -1;
+    }
+  else
+    SWAP (rl_point, rl_mark);
+
+  return 0;
+}