commit bash-20060720 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 22:50:46 -05:00
parent e7f1978acf
commit 9697d2dc75
13 changed files with 1757 additions and 48 deletions
+33 -2
View 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
+33 -1
View 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
+1
View File
@@ -28,6 +28,7 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <string.h>
#include "mstats.h"
+202
View File
@@ -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 */
+1
View File
@@ -22,6 +22,7 @@
#endif
#include <stdio.h>
#include <string.h>
#include "imalloc.h"
#include "table.h"
+290
View File
@@ -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;
}
+41 -38
View 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.
@@ -59,10 +59,6 @@
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);
}
+1
View 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;
+1 -7
View 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
+12
View 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
+800
View File
@@ -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 */
/* 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;
}
/* 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);
}
/* 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;
}
#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 */
+8
View 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)
+334
View File
@@ -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
#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 */
/* 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;
}
#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 */