'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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
--- /dev/null
+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
+])
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+# 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.
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+
+
+
+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
+
+
--- /dev/null
+.\"
+.\" 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 .
--- /dev/null
+/*******************************************************************************
+ * $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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* 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
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* 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;
+}