home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
util
/
vim-3.0.lha
/
Vim
/
src
/
getchar.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-09
|
34KB
|
1,476 lines
/* vi:ts=4:sw=4
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Read the file "credits.txt" for a list of people who contributed.
* Read the file "uganda.txt" for copying and usage conditions.
*/
/*
* getchar.c
*
* functions related with getting a character from the user/mapping/redo/...
*
* manipulations with redo buffer and stuff buffer
* mappings and abbreviations
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
/*
* structure used to store one block of the stuff/redo/macro buffers
*/
struct bufblock
{
struct bufblock *b_next; /* pointer to next bufblock */
char_u b_str[1]; /* contents (actually longer) */
};
#define MINIMAL_SIZE 20 /* minimal size for b_str */
/*
* header used for the stuff buffer and the redo buffer
*/
struct buffheader
{
struct bufblock bh_first; /* first (dummy) block of list */
struct bufblock *bh_curr; /* bufblock for appending */
int bh_index; /* index for reading */
int bh_space; /* space in bh_curr for appending */
};
static struct buffheader stuffbuff = {{NULL, {NUL}}, NULL, 0, 0};
static struct buffheader redobuff = {{NULL, {NUL}}, NULL, 0, 0};
static struct buffheader recordbuff = {{NULL, {NUL}}, NULL, 0, 0};
/*
* when block_redo is TRUE redo buffer will not be changed
* used by edit() to repeat insertions and 'V' command for redoing
*/
static int block_redo = FALSE;
/*
* structure used for mapping
*/
struct mapblock
{
struct mapblock *m_next; /* next mapblock */
char_u *m_keys; /* mapped from */
int m_keylen; /* strlen(m_keys) */
char_u *m_str; /* mapped to */
int m_mode; /* valid mode */
int m_noremap; /* if non-zero no re-mapping for m_str */
};
static struct mapblock maplist = {NULL, NULL, 0, NULL, 0, 0};
/* first dummy entry in maplist */
/*
* variables used by vgetorpeek() and flush_buffers()
*
* typestr contains all characters that are not consumed yet.
* The part in front may contain the result of mappings, abbreviations and
* @a commands. The lenght of this part is typemaplen.
* After it are characters that come from the terminal.
* no_abbr_cnt is the number of characters in typestr that should not be
* considered for abbreviations.
* Some parts of typestr may not be mapped. These parts are remembered in
* the noremaplist.
*/
#define MAXMAPLEN 50 /* maximum length of key sequence to be mapped */
/* must be able to hold an Amiga resize report */
static char_u *typestr = NULL; /* NUL-terminated buffer for typeahead characters */
static char_u typebuf[MAXMAPLEN + 3]; /* initial typestr */
static int typemaplen = 0; /* number of mapped characters in typestr */
static int no_abbr_cnt = 0; /* number of chars without abbrev. in typestr */
/*
* parts int typestr that should not be mapped are remembered with a list
* of noremap structs. Noremaplist is the first.
*/
struct noremap
{
int nr_off; /* offset to not remappable chars */
int nr_len; /* number of not remappable chars */
struct noremap *nr_next; /* next entry in the list */
};
static struct noremap noremaplist = {0, 0, NULL};
static void free_buff __ARGS((struct buffheader *));
static char_u *get_bufcont __ARGS((struct buffheader *, int));
static void add_buff __ARGS((struct buffheader *, char_u *));
static void add_num_buff __ARGS((struct buffheader *, long));
static void add_char_buff __ARGS((struct buffheader *, int));
static int read_stuff __ARGS((int));
static void start_stuff __ARGS((void));
static int read_redo __ARGS((int));
static void init_typestr __ARGS((void));
static void gotchars __ARGS((char_u *, int));
static int vgetorpeek __ARGS((int));
static void showmap __ARGS((struct mapblock *));
/*
* free and clear a buffer
*/
static void
free_buff(buf)
struct buffheader *buf;
{
register struct bufblock *p, *np;
for (p = buf->bh_first.b_next; p != NULL; p = np)
{
np = p->b_next;
free(p);
}
buf->bh_first.b_next = NULL;
}
/*
* return the contents of a buffer as a single string
*/
static char_u *
get_bufcont(buffer, dozero)
struct buffheader *buffer;
int dozero; /* count == zero is not an error */
{
long_u count = 0;
char_u *p = NULL;
struct bufblock *bp;
/* compute the total length of the string */
for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
count += STRLEN(bp->b_str);
if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL)
{
*p = NUL;
for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
strcat((char *)p, (char *)bp->b_str);
}
return (p);
}
/*
* return the contents of the record buffer as a single string
* and clear the record buffer
*/
char_u *
get_recorded()
{
char_u *p;
p = get_bufcont(&recordbuff, TRUE);
free_buff(&recordbuff);
return (p);
}
/*
* return the contents of the redo buffer as a single string
*/
char_u *
get_inserted()
{
return(get_bufcont(&redobuff, FALSE));
}
/*
* add string "s" after the current block of buffer "buf"
*/
static void
add_buff(buf, s)
register struct buffheader *buf;
char_u *s;
{
struct bufblock *p;
long_u n;
long_u len;
if ((n = STRLEN(s)) == 0) /* don't add empty strings */
return;
if (buf->bh_first.b_next == NULL) /* first add to list */
{
buf->bh_space = 0;
buf->bh_curr = &(buf->bh_first);
}
else if (buf->bh_curr == NULL) /* buffer has already been read */
{
EMSG("Add to read buffer");
return;
}
else if (buf->bh_index != 0)
STRCPY(buf->bh_first.b_next->b_str, buf->bh_first.b_next->b_str + buf->bh_index);
buf->bh_index = 0;
if (buf->bh_space >= n)
{
strcat((char *)buf->bh_curr->b_str, (char *)s);
buf->bh_space -= n;
}
else
{
if (n < MINIMAL_SIZE)
len = MINIMAL_SIZE;
else
len = n;
p = (struct bufblock *)lalloc((long_u)(sizeof(struct bufblock) + len), TRUE);
if (p == NULL)
return; /* no space, just forget it */
buf->bh_space = len - n;
STRCPY(p->b_str, s);
p->b_next = buf->bh_curr->b_next;
buf->bh_curr->b_next = p;
buf->bh_curr = p;
}
return;
}
static void
add_num_buff(buf, n)
struct buffheader *buf;
long n;
{
char_u number[32];
sprintf((char *)number, "%ld", n);
add_buff(buf, number);
}
static void
add_char_buff(buf, c)
struct buffheader *buf;
int c;
{
char_u temp[2];
temp[0] = c;
temp[1] = NUL;
add_buff(buf, temp);
}
/*
* get one character from the stuff buffer
* If advance == TRUE go to the next char.
*/
static int
read_stuff(advance)
int advance;
{
register char_u c;
register struct bufblock *curr;
if (stuffbuff.bh_first.b_next == NULL) /* buffer is empty */
return NUL;
curr = stuffbuff.bh_first.b_next;
c = curr->b_str[stuffbuff.bh_index];
if (advance)
{
if (curr->b_str[++stuffbuff.bh_index] == NUL)
{
stuffbuff.bh_first.b_next = curr->b_next;
free(curr);
stuffbuff.bh_index = 0;
}
}
return c;
}
/*
* prepare stuff buffer for reading (if it contains something)
*/
static void
start_stuff()
{
if (stuffbuff.bh_first.b_next != NULL)
{
stuffbuff.bh_curr = &(stuffbuff.bh_first);
stuffbuff.bh_space = 0;
}
}
/*
* check if the stuff buffer is empty
*/
int
stuff_empty()
{
return (stuffbuff.bh_first.b_next == NULL);
}
/*
* Remove the contents of the stuff buffer and the mapped characters in the
* typeahead buffer (used in case of an error). If 'typeahead' is true,
* flush all typeahead characters (used when interrupted by a CTRL-C).
*/
void
flush_buffers(typeahead)
int typeahead;
{
struct noremap *p;
init_typestr();
start_stuff();
while (read_stuff(TRUE) != NUL)
;
if (typeahead) /* remove all typeahead */
{
/*
* We have to get all characters, because we may delete the first
* part of an escape sequence.
* In an xterm we get one char at a time and we have to get them all.
*/
while (inchar(typestr, MAXMAPLEN, 10))
;
*typestr = NUL;
}
else /* remove mapped characters only */
STRCPY(typestr, typestr + typemaplen);
typemaplen = 0;
no_abbr_cnt = 0;
noremaplist.nr_len = 0;
noremaplist.nr_off = 0;
while (noremaplist.nr_next)
{
p = noremaplist.nr_next->nr_next;
free(noremaplis