This is misc2.c in view mode; [Download] [Up]
/* vi:set ts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* misc2.c: Various functions.
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
/*
* coladvance(col)
*
* Try to advance the Cursor to the specified column.
*
* return OK if desired column is reached, FAIL if not
*/
int
coladvance(wcol)
colnr_t wcol;
{
int idx;
char_u *ptr;
colnr_t col;
ptr = ml_get_curline();
/* try to advance to the specified column */
idx = -1;
col = 0;
while (col <= wcol && *ptr)
{
++idx;
/* Count a tab for what it's worth (if list mode not on) */
col += lbr_chartabsize(ptr, col);
++ptr;
}
/*
* in insert mode it is allowed to be one char beyond the end of the line
*/
if ((State & INSERT) && col <= wcol)
++idx;
if (idx < 0)
curwin->w_cursor.col = 0;
else
curwin->w_cursor.col = idx;
if (col <= wcol)
return FAIL; /* Couldn't reach column */
else
return OK; /* Reached column */
}
/*
* inc(p)
*
* Increment the line pointer 'p' crossing line boundaries as necessary.
* Return 1 when crossing a line, -1 when at end of file, 0 otherwise.
*/
int
inc_cursor()
{
return inc(&curwin->w_cursor);
}
int
inc(lp)
FPOS *lp;
{
char_u *p = ml_get_pos(lp);
if (*p != NUL) /* still within line, move to next char (may be NUL) */
{
lp->col++;
return ((p[1] != NUL) ? 0 : 1);
}
if (lp->lnum != curbuf->b_ml.ml_line_count) /* there is a next line */
{
lp->col = 0;
lp->lnum++;
return 1;
}
return -1;
}
/*
* incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
*/
int
incl(lp)
FPOS *lp;
{
int r;
if ((r = inc(lp)) == 1 && lp->col)
r = inc(lp);
return r;
}
/*
* dec(p)
*
* Decrement the line pointer 'p' crossing line boundaries as necessary.
* Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
*/
int
dec_cursor()
{
return dec(&curwin->w_cursor);
}
int
dec(lp)
FPOS *lp;
{
if (lp->col > 0)
{ /* still within line */
lp->col--;
return 0;
}
if (lp->lnum > 1)
{ /* there is a prior line */
lp->lnum--;
lp->col = STRLEN(ml_get(lp->lnum));
return 1;
}
return -1; /* at start of file */
}
/*
* decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
*/
int
decl(lp)
FPOS *lp;
{
int r;
if ((r = dec(lp)) == 1 && lp->col)
r = dec(lp);
return r;
}
/*
* Make sure curwin->w_cursor.lnum is valid.
*/
void
check_cursor_lnum()
{
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
if (curwin->w_cursor.lnum <= 0)
curwin->w_cursor.lnum = 1;
}
/*
* make sure curwin->w_cursor in on a valid character
*/
void
adjust_cursor()
{
colnr_t len;
check_cursor_lnum();
len = STRLEN(ml_get_curline());
if (len == 0)
curwin->w_cursor.col = 0;
else if (curwin->w_cursor.col >= len)
curwin->w_cursor.col = len - 1;
}
/*
* When curwin->w_leftcol has changed, adjust the cursor position.
* Return TRUE if the cursor was moved.
*/
int
leftcol_changed()
{
long lastcol;
colnr_t s, e;
int retval = FALSE;
changed_cline_bef_curs();
lastcol = curwin->w_leftcol + Columns - (curwin->w_p_nu ? 8 : 0) - 1;
validate_virtcol();
/*
* If the cursor is right or left of the screen, move it to last or first
* character.
*/
if (curwin->w_virtcol > (colnr_t)lastcol)
{
retval = TRUE;
coladvance((colnr_t)lastcol);
}
else if (curwin->w_virtcol < curwin->w_leftcol)
{
retval = TRUE;
(void)coladvance(curwin->w_leftcol);
}
/*
* If the start of the character under the cursor is not on the screen,
* advance the cursor one more char. If this fails (last char of the
* line) adjust the scrolling.
*/
getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
if (e > (colnr_t)lastcol)
{
retval = TRUE;
coladvance(s - 1);
}
else if (s < curwin->w_leftcol)
{
retval = TRUE;
if (coladvance(e + 1) == FAIL) /* there isn't another character */
{
curwin->w_leftcol = s; /* adjust w_leftcol instead */
changed_cline_bef_curs();
}
}
redraw_later(NOT_VALID);
return retval;
}
/**********************************************************************
* Various routines dealing with allocation and deallocation of memory.
*/
/*
* Some memory is reserved for error messages and for being able to
* call mf_release_all(), which needs some memory for mf_trans_add().
*/
#define KEEP_ROOM 8192L
/*
* Note: if unsinged is 16 bits we can only allocate up to 64K with alloc().
* Use lalloc for larger blocks.
*/
char_u *
alloc(size)
unsigned size;
{
return (lalloc((long_u)size, TRUE));
}
/*
* Allocate memory and set all bytes to zero.
*/
char_u *
alloc_clear(size)
unsigned size;
{
char_u *p;
p = (lalloc((long_u)size, TRUE));
if (p != NULL)
(void)vim_memset(p, 0, (size_t)size);
return p;
}
/*
* alloc() with check for maximum line length
*/
char_u *
alloc_check(size)
unsigned size;
{
#if !defined(UNIX) && !defined(__EMX__)
if (sizeof(int) == 2 && size > 0x7fff)
{
EMSG("Line is becoming too long");
return NULL;
}
#endif
return (lalloc((long_u)size, TRUE));
}
char_u *
lalloc(size, message)
long_u size;
int message;
{
char_u *p; /* pointer to new storage space */
static int releasing = FALSE; /* don't do mf_release_all() recursive */
int try_again;
if (size <= 0)
{
EMSGN("Internal error: lalloc(%ld, )", size);
return NULL;
}
#if defined(MSDOS) && !defined(DJGPP)
if (size >= 0xfff0) /* in MSDOS we can't deal with >64K blocks */
p = NULL;
else
#endif
/*
* If out of memory, try to release some memfile blocks.
* If some blocks are released call malloc again.
*/
for (;;)
{
if ((p = (char_u *)malloc(size)) != NULL)
{
if (mch_avail_mem(TRUE) < KEEP_ROOM && !releasing)
{ /* System is low... no go! */
vim_free((char *)p);
p = NULL;
}
}
/*
* Remember that mf_release_all() is being called to avoid an endless loop,
* because mf_release_all() may call alloc() recursively.
*/
if (p != NULL || releasing)
break;
releasing = TRUE;
try_again = mf_release_all();
releasing = FALSE;
if (!try_again)
break;
}
/*
* Avoid repeating the error message many times (they take 1 second each).
* Did_outofmem_msg is reset when a character is read.
*/
if (message && p == NULL)
do_outofmem_msg();
return (p);
}
void
do_outofmem_msg()
{
if (!did_outofmem_msg)
{
emsg(e_outofmem);
did_outofmem_msg = TRUE;
}
}
/*
* copy a string into newly allocated memory
*/
char_u *
vim_strsave(string)
char_u *string;
{
char_u *p;
p = alloc((unsigned) (STRLEN(string) + 1));
if (p != NULL)
STRCPY(p, string);
return p;
}
char_u *
vim_strnsave(string, len)
char_u *string;
int len;
{
char_u *p;
p = alloc((unsigned) (len + 1));
if (p != NULL)
{
STRNCPY(p, string, len);
p[len] = NUL;
}
return p;
}
/*
* like vim_strnsave(), but remove backslashes from the string.
*/
char_u *
vim_strnsave_esc(string, len)
char_u *string;
int len;
{
char_u *p1, *p2;
p1 = alloc((unsigned) (len + 1));
if (p1 != NULL)
{
STRNCPY(p1, string, len);
p1[len] = NUL;
for (p2 = p1; *p2; ++p2)
if (*p2 == '\\' && *(p2 + 1) != NUL)
STRCPY(p2, p2 + 1);
}
return p1;
}
/*
* Same as vim_strsave(), but any characters found in esc_chars are preceded
* by a backslash.
*/
char_u *
vim_strsave_escaped(string, esc_chars)
char_u *string;
char_u *esc_chars;
{
char_u *p;
char_u *p2;
char_u *escaped_string;
unsigned length;
/*
* First count the number of backslashes required.
* Then allocate the memory and insert them.
*/
length = 1; /* count the trailing '/' and NUL */
for (p = string; *p; p++)
{
if (vim_strchr(esc_chars, *p) != NULL)
++length; /* count a backslash */
++length; /* count an ordinary char */
}
escaped_string = alloc(length);
if (escaped_string != NULL)
{
p2 = escaped_string;
for (p = string; *p; p++)
{
if (vim_strchr(esc_chars, *p) != NULL)
*p2++ = '\\';
*p2++ = *p;
}
*p2 = NUL;
}
return escaped_string;
}
/*
* copy a number of spaces
*/
void
copy_spaces(ptr, count)
char_u *ptr;
size_t count;
{
size_t i = count;
char_u *p = ptr;
while (i--)
*p++ = ' ';
}
/*
* delete spaces at the end of a string
*/
void
del_trailing_spaces(ptr)
char_u *ptr;
{
char_u *q;
q = ptr + STRLEN(ptr);
while (--q > ptr && vim_iswhite(q[0]) && q[-1] != '\\' &&
q[-1] != Ctrl('V'))
*q = NUL;
}
/*
* vim_strncpy()
*
* This is here because strncpy() does not guarantee successful results when
* the to and from strings overlap. It is only currently called from nextwild()
* which copies part of the command line to another part of the command line.
* This produced garbage when expanding files etc in the middle of the command
* line (on my terminal, anyway) -- webb.
*/
void
vim_strncpy(to, from, len)
char_u *to;
char_u *from;
int len;
{
int i;
if (to <= from)
{
while (len-- && *from)
*to++ = *from++;
if (len >= 0)
*to = *from; /* Copy NUL */
}
else
{
for (i = 0; i < len; i++)
{
to++;
if (*from++ == NUL)
{
i++;
break;
}
}
for (; i > 0; i--)
*--to = *--from;
}
}
/*
* Isolate one part of a string option where parts are separated with commas.
* The part is copied into buf[maxlen].
* "*option" is advanced to the next part.
* The length is returned.
*/
int
copy_option_part(option, buf, maxlen, sep_chars)
char_u **option;
char_u *buf;
int maxlen;
char *sep_chars;
{
int len = 0;
char_u *p = *option;
/* skip '.' at start of option part, for 'suffixes' */
if (*p == '.')
buf[len++] = *p++;
while (*p && vim_strchr((char_u *)sep_chars, *p) == NULL)
{
/*
* Skip backslash before a separator character and space.
*/
if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL)
++p;
if (len < maxlen - 1)
buf[len++] = *p;
++p;
}
buf[len] = NUL;
p = skip_to_option_part(p); /* p points to next file name */
*option = p;
return len;
}
/*
* replacement for free() that ignores NULL pointers
*/
void
vim_free(x)
void *x;
{
if (x != NULL)
free(x);
}
#ifndef HAVE_MEMSET
void *
vim_memset(ptr, c, size)
void *ptr;
int c;
size_t size;
{
char *p = ptr;
while (size-- > 0)
*p++ = c;
return ptr;
}
#endif
#ifdef VIM_MEMMOVE
/*
* Version of memmove that handles overlapping source and destination.
* For systems that don't have a function that is guaranteed to do that (SYSV).
*/
void
vim_memmove(dst_arg, src_arg, len)
void *src_arg, *dst_arg;
size_t len;
{
/*
* A void doesn't have a size, we use char pointers.
*/
char *dst = dst_arg, *src = src_arg;
/* overlap, copy backwards */
if (dst > src && dst < src + len)
{
src +=len;
dst +=len;
while (len-- > 0)
*--dst = *--src;
}
else /* copy forwards */
while (len-- > 0)
*dst++ = *src++;
}
#endif
#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO)
/*
* Compare two strings, ignoring case.
* return 0 for match, 1 for difference
*/
int
vim_stricmp(s1, s2)
char *s1;
char *s2;
{
for (;;)
{
if (TO_UPPER(*s1) != TO_UPPER(*s2))
return 1; /* this character different */
if (*s1 == NUL)
break; /* strings match until NUL */
++s1;
++s2;
}
return 0; /* strings match */
}
#endif
#if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO)
/*
* Compare two strings, for length "len", ignoring case.
* return 0 for match, 1 for difference
*/
int
vim_strnicmp(s1, s2, len)
char *s1;
char *s2;
size_t len;
{
while (len)
{
if (TO_UPPER(*s1) != TO_UPPER(*s2))
return 1; /* this character different */
if (*s1 == NUL)
break; /* strings match until NUL */
++s1;
++s2;
--len;
}
return 0; /* strings match */
}
#endif
/*
* Version of strchr() and strrchr() that handle unsigned char strings
* with characters above 128 correctly. Also it doesn't return a pointer to
* the NUL at the end of the string.
*/
char_u *
vim_strchr(string, n)
char_u *string;
int n;
{
while (*string)
{
if (*string == n)
return string;
++string;
}
return NULL;
}
char_u *
vim_strrchr(string, n)
char_u *string;
int n;
{
char_u *retval = NULL;
while (*string)
{
if (*string == n)
retval = string;
++string;
}
return retval;
}
/*
* Vim's version of strpbrk(), in case it's missing.
*/
#if !defined(HAVE_STRPBRK) || defined(PROTO)
# ifdef vim_strpbrk
# undef vim_strpbrk
# endif
char_u *
vim_strpbrk(s, charset)
char_u *s;
char_u *charset;
{
while (*s)
{
if (vim_strchr(charset, *s) != NULL)
return s;
++s;
}
return NULL;
}
#endif
/*
* Vim has its own isspace() function, because on some machines isspace()
* can't handle characters above 128.
*/
int
vim_isspace(x)
int x;
{
return ((x >= 9 && x <= 13) || x == ' ');
}
/************************************************************************
* Functions for hanlding growing arrays.
*/
/*
* Clear an allocated growing array.
*/
void
ga_clear(ga)
struct growarray *ga;
{
vim_free(ga->ga_data);
ga->ga_data = NULL;
ga->ga_room = 0;
ga->ga_len = 0;
}
/*
* Make room in a growing array for at least "n" items.
* Return FAIL for failure, OK otherwise.
*/
int
ga_grow(ga, n)
struct growarray *ga;
int n; /* number of items to grow the array */
{
size_t len;
char_u *pp;
if (ga->ga_room < n)
{
if (n < ga->ga_growsize)
n = ga->ga_growsize;
len = ga->ga_itemsize * (ga->ga_len + n);
pp = alloc_clear((unsigned)len);
if (pp == NULL)
return FAIL;
ga->ga_room = ga->ga_growsize;
if (ga->ga_data != NULL)
vim_memmove(pp, ga->ga_data,
(size_t)(ga->ga_itemsize * ga->ga_len));
ga->ga_data = pp;
}
return OK;
}
/************************************************************************
* functions that use lookup tables for various things, generally to do with
* special key codes.
*/
/*
* Some useful tables.
*/
static struct
{
int mod_mask; /* Bit-mask for particular key modifier */
char_u name; /* Single letter name of modifier */
} mod_mask_table[] =
{
{MOD_MASK_ALT, (char_u)'M'},
{MOD_MASK_CTRL, (char_u)'C'},
{MOD_MASK_SHIFT, (char_u)'S'},
{MOD_MASK_2CLICK, (char_u)'2'},
{MOD_MASK_3CLICK, (char_u)'3'},
{MOD_MASK_4CLICK, (char_u)'4'},
{0x0, NUL}
};
/*
* Shifted key terminal codes and their unshifted equivalent.
* Don't add mouse codes here, they are handled seperately!
*/
static char_u shifted_keys_table[] =
{
/* shifted unshifted */
'&', '9', '@', '1', /* begin */
'&', '0', '@', '2', /* cancel */
'*', '1', '@', '4', /* command */
'*', '2', '@', '5', /* copy */
'*', '3', '@', '6', /* create */
'*', '4', 'k', 'D', /* delete char */
'*', '5', 'k', 'L', /* delete line */
'*', '7', '@', '7', /* end */
'*', '9', '@', '9', /* exit */
'*', '0', '@', '0', /* find */
'#', '1', '%', '1', /* help */
'#', '2', 'k', 'h', /* home */
'#', '3', 'k', 'I', /* insert */
'#', '4', 'k', 'l', /* left arrow */
'%', 'a', '%', '3', /* message */
'%', 'b', '%', '4', /* move */
'%', 'c', '%', '5', /* next */
'%', 'd', '%', '7', /* options */
'%', 'e', '%', '8', /* previous */
'%', 'f', '%', '9', /* print */
'%', 'g', '%', '0', /* redo */
'%', 'h', '&', '3', /* replace */
'%', 'i', 'k', 'r', /* right arrow */
'%', 'j', '&', '5', /* resume */
'!', '1', '&', '6', /* save */
'!', '2', '&', '7', /* suspend */
'!', '3', '&', '8', /* undo */
KS_EXTRA, KE_S_UP, 'k', 'u', /* up arrow */
KS_EXTRA, KE_S_DOWN, 'k', 'd', /* down arrow */
KS_EXTRA, KE_S_F1, 'k', '1', /* F1 */
KS_EXTRA, KE_S_F2, 'k', '2',
KS_EXTRA, KE_S_F3, 'k', '3',
KS_EXTRA, KE_S_F4, 'k', '4',
KS_EXTRA, KE_S_F5, 'k', '5',
KS_EXTRA, KE_S_F6, 'k', '6',
KS_EXTRA, KE_S_F7, 'k', '7',
KS_EXTRA, KE_S_F8, 'k', '8',
KS_EXTRA, KE_S_F9, 'k', '9',
KS_EXTRA, KE_S_F10, 'k', ';', /* F10 */
KS_EXTRA, KE_S_F11, 'F', '1',
KS_EXTRA, KE_S_F12, 'F', '2',
KS_EXTRA, KE_S_F13, 'F', '3',
KS_EXTRA, KE_S_F14, 'F', '4',
KS_EXTRA, KE_S_F15, 'F', '5',
KS_EXTRA, KE_S_F16, 'F', '6',
KS_EXTRA, KE_S_F17, 'F', '7',
KS_EXTRA, KE_S_F18, 'F', '8',
KS_EXTRA, KE_S_F19, 'F', '9',
KS_EXTRA, KE_S_F20, 'F', 'A',
KS_EXTRA, KE_S_F21, 'F', 'B',
KS_EXTRA, KE_S_F22, 'F', 'C',
KS_EXTRA, KE_S_F23, 'F', 'D',
KS_EXTRA, KE_S_F24, 'F', 'E',
KS_EXTRA, KE_S_F25, 'F', 'F',
KS_EXTRA, KE_S_F26, 'F', 'G',
KS_EXTRA, KE_S_F27, 'F', 'H',
KS_EXTRA, KE_S_F28, 'F', 'I',
KS_EXTRA, KE_S_F29, 'F', 'J',
KS_EXTRA, KE_S_F30, 'F', 'K',
KS_EXTRA, KE_S_F31, 'F', 'L',
KS_EXTRA, KE_S_F32, 'F', 'M',
KS_EXTRA, KE_S_F33, 'F', 'N',
KS_EXTRA, KE_S_F34, 'F', 'O',
KS_EXTRA, KE_S_F35, 'F', 'P',
KS_EXTRA, KE_S_TAB, KS_EXTRA, KE_TAB, /* TAB */
NUL
};
static struct key_name_entry
{
int key; /* Special key code or ascii value */
char_u *name; /* Name of key */
} key_names_table[] =
{
{' ', (char_u *)"Space"},
{TAB, (char_u *)"Tab"},
{K_TAB, (char_u *)"Tab"},
{NL, (char_u *)"NL"},
{NL, (char_u *)"NewLine"}, /* Alternative name */
{NL, (char_u *)"LineFeed"}, /* Alternative name */
{NL, (char_u *)"LF"}, /* Alternative name */
{CR, (char_u *)"CR"},
{CR, (char_u *)"Return"}, /* Alternative name */
{ESC, (char_u *)"Esc"},
{'|', (char_u *)"Bar"},
{K_UP, (char_u *)"Up"},
{K_DOWN, (char_u *)"Down"},
{K_LEFT, (char_u *)"Left"},
{K_RIGHT, (char_u *)"Right"},
{K_F1, (char_u *)"F1"},
{K_F2, (char_u *)"F2"},
{K_F3, (char_u *)"F3"},
{K_F4, (char_u *)"F4"},
{K_F5, (char_u *)"F5"},
{K_F6, (char_u *)"F6"},
{K_F7, (char_u *)"F7"},
{K_F8, (char_u *)"F8"},
{K_F9, (char_u *)"F9"},
{K_F10, (char_u *)"F10"},
{K_F11, (char_u *)"F11"},
{K_F12, (char_u *)"F12"},
{K_F13, (char_u *)"F13"},
{K_F14, (char_u *)"F14"},
{K_F15, (char_u *)"F15"},
{K_F16, (char_u *)"F16"},
{K_F17, (char_u *)"F17"},
{K_F18, (char_u *)"F18"},
{K_F19, (char_u *)"F19"},
{K_F20, (char_u *)"F20"},
{K_F21, (char_u *)"F21"},
{K_F22, (char_u *)"F22"},
{K_F23, (char_u *)"F23"},
{K_F24, (char_u *)"F24"},
{K_F25, (char_u *)"F25"},
{K_F26, (char_u *)"F26"},
{K_F27, (char_u *)"F27"},
{K_F28, (char_u *)"F28"},
{K_F29, (char_u *)"F29"},
{K_F30, (char_u *)"F30"},
{K_F31, (char_u *)"F31"},
{K_F32, (char_u *)"F32"},
{K_F33, (char_u *)"F33"},
{K_F34, (char_u *)"F34"},
{K_F35, (char_u *)"F35"},
{K_HELP, (char_u *)"Help"},
{K_UNDO, (char_u *)"Undo"},
{K_BS, (char_u *)"BS"},
{K_BS, (char_u *)"BackSpace"}, /* Alternative name */
{K_INS, (char_u *)"Insert"},
{K_INS, (char_u *)"Ins"}, /* Alternative name */
{K_DEL, (char_u *)"Del"},
{K_DEL, (char_u *)"Delete"}, /* Alternative name */
{K_HOME, (char_u *)"Home"},
{K_END, (char_u *)"End"},
{K_PAGEUP, (char_u *)"PageUp"},
{K_PAGEDOWN, (char_u *)"PageDown"},
{K_KHOME, (char_u *)"kHome"},
{K_KEND, (char_u *)"kEnd"},
{K_KPAGEUP, (char_u *)"kPageUp"},
{K_KPAGEDOWN, (char_u *)"kPageDown"},
{K_MOUSE, (char_u *)"Mouse"},
{K_LEFTMOUSE, (char_u *)"LeftMouse"},
{K_LEFTDRAG, (char_u *)"LeftDrag"},
{K_LEFTRELEASE, (char_u *)"LeftRelease"},
{K_MIDDLEMOUSE, (char_u *)"MiddleMouse"},
{K_MIDDLEDRAG, (char_u *)"MiddleDrag"},
{K_MIDDLERELEASE, (char_u *)"MiddleRelease"},
{K_RIGHTMOUSE, (char_u *)"RightMouse"},
{K_RIGHTDRAG, (char_u *)"RightDrag"},
{K_RIGHTRELEASE, (char_u *)"RightRelease"},
{K_ZERO, (char_u *)"Nul"},
{0, NULL}
};
#define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry))
#ifdef USE_MOUSE
static struct
{
int pseudo_code; /* Code for pseudo mouse event */
int button; /* Which mouse button is it? */
int is_click; /* Is it a mouse button click event? */
int is_drag; /* Is it a mouse drag event? */
} mouse_table[] =
{
{KE_LEFTMOUSE, MOUSE_LEFT, TRUE, FALSE},
{KE_LEFTDRAG, MOUSE_LEFT, FALSE, TRUE},
{KE_LEFTRELEASE, MOUSE_LEFT, FALSE, FALSE},
{KE_MIDDLEMOUSE, MOUSE_MIDDLE, TRUE, FALSE},
{KE_MIDDLEDRAG, MOUSE_MIDDLE, FALSE, TRUE},
{KE_MIDDLERELEASE, MOUSE_MIDDLE, FALSE, FALSE},
{KE_RIGHTMOUSE, MOUSE_RIGHT, TRUE, FALSE},
{KE_RIGHTDRAG, MOUSE_RIGHT, FALSE, TRUE},
{KE_RIGHTRELEASE, MOUSE_RIGHT, FALSE, FALSE},
{KE_IGNORE, MOUSE_RELEASE, FALSE, TRUE}, /* DRAG without CLICK */
{KE_IGNORE, MOUSE_RELEASE, FALSE, FALSE}, /* RELEASE without CLICK */
{0, 0, 0, 0},
};
#endif /* USE_MOUSE */
/*
* Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
* modifier name ('S' for Shift, 'C' for Ctrl etc).
*/
int
name_to_mod_mask(c)
int c;
{
int i;
for (i = 0; mod_mask_table[i].mod_mask; i++)
if (TO_LOWER(c) == TO_LOWER(mod_mask_table[i].name))
return mod_mask_table[i].mod_mask;
return 0x0;
}
/*
* Decide whether the given key code (K_*) is a shifted special
* key (by looking at mod_mask). If it is, then return the appropriate shifted
* key code, otherwise just return the character as is.
*/
int
check_shifted_spec_key(c)
int c;
{
int i;
int key0;
int key1;
if (mod_mask & MOD_MASK_SHIFT)
{
if (c == TAB) /* TAB is not in the table, K_TAB is */
return K_S_TAB;
key0 = KEY2TERMCAP0(c);
key1 = KEY2TERMCAP1(c);
for (i = 0; shifted_keys_table[i] != NUL; i += 4)
if (key0 == shifted_keys_table[i + 2] &&
key1 == shifted_keys_table[i + 3])
return TERMCAP2KEY(shifted_keys_table[i],
shifted_keys_table[i + 1]);
}
return c;
}
/*
* Decide whether the given special key is shifted or not. If it is we
* return OK and change it to the equivalent unshifted special key code,
* otherwise we leave it as is and return FAIL.
*/
int
unshift_special_key(p)
char_u *p;
{
int i;
for (i = 0; shifted_keys_table[i]; i += 4)
if (p[0] == shifted_keys_table[i] && p[1] == shifted_keys_table[i + 1])
{
p[0] = shifted_keys_table[i + 2];
p[1] = shifted_keys_table[i + 3];
return OK;
}
return FAIL;
}
/*
* Return a string which contains the name of the given key when the given
* modifiers are down.
*/
char_u *
get_special_key_name(c, modifiers)
int c;
int modifiers;
{
static char_u string[MAX_KEY_NAME_LEN + 1];
int i, idx;
int table_idx;
char_u *s;
char_u name[2];
string[0] = '<';
idx = 1;
/* translate shifted keys into unshifted keys and set modifier */
if (IS_SPECIAL(c))
{
name[0] = KEY2TERMCAP0(c);
name[1] = KEY2TERMCAP1(c);
if (unshift_special_key(&name[0]))
modifiers |= MOD_MASK_SHIFT;
c = TERMCAP2KEY(name[0], name[1]);
}
/* try to find the key in the special key table */
table_idx = find_special_key_in_table(c);
/*
* When not a known special key, and not a printable character, try to
* extract modifiers.
*/
if (table_idx < 0 && !isprintchar(c) && (c & 0x80))
{
c &= 0x7f;
modifiers |= MOD_MASK_ALT;
/* try again to find the un-modified key in the special key table */
table_idx = find_special_key_in_table(c);
}
if (table_idx < 0 && !isprintchar(c) && c < ' ')
{
c += '@';
modifiers |= MOD_MASK_CTRL;
}
/* translate the modifier into a string */
for (i = 0; mod_mask_table[i].mod_mask; i++)
if (modifiers & mod_mask_table[i].mod_mask)
{
string[idx++] = mod_mask_table[i].name;
string[idx++] = (char_u)'-';
}
if (table_idx < 0) /* unknown special key, output t_xx */
{
if (IS_SPECIAL(c))
{
string[idx++] = 't';
string[idx++] = '_';
string[idx++] = KEY2TERMCAP0(c);
string[idx++] = KEY2TERMCAP1(c);
}
/* Not a special key, only modifiers, output directly */
else
{
if (isprintchar(c))
string[idx++] = c;
else
{
s = transchar(c);
while (*s)
string[idx++] = *s++;
}
}
}
else /* use name of special key */
{
STRCPY(string + idx, key_names_table[table_idx].name);
idx = STRLEN(string);
}
string[idx++] = '>';
string[idx] = NUL;
return string;
}
/*
* Try translating a <> name at (*srcp)[] to dst[].
* Return the number of characters added to dst[].
* srcp is advanced to after the <> name.
* dst[] must be big enough to hold the result!
*/
int
trans_special(srcp, dst, single)
char_u **srcp;
char_u *dst;
int single; /* want a single byte code */
{
int dlen = 0;
char_u *last_dash;
char_u *end_of_name;
char_u *src;
char_u *bp;
int modifiers;
int bit;
int key;
src = *srcp;
if (src[0] != '<')
return 0;
/* Find end of modifier list */
last_dash = src;
for (bp = src + 1; *bp == '-' || isidchar(*bp); bp++)
{
if (*bp == '-')
{
last_dash = bp;
if (bp[1] != NUL && bp[2] == '>')
++bp; /* anything accepted, like <C-?> */
}
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
bp += 3; /* skip t_xx, xx may be '-' or '>' */
}
if (*bp == '>') /* found matching '>' */
{
end_of_name = bp + 1;
/* Which modifiers are given? */
modifiers = 0x0;
for (bp = src + 1; bp < last_dash; bp++)
{
if (*bp != '-')
{
bit = name_to_mod_mask(*bp);
if (bit == 0x0)
break; /* Illegal modifier name */
modifiers |= bit;
}
}
/*
* Legal modifier name.
*/
if (bp >= last_dash)
{
/*
* Modifier with single letter, or special key name.
*/
if (modifiers != 0 && last_dash[2] == '>')
key = last_dash[1];
else
key = get_special_key_code(last_dash + 1);
/*
* get_special_key_code() may return NUL for invalid
* special key name.
*/
if (key != NUL)
{
/*
* Special trick: for <S-TAB> K_TAB is used
* instead of TAB (there are two codes for the
* same thing).
*/
if (key == TAB && modifiers == MOD_MASK_SHIFT)
key = K_TAB;
/*
* Special Key name with or without modifier.
*/
if (IS_SPECIAL(key))
{
/* Put the appropriate modifier in a string */
if (modifiers != 0)
{
dst[dlen++] = K_SPECIAL;
dst[dlen++] = KS_MODIFIER;
dst[dlen++] = modifiers;
}
dst[dlen++] = K_SPECIAL;
dst[dlen++] = KEY2TERMCAP0(key);
dst[dlen++] = KEY2TERMCAP1(key);
}
/*
* Normal Key with or without modifier.
*/
else
{
if (modifiers & MOD_MASK_SHIFT)
key = TO_UPPER(key);
if (modifiers & MOD_MASK_CTRL)
key &= 0x1f;
if (modifiers & MOD_MASK_ALT)
key |= 0x80;
dst[dlen++] = key;
}
*srcp = end_of_name;
return dlen;
}
}
}
return 0;
}
/*
* Try to find key "c" in the special key table.
* Return the index when found, -1 when not found.
*/
int
find_special_key_in_table(c)
int c;
{
int i;
for (i = 0; key_names_table[i].name != NULL; i++)
if (c == key_names_table[i].key)
break;
if (key_names_table[i].name == NULL)
i = -1;
return i;
}
/*
* Find the special key with the given name (the given string does not have to
* end with NUL, the name is assumed to end before the first non-idchar).
* If the name starts with "t_" the next two characters are interpreted as a
* termcap name.
* Return the key code, or 0 if not found.
*/
int
get_special_key_code(name)
char_u *name;
{
char_u *table_name;
char_u string[3];
int i, j;
/*
* If it's <t_xx> we get the code for xx from the termcap
*/
if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL)
{
string[0] = name[2];
string[1] = name[3];
string[2] = NUL;
if (add_termcap_entry(string, FALSE) == OK)
return TERMCAP2KEY(name[2], name[3]);
}
else
for (i = 0; key_names_table[i].name != NULL; i++)
{
table_name = key_names_table[i].name;
for (j = 0; isidchar(name[j]) && table_name[j] != NUL; j++)
if (TO_LOWER(table_name[j]) != TO_LOWER(name[j]))
break;
if (!isidchar(name[j]) && table_name[j] == NUL)
return key_names_table[i].key;
}
return 0;
}
char_u *
get_key_name(i)
int i;
{
if (i >= KEY_NAMES_TABLE_LEN)
return NULL;
return key_names_table[i].name;
}
#ifdef USE_MOUSE
/*
* Look up the given mouse code to return the relevant information in the other
* arguments. Return which button is down or was released.
*/
int
get_mouse_button(code, is_click, is_drag)
int code;
int *is_click;
int *is_drag;
{
int i;
for (i = 0; mouse_table[i].pseudo_code; i++)
if (code == mouse_table[i].pseudo_code)
{
*is_click = mouse_table[i].is_click;
*is_drag = mouse_table[i].is_drag;
return mouse_table[i].button;
}
return 0; /* Shouldn't get here */
}
/*
* Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
* the given information about which mouse button is down, and whether the
* mouse was clicked, dragged or released.
*/
int
get_pseudo_mouse_code(button, is_click, is_drag)
int button; /* eg MOUSE_LEFT */
int is_click;
int is_drag;
{
int i;
for (i = 0; mouse_table[i].pseudo_code; i++)
if (button == mouse_table[i].button
&& is_click == mouse_table[i].is_click
&& is_drag == mouse_table[i].is_drag)
{
return mouse_table[i].pseudo_code;
}
return KE_IGNORE; /* not recongnized, ignore it */
}
#endif /* USE_MOUSE */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.