]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20060720 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:50:46 +0000 (22:50 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:50:46 +0000 (22:50 -0500)
13 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
lib/malloc/stats.c
lib/malloc/stats.c~ [new file with mode: 0644]
lib/malloc/table.c
lib/malloc/table.c~ [new file with mode: 0644]
lib/readline/display.c
lib/readline/rlprivate.h
lib/readline/terminal.c
lib/termcap/termcap.c
lib/termcap/termcap.c~ [new file with mode: 0644]
lib/termcap/tparam.c
lib/termcap/tparam.c~ [new file with mode: 0644]

index 3f85d2216207b4ad799b7478f4ba83376b2fa3da..c0eeaa1156aadb3baa8523cf3f6c6605b1b3105a 100644 (file)
@@ -13511,7 +13511,7 @@ builtins/read.def
          unwind-protect that restores the default completion function
 
 lib/readline/display.c
-       - make sure to set local_prompt_len in rl_message()
+       - make sure to set local_prompt_len in rl_message() [in bash-3.2-alpha]
 
                                    7/5
                                    ---
@@ -13523,15 +13523,46 @@ builtins/printf.def
                                    ---
 lib/readline/display.c
        - save and restore local_prompt_len in rl_{save,restore}_prompt
+         [in bash-3.2-alpha]
 
                                    7/9
                                    ---
 lib/readline/display.c
        - make sure that _rl_move_cursor_relative sets cpos_adjusted when it
          offsets `dpos' by wrap_offset in a multi-byte locale.  Bug reported
-         by Andreas Schwab
+         by Andreas Schwab and Egmont Koblinger
 
 subst.c
        - make sure that the call to mbstowcs in string_extract_verbatim is
          passed a string with enough space for the closing NUL.  Reported
          by Andreas Schwab
+
+                                  7/18
+                                  ----
+lib/readline/{display,terminal}.c
+       - remove #ifdefs for HACK_TERMCAP_MOTION so we can use
+         _rl_term_forward_char in the redisplay code unconditionally
+
+lib/readline/rlprivate.h
+       - new extern declaration for _rl_term_forward_char
+
+lib/readline/display.c
+       - in _rl_move_cursor_relative, use `dpos' instead of `new' when
+         deciding whether or not a CR is faster than moving the cursor from
+         its current position
+       - in _rl_move_cursor_relative, we can use _rl_term_forward_char to
+         move the cursor forward in a multibyte locale, if it's available.
+         Since that function doesn't have a handle on where the cursor is in
+         the display buffer, it has to output a cr and print all the data
+       - change variable denoting the position of the cursor in the line buffer
+         from c_pos (variable local to rl_redisplay) to cpos_buffer_position
+         (variable local to file) for future use by other functions
+
+                                  7/25
+                                  ----
+lib/malloc/{stats,table}.h
+       - include <string.h> for prototypes for memset, strlen
+
+lib/termcap/{termcap,tparam}.c
+       - include <string.h> and provide macro replacement for bcopy if
+         necessary
index 7a2ec13f5d4c943d91b37ac02989f0a672fa2eae..56fb9dce9936010d2278b340fa32b77a2b15800d 100644 (file)
@@ -13511,7 +13511,7 @@ builtins/read.def
          unwind-protect that restores the default completion function
 
 lib/readline/display.c
-       - make sure to set local_prompt_len in rl_message()
+       - make sure to set local_prompt_len in rl_message() [in bash-3.2-alpha]
 
                                    7/5
                                    ---
@@ -13523,10 +13523,42 @@ builtins/printf.def
                                    ---
 lib/readline/display.c
        - save and restore local_prompt_len in rl_{save,restore}_prompt
+         [in bash-3.2-alpha]
 
                                    7/9
                                    ---
 lib/readline/display.c
        - make sure that _rl_move_cursor_relative sets cpos_adjusted when it
          offsets `dpos' by wrap_offset in a multi-byte locale.  Bug reported
+         by Andreas Schwab and Egmont Koblinger
+
+subst.c
+       - make sure that the call to mbstowcs in string_extract_verbatim is
+         passed a string with enough space for the closing NUL.  Reported
          by Andreas Schwab
+
+                                  7/18
+                                  ----
+lib/readline/{display,terminal}.c
+       - remove #ifdefs for HACK_TERMCAP_MOTION so we can use
+         _rl_term_forward_char in the redisplay code unconditionally
+
+lib/readline/rlprivate.h
+       - new extern declaration for _rl_term_forward_char
+
+lib/readline/display.c
+       - in _rl_move_cursor_relative, use `dpos' instead of `new' when
+         deciding whether or not a CR is faster than moving the cursor from
+         its current position
+       - in _rl_move_cursor_relative, we can use _rl_term_forward_char to
+         move the cursor forward in a multibyte locale, if it's available.
+         Since that function doesn't have a handle on where the cursor is in
+         the display buffer, it has to output a cr and print all the data
+       - change variable denoting the position of the cursor in the line buffer
+         from c_pos (variable local to rl_redisplay) to cpos_buffer_position
+         (variable local to file) for future use by other functions
+
+                                  7/25
+                                  ----
+lib/malloc/{stats,table}.h
+       - include <string.h> for prototypes for memset, strlen
index 18c3cef5911f05a2a2c959fc8c94c4611192a641..0d119fab5143a664d92c32e989e635c761f406d8 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
+#include <string.h>
 
 #include "mstats.h"
 
diff --git a/lib/malloc/stats.c~ b/lib/malloc/stats.c~
new file mode 100644 (file)
index 0000000..18c3cef
--- /dev/null
@@ -0,0 +1,202 @@
+/* stats.c - malloc statistics */
+
+/*  Copyright (C) 2001-2003 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, 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 USA. */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "imalloc.h"
+
+#ifdef MALLOC_STATS
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include "mstats.h"
+
+extern int malloc_free_blocks __P((int));
+
+extern struct _malstats _mstats;
+
+extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
+
+struct bucket_stats
+malloc_bucket_stats (size)
+     int size;
+{
+  struct bucket_stats v;
+
+  v.nfree = 0;
+
+  if (size < 0 || size >= NBUCKETS)
+    {
+      v.blocksize = 0;
+      v.nused = v.nmal = v.nmorecore = v.nlesscore = v.nsplit = 0;
+      return v;
+    }
+
+  v.blocksize = 1 << (size + 3);
+  v.nused = _mstats.nmalloc[size];
+  v.nmal = _mstats.tmalloc[size];
+  v.nmorecore = _mstats.nmorecore[size];
+  v.nlesscore = _mstats.nlesscore[size];
+  v.nsplit = _mstats.nsplit[size];
+  v.ncoalesce = _mstats.ncoalesce[size];
+
+  v.nfree = malloc_free_blocks (size); /* call back to malloc.c */
+
+  return v;
+}
+
+/* Return a copy of _MSTATS, with two additional fields filled in:
+   BYTESFREE is the total number of bytes on free lists.  BYTESUSED
+   is the total number of bytes in use.  These two fields are fairly
+   expensive to compute, so we do it only when asked to. */
+struct _malstats
+malloc_stats ()
+{
+  struct _malstats result;
+  struct bucket_stats v;
+  register int i;
+
+  result = _mstats;
+  result.bytesused = result.bytesfree = 0;
+  for (i = 0; i < NBUCKETS; i++)
+    {
+      v = malloc_bucket_stats (i);
+      result.bytesfree += v.nfree * v.blocksize;
+      result.bytesused += v.nused * v.blocksize;
+    }
+  return (result);
+}
+
+static void
+_print_malloc_stats (s, fp)
+     char *s;
+     FILE *fp;
+{
+  register int i;
+  unsigned long totused, totfree;
+  struct bucket_stats v;
+
+  fprintf (fp, "Memory allocation statistics: %s\n    size\tfree\tin use\ttotal\tmorecore lesscore split\tcoalesce\n", s ? s : "");
+  for (i = totused = totfree = 0; i < NBUCKETS; i++)
+    {
+      v = malloc_bucket_stats (i);
+      if (v.nmal > 0)
+       fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce);
+      totfree += v.nfree * v.blocksize;
+      totused += v.nused * v.blocksize;
+    }
+  fprintf (fp, "\nTotal bytes in use: %lu, total bytes free: %lu\n",
+          totused, totfree);
+  fprintf (fp, "\nTotal bytes requested by application: %lu\n", _mstats.bytesreq);
+  fprintf (fp, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n",
+          _mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy);
+  fprintf (fp, "Total sbrks: %d, total bytes via sbrk: %d\n",
+          _mstats.nsbrk, _mstats.tsbrk);
+  fprintf (fp, "Total blocks split: %d, total block coalesces: %d\n",
+          _mstats.tbsplit, _mstats.tbcoalesce);
+}
+
+void
+print_malloc_stats (s)
+     char *s;
+{
+  _print_malloc_stats (s, stderr);
+}
+
+void
+fprint_malloc_stats (s, fp)
+     char *s;
+     FILE *fp;
+{
+  _print_malloc_stats (s, fp);
+}
+
+#define TRACEROOT "/var/tmp/maltrace/stats."
+
+void
+trace_malloc_stats (s, fn)
+     char *s, *fn;
+{
+  FILE *fp;
+  char defname[sizeof (TRACEROOT) + 64];
+  static char mallbuf[1024];
+
+  fp = _imalloc_fopen (s, fn, TRACEROOT, defname, sizeof (defname));
+  if (fp)
+    {
+      setvbuf (fp, mallbuf, _IOFBF, sizeof (mallbuf));
+      _print_malloc_stats (s, fp);
+      fflush(fp);
+      fclose(fp);
+    }
+}
+
+#endif /* MALLOC_STATS */
+
+#if defined (MALLOC_STATS) || defined (MALLOC_TRACE)
+FILE *
+_imalloc_fopen (s, fn, def, defbuf, defsiz)
+     char *s;
+     char *fn;
+     char *def;
+     char *defbuf;
+     size_t defsiz;
+{
+  char fname[1024];
+  long l;
+  FILE *fp;
+
+  l = (long)getpid ();
+  if (fn == 0)
+    {
+      sprintf (defbuf, "%s%ld", def, l);
+      fp = fopen(defbuf, "w");
+    }
+  else
+    {
+      char *p, *q, *r;
+      char pidbuf[32];
+      int sp;
+
+      sprintf (pidbuf, "%ld", l);
+      if ((strlen (pidbuf) + strlen (fn) + 2) >= sizeof (fname))
+       return;
+      for (sp = 0, p = fname, q = fn; *q; )
+       {
+         if (sp == 0 && *q == '%' && q[1] == 'p')
+           {
+             sp = 1;
+             for (r = pidbuf; *r; )
+               *p++ = *r++;
+             q += 2;
+           }
+         else
+           *p++ = *q++;
+       }
+      *p = '\0';
+      fp = fopen (fname, "w");
+    }
+
+  return fp;
+}
+#endif /* MALLOC_STATS || MALLOC_TRACE */
index ee37b3a716c75678a5e11c5ba9d5e744c5aa17b6..b9310a6a001c268518de3dc128dcb459e66b731d 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include <stdio.h>
+#include <string.h>
 
 #include "imalloc.h"
 #include "table.h"
diff --git a/lib/malloc/table.c~ b/lib/malloc/table.c~
new file mode 100644 (file)
index 0000000..ee37b3a
--- /dev/null
@@ -0,0 +1,290 @@
+/* table.c - bookkeeping functions for allocated memory */
+
+/* Copyright (C) 2001-2003 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash 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.
+
+   Bash 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 Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "imalloc.h"
+#include "table.h"
+
+extern int malloc_register;
+
+#ifdef MALLOC_REGISTER
+
+#define FIND_ALLOC     0x01    /* allocate new entry or find existing */
+#define FIND_EXIST     0x02    /* find existing entry */
+
+static int table_count = 0;
+static int table_allocated = 0;
+static mr_table_t mem_table[REG_TABLE_SIZE];
+static mr_table_t mem_overflow;
+
+/*
+ * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
+ */
+static unsigned int
+mt_hash (key)
+     const PTR_T key;
+{
+  unsigned int a, b, c;
+  unsigned long x;
+
+  /* set up the internal state */
+  a = 0x9e3779b9;      /* the golden ratio; an arbitrary value */
+  x = (unsigned long)key;              /* truncation is OK */
+  b = x >> 8;
+  c = x >> 3;                          /* XXX - was >> 4 */
+
+  HASH_MIX(a, b, c);
+  return c;
+}
+
+#if 0
+static unsigned int
+which_bucket (mem)
+     PTR_T mem;
+{
+  return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
+}
+#else
+#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
+#endif
+
+static mr_table_t *
+find_entry (mem, flags)
+     PTR_T mem;
+     int flags;
+{
+  unsigned int bucket;
+  register mr_table_t *tp;
+  mr_table_t *endp, *lastp;
+
+  if (mem_overflow.mem == mem)
+    return (&mem_overflow);
+
+  bucket = which_bucket (mem); /* get initial hash */
+  tp = endp = mem_table + bucket;
+  lastp = mem_table + REG_TABLE_SIZE;
+
+  while (1)
+    {
+      if (tp->mem == mem)
+       return (tp);
+      if (tp->mem == 0 && (flags & FIND_ALLOC))
+       {
+         table_count++;
+         return (tp);
+       }
+
+      tp++;
+
+      if (tp == lastp)         /* wrap around */
+        tp = mem_table;
+
+      if (tp == endp && (flags & FIND_EXIST))
+        return ((mr_table_t *)NULL);
+
+      if (tp == endp && (flags & FIND_ALLOC))
+        break;
+    }
+
+  /* oops.  table is full.  replace an existing free entry. */
+  do
+    {
+      /* If there are no free entries, punt right away without searching. */
+      if (table_allocated == REG_TABLE_SIZE)
+       break;
+
+      if (tp->flags & MT_FREE)
+       {
+         memset(tp, 0, sizeof (mr_table_t));
+         return (tp);
+       }
+      tp++;
+
+      if (tp == lastp)
+       tp = mem_table;
+    }
+  while (tp != endp);
+
+  /* wow. entirely full.  return mem_overflow dummy entry. */
+  tp = &mem_overflow;
+  memset (tp, 0, sizeof (mr_table_t));
+  return tp;
+}
+
+mr_table_t *
+mr_table_entry (mem)
+     PTR_T mem;
+{
+  return (find_entry (mem, FIND_EXIST));
+}
+
+void
+mregister_describe_mem (mem, fp)
+     PTR_T mem;
+     FILE *fp;
+{
+  mr_table_t *entry;
+
+  entry = find_entry (mem, FIND_EXIST);
+  if (entry == 0)
+    return;
+  fprintf (fp, "malloc: %p: %s: last %s from %s:%d\n",
+               mem,
+               (entry->flags & MT_ALLOC) ? "allocated" : "free",
+               (entry->flags & MT_ALLOC) ? "allocated" : "freed",
+               entry->file ? entry->file : "unknown",
+               entry->line);
+}
+
+void
+mregister_alloc (tag, mem, size, file, line)
+     const char *tag;
+     PTR_T mem;
+     size_t size;
+     const char *file;
+     int line;
+{
+  mr_table_t *tentry;
+
+  tentry = find_entry (mem, FIND_ALLOC);
+
+  if (tentry == 0)
+    {
+      /* oops.  table is full.  punt. */
+      fprintf (stderr, _("register_alloc: alloc table is full with FIND_ALLOC?\n"));
+      return;
+    }
+  
+  if (tentry->flags & MT_ALLOC)
+    {
+      /* oops.  bad bookkeeping. ignore for now */
+      fprintf (stderr, _("register_alloc: %p already in table as allocated?\n"), mem);
+    }
+
+  tentry->mem = mem;
+  tentry->size = size;
+  tentry->func = tag;
+  tentry->flags = MT_ALLOC;
+  tentry->file = file;
+  tentry->line = line;
+  tentry->nalloc++;
+
+  if (tentry != &mem_overflow)
+    table_allocated++;
+}
+
+void
+mregister_free (mem, size, file, line)
+     PTR_T mem;
+     int size;
+     const char *file;
+     int line;
+{
+  mr_table_t *tentry;
+
+  tentry = find_entry (mem, FIND_EXIST);
+  if (tentry == 0)
+    {
+      /* oops.  not found. */
+#if 0
+      fprintf (stderr, "register_free: %p not in allocation table?\n", mem);
+#endif
+      return;
+    }
+  if (tentry->flags & MT_FREE)
+    {
+      /* oops.  bad bookkeeping. ignore for now */
+      fprintf (stderr, _("register_free: %p already in table as free?\n"), mem);
+    }
+       
+  tentry->flags = MT_FREE;
+  tentry->func = "free";
+  tentry->file = file;
+  tentry->line = line;
+  tentry->nfree++;
+
+  if (tentry != &mem_overflow)
+    table_allocated--;
+}
+
+/* If we ever add more flags, this will require changes. */
+static char *
+_entry_flags(x)
+     int x;
+{
+  if (x & MT_FREE)
+    return "free";
+  else if (x & MT_ALLOC)
+    return "allocated";
+  else
+    return "undetermined?";
+}
+
+static void
+_register_dump_table(fp)
+     FILE *fp;
+{
+  register int i;
+  mr_table_t entry;
+
+  for (i = 0; i < REG_TABLE_SIZE; i++)
+    {
+      entry = mem_table[i];
+      if (entry.mem)
+       fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i,
+                                               entry.mem, entry.size,
+                                               _entry_flags(entry.flags),
+                                               entry.func ? entry.func : "unknown",
+                                               entry.file ? entry.file : "unknown",
+                                               entry.line,
+                                               entry.nalloc, entry.nfree);
+    }
+}
+void
+mregister_dump_table()
+{
+  _register_dump_table (stderr);
+}
+
+void
+mregister_table_init ()
+{
+  memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE);
+  memset (&mem_overflow, 0, sizeof (mr_table_t));
+  table_count = 0;
+}
+
+#endif /* MALLOC_REGISTER */
+
+int
+malloc_set_register(n)
+     int n;
+{
+  int old;
+
+  old = malloc_register;
+  malloc_register = n;
+  return old;
+}
index a1b476d266af4772d54c0464a29c202af84ac7f8..253cf65f8b38427d147edf7750ed0bba780f7276 100644 (file)
@@ -1,6 +1,6 @@
 /* display.c -- readline redisplay facility. */
 
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2006 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.
 extern char *strchr (), *strrchr ();
 #endif /* !strchr && !__STDC__ */
 
-#if defined (HACK_TERMCAP_MOTION)
-extern char *_rl_term_forward_char;
-#endif
-
 static void update_line PARAMS((char *, char *, int, int, int, int));
 static void space_to_eol PARAMS((int));
 static void delete_chars PARAMS((int));
@@ -80,7 +76,8 @@ static int *inv_lbreaks, *vis_lbreaks;
 static int inv_lbsize, vis_lbsize;
 
 /* Heuristic used to decide whether it is faster to move from CUR to NEW
-   by backing up or outputting a carriage return and moving forward. */
+   by backing up or outputting a carriage return and moving forward.  CUR
+   and NEW are either both buffer positions or absolute screen positions. */
 #define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
 
 /* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
@@ -143,6 +140,7 @@ int _rl_last_c_pos = 0;
 int _rl_last_v_pos = 0;
 
 static int cpos_adjusted;
+static int cpos_buffer_position;
 
 /* Number of lines currently on screen minus 1. */
 int _rl_vis_botlin = 0;
@@ -460,7 +458,7 @@ rl_redisplay ()
 {
   register int in, out, c, linenum, cursor_linenum;
   register char *line;
-  int c_pos, inv_botlin, lb_botlin, lb_linenum, o_cpos;
+  int inv_botlin, lb_botlin, lb_linenum, o_cpos;
   int newlines, lpos, temp, modmark, n0, num;
   char *prompt_this_line;
 #if defined (HANDLE_MULTIBYTE)
@@ -484,7 +482,7 @@ rl_redisplay ()
     }
 
   /* Draw the line into the buffer. */
-  c_pos = -1;
+  cpos_buffer_position = -1;
 
   line = invisible_line;
   out = inv_botlin = 0;
@@ -666,7 +664,7 @@ rl_redisplay ()
   prompt_last_screen_line = newlines;
 
   /* Draw the rest of the line (after the prompt) into invisible_line, keeping
-     track of where the cursor is (c_pos), the number of the line containing
+     track of where the cursor is (cpos_buffer_position), the number of the line containing
      the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
      It maintains an array of line breaks for display (inv_lbreaks).
      This handles expanding tabs for display and displaying meta characters. */
@@ -719,7 +717,7 @@ rl_redisplay ()
 
       if (in == rl_point)
        {
-         c_pos = out;
+         cpos_buffer_position = out;
          lb_linenum = newlines;
        }
 
@@ -813,7 +811,7 @@ rl_redisplay ()
                  }
              if (in == rl_point)
                {
-                 c_pos = out;
+                 cpos_buffer_position = out;
                  lb_linenum = newlines;
                }
              for (i = in; i < in+wc_bytes; i++)
@@ -844,9 +842,9 @@ rl_redisplay ()
 
     }
   line[out] = '\0';
-  if (c_pos < 0)
+  if (cpos_buffer_position < 0)
     {
-      c_pos = out;
+      cpos_buffer_position = out;
       lb_linenum = newlines;
     }
 
@@ -855,7 +853,7 @@ rl_redisplay ()
   inv_lbreaks[newlines+1] = out;
   cursor_linenum = lb_linenum;
 
-  /* C_POS == position in buffer where cursor should be placed.
+  /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
      CURSOR_LINENUM == line number where the cursor should be placed. */
 
   /* PWP: now is when things get a bit hairy.  The visible and invisible
@@ -1011,7 +1009,7 @@ rl_redisplay ()
          pos = inv_lbreaks[cursor_linenum];
          /* nleft == number of characters in the line buffer between the
             start of the line and the desired cursor position. */
-         nleft = c_pos - pos;
+         nleft = cpos_buffer_position - pos;
 
          /* NLEFT is now a number of characters in a buffer.  When in a
             multibyte locale, however, _rl_last_c_pos is an absolute cursor
@@ -1057,11 +1055,11 @@ rl_redisplay ()
         will be LMARGIN. */
 
       /* The number of characters that will be displayed before the cursor. */
-      ndisp = c_pos - wrap_offset;
+      ndisp = cpos_buffer_position - wrap_offset;
       nleft  = prompt_visible_length + wrap_offset;
       /* Where the new cursor position will be on the screen.  This can be
         longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
-      phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset);
+      phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
       t = _rl_screenwidth / 3;
 
       /* If the number of characters had already exceeded the screenwidth,
@@ -1072,7 +1070,7 @@ rl_redisplay ()
         two-thirds of the way across the screen. */
       if (phys_c_pos > _rl_screenwidth - 2)
        {
-         lmargin = c_pos - (2 * t);
+         lmargin = cpos_buffer_position - (2 * t);
          if (lmargin < 0)
            lmargin = 0;
          /* If the left margin would be in the middle of a prompt with
@@ -1086,7 +1084,7 @@ rl_redisplay ()
        {
          /* If we are moving back towards the beginning of the line and
             the last margin is no longer correct, compute a new one. */
-         lmargin = ((c_pos - 1) / t) * t;      /* XXX */
+         lmargin = ((cpos_buffer_position - 1) / t) * t;       /* XXX */
          if (wrap_offset && lmargin > 0 && lmargin < nleft)
            lmargin = nleft;
        }
@@ -1131,7 +1129,7 @@ rl_redisplay ()
          if (visible_first_line_len > _rl_screenwidth)
            visible_first_line_len = _rl_screenwidth;
 
-         _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+         _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
          last_lmargin = lmargin;
        }
     }
@@ -1724,11 +1722,7 @@ _rl_move_cursor_relative (new, data)
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
     {
       dpos = _rl_col_width (data, 0, new);
-#if 0
-      if (dpos > woff)
-#else
-      if (dpos > prompt_last_invisible)
-#endif
+      if (dpos > prompt_last_invisible)                /* XXX - don't use woff here */
        {
          dpos -= woff;
          /* Since this will be assigned to _rl_last_c_pos at the end (more
@@ -1754,7 +1748,7 @@ _rl_move_cursor_relative (new, data)
   else
 #endif
   i = _rl_last_c_pos - woff;
-  if (new == 0 || CR_FASTER (new, _rl_last_c_pos) ||
+  if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
       (_rl_term_autowrap && i == _rl_screenwidth))
     {
 #if defined (__MSDOS__)
@@ -1776,19 +1770,27 @@ _rl_move_cursor_relative (new, data)
         sequence telling the terminal to move forward one character.
         That kind of control is for people who don't know what the
         data is underneath the cursor. */
-#if defined (HACK_TERMCAP_MOTION)
-      if (_rl_term_forward_char)
-       {
-         for (i = cpos; i < dpos; i++)
-           tputs (_rl_term_forward_char, 1, _rl_output_character_function);
-       }
-      else
-#endif /* HACK_TERMCAP_MOTION */
+
+      /* However, we need a handle on where the current display position is
+        in the buffer for the immediately preceding comment to be true.
+        In multibyte locales, we don't currently have that info available.
+        Without it, we don't know where the data we have to display begins
+        in the buffer and we have to go back to the beginning of the screen
+        line.  In this case, we can use the terminal sequence to move forward
+        if it's available. */
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
        {
-         tputs (_rl_term_cr, 1, _rl_output_character_function);
-         for (i = 0; i < new; i++)
-           putc (data[i], rl_outstream);
+         if (_rl_term_forward_char)
+           {
+             for (i = cpos; i < dpos; i++)
+               tputs (_rl_term_forward_char, 1, _rl_output_character_function);
+           }
+         else
+           {
+             tputs (_rl_term_cr, 1, _rl_output_character_function);
+             for (i = 0; i < new; i++)
+               putc (data[i], rl_outstream);
+           }
        }
       else
        for (i = cpos; i < new; i++)
@@ -2216,7 +2218,8 @@ _rl_update_final ()
       char *last_line;
 
       last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
-      _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);
+      cpos_buffer_position = -1;       /* don't know where we are in buffer */
+      _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);       /* XXX */
       _rl_clear_to_eol (0);
       putc (last_line[_rl_screenwidth - 1], rl_outstream);
     }
index d85fa9f9a62fd090f095c0f7d13ea6d5cb47df85..64aa7bdd3fa4339e72afe3bfc278f39a279f533f 100644 (file)
@@ -408,6 +408,7 @@ extern char *_rl_term_up;
 extern char *_rl_term_dc;
 extern char *_rl_term_cr;
 extern char *_rl_term_IC;
+extern char *_rl_term_forward_char;
 extern int _rl_screenheight;
 extern int _rl_screenwidth;
 extern int _rl_screenchars;
index ce3cfe5ad84338b278e3a0492a5d8cf16aed0f6c..b70ed16fb3a6c54cf9519c846fde53c749764a37 100644 (file)
@@ -125,9 +125,7 @@ char *_rl_term_IC;
 char *_rl_term_dc;
 char *_rl_term_DC;
 
-#if defined (HACK_TERMCAP_MOTION)
 char *_rl_term_forward_char;
-#endif  /* HACK_TERMCAP_MOTION */
 
 /* How to go up a line. */
 char *_rl_term_up;
@@ -391,9 +389,7 @@ static struct _tc_string tc_strings[] =
   { "le", &_rl_term_backspace },
   { "mm", &_rl_term_mm },
   { "mo", &_rl_term_mo },
-#if defined (HACK_TERMCAP_MOTION)
   { "nd", &_rl_term_forward_char },
-#endif
   { "pc", &_rl_term_pc },
   { "up", &_rl_term_up },
   { "vb", &_rl_visible_bell },
@@ -490,9 +486,7 @@ _rl_init_terminal_io (terminal_name)
       _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
       _rl_term_mm = _rl_term_mo = (char *)NULL;
       _rl_term_ve = _rl_term_vs = (char *)NULL;
-#if defined (HACK_TERMCAP_MOTION)
-      term_forward_char = (char *)NULL;
-#endif
+      _rl_term_forward_char = (char *)NULL;
       _rl_terminal_can_insert = term_has_meta = 0;
 
       /* Reasonable defaults for tgoto().  Readline currently only uses
index 780b15ce4eba51090349a68e96e76f2ad8729859..0addcc64e868f8caa96c3c05220a57214b454471 100644 (file)
@@ -27,6 +27,10 @@ Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.  */
 
 #include <fcntl.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #ifdef HAVE_STDLIB_H
 #  include <stdlib.h>
 #else
@@ -35,6 +39,14 @@ extern char *malloc ();
 extern char *realloc ();
 #endif
 
+#if defined (HAVE_STRING_H)
+#include <string.h>
+#endif
+
+#if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS))
+#  define bcopy(s, d, n)       memcpy ((d), (s), (n))
+#endif
+
 #else /* not HAVE_CONFIG_H */
 
 #ifdef STDC_HEADERS
diff --git a/lib/termcap/termcap.c~ b/lib/termcap/termcap.c~
new file mode 100644 (file)
index 0000000..780b15c
--- /dev/null
@@ -0,0 +1,800 @@
+/* Work-alike for termcap, plus extra features.
+   Copyright (C) 1985, 86, 93, 94, 95 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, 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; see the file COPYING.  If not, write to the
+Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.  */
+
+/* Emacs config.h may rename various library functions such as malloc.  */
+#ifdef HAVE_CONFIG_H
+
+#include <config.h>
+
+/* Get the O_* definitions for open et al.  */
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+
+#include <fcntl.h>
+
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#else
+extern char *getenv ();
+extern char *malloc ();
+extern char *realloc ();
+#endif
+
+#else /* not HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+#endif
+
+/* Do this after the include, in case string.h prototypes bcopy.  */
+#if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef _POSIX_VERSION
+#include <fcntl.h>
+#endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#ifndef NULL
+#define NULL (char *) 0
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+/* BUFSIZE is the initial size allocated for the buffer
+   for reading the termcap file.
+   It is not a limit.
+   Make it large normally for speed.
+   Make it variable when debugging, so can exercise
+   increasing the space dynamically.  */
+
+#ifndef BUFSIZE
+#ifdef DEBUG
+#define BUFSIZE bufsize
+
+int bufsize = 128;
+#else
+#define BUFSIZE 2048
+#endif
+#endif
+
+#include "ltcap.h"
+
+#ifndef TERMCAP_FILE
+#define TERMCAP_FILE "/etc/termcap"
+#endif
+
+#ifndef emacs
+static void
+memory_out ()
+{
+  write (2, "virtual memory exhausted\n", 25);
+  exit (1);
+}
+
+static char *
+xmalloc (size)
+     unsigned size;
+{
+  register char *tem = malloc (size);
+
+  if (!tem)
+    memory_out ();
+  return tem;
+}
+
+static char *
+xrealloc (ptr, size)
+     char *ptr;
+     unsigned size;
+{
+  register char *tem = realloc (ptr, size);
+
+  if (!tem)
+    memory_out ();
+  return tem;
+}
+#endif /* not emacs */
+\f
+/* Looking up capabilities in the entry already found.  */
+
+/* The pointer to the data made by tgetent is left here
+   for tgetnum, tgetflag and tgetstr to find.  */
+static char *term_entry;
+
+static char *tgetst1 ();
+
+/* Search entry BP for capability CAP.
+   Return a pointer to the capability (in BP) if found,
+   0 if not found.  */
+
+static char *
+find_capability (bp, cap)
+     register char *bp, *cap;
+{
+  for (; *bp; bp++)
+    if (bp[0] == ':'
+       && bp[1] == cap[0]
+       && bp[2] == cap[1])
+      return &bp[4];
+  return NULL;
+}
+
+__private_extern__
+int
+tgetnum (cap)
+     char *cap;
+{
+  register char *ptr = find_capability (term_entry, cap);
+  if (!ptr || ptr[-1] != '#')
+    return -1;
+  return atoi (ptr);
+}
+
+__private_extern__
+int
+tgetflag (cap)
+     char *cap;
+{
+  register char *ptr = find_capability (term_entry, cap);
+  return ptr && ptr[-1] == ':';
+}
+
+/* Look up a string-valued capability CAP.
+   If AREA is non-null, it points to a pointer to a block in which
+   to store the string.  That pointer is advanced over the space used.
+   If AREA is null, space is allocated with `malloc'.  */
+
+__private_extern__
+char *
+tgetstr (cap, area)
+     char *cap;
+     char **area;
+{
+  register char *ptr = find_capability (term_entry, cap);
+  if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
+    return NULL;
+  return tgetst1 (ptr, area);
+}
+
+/* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
+   gives meaning of character following \, or a space if no special meaning.
+   Eight characters per line within the string.  */
+
+static char esctab[]
+  = " \007\010  \033\014 \
+      \012 \
+  \015 \011 \013 \
+        ";
+
+/* PTR points to a string value inside a termcap entry.
+   Copy that value, processing \ and ^ abbreviations,
+   into the block that *AREA points to,
+   or to newly allocated storage if AREA is NULL.
+   Return the address to which we copied the value,
+   or NULL if PTR is NULL.  */
+
+static char *
+tgetst1 (ptr, area)
+     char *ptr;
+     char **area;
+{
+  register char *p, *r;
+  register int c;
+  register int size;
+  char *ret;
+  register int c1;
+
+  if (!ptr)
+    return NULL;
+
+  /* `ret' gets address of where to store the string.  */
+  if (!area)
+    {
+      /* Compute size of block needed (may overestimate).  */
+      p = ptr;
+      while ((c = *p++) && c != ':' && c != '\n')
+       ;
+      ret = (char *) xmalloc (p - ptr + 1);
+    }
+  else
+    ret = *area;
+
+  /* Copy the string value, stopping at null or colon.
+     Also process ^ and \ abbreviations.  */
+  p = ptr;
+  r = ret;
+  while ((c = *p++) && c != ':' && c != '\n')
+    {
+      if (c == '^')
+       {
+         c = *p++;
+         if (c == '?')
+           c = 0177;
+         else
+           c &= 037;
+       }
+      else if (c == '\\')
+       {
+         c = *p++;
+         if (c >= '0' && c <= '7')
+           {
+             c -= '0';
+             size = 0;
+
+             while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
+               {
+                 c *= 8;
+                 c += c1 - '0';
+                 p++;
+               }
+           }
+         else if (c >= 0100 && c < 0200)
+           {
+             c1 = esctab[(c & ~040) - 0100];
+             if (c1 != ' ')
+               c = c1;
+           }
+       }
+      *r++ = c;
+    }
+  *r = '\0';
+  /* Update *AREA.  */
+  if (area)
+    *area = r + 1;
+  return ret;
+}
+\f
+/* Outputting a string with padding.  */
+
+short ospeed;
+/* If OSPEED is 0, we use this as the actual baud rate.  */
+int tputs_baud_rate;
+__private_extern__ char PC = '\0';
+
+/* Actual baud rate if positive;
+   - baud rate / 100 if negative.  */
+
+static int speeds[] =
+  {
+#ifdef VMS
+    0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
+    -20, -24, -36, -48, -72, -96, -192
+#else /* not VMS */
+    0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
+    -18, -24, -48, -96, -192, -288, -384, -576, -1152
+#endif /* not VMS */
+  };
+
+__private_extern__
+void
+tputs (str, nlines, outfun)
+     register char *str;
+     int nlines;
+     register int (*outfun) ();
+{
+  register int padcount = 0;
+  register int speed;
+
+#ifdef emacs
+  extern baud_rate;
+  speed = baud_rate;
+  /* For quite high speeds, convert to the smaller
+     units to avoid overflow.  */
+  if (speed > 10000)
+    speed = - speed / 100;
+#else
+  if (ospeed == 0)
+    speed = tputs_baud_rate;
+  else if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0]))
+    speed = speeds[ospeed];
+  else
+    speed = 0;
+#endif
+
+  if (!str)
+    return;
+
+  while (*str >= '0' && *str <= '9')
+    {
+      padcount += *str++ - '0';
+      padcount *= 10;
+    }
+  if (*str == '.')
+    {
+      str++;
+      padcount += *str++ - '0';
+    }
+  if (*str == '*')
+    {
+      str++;
+      padcount *= nlines;
+    }
+  while (*str)
+    (*outfun) (*str++);
+
+  /* PADCOUNT is now in units of tenths of msec.
+     SPEED is measured in characters per 10 seconds
+     or in characters per .1 seconds (if negative).
+     We use the smaller units for larger speeds to avoid overflow.  */
+  padcount *= speed;
+  padcount += 500;
+  padcount /= 1000;
+  if (speed < 0)
+    padcount = -padcount;
+  else
+    {
+      padcount += 50;
+      padcount /= 100;
+    }
+
+  while (padcount-- > 0)
+    (*outfun) (PC);
+}
+\f
+/* Finding the termcap entry in the termcap data base.  */
+
+struct buffer
+  {
+    char *beg;
+    int size;
+    char *ptr;
+    int ateof;
+    int full;
+  };
+
+/* Forward declarations of static functions.  */
+
+static int scan_file ();
+static char *gobble_line ();
+static int compare_contin ();
+static int name_match ();
+
+#ifdef VMS
+
+#include <rmsdef.h>
+#include <fab.h>
+#include <nam.h>
+
+static int
+valid_filename_p (fn)
+     char *fn;
+{
+  struct FAB fab = cc$rms_fab;
+  struct NAM nam = cc$rms_nam;
+  char esa[NAM$C_MAXRSS];
+
+  fab.fab$l_fna = fn;
+  fab.fab$b_fns = strlen(fn);
+  fab.fab$l_nam = &nam;
+  fab.fab$l_fop = FAB$M_NAM;
+
+  nam.nam$l_esa = esa;
+  nam.nam$b_ess = sizeof esa;
+
+  return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
+}
+
+#else /* !VMS */
+
+#ifdef MSDOS /* MW, May 1993 */
+static int
+valid_filename_p (fn)
+     char *fn;
+{
+  return *fn == '\\' || *fn == '/' ||
+    (*fn >= 'A' && *fn <= 'z' && fn[1] == ':');
+}
+#else
+#define valid_filename_p(fn) (*(fn) == '/')
+#endif
+
+#endif /* !VMS */
+
+/* Find the termcap entry data for terminal type NAME
+   and store it in the block that BP points to.
+   Record its address for future use.
+
+   If BP is null, space is dynamically allocated.
+
+   Return -1 if there is some difficulty accessing the data base
+   of terminal types,
+   0 if the data base is accessible but the type NAME is not defined
+   in it, and some other value otherwise.  */
+
+__private_extern__
+int
+tgetent (bp, name)
+     char *bp, *name;
+{
+  register char *termcap_name;
+  register int fd;
+  struct buffer buf;
+  register char *bp1;
+  char *bp2;
+  char *term;
+  int malloc_size = 0;
+  register int c;
+  char *tcenv;                 /* TERMCAP value, if it contains :tc=.  */
+  char *indirect = NULL;       /* Terminal type in :tc= in TERMCAP value.  */
+  int filep;
+
+#ifdef INTERNAL_TERMINAL
+  /* For the internal terminal we don't want to read any termcap file,
+     so fake it.  */
+  if (!strcmp (name, "internal"))
+    {
+      term = INTERNAL_TERMINAL;
+      if (!bp)
+       {
+         malloc_size = 1 + strlen (term);
+         bp = (char *) xmalloc (malloc_size);
+       }
+      strcpy (bp, term);
+      goto ret;
+    }
+#endif /* INTERNAL_TERMINAL */
+
+  /* For compatibility with programs like `less' that want to
+     put data in the termcap buffer themselves as a fallback.  */
+  if (bp)
+    term_entry = bp;
+
+  termcap_name = getenv ("TERMCAP");
+  if (termcap_name && *termcap_name == '\0')
+    termcap_name = NULL;
+#if 0
+#if defined (MSDOS) && !defined (TEST)
+  if (termcap_name && (*termcap_name == '\\'
+                      || *termcap_name == '/'
+                      || termcap_name[1] == ':'))
+    dostounix_filename(termcap_name);
+#endif
+#endif
+
+  filep = termcap_name && valid_filename_p (termcap_name);
+
+  /* If termcap_name is non-null and starts with / (in the un*x case, that is),
+     it is a file name to use instead of /etc/termcap.
+     If it is non-null and does not start with /,
+     it is the entry itself, but only if
+     the name the caller requested matches the TERM variable.  */
+
+  if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
+    {
+      indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
+      if (!indirect)
+       {
+         if (!bp)
+           bp = termcap_name;
+         else
+           strcpy (bp, termcap_name);
+         goto ret;
+       }
+      else
+       {                       /* It has tc=.  Need to read /etc/termcap.  */
+         tcenv = termcap_name;
+         termcap_name = NULL;
+       }
+    }
+
+  if (!termcap_name || !filep)
+    termcap_name = TERMCAP_FILE;
+
+  /* Here we know we must search a file and termcap_name has its name.  */
+
+#ifdef MSDOS
+  fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
+#else
+  fd = open (termcap_name, O_RDONLY, 0);
+#endif
+  if (fd < 0)
+    return -1;
+
+  buf.size = BUFSIZE;
+  /* Add 1 to size to ensure room for terminating null.  */
+  buf.beg = (char *) xmalloc (buf.size + 1);
+  term = indirect ? indirect : name;
+
+  if (!bp)
+    {
+      malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
+      bp = (char *) xmalloc (malloc_size);
+    }
+  bp1 = bp;
+
+  if (indirect)
+    /* Copy the data from the environment variable.  */
+    {
+      strcpy (bp, tcenv);
+      bp1 += strlen (tcenv);
+    }
+
+  while (term)
+    {
+      /* Scan the file, reading it via buf, till find start of main entry.  */
+      if (scan_file (term, fd, &buf) == 0)
+       {
+         close (fd);
+         free (buf.beg);
+         if (malloc_size)
+           free (bp);
+         return 0;
+       }
+
+      /* Free old `term' if appropriate.  */
+      if (term != name)
+       free (term);
+
+      /* If BP is malloc'd by us, make sure it is big enough.  */
+      if (malloc_size)
+       {
+         malloc_size = bp1 - bp + buf.size;
+         termcap_name = (char *) xrealloc (bp, malloc_size);
+         bp1 += termcap_name - bp;
+         bp = termcap_name;
+       }
+
+      bp2 = bp1;
+
+      /* Copy the line of the entry from buf into bp.  */
+      termcap_name = buf.ptr;
+      while ((*bp1++ = c = *termcap_name++) && c != '\n')
+       /* Drop out any \ newline sequence.  */
+       if (c == '\\' && *termcap_name == '\n')
+         {
+           bp1--;
+           termcap_name++;
+         }
+      *bp1 = '\0';
+
+      /* Does this entry refer to another terminal type's entry?
+        If something is found, copy it into heap and null-terminate it.  */
+      term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
+    }
+
+  close (fd);
+  free (buf.beg);
+
+  if (malloc_size)
+    bp = (char *) xrealloc (bp, bp1 - bp + 1);
+
+ ret:
+  term_entry = bp;
+  return 1;
+}
+
+/* Given file open on FD and buffer BUFP,
+   scan the file from the beginning until a line is found
+   that starts the entry for terminal type STR.
+   Return 1 if successful, with that line in BUFP,
+   or 0 if no entry is found in the file.  */
+
+static int
+scan_file (str, fd, bufp)
+     char *str;
+     int fd;
+     register struct buffer *bufp;
+{
+  register char *end;
+
+  bufp->ptr = bufp->beg;
+  bufp->full = 0;
+  bufp->ateof = 0;
+  *bufp->ptr = '\0';
+
+  lseek (fd, 0L, 0);
+
+  while (!bufp->ateof)
+    {
+      /* Read a line into the buffer.  */
+      end = NULL;
+      do
+       {
+         /* if it is continued, append another line to it,
+            until a non-continued line ends.  */
+         end = gobble_line (fd, bufp, end);
+       }
+      while (!bufp->ateof && end[-2] == '\\');
+
+      if (*bufp->ptr != '#'
+         && name_match (bufp->ptr, str))
+       return 1;
+
+      /* Discard the line just processed.  */
+      bufp->ptr = end;
+    }
+  return 0;
+}
+
+/* Return nonzero if NAME is one of the names specified
+   by termcap entry LINE.  */
+
+static int
+name_match (line, name)
+     char *line, *name;
+{
+  register char *tem;
+
+  if (!compare_contin (line, name))
+    return 1;
+  /* This line starts an entry.  Is it the right one?  */
+  for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
+    if (*tem == '|' && !compare_contin (tem + 1, name))
+      return 1;
+
+  return 0;
+}
+
+static int
+compare_contin (str1, str2)
+     register char *str1, *str2;
+{
+  register int c1, c2;
+  while (1)
+    {
+      c1 = *str1++;
+      c2 = *str2++;
+      while (c1 == '\\' && *str1 == '\n')
+       {
+         str1++;
+         while ((c1 = *str1++) == ' ' || c1 == '\t');
+       }
+      if (c2 == '\0')
+       {
+         /* End of type being looked up.  */
+         if (c1 == '|' || c1 == ':')
+           /* If end of name in data base, we win.  */
+           return 0;
+         else
+           return 1;
+        }
+      else if (c1 != c2)
+       return 1;
+    }
+}
+
+/* Make sure that the buffer <- BUFP contains a full line
+   of the file open on FD, starting at the place BUFP->ptr
+   points to.  Can read more of the file, discard stuff before
+   BUFP->ptr, or make the buffer bigger.
+
+   Return the pointer to after the newline ending the line,
+   or to the end of the file, if there is no newline to end it.
+
+   Can also merge on continuation lines.  If APPEND_END is
+   non-null, it points past the newline of a line that is
+   continued; we add another line onto it and regard the whole
+   thing as one line.  The caller decides when a line is continued.  */
+
+static char *
+gobble_line (fd, bufp, append_end)
+     int fd;
+     register struct buffer *bufp;
+     char *append_end;
+{
+  register char *end;
+  register int nread;
+  register char *buf = bufp->beg;
+  register char *tem;
+
+  if (!append_end)
+    append_end = bufp->ptr;
+
+  while (1)
+    {
+      end = append_end;
+      while (*end && *end != '\n') end++;
+      if (*end)
+        break;
+      if (bufp->ateof)
+       return buf + bufp->full;
+      if (bufp->ptr == buf)
+       {
+         if (bufp->full == bufp->size)
+           {
+             bufp->size *= 2;
+             /* Add 1 to size to ensure room for terminating null.  */
+             tem = (char *) xrealloc (buf, bufp->size + 1);
+             bufp->ptr = (bufp->ptr - buf) + tem;
+             append_end = (append_end - buf) + tem;
+             bufp->beg = buf = tem;
+           }
+       }
+      else
+       {
+         append_end -= bufp->ptr - buf;
+         bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
+         bufp->ptr = buf;
+       }
+      if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
+       bufp->ateof = 1;
+      bufp->full += nread;
+      buf[bufp->full] = '\0';
+    }
+  return end + 1;
+}
+\f
+#ifdef TEST
+
+#ifdef NULL
+#undef NULL
+#endif
+
+#include <stdio.h>
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *term;
+  char *buf;
+
+  term = argv[1];
+  printf ("TERM: %s\n", term);
+
+  buf = (char *) tgetent (0, term);
+  if ((int) buf <= 0)
+    {
+      printf ("No entry.\n");
+      return 0;
+    }
+
+  printf ("Entry: %s\n", buf);
+
+  tprint ("cm");
+  tprint ("AL");
+
+  printf ("co: %d\n", tgetnum ("co"));
+  printf ("am: %d\n", tgetflag ("am"));
+}
+
+tprint (cap)
+     char *cap;
+{
+  char *x = tgetstr (cap, 0);
+  register char *y;
+
+  printf ("%s: ", cap);
+  if (x)
+    {
+      for (y = x; *y; y++)
+       if (*y <= ' ' || *y == 0177)
+         printf ("\\%0o", *y);
+       else
+         putchar (*y);
+      free (x);
+    }
+  else
+    printf ("none");
+  putchar ('\n');
+}
+
+#endif /* TEST */
index 1c83f0450aef8b31da89fb903d79e77a27696f02..644042d29b2fcd87e3fae7678bb8ff60abe64d51 100644 (file)
@@ -27,6 +27,14 @@ extern char *malloc ();
 extern char *realloc ();
 #endif
 
+#if defined (HAVE_STRING_H)
+#include <string.h>
+#endif
+
+#if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS))
+#  define bcopy(s, d, n)       memcpy ((d), (s), (n))
+#endif
+
 #else /* not HAVE_CONFIG_H */
 
 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
diff --git a/lib/termcap/tparam.c~ b/lib/termcap/tparam.c~
new file mode 100644 (file)
index 0000000..1c83f04
--- /dev/null
@@ -0,0 +1,334 @@
+/* Merge parameters into a termcap entry string.
+   Copyright (C) 1985, 87, 93, 95 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, 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; see the file COPYING.  If not, write to the
+Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.  */
+
+/* Emacs config.h may rename various library functions such as malloc.  */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+
+#ifdef HAVE_STDLIB_H 
+#  include <stdlib.h>
+#else
+extern char *getenv ();
+extern char *malloc ();
+extern char *realloc ();
+#endif
+
+#else /* not HAVE_CONFIG_H */
+
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#include "ltcap.h"
+
+#ifndef NULL
+#define NULL (char *) 0
+#endif
+\f
+#ifndef emacs
+static void
+memory_out ()
+{
+  write (2, "virtual memory exhausted\n", 25);
+  exit (1);
+}
+
+static char *
+xmalloc (size)
+     unsigned size;
+{
+  register char *tem = malloc (size);
+
+  if (!tem)
+    memory_out ();
+  return tem;
+}
+
+static char *
+xrealloc (ptr, size)
+     char *ptr;
+     unsigned size;
+{
+  register char *tem = realloc (ptr, size);
+
+  if (!tem)
+    memory_out ();
+  return tem;
+}
+#endif /* not emacs */
+\f
+/* Assuming STRING is the value of a termcap string entry
+   containing `%' constructs to expand parameters,
+   merge in parameter values and store result in block OUTSTRING points to.
+   LEN is the length of OUTSTRING.  If more space is needed,
+   a block is allocated with `malloc'.
+
+   The value returned is the address of the resulting string.
+   This may be OUTSTRING or may be the address of a block got with `malloc'.
+   In the latter case, the caller must free the block.
+
+   The fourth and following args to tparam serve as the parameter values.  */
+
+static char *tparam1 ();
+
+/* VARARGS 2 */
+char *
+tparam (string, outstring, len, arg0, arg1, arg2, arg3)
+     char *string;
+     char *outstring;
+     int len;
+     int arg0, arg1, arg2, arg3;
+{
+  int arg[4];
+
+  arg[0] = arg0;
+  arg[1] = arg1;
+  arg[2] = arg2;
+  arg[3] = arg3;
+  return tparam1 (string, outstring, len, NULL, NULL, arg);
+}
+
+__private_extern__ char *BC;
+__private_extern__ char *UP;
+
+static char tgoto_buf[50];
+
+__private_extern__
+char *
+tgoto (cm, hpos, vpos)
+     char *cm;
+     int hpos, vpos;
+{
+  int args[2];
+  if (!cm)
+    return NULL;
+  args[0] = vpos;
+  args[1] = hpos;
+  return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
+}
+
+static char *
+tparam1 (string, outstring, len, up, left, argp)
+     char *string;
+     char *outstring;
+     int len;
+     char *up, *left;
+     register int *argp;
+{
+  register int c;
+  register char *p = string;
+  register char *op = outstring;
+  char *outend;
+  int outlen = 0;
+
+  register int tem;
+  int *old_argp = argp;
+  int doleft = 0;
+  int doup = 0;
+
+  outend = outstring + len;
+
+  while (1)
+    {
+      /* If the buffer might be too short, make it bigger.  */
+      if (op + 5 >= outend)
+       {
+         register char *new;
+         if (outlen == 0)
+           {
+             outlen = len + 40;
+             new = (char *) xmalloc (outlen);
+             outend += 40;
+             bcopy (outstring, new, op - outstring);
+           }
+         else
+           {
+             outend += outlen;
+             outlen *= 2;
+             new = (char *) xrealloc (outstring, outlen);
+           }
+         op += new - outstring;
+         outend += new - outstring;
+         outstring = new;
+       }
+      c = *p++;
+      if (!c)
+       break;
+      if (c == '%')
+       {
+         c = *p++;
+         tem = *argp;
+         switch (c)
+           {
+           case 'd':           /* %d means output in decimal.  */
+             if (tem < 10)
+               goto onedigit;
+             if (tem < 100)
+               goto twodigit;
+           case '3':           /* %3 means output in decimal, 3 digits.  */
+             if (tem > 999)
+               {
+                 *op++ = tem / 1000 + '0';
+                 tem %= 1000;
+               }
+             *op++ = tem / 100 + '0';
+           case '2':           /* %2 means output in decimal, 2 digits.  */
+           twodigit:
+             tem %= 100;
+             *op++ = tem / 10 + '0';
+           onedigit:
+             *op++ = tem % 10 + '0';
+             argp++;
+             break;
+
+           case 'C':
+             /* For c-100: print quotient of value by 96, if nonzero,
+                then do like %+.  */
+             if (tem >= 96)
+               {
+                 *op++ = tem / 96;
+                 tem %= 96;
+               }
+           case '+':           /* %+x means add character code of char x.  */
+             tem += *p++;
+           case '.':           /* %. means output as character.  */
+             if (left)
+               {
+                 /* If want to forbid output of 0 and \n and \t,
+                    and this is one of them, increment it.  */
+                 while (tem == 0 || tem == '\n' || tem == '\t')
+                   {
+                     tem++;
+                     if (argp == old_argp)
+                       doup++, outend -= strlen (up);
+                     else
+                       doleft++, outend -= strlen (left);
+                   }
+               }
+             *op++ = tem ? tem : 0200;
+           case 'f':           /* %f means discard next arg.  */
+             argp++;
+             break;
+
+           case 'b':           /* %b means back up one arg (and re-use it).  */
+             argp--;
+             break;
+
+           case 'r':           /* %r means interchange following two args.  */
+             argp[0] = argp[1];
+             argp[1] = tem;
+             old_argp++;
+             break;
+
+           case '>':           /* %>xy means if arg is > char code of x, */
+             if (argp[0] > *p++) /* then add char code of y to the arg, */
+               argp[0] += *p;  /* and in any case don't output.  */
+             p++;              /* Leave the arg to be output later.  */
+             break;
+
+           case 'a':           /* %a means arithmetic.  */
+             /* Next character says what operation.
+                Add or subtract either a constant or some other arg.  */
+             /* First following character is + to add or - to subtract
+                or = to assign.  */
+             /* Next following char is 'p' and an arg spec
+                (0100 plus position of that arg relative to this one)
+                or 'c' and a constant stored in a character.  */
+             tem = p[2] & 0177;
+             if (p[1] == 'p')
+               tem = argp[tem - 0100];
+             if (p[0] == '-')
+               argp[0] -= tem;
+             else if (p[0] == '+')
+               argp[0] += tem;
+             else if (p[0] == '*')
+               argp[0] *= tem;
+             else if (p[0] == '/')
+               argp[0] /= tem;
+             else
+               argp[0] = tem;
+
+             p += 3;
+             break;
+
+           case 'i':           /* %i means add one to arg, */
+             argp[0] ++;       /* and leave it to be output later.  */
+             argp[1] ++;       /* Increment the following arg, too!  */
+             break;
+
+           case '%':           /* %% means output %; no arg.  */
+             goto ordinary;
+
+           case 'n':           /* %n means xor each of next two args with 140.  */
+             argp[0] ^= 0140;
+             argp[1] ^= 0140;
+             break;
+
+           case 'm':           /* %m means xor each of next two args with 177.  */
+             argp[0] ^= 0177;
+             argp[1] ^= 0177;
+             break;
+
+           case 'B':           /* %B means express arg as BCD char code.  */
+             argp[0] += 6 * (tem / 10);
+             break;
+
+           case 'D':           /* %D means weird Delta Data transformation.  */
+             argp[0] -= 2 * (tem % 16);
+             break;
+           }
+       }
+      else
+       /* Ordinary character in the argument string.  */
+      ordinary:
+       *op++ = c;
+    }
+  *op = 0;
+  while (doup-- > 0)
+    strcat (op, up);
+  while (doleft-- > 0)
+    strcat (op, left);
+  return outstring;
+}
+\f
+#ifdef DEBUG
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char buf[50];
+  int args[3];
+  args[0] = atoi (argv[2]);
+  args[1] = atoi (argv[3]);
+  args[2] = atoi (argv[4]);
+  tparam1 (argv[1], buf, "LEFT", "UP", args);
+  printf ("%s\n", buf);
+  return 0;
+}
+
+#endif /* DEBUG */