refactor: remove char_u (#22829)

Closes https://github.com/neovim/neovim/issues/459
This commit is contained in:
dundargoc
2023-04-02 10:11:42 +02:00
committed by GitHub
parent 9084948893
commit d510bfbc8e
40 changed files with 340 additions and 1965 deletions

View File

@@ -25,7 +25,6 @@ describe('ffi.cdef', function()
local ffi = require('ffi')
ffi.cdef[[
typedef unsigned char char_u;
typedef struct window_S win_T;
typedef struct {} stl_hlrec_t;
typedef struct {} StlClickRecord;

View File

@@ -413,7 +413,7 @@ describe('treesitter highlighting', function()
it("supports injected languages", function()
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
#define foo void main() { \
return 42; \
}
@@ -421,7 +421,7 @@ describe('treesitter highlighting', function()
screen:expect{grid=[[
int x = INT_MAX; |
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))|
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) |
#define foo void main() { \ |
return 42; \ |
} |
@@ -450,7 +450,7 @@ describe('treesitter highlighting', function()
screen:expect{grid=[[
{3:int} x = {5:INT_MAX}; |
#define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
#define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
#define foo {3:void} main() { \ |
{4:return} {5:42}; \ |
} |
@@ -473,7 +473,7 @@ describe('treesitter highlighting', function()
it("supports overriding queries, like ", function()
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
#define foo void main() { \
return 42; \
}
@@ -489,7 +489,7 @@ describe('treesitter highlighting', function()
screen:expect{grid=[[
{3:int} x = {5:INT_MAX}; |
#define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
#define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
#define foo {3:void} main() { \ |
{4:return} {5:42}; \ |
} |
@@ -567,7 +567,7 @@ describe('treesitter highlighting', function()
it("supports highlighting with priority", function()
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
#define foo void main() { \
return 42; \
}
@@ -580,7 +580,7 @@ describe('treesitter highlighting', function()
-- expect everything to have Constant highlight
screen:expect{grid=[[
{12:int}{8: x = INT_MAX;} |
{8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}|
{8:#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))} |
{8:#define foo void main() { \} |
{8: return 42; \} |
{8: }} |

View File

@@ -627,8 +627,8 @@ end]]
before_each(function()
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
#define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
#define READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
#define VALUE 123
#define VALUE1 123
#define VALUE2 123
@@ -650,8 +650,8 @@ int x = INT_MAX;
{3, 14, 3, 17}, -- VALUE 123
{4, 15, 4, 18}, -- VALUE1 123
{5, 15, 5, 18}, -- VALUE2 123
{1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
{2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{1, 26, 1, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
{2, 29, 2, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
helpers.feed('ggo<esc>')
@@ -661,8 +661,8 @@ int x = INT_MAX;
{4, 14, 4, 17}, -- VALUE 123
{5, 15, 5, 18}, -- VALUE1 123
{6, 15, 6, 18}, -- VALUE2 123
{2, 26, 2, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
{3, 29, 3, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{2, 26, 2, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
{3, 29, 3, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
end)
end)
@@ -682,8 +682,8 @@ int x = INT_MAX;
{3, 14, 5, 18}, -- VALUE 123
-- VALUE1 123
-- VALUE2 123
{1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{1, 26, 2, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
helpers.feed('ggo<esc>')
@@ -694,8 +694,8 @@ int x = INT_MAX;
{4, 14, 6, 18}, -- VALUE 123
-- VALUE1 123
-- VALUE2 123
{2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{2, 26, 3, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
end)
end)
@@ -722,8 +722,8 @@ int x = INT_MAX;
{3, 14, 5, 18}, -- VALUE 123
-- VALUE1 123
-- VALUE2 123
{1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{1, 26, 2, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
helpers.feed('ggo<esc>')
@@ -734,8 +734,8 @@ int x = INT_MAX;
{4, 14, 6, 18}, -- VALUE 123
-- VALUE1 123
-- VALUE2 123
{2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{2, 26, 3, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
-- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
end)
@@ -768,8 +768,8 @@ int x = INT_MAX;
{3, 15, 3, 16}, -- VALUE 123
{4, 16, 4, 17}, -- VALUE1 123
{5, 16, 5, 17}, -- VALUE2 123
{1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
{2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
{1, 26, 1, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
{2, 29, 2, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
end)
it("should list all directives", function()

View File

@@ -1,172 +0,0 @@
#include <stdbool.h>
#include "nvim/ascii.h"
#include "nvim/macros.h"
#include "nvim/charset.h"
#include "nvim/eval/typval.h"
#include "nvim/vim.h"
int hex2nr(int c)
{
if ((c >= 'a') && (c <= 'f')) {
return c - 'a' + 10;
}
if ((c >= 'A') && (c <= 'F')) {
return c - 'A' + 10;
}
return c - '0';
}
void vim_str2nr(const char_u *const start, int *const prep, int *const len,
const int what, varnumber_T *const nptr,
uvarnumber_T *const unptr, const int maxlen)
{
const char *ptr = (const char *)start;
#define STRING_ENDED(ptr) \
(!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
int pre = 0; // default is decimal
const bool negative = (ptr[0] == '-');
uvarnumber_T un = 0;
if (negative) {
ptr++;
}
if (what & STR2NR_FORCE) {
// When forcing main consideration is skipping the prefix. Octal and decimal
// numbers have no prefixes to skip. pre is not set.
switch ((unsigned)what & (~(unsigned)STR2NR_FORCE)) {
case STR2NR_HEX: {
if (!STRING_ENDED(ptr + 2)
&& ptr[0] == '0'
&& (ptr[1] == 'x' || ptr[1] == 'X')
&& ascii_isxdigit(ptr[2])) {
ptr += 2;
}
goto vim_str2nr_hex;
}
case STR2NR_BIN: {
if (!STRING_ENDED(ptr + 2)
&& ptr[0] == '0'
&& (ptr[1] == 'b' || ptr[1] == 'B')
&& ascii_isbdigit(ptr[2])) {
ptr += 2;
}
goto vim_str2nr_bin;
}
case STR2NR_OCT: {
goto vim_str2nr_oct;
}
case 0: {
goto vim_str2nr_dec;
}
default: {
abort();
}
}
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
&& !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1];
// Detect hexadecimal: 0x or 0X followed by hex digit
if ((what & STR2NR_HEX)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x')
&& ascii_isxdigit(ptr[2])) {
ptr += 2;
goto vim_str2nr_hex;
}
// Detect binary: 0b or 0B followed by 0 or 1
if ((what & STR2NR_BIN)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b')
&& ascii_isbdigit(ptr[2])) {
ptr += 2;
goto vim_str2nr_bin;
}
// Detect octal number: zero followed by octal digits without '8' or '9'
pre = 0;
if (!(what & STR2NR_OCT)) {
goto vim_str2nr_dec;
}
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
if (ptr[i] > '7') {
goto vim_str2nr_dec;
}
}
pre = '0';
goto vim_str2nr_oct;
} else {
goto vim_str2nr_dec;
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
abort(); // Shouldve used goto earlier.
#define PARSE_NUMBER(base, cond, conv) \
do { \
while (!STRING_ENDED(ptr) && (cond)) { \
/* avoid ubsan error for overflow */ \
if (un < UVARNUMBER_MAX / base) { \
un = base * un + (uvarnumber_T)(conv); \
} else { \
un = UVARNUMBER_MAX; \
} \
ptr++; \
} \
} while (0)
switch (pre) {
case 'b':
case 'B': {
vim_str2nr_bin:
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
break;
}
case '0': {
vim_str2nr_oct:
PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
break;
}
case 0: {
vim_str2nr_dec:
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
break;
}
case 'x':
case 'X': {
vim_str2nr_hex:
PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
break;
}
}
#undef PARSE_NUMBER
if (prep != NULL) {
*prep = pre;
}
if (len != NULL) {
*len = (int)(ptr - (const char *)start);
}
if (nptr != NULL) {
if (negative) { // account for leading '-' for decimal numbers
// avoid ubsan error for overflow
if (un > VARNUMBER_MAX) {
*nptr = VARNUMBER_MIN;
} else {
*nptr = -(varnumber_T)un;
}
} else {
if (un > VARNUMBER_MAX) {
un = VARNUMBER_MAX;
}
*nptr = (varnumber_T)un;
}
}
if (unptr != NULL) {
*unptr = un;
}
#undef STRING_ENDED
}

View File

@@ -1,195 +0,0 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// @file garray.c
///
/// Functions for handling growing arrays.
#include <string.h>
#include <inttypes.h>
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/log.h"
#include "nvim/memory.h"
#include "nvim/path.h"
#include "nvim/garray.h"
#include "nvim/strings.h"
// #include "nvim/globals.h"
#include "nvim/memline.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "garray.c.generated.h"
#endif
/// Clear an allocated growing array.
void ga_clear(garray_T *gap)
{
xfree(gap->ga_data);
// Initialize growing array without resetting itemsize or growsize
gap->ga_data = NULL;
gap->ga_maxlen = 0;
gap->ga_len = 0;
}
/// Clear a growing array that contains a list of strings.
///
/// @param gap
void ga_clear_strings(garray_T *gap)
{
GA_DEEP_CLEAR_PTR(gap);
}
/// Initialize a growing array.
///
/// @param gap
/// @param itemsize
/// @param growsize
void ga_init(garray_T *gap, int itemsize, int growsize)
{
gap->ga_data = NULL;
gap->ga_maxlen = 0;
gap->ga_len = 0;
gap->ga_itemsize = itemsize;
ga_set_growsize(gap, growsize);
}
/// A setter for the growsize that guarantees it will be at least 1.
///
/// @param gap
/// @param growsize
void ga_set_growsize(garray_T *gap, int growsize)
{
if (growsize < 1) {
WLOG("trying to set an invalid ga_growsize: %d", growsize);
gap->ga_growsize = 1;
} else {
gap->ga_growsize = growsize;
}
}
/// Make room in growing array "gap" for at least "n" items.
///
/// @param gap
/// @param n
void ga_grow(garray_T *gap, int n)
{
if (gap->ga_maxlen - gap->ga_len >= n) {
// the garray still has enough space, do nothing
return;
}
if (gap->ga_growsize < 1) {
WLOG("ga_growsize(%d) is less than 1", gap->ga_growsize);
}
// the garray grows by at least growsize
if (n < gap->ga_growsize) {
n = gap->ga_growsize;
}
int new_maxlen = gap->ga_len + n;
size_t new_size = (size_t)(gap->ga_itemsize * new_maxlen);
size_t old_size = (size_t)(gap->ga_itemsize * gap->ga_maxlen);
// reallocate and clear the new memory
char *pp = xrealloc(gap->ga_data, new_size);
memset(pp + old_size, 0, new_size - old_size);
gap->ga_maxlen = new_maxlen;
gap->ga_data = pp;
}
/// For a growing array that contains a list of strings: concatenate all the
/// strings with sep as separator.
///
/// @param gap
/// @param sep
///
/// @returns the concatenated strings
char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
FUNC_ATTR_NONNULL_RET
{
const size_t nelem = (size_t) gap->ga_len;
const char **strings = gap->ga_data;
if (nelem == 0) {
return (char_u *) xstrdup("");
}
size_t len = 0;
for (size_t i = 0; i < nelem; i++) {
len += strlen(strings[i]);
}
// add some space for the (num - 1) separators
len += (nelem - 1) * strlen(sep);
char *const ret = xmallocz(len);
char *s = ret;
for (size_t i = 0; i < nelem - 1; i++) {
s = xstpcpy(s, strings[i]);
s = xstpcpy(s, sep);
}
strcpy(s, strings[nelem - 1]);
return (char_u *) ret;
}
/// For a growing array that contains a list of strings: concatenate all the
/// strings with a separating comma.
///
/// @param gap
///
/// @returns the concatenated strings
char_u* ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET
{
return ga_concat_strings_sep(gap, ",");
}
/// Concatenate a string to a growarray which contains characters.
/// When "s" is NULL does not do anything.
///
/// WARNING:
/// - Does NOT copy the NUL at the end!
/// - The parameter may not overlap with the growing array
///
/// @param gap
/// @param s
void ga_concat(garray_T *gap, const char_u *restrict s)
{
if (s == NULL) {
return;
}
ga_concat_len(gap, (const char *restrict) s, strlen((char *) s));
}
/// Concatenate a string to a growarray which contains characters
///
/// @param[out] gap Growarray to modify.
/// @param[in] s String to concatenate.
/// @param[in] len String length.
void ga_concat_len(garray_T *const gap, const char *restrict s,
const size_t len)
FUNC_ATTR_NONNULL_ALL
{
if (len) {
ga_grow(gap, (int) len);
char *data = gap->ga_data;
memcpy(data + gap->ga_len, s, len);
gap->ga_len += (int) len;
}
}
/// Append one byte to a growarray which contains bytes.
///
/// @param gap
/// @param c
void ga_append(garray_T *gap, char c)
{
GA_APPEND(char, gap, c);
}

View File

@@ -1,4 +0,0 @@
char *gettext(const char *s)
{
return (char *)s;
}

View File

@@ -1,559 +0,0 @@
#include <stdbool.h>
#include "nvim/types.h"
#include "nvim/keycodes.h"
#include "nvim/ascii.h"
#include "nvim/eval/typval.h"
#define MOD_KEYS_ENTRY_SIZE 5
static char_u modifier_keys_table[] =
{
MOD_MASK_SHIFT, '&', '9', '@', '1',
MOD_MASK_SHIFT, '&', '0', '@', '2',
MOD_MASK_SHIFT, '*', '1', '@', '4',
MOD_MASK_SHIFT, '*', '2', '@', '5',
MOD_MASK_SHIFT, '*', '3', '@', '6',
MOD_MASK_SHIFT, '*', '4', 'k', 'D',
MOD_MASK_SHIFT, '*', '5', 'k', 'L',
MOD_MASK_SHIFT, '*', '7', '@', '7',
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7',
MOD_MASK_SHIFT, '*', '9', '@', '9',
MOD_MASK_SHIFT, '*', '0', '@', '0',
MOD_MASK_SHIFT, '#', '1', '%', '1',
MOD_MASK_SHIFT, '#', '2', 'k', 'h',
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h',
MOD_MASK_SHIFT, '#', '3', 'k', 'I',
MOD_MASK_SHIFT, '#', '4', 'k', 'l',
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l',
MOD_MASK_SHIFT, '%', 'a', '%', '3',
MOD_MASK_SHIFT, '%', 'b', '%', '4',
MOD_MASK_SHIFT, '%', 'c', '%', '5',
MOD_MASK_SHIFT, '%', 'd', '%', '7',
MOD_MASK_SHIFT, '%', 'e', '%', '8',
MOD_MASK_SHIFT, '%', 'f', '%', '9',
MOD_MASK_SHIFT, '%', 'g', '%', '0',
MOD_MASK_SHIFT, '%', 'h', '&', '3',
MOD_MASK_SHIFT, '%', 'i', 'k', 'r',
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r',
MOD_MASK_SHIFT, '%', 'j', '&', '5',
MOD_MASK_SHIFT, '!', '1', '&', '6',
MOD_MASK_SHIFT, '!', '2', '&', '7',
MOD_MASK_SHIFT, '!', '3', '&', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R',
MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB,
NUL
};
int simplify_key(const int key, int *modifiers)
{
if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) {
// TAB is a special case.
if (key == TAB && (*modifiers & MOD_MASK_SHIFT)) {
*modifiers &= ~MOD_MASK_SHIFT;
return K_S_TAB;
}
const int key0 = KEY2TERMCAP0(key);
const int key1 = KEY2TERMCAP1(key);
for (int i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE) {
if (key0 == modifier_keys_table[i + 3]
&& key1 == modifier_keys_table[i + 4]
&& (*modifiers & modifier_keys_table[i])) {
*modifiers &= ~modifier_keys_table[i];
return TERMCAP2KEY(modifier_keys_table[i + 1],
modifier_keys_table[i + 2]);
}
}
}
return key;
}
int handle_x_keys(const int key)
FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (key) {
case K_XUP: return K_UP;
case K_XDOWN: return K_DOWN;
case K_XLEFT: return K_LEFT;
case K_XRIGHT: return K_RIGHT;
case K_XHOME: return K_HOME;
case K_ZHOME: return K_HOME;
case K_XEND: return K_END;
case K_ZEND: return K_END;
case K_XF1: return K_F1;
case K_XF2: return K_F2;
case K_XF3: return K_F3;
case K_XF4: return K_F4;
case K_S_XF1: return K_S_F1;
case K_S_XF2: return K_S_F2;
case K_S_XF3: return K_S_F3;
case K_S_XF4: return K_S_F4;
}
return key;
}
static const struct key_name_entry {
int key; // Special key code or ascii value
const char *name; // Name of key
} key_names_table[] = {
{ ' ', "Space" },
{ TAB, "Tab" },
{ K_TAB, "Tab" },
{ NL, "NL" },
{ NL, "NewLine" }, // Alternative name
{ NL, "LineFeed" }, // Alternative name
{ NL, "LF" }, // Alternative name
{ CAR, "CR" },
{ CAR, "Return" }, // Alternative name
{ CAR, "Enter" }, // Alternative name
{ K_BS, "BS" },
{ K_BS, "BackSpace" }, // Alternative name
{ ESC, "Esc" },
{ CSI, "CSI" },
{ K_CSI, "xCSI" },
{ '|', "Bar" },
{ '\\', "Bslash" },
{ K_DEL, "Del" },
{ K_DEL, "Delete" }, // Alternative name
{ K_KDEL, "kDel" },
{ K_KDEL, "KPPeriod" }, // termkey KPPeriod value
{ K_UP, "Up" },
{ K_DOWN, "Down" },
{ K_LEFT, "Left" },
{ K_RIGHT, "Right" },
{ K_XUP, "xUp" },
{ K_XDOWN, "xDown" },
{ K_XLEFT, "xLeft" },
{ K_XRIGHT, "xRight" },
{ K_KUP, "kUp" },
{ K_KUP, "KP8" },
{ K_KDOWN, "kDown" },
{ K_KDOWN, "KP2" },
{ K_KLEFT, "kLeft" },
{ K_KLEFT, "KP4" },
{ K_KRIGHT, "kRight" },
{ K_KRIGHT, "KP6" },
{ K_F1, "F1" },
{ K_F2, "F2" },
{ K_F3, "F3" },
{ K_F4, "F4" },
{ K_F5, "F5" },
{ K_F6, "F6" },
{ K_F7, "F7" },
{ K_F8, "F8" },
{ K_F9, "F9" },
{ K_F10, "F10" },
{ K_F11, "F11" },
{ K_F12, "F12" },
{ K_F13, "F13" },
{ K_F14, "F14" },
{ K_F15, "F15" },
{ K_F16, "F16" },
{ K_F17, "F17" },
{ K_F18, "F18" },
{ K_F19, "F19" },
{ K_F20, "F20" },
{ K_F21, "F21" },
{ K_F22, "F22" },
{ K_F23, "F23" },
{ K_F24, "F24" },
{ K_F25, "F25" },
{ K_F26, "F26" },
{ K_F27, "F27" },
{ K_F28, "F28" },
{ K_F29, "F29" },
{ K_F30, "F30" },
{ K_F31, "F31" },
{ K_F32, "F32" },
{ K_F33, "F33" },
{ K_F34, "F34" },
{ K_F35, "F35" },
{ K_F36, "F36" },
{ K_F37, "F37" },
{ K_XF1, "xF1" },
{ K_XF2, "xF2" },
{ K_XF3, "xF3" },
{ K_XF4, "xF4" },
{ K_HELP, "Help" },
{ K_UNDO, "Undo" },
{ K_INS, "Insert" },
{ K_INS, "Ins" }, // Alternative name
{ K_KINS, "kInsert" },
{ K_KINS, "KP0" },
{ K_HOME, "Home" },
{ K_KHOME, "kHome" },
{ K_KHOME, "KP7" },
{ K_XHOME, "xHome" },
{ K_ZHOME, "zHome" },
{ K_END, "End" },
{ K_KEND, "kEnd" },
{ K_XEND, "xEnd" },
{ K_ZEND, "zEnd" },
{ K_PAGEUP, "PageUp" },
{ K_PAGEDOWN, "PageDown" },
{ K_KPAGEUP, "kPageUp" },
{ K_KPAGEUP, "KP9" },
{ K_KPAGEDOWN, "kPageDown" },
{ K_KPAGEDOWN, "KP3" },
{ K_KORIGIN, "kOrigin" },
{ K_KORIGIN, "KP5" },
{ K_KPLUS, "kPlus" },
{ K_KPLUS, "KPPlus" },
{ K_KMINUS, "kMinus" },
{ K_KMINUS, "KPMinus" },
{ K_KDIVIDE, "kDivide" },
{ K_KDIVIDE, "KPDiv" },
{ K_KMULTIPLY, "kMultiply" },
{ K_KMULTIPLY, "KPMult" },
{ K_KENTER, "kEnter" },
{ K_KENTER, "KPEnter" },
{ K_KPOINT, "kPoint" },
{ K_K0, "k0" },
{ K_K1, "k1" },
{ K_K2, "k2" },
{ K_K3, "k3" },
{ K_K4, "k4" },
{ K_K5, "k5" },
{ K_K6, "k6" },
{ K_K7, "k7" },
{ K_K8, "k8" },
{ K_K9, "k9" },
{ '<', "lt" },
{ K_MOUSE, "Mouse" },
{ K_LEFTMOUSE, "LeftMouse" },
{ K_LEFTMOUSE_NM, "LeftMouseNM" },
{ K_LEFTDRAG, "LeftDrag" },
{ K_LEFTRELEASE, "LeftRelease" },
{ K_LEFTRELEASE_NM, "LeftReleaseNM" },
{ K_MIDDLEMOUSE, "MiddleMouse" },
{ K_MIDDLEDRAG, "MiddleDrag" },
{ K_MIDDLERELEASE, "MiddleRelease" },
{ K_RIGHTMOUSE, "RightMouse" },
{ K_RIGHTDRAG, "RightDrag" },
{ K_RIGHTRELEASE, "RightRelease" },
{ K_MOUSEDOWN, "ScrollWheelUp" },
{ K_MOUSEUP, "ScrollWheelDown" },
{ K_MOUSELEFT, "ScrollWheelRight" },
{ K_MOUSERIGHT, "ScrollWheelLeft" },
{ K_MOUSEDOWN, "MouseDown" }, // OBSOLETE: Use
{ K_MOUSEUP, "MouseUp" }, // ScrollWheelXXX instead
{ K_X1MOUSE, "X1Mouse" },
{ K_X1DRAG, "X1Drag" },
{ K_X1RELEASE, "X1Release" },
{ K_X2MOUSE, "X2Mouse" },
{ K_X2DRAG, "X2Drag" },
{ K_X2RELEASE, "X2Release" },
{ K_DROP, "Drop" },
{ K_ZERO, "Nul" },
{ K_SNR, "SNR" },
{ K_PLUG, "Plug" },
{ K_PASTE, "Paste" },
{ 0, NULL }
};
int get_special_key_code(const char_u *name)
{
for (int i = 0; key_names_table[i].name != NULL; i++) {
const char *const table_name = key_names_table[i].name;
int j;
for (j = 0; ascii_isident(name[j]) && table_name[j] != NUL; j++) {
if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) {
break;
}
}
if (!ascii_isident(name[j]) && table_name[j] == NUL) {
return key_names_table[i].key;
}
}
return 0;
}
static const struct modmasktable {
short mod_mask; ///< Bit-mask for particular key modifier.
short mod_flag; ///< Bit(s) for particular key modifier.
char_u name; ///< Single letter name of modifier.
} mod_mask_table[] = {
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'M'},
{MOD_MASK_META, MOD_MASK_META, (char_u)'T'},
{MOD_MASK_CTRL, MOD_MASK_CTRL, (char_u)'C'},
{MOD_MASK_SHIFT, MOD_MASK_SHIFT, (char_u)'S'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'},
{MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'},
// 'A' must be the last one
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'},
{0, 0, NUL}
};
int name_to_mod_mask(int c)
{
c = TOUPPER_ASC(c);
for (size_t i = 0; mod_mask_table[i].mod_mask != 0; i++) {
if (c == mod_mask_table[i].name) {
return mod_mask_table[i].mod_flag;
}
}
return 0;
}
static int extract_modifiers(int key, int *modp)
{
int modifiers = *modp;
if (!(modifiers & MOD_MASK_CMD)) { // Command-key is special
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) {
key = TOUPPER_ASC(key);
modifiers &= ~MOD_MASK_SHIFT;
}
}
if ((modifiers & MOD_MASK_CTRL)
&& ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) {
key = Ctrl_chr(key);
modifiers &= ~MOD_MASK_CTRL;
if (key == 0) { // <C-@> is <Nul>
key = K_ZERO;
}
}
*modp = modifiers;
return key;
}
int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
const bool keycode, const bool keep_x_key,
const bool in_string)
{
const char_u *last_dash;
const char_u *end_of_name;
const char_u *src;
const char_u *bp;
const char_u *const end = *srcp + src_len - 1;
int modifiers;
int bit;
int key;
uvarnumber_T n;
int l;
if (src_len == 0) {
return 0;
}
src = *srcp;
if (src[0] != '<') {
return 0;
}
// Find end of modifier list
last_dash = src;
for (bp = src + 1; bp <= end && (*bp == '-' || ascii_isident(*bp)); bp++) {
if (*bp == '-') {
last_dash = bp;
if (bp + 1 <= end) {
l = utfc_ptr2len_len(bp + 1, (int)(end - bp) + 1);
// Anything accepted, like <C-?>.
// <C-"> or <M-"> are not special in strings as " is
// the string delimiter. With a backslash it works: <M-\">
if (end - bp > l && !(in_string && bp[1] == '"') && bp[2] == '>') {
bp += l;
} else if (end - bp > 2 && in_string && bp[1] == '\\'
&& bp[2] == '"' && bp[3] == '>') {
bp += 2;
}
}
}
if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') {
bp += 3; // skip t_xx, xx may be '-' or '>'
} else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
bp += l + 5;
break;
}
}
if (bp <= end && *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) {
if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& ascii_isdigit(last_dash[6])) {
// <Char-123> or <Char-033> or <Char-0x33>
vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
key = (int)n;
} else {
int off = 1;
// Modifier with single letter, or special key name.
if (in_string && last_dash[1] == '\\' && last_dash[2] == '"') {
off = 2;
}
l = mb_ptr2len(last_dash + 1);
if (modifiers != 0 && last_dash[l + 1] == '>') {
key = PTR2CHAR(last_dash + off);
} else {
key = get_special_key_code(last_dash + off);
if (!keep_x_key) {
key = handle_x_keys(key);
}
}
}
// get_special_key_code() may return NUL for invalid
// special key name.
if (key != NUL) {
// Only use a modifier when there is no special key code that
// includes the modifier.
key = simplify_key(key, &modifiers);
if (!keycode) {
// don't want keycode, use single byte code
if (key == K_BS) {
key = BS;
} else if (key == K_DEL || key == K_KDEL) {
key = DEL;
}
}
// Normal Key with modifier:
// Try to make a single byte code (except for Alt/Meta modifiers).
if (!IS_SPECIAL(key)) {
key = extract_modifiers(key, &modifiers);
}
*modp = modifiers;
*srcp = end_of_name;
return key;
}
}
}
return 0;
}
char_u *add_char2buf(int c, char_u *s)
{
char_u temp[MB_MAXBYTES + 1];
const int len = utf_char2bytes(c, temp);
for (int i = 0; i < len; ++i) {
c = temp[i];
// Need to escape K_SPECIAL and CSI like in the typeahead buffer.
if (c == K_SPECIAL) {
*s++ = K_SPECIAL;
*s++ = KS_SPECIAL;
*s++ = KE_FILLER;
} else {
*s++ = c;
}
}
return s;
}
unsigned int trans_special(const char_u **srcp, const size_t src_len,
char_u *const dst, const bool keycode,
const bool in_string)
{
int modifiers = 0;
int key;
unsigned int dlen = 0;
key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string);
if (key == 0) {
return 0;
}
// Put the appropriate modifier in a string.
if (modifiers != 0) {
dst[dlen++] = K_SPECIAL;
dst[dlen++] = KS_MODIFIER;
dst[dlen++] = (char_u)modifiers;
}
if (IS_SPECIAL(key)) {
dst[dlen++] = K_SPECIAL;
dst[dlen++] = (char_u)KEY2TERMCAP0(key);
dst[dlen++] = KEY2TERMCAP1(key);
} else if (!keycode) {
dlen += (unsigned int)(*mb_char2bytes)(key, dst + dlen);
} else if (keycode) {
char_u *after = add_char2buf(key, dst + dlen);
assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX);
dlen = (unsigned int)(after - dst);
} else {
dst[dlen++] = (char_u)key;
}
return dlen;
}

View File

@@ -1,266 +0,0 @@
#include <stddef.h>
#include <inttypes.h>
#include <assert.h>
#include <stdbool.h>
#include "nvim/types.h"
#include "nvim/mbyte.h"
#include "nvim/ascii.h"
const uint8_t utf8len_tab_zero[] = {
//1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 2
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 4
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 6
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 8
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // A
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // C
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0, // E
};
const uint8_t utf8len_tab[] = {
// ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B?
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C?
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D?
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E?
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1, // F?
};
int utf_ptr2char(const char_u *const p)
{
if (p[0] < 0x80) { // Be quick for ASCII.
return p[0];
}
const uint8_t len = utf8len_tab_zero[p[0]];
if (len > 1 && (p[1] & 0xc0) == 0x80) {
if (len == 2) {
return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
}
if ((p[2] & 0xc0) == 0x80) {
if (len == 3) {
return (((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
+ (p[2] & 0x3f));
}
if ((p[3] & 0xc0) == 0x80) {
if (len == 4) {
return (((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
+ ((p[2] & 0x3f) << 6) + (p[3] & 0x3f));
}
if ((p[4] & 0xc0) == 0x80) {
if (len == 5) {
return (((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
+ ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
+ (p[4] & 0x3f));
}
if ((p[5] & 0xc0) == 0x80 && len == 6) {
return (((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
+ ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
+ ((p[4] & 0x3f) << 6) + (p[5] & 0x3f));
}
}
}
}
}
// Illegal value: just return the first byte.
return p[0];
}
bool utf_composinglike(const char_u *p1, const char_u *p2)
{
return false;
}
char_u *string_convert(const vimconv_T *conv, char_u *data, size_t *size)
{
return NULL;
}
int utf_ptr2len_len(const char_u *p, int size)
{
int len;
int i;
int m;
len = utf8len_tab[*p];
if (len == 1)
return 1; /* NUL, ascii or illegal lead byte */
if (len > size)
m = size; /* incomplete byte sequence. */
else
m = len;
for (i = 1; i < m; ++i)
if ((p[i] & 0xc0) != 0x80)
return 1;
return len;
}
int utfc_ptr2len_len(const char_u *p, int size)
{
int len;
int prevlen;
if (size < 1 || *p == NUL)
return 0;
if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) /* be quick for ASCII */
return 1;
/* Skip over first UTF-8 char, stopping at a NUL byte. */
len = utf_ptr2len_len(p, size);
/* Check for illegal byte and incomplete byte sequence. */
if ((len == 1 && p[0] >= 0x80) || len > size)
return 1;
/*
* Check for composing characters. We can handle only the first six, but
* skip all of them (otherwise the cursor would get stuck).
*/
prevlen = 0;
while (len < size) {
int len_next_char;
if (p[len] < 0x80)
break;
/*
* Next character length should not go beyond size to ensure that
* UTF_COMPOSINGLIKE(...) does not read beyond size.
*/
len_next_char = utf_ptr2len_len(p + len, size - len);
if (len_next_char > size - len)
break;
if (!UTF_COMPOSINGLIKE(p + prevlen, p + len))
break;
/* Skip over composing char */
prevlen = len;
len += len_next_char;
}
return len;
}
int utf_char2len(const int c)
{
if (c < 0x80) {
return 1;
} else if (c < 0x800) {
return 2;
} else if (c < 0x10000) {
return 3;
} else if (c < 0x200000) {
return 4;
} else if (c < 0x4000000) {
return 5;
} else {
return 6;
}
}
int utf_char2bytes(const int c, char_u *const buf)
{
if (c < 0x80) { // 7 bits
buf[0] = c;
return 1;
} else if (c < 0x800) { // 11 bits
buf[0] = 0xc0 + ((unsigned)c >> 6);
buf[1] = 0x80 + (c & 0x3f);
return 2;
} else if (c < 0x10000) { // 16 bits
buf[0] = 0xe0 + ((unsigned)c >> 12);
buf[1] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[2] = 0x80 + (c & 0x3f);
return 3;
} else if (c < 0x200000) { // 21 bits
buf[0] = 0xf0 + ((unsigned)c >> 18);
buf[1] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[3] = 0x80 + (c & 0x3f);
return 4;
} else if (c < 0x4000000) { // 26 bits
buf[0] = 0xf8 + ((unsigned)c >> 24);
buf[1] = 0x80 + (((unsigned)c >> 18) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[3] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[4] = 0x80 + (c & 0x3f);
return 5;
} else { // 31 bits
buf[0] = 0xfc + ((unsigned)c >> 30);
buf[1] = 0x80 + (((unsigned)c >> 24) & 0x3f);
buf[2] = 0x80 + (((unsigned)c >> 18) & 0x3f);
buf[3] = 0x80 + (((unsigned)c >> 12) & 0x3f);
buf[4] = 0x80 + (((unsigned)c >> 6) & 0x3f);
buf[5] = 0x80 + (c & 0x3f);
return 6;
}
}
int utf_ptr2len(const char_u *const p)
{
if (*p == NUL) {
return 0;
}
const int len = utf8len_tab[*p];
for (int i = 1; i < len; i++) {
if ((p[i] & 0xc0) != 0x80) {
return 1;
}
}
return len;
}
int utfc_ptr2len(const char_u *const p)
{
uint8_t b0 = (uint8_t)(*p);
if (b0 == NUL) {
return 0;
}
if (b0 < 0x80 && p[1] < 0x80) { // be quick for ASCII
return 1;
}
// Skip over first UTF-8 char, stopping at a NUL byte.
int len = utf_ptr2len(p);
// Check for illegal byte.
if (len == 1 && b0 >= 0x80) {
return 1;
}
// Check for composing characters. We can handle only the first six, but
// skip all of them (otherwise the cursor would get stuck).
int prevlen = 0;
for (;;) {
if (p[len] < 0x80 || !UTF_COMPOSINGLIKE(p + prevlen, p + len)) {
return len;
}
// Skip over composing char.
prevlen = len;
len += utf_ptr2len(p + len);
}
}
void mb_copy_char(const char_u **fp, char_u **tp)
{
const size_t l = utfc_ptr2len(*fp);
memmove(*tp, *fp, (size_t)l);
*tp += l;
*fp += l;
}

View File

@@ -1,101 +0,0 @@
#include <stdlib.h>
#include <assert.h>
#include "nvim/lib/ringbuf.h"
enum { RB_SIZE = 1024 };
typedef struct {
void *ptr;
size_t size;
} AllocRecord;
RINGBUF_TYPEDEF(AllocRecords, AllocRecord)
RINGBUF_INIT(AllocRecords, arecs, AllocRecord, RINGBUF_DUMMY_FREE)
RINGBUF_STATIC(static, AllocRecords, AllocRecord, arecs, RB_SIZE)
size_t allocated_memory = 0;
size_t ever_allocated_memory = 0;
size_t allocated_memory_limit = SIZE_MAX;
void *xmalloc(const size_t size)
{
void *ret = malloc(size);
allocated_memory += size;
ever_allocated_memory += size;
assert(allocated_memory <= allocated_memory_limit);
assert(arecs_rb_length(&arecs) < RB_SIZE);
arecs_rb_push(&arecs, (AllocRecord) {
.ptr = ret,
.size = size,
});
return ret;
}
void xfree(void *const p)
{
if (p == NULL) {
return;
}
RINGBUF_FORALL(&arecs, AllocRecord, arec) {
if (arec->ptr == p) {
allocated_memory -= arec->size;
arecs_rb_remove(&arecs, arecs_rb_find_idx(&arecs, arec));
return;
}
}
abort();
}
void *xrealloc(void *const p, size_t new_size)
{
void *ret = realloc(p, new_size);
RINGBUF_FORALL(&arecs, AllocRecord, arec) {
if (arec->ptr == p) {
allocated_memory -= arec->size;
allocated_memory += new_size;
if (new_size > arec->size) {
ever_allocated_memory += (new_size - arec->size);
}
arec->ptr = ret;
arec->size = new_size;
return ret;
}
}
abort();
return (void *)(intptr_t)1;
}
char *xstrdup(const char *str)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
FUNC_ATTR_NONNULL_ALL
{
return xmemdupz(str, strlen(str));
}
void *xmallocz(size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
{
size_t total_size = size + 1;
assert(total_size > size);
void *ret = xmalloc(total_size);
((char *)ret)[size] = 0;
return ret;
}
char *xstpcpy(char *restrict dst, const char *restrict src)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
const size_t len = strlen(src);
return (char *)memcpy(dst, src, len + 1) + len;
}
void *xmemdupz(const void *data, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
FUNC_ATTR_NONNULL_ALL
{
return memcpy(xmallocz(len), data, len);
}

View File

@@ -1,101 +0,0 @@
#!/bin/sh
set -e
set -x
test -z "$POSH_VERSION" && set -u
PROJECT_SOURCE_DIR=.
PROJECT_BINARY_DIR="$PROJECT_SOURCE_DIR/build"
KLEE_TEST_DIR="$PROJECT_SOURCE_DIR/test/symbolic/klee"
KLEE_BIN_DIR="$PROJECT_BINARY_DIR/klee"
KLEE_OUT_DIR="$KLEE_BIN_DIR/out"
help() {
echo "Usage:"
echo
echo " $0 -c fname"
echo " $0 fname"
echo " $0 -s"
echo
echo "First form compiles executable out of test/symbolic/klee/{fname}.c."
echo "Compiled executable is placed into build/klee/{fname}. Must first"
echo "successfully compile Neovim in order to generate declarations."
echo
echo "Second form runs KLEE in a docker container using file "
echo "test/symbolic/klee/{fname.c}. Bitcode is placed into build/klee/a.bc,"
echo "results are placed into build/klee/out/. The latter is first deleted if"
echo "it exists."
echo
echo "Third form runs ktest-tool which prints errors found by KLEE via "
echo "the same container used to run KLEE."
}
main() {
local compile=
local print_errs=
if test "$1" = "--help" ; then
help
return
fi
if test "$1" = "-s" ; then
print_errs=1
shift
elif test "$1" = "-c" ; then
compile=1
shift
fi
if test -z "$print_errs" ; then
local test="$1" ; shift
fi
local includes=
includes="$includes -I$KLEE_TEST_DIR"
includes="$includes -I/home/klee/klee_src/include"
includes="$includes -I$PROJECT_SOURCE_DIR/src"
includes="$includes -I$PROJECT_BINARY_DIR/src/nvim/auto"
includes="$includes -I$PROJECT_BINARY_DIR/include"
includes="$includes -I$PROJECT_BINARY_DIR/cmake.config"
includes="$includes -I/host-includes"
local defines=
defines="$defines -DINCLUDE_GENERATED_DECLARATIONS"
test -z "$compile" && defines="$defines -DUSE_KLEE"
test -d "$KLEE_BIN_DIR" || mkdir -p "$KLEE_BIN_DIR"
if test -z "$compile" ; then
local line1='cd /image'
if test -z "$print_errs" ; then
test -d "$KLEE_OUT_DIR" && rm -r "$KLEE_OUT_DIR"
line1="$line1 && $(echo clang \
$includes $defines \
-o "$KLEE_BIN_DIR/a.bc" -emit-llvm -g -c \
"$KLEE_TEST_DIR/$test.c")"
line1="$line1 && klee --libc=uclibc --posix-runtime "
line1="$line1 '--output-dir=$KLEE_OUT_DIR' '$KLEE_BIN_DIR/a.bc'"
fi
local line2="for t in '$KLEE_OUT_DIR'/*.err"
line2="$line2 ; do ktest-tool --write-ints"
line2="$line2 \"\$(printf '%s' \"\$t\" | sed -e 's@\\.[^/]*\$@.ktest@')\""
line2="$line2 ; done"
printf '%s\n%s\n' "$line1" "$line2" | \
docker run \
--volume "$(cd "$PROJECT_SOURCE_DIR" && pwd)":/image \
--volume "/usr/include":/host-includes \
--interactive \
--rm \
--ulimit='stack=-1:-1' \
klee/klee \
/bin/sh -x
else
clang \
$includes $defines \
-o "$KLEE_BIN_DIR/$test" \
-O0 -g \
"$KLEE_TEST_DIR/$test.c"
fi
}
main "$@"

View File

@@ -1,105 +0,0 @@
#ifdef USE_KLEE
# include <klee/klee.h>
#else
# include <string.h>
# include <stdio.h>
#endif
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/mbyte.h"
#include "nvim/memory.c"
#include "nvim/mbyte.c"
#include "nvim/charset.c"
#include "nvim/garray.c"
#include "nvim/gettext.c"
#include "nvim/keycodes.c"
#include "nvim/viml/parser/expressions.c"
#define INPUT_SIZE 7
uint8_t avoid_optimizing_out;
void simple_get_line(void *cookie, ParserLine *ret_pline)
{
ParserLine **plines_p = (ParserLine **)cookie;
*ret_pline = **plines_p;
(*plines_p)++;
}
int main(const int argc, const char *const *const argv,
const char *const *const environ)
{
char input[INPUT_SIZE];
uint8_t shift;
int flags;
avoid_optimizing_out = argc;
#ifndef USE_KLEE
sscanf(argv[2], "%d", &flags);
#endif
#ifdef USE_KLEE
klee_make_symbolic(input, sizeof(input), "input");
klee_make_symbolic(&shift, sizeof(shift), "shift");
klee_make_symbolic(&flags, sizeof(flags), "flags");
klee_assume(shift < INPUT_SIZE);
klee_assume(flags <= (kELFlagPeek|kELFlagAllowFloat|kELFlagForbidEOC
|kELFlagForbidScope|kELFlagIsNotCmp));
#endif
ParserLine plines[] = {
{
#ifdef USE_KLEE
.data = &input[shift],
.size = sizeof(input) - shift,
#else
.data = (const char *)argv[1],
.size = strlen(argv[1]),
#endif
.allocated = false,
},
{
.data = NULL,
.size = 0,
.allocated = false,
},
};
#ifdef USE_KLEE
assert(plines[0].size <= INPUT_SIZE);
assert((plines[0].data[0] != 5) | (plines[0].data[0] != argc));
#endif
ParserLine *cur_pline = &plines[0];
ParserState pstate = {
.reader = {
.get_line = simple_get_line,
.cookie = &cur_pline,
.lines = KV_INITIAL_VALUE,
.conv.vc_type = CONV_NONE,
},
.pos = { 0, 0 },
.colors = NULL,
.can_continuate = false,
};
kvi_init(pstate.reader.lines);
allocated_memory_limit = 0;
LexExprToken token = viml_pexpr_next_token(&pstate, flags);
if (flags & kELFlagPeek) {
assert(pstate.pos.line == 0 && pstate.pos.col == 0);
} else {
assert((pstate.pos.line == 0)
? (pstate.pos.col > 0)
: (pstate.pos.line == 1 && pstate.pos.col == 0));
}
assert(allocated_memory == 0);
assert(ever_allocated_memory == 0);
#ifndef USE_KLEE
fprintf(stderr, "tkn: %s\n", viml_pexpr_repr_token(&pstate, token, NULL));
#endif
}

View File

@@ -1,117 +0,0 @@
#ifdef USE_KLEE
# include <klee/klee.h>
#else
# include <string.h>
#endif
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/mbyte.h"
#include "nvim/memory.c"
#include "nvim/mbyte.c"
#include "nvim/charset.c"
#include "nvim/garray.c"
#include "nvim/gettext.c"
#include "nvim/viml/parser/expressions.c"
#include "nvim/keycodes.c"
#define INPUT_SIZE 50
uint8_t avoid_optimizing_out;
void simple_get_line(void *cookie, ParserLine *ret_pline)
{
ParserLine **plines_p = (ParserLine **)cookie;
*ret_pline = **plines_p;
(*plines_p)++;
}
int main(const int argc, const char *const *const argv,
const char *const *const environ)
{
char input[INPUT_SIZE];
uint8_t shift;
unsigned flags;
const bool peek = false;
avoid_optimizing_out = argc;
#ifndef USE_KLEE
sscanf(argv[2], "%d", &flags);
#endif
#ifdef USE_KLEE
klee_make_symbolic(input, sizeof(input), "input");
klee_make_symbolic(&shift, sizeof(shift), "shift");
klee_make_symbolic(&flags, sizeof(flags), "flags");
klee_assume(shift < INPUT_SIZE);
klee_assume(
flags <= (kExprFlagsMulti|kExprFlagsDisallowEOC|kExprFlagsParseLet));
#endif
ParserLine plines[] = {
{
#ifdef USE_KLEE
.data = &input[shift],
.size = sizeof(input) - shift,
#else
.data = argv[1],
.size = strlen(argv[1]),
#endif
.allocated = false,
},
{
.data = NULL,
.size = 0,
.allocated = false,
},
};
#ifdef USE_KLEE
assert(plines[0].size <= INPUT_SIZE);
assert((plines[0].data[0] != 5) | (plines[0].data[0] != argc));
#endif
ParserLine *cur_pline = &plines[0];
ParserHighlight colors;
kvi_init(colors);
ParserState pstate = {
.reader = {
.get_line = simple_get_line,
.cookie = &cur_pline,
.lines = KV_INITIAL_VALUE,
.conv.vc_type = CONV_NONE,
},
.pos = { 0, 0 },
.colors = &colors,
.can_continuate = false,
};
kvi_init(pstate.reader.lines);
const ExprAST ast = viml_pexpr_parse(&pstate, (int)flags);
assert(ast.root != NULL || ast.err.msg);
if (flags & kExprFlagsParseLet) {
assert(ast.err.msg != NULL
|| ast.root->type == kExprNodeAssignment
|| (ast.root->type == kExprNodeListLiteral
&& ast.root->children != NULL)
|| ast.root->type == kExprNodeComplexIdentifier
|| ast.root->type == kExprNodeCurlyBracesIdentifier
|| ast.root->type == kExprNodePlainIdentifier
|| ast.root->type == kExprNodeRegister
|| ast.root->type == kExprNodeEnvironment
|| ast.root->type == kExprNodeOption
|| ast.root->type == kExprNodeSubscript
|| ast.root->type == kExprNodeConcatOrSubscript);
}
// Cant possibly have more highlight tokens then there are bytes in string.
assert(kv_size(colors) <= INPUT_SIZE - shift);
kvi_destroy(colors);
// Not destroying pstate.reader.lines because there is no way it could exceed
// its limits in the current circumstances.
viml_pexpr_free_ast(ast);
assert(allocated_memory == 0);
}

View File

@@ -349,7 +349,7 @@ local special_vals = nil
lua2typvalt = function(l, processed)
if not special_vals then
special_vals = {
[null_string] = {'VAR_STRING', {v_string=ffi.cast('char_u*', nil)}},
[null_string] = {'VAR_STRING', {v_string=ffi.cast('char*', nil)}},
[null_list] = {'VAR_LIST', {v_list=ffi.cast('list_T*', nil)}},
[null_dict] = {'VAR_DICT', {v_dict=ffi.cast('dict_T*', nil)}},
[nil_value] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarNull}},

View File

@@ -12,7 +12,7 @@ describe('trunc_string', function()
local buflen = 40
local function test_inplace(s, expected, room)
room = room and room or 20
local buf = cimp.xmalloc(ffi.sizeof('char_u') * buflen)
local buf = cimp.xmalloc(ffi.sizeof('char') * buflen)
ffi.C.strcpy(buf, s)
cimp.trunc_string(buf, buf, room, buflen)
eq(expected, ffi.string(buf))
@@ -21,7 +21,7 @@ describe('trunc_string', function()
local function test_copy(s, expected, room)
room = room and room or 20
local buf = cimp.xmalloc(ffi.sizeof('char_u') * buflen)
local buf = cimp.xmalloc(ffi.sizeof('char') * buflen)
local str = cimp.xstrdup(to_cstr(s))
cimp.trunc_string(str, buf, room, buflen)
eq(expected, ffi.string(buf))

View File

@@ -37,7 +37,7 @@ child_call_once(function()
-- requires refactor of UNDO_HASH_SIZE into constant/enum for ffi
--
-- compute a hash for this undofile
buffer_hash = ffi.new('char_u[32]')
buffer_hash = ffi.new('char[32]')
undo.u_compute_hash(file_buffer, buffer_hash)
end)