Merge #3916 "Add support for binary numbers".

This commit is contained in:
Justin M. Keyes 2016-01-20 23:46:31 -05:00
commit 9eb6a44564
17 changed files with 844 additions and 533 deletions

View File

@ -371,8 +371,10 @@ CTRL-X Subtract [count] from the number or alphabetic
character at or after the cursor.
The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
octal and hexadecimal numbers and alphabetic characters. This depends on the
'nrformats' option.
binary/octal/hexadecimal numbers and alphabetic characters. This
depends on the 'nrformats' option.
- When 'nrformats' includes "bin", Vim considers numbers starting with '0b' or
'0B' as binary.
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
to be octal, unless the number includes a '8' or '9'. Other numbers are
decimal and may have a preceding minus sign.
@ -386,6 +388,10 @@ octal and hexadecimal numbers and alphabetic characters. This depends on the
under or after the cursor. This is useful to make lists with an alphabetic
index.
For decimals a leading negative sign is considered for incrementing or
decrementing, for binary and octal and hex values, it won't be considered. To
ignore the sign Visually select the number before using CTRL-A or CTRL-X.
For numbers with leading zeros (including all octal and hexadecimal numbers),
Vim preserves the number of characters in the number when possible. CTRL-A on
"0077" results in "0100", CTRL-X on "0x100" results in "0x0ff".
@ -397,6 +403,10 @@ octal number.
Note that when 'nrformats' includes "octal", decimal numbers with leading
zeros cause mistakes, because they can be confused with octal numbers.
Note similarly, when 'nrformats' includes "bin", binary numbers with a leading
'0x' or '0X' can be interpreted as hexadecimal rather than binary since '0b'
are valid hexadecimal digits.
The CTRL-A command is very useful in a macro. Example: Use the following
steps to make a numbered list.
@ -1602,7 +1612,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|.
*:sor* *:sort*
:[range]sor[t][!] [i][u][r][n][x][o] [/{pattern}/]
:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
Sort lines in [range]. When no range is given all
lines are sorted.
@ -1622,6 +1632,9 @@ found here: |sort()|, |uniq()|.
With [o] sorting is done on the first octal number in
the line (after or inside a {pattern} match).
With [b] sorting is done on the first binary number in
the line (after or inside a {pattern} match).
With [u] only keep the first of a sequence of
identical lines (ignoring case when [i] is used).
Without this flag, a sequence of identical lines

View File

@ -65,14 +65,16 @@ the Number. Examples:
Number 0 --> String "0" ~
Number -1 --> String "-1" ~
*octal*
Conversion from a String to a Number is done by converting the first digits
to a number. Hexadecimal "0xf9" and Octal "017" numbers are recognized. If
the String doesn't start with digits, the result is zero. Examples:
Conversion from a String to a Number is done by converting the first digits to
a number. Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
recognized. If the String doesn't start with digits, the result is zero.
Examples:
String "456" --> Number 456 ~
String "6bar" --> Number 6 ~
String "foo" --> Number 0 ~
String "0xf1" --> Number 241 ~
String "0100" --> Number 64 ~
String "0b101" --> Number 5 ~
String "-8" --> Number -8 ~
String "+8" --> Number 0 ~
@ -4919,6 +4921,9 @@ printf({fmt}, {expr1} ...) *printf()*
%c single byte
%d decimal number
%5d decimal number padded with spaces to 5 characters
%b binary number
%08b binary number padded with zeros to at least 8 characters
%B binary number using upper case letters
%x hex number
%04x hex number padded with zeros to at least 4 characters
%X hex number using upper case letters
@ -5005,20 +5010,19 @@ printf({fmt}, {expr1} ...) *printf()*
The conversion specifiers and their meanings are:
*printf-d* *printf-o* *printf-x* *printf-X*
doxX The Number argument is converted to signed decimal
(d), unsigned octal (o), or unsigned hexadecimal (x
and X) notation. The letters "abcdef" are used for
x conversions; the letters "ABCDEF" are used for X
conversions.
The precision, if any, gives the minimum number of
digits that must appear; if the converted value
requires fewer digits, it is padded on the left with
zeros.
In no case does a non-existent or small field width
cause truncation of a numeric field; if the result of
a conversion is wider than the field width, the field
is expanded to contain the conversion result.
*printf-d* *printf-b* *printf-B* *printf-o* *printf-x* *printf-X*
dbBoxX The Number argument is converted to signed decimal (d),
unsigned binary (b and B), unsigned octal (o), or
unsigned hexadecimal (x and X) notation. The letters
"abcdef" are used for x conversions; the letters
"ABCDEF" are used for X conversions. The precision, if
any, gives the minimum number of digits that must
appear; if the converted value requires fewer digits, it
is padded on the left with zeros. In no case does a
non-existent or small field width cause truncation of a
numeric field; if the result of a conversion is wider
than the field width, the field is expanded to contain
the conversion result.
*printf-c*
c The Number argument is converted to a byte, and the
@ -6134,12 +6138,14 @@ str2float( {expr}) *str2float()*
str2nr( {expr} [, {base}]) *str2nr()*
Convert string {expr} to a number.
{base} is the conversion base, it can be 8, 10 or 16.
{base} is the conversion base, it can be 2, 8, 10 or 16.
When {base} is omitted base 10 is used. This also means that
a leading zero doesn't cause octal conversion to be used, as
with the default String to Number conversion.
When {base} is 16 a leading "0x" or "0X" is ignored. With a
different base the result will be zero.
different base the result will be zero. Similarly, when {base}
is 8 a leading "0" is ignored, and when {base} is 2 a leading
"0b" or "0B" is ignored.
Text after the number is silently ignored.

View File

@ -85,10 +85,25 @@
# define PATHSEPSTR "/"
#endif
static inline bool ascii_iswhite(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
static inline bool ascii_isdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
static inline bool ascii_isxdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
static inline bool ascii_isspace(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
static inline bool ascii_iswhite(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isdigit(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isxdigit(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isbdigit(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isspace(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
/// Checks if `c` is a space or tab character.
///
@ -122,6 +137,14 @@ static inline bool ascii_isxdigit(int c)
|| (c >= 'A' && c <= 'F');
}
/// Checks if `c` is a binary digit, that is, 0-1.
///
/// @see {ascii_isdigit}
static inline bool ascii_isbdigit(int c)
{
return (c == '0' || c == '1');
}
/// Checks if `c` is a white-space character, that is,
/// one of \f, \n, \r, \t, \v.
///

View File

@ -1454,6 +1454,24 @@ char_u* skipdigits(char_u *q)
return p;
}
/// skip over binary digits
///
/// @param q pointer to string
///
/// @return Pointer to the character after the skipped digits.
const char* skipbin(const char *q)
FUNC_ATTR_PURE
FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
{
const char *p = q;
while (ascii_isbdigit(*p)) {
// skip to next non-digit
p++;
}
return p;
}
/// skip over digits and hex characters
///
/// @param q
@ -1485,6 +1503,24 @@ char_u* skiptodigit(char_u *q)
return p;
}
/// skip to binary character (or NUL after the string)
///
/// @param q pointer to string
///
/// @return Pointer to the binary character or (NUL after the string).
const char* skiptobin(const char *q)
FUNC_ATTR_PURE
FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
{
const char *p = q;
while (*p != NUL && !ascii_isbdigit(*p)) {
// skip to next digit
p++;
}
return p;
}
/// skip to hex character (or NUL after the string)
///
/// @param q
@ -1720,67 +1756,77 @@ int vim_isblankline(char_u *lbuf)
}
/// Convert a string into a long and/or unsigned long, taking care of
/// hexadecimal and octal numbers. Accepts a '-' sign.
/// If "hexp" is not NULL, returns a flag to indicate the type of the number:
/// hexadecimal, octal and binary numbers. Accepts a '-' sign.
/// If "prep" is not NULL, returns a flag to indicate the type of the number:
/// 0 decimal
/// '0' octal
/// 'B' bin
/// 'b' bin
/// 'X' hex
/// 'x' hex
/// If "len" is not NULL, the length of the number in characters is returned.
/// If "nptr" is not NULL, the signed result is returned in it.
/// If "unptr" is not NULL, the unsigned result is returned in it.
/// If "dobin" is non-zero recognize binary numbers, when > 1 always assume
/// binary number.
/// If "dooct" is non-zero recognize octal numbers, when > 1 always assume
/// octal number.
/// If "dohex" is non-zero recognize hex numbers, when > 1 always assume
/// hex number.
///
/// @param start
/// @param hexp Returns type of number 0 = decimal, 'x' or 'X' is hex,
// '0' = octal
/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
// '0' = octal, 'b' or 'B' is bin
/// @param len Returns the detected length of number.
/// @param dobin recognize binary number
/// @param dooct recognize octal number
/// @param dohex recognize hex number
/// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result.
void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
void vim_str2nr(char_u *start, int *prep, int *len,
int dobin, int dooct, int dohex,
long *nptr, unsigned long *unptr)
{
char_u *ptr = start;
int hex = 0; // default is decimal
int negative = FALSE;
int pre = 0; // default is decimal
int negative = false;
unsigned long un = 0;
int n;
if (ptr[0] == '-') {
negative = TRUE;
++ptr;
negative = true;
ptr++;
}
// Recognize hex and octal.
// Recognize hex, octal, and bin.
if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) {
hex = ptr[1];
pre = ptr[1];
if (dohex
&& ((hex == 'X') || (hex == 'x'))
&& ((pre == 'X') || (pre == 'x'))
&& ascii_isxdigit(ptr[2])) {
// hexadecimal
ptr += 2;
} else if (dobin
&& ((pre == 'B') || (pre == 'b'))
&& ascii_isbdigit(ptr[2])) {
// binary
ptr += 2;
} else {
// default is decimal
hex = 0;
pre = 0;
if (dooct) {
// Don't interpret "0", "08" or "0129" as octal.
for (n = 1; ascii_isdigit(ptr[n]); ++n) {
if (ptr[n] > '7') {
// can't be octal
hex = 0;
pre = 0;
break;
}
if (ptr[n] >= '0') {
// assume octal
hex = '0';
pre = '0';
}
}
}
@ -1788,14 +1834,26 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
if ((hex == '0') || (dooct > 1)) {
if ((pre == 'B') || (pre == 'b') || (dobin > 1)) {
// bin
if (pre != 0) {
n += 2; // skip over "0b"
}
while ('0' <= *ptr && *ptr <= '1') {
un = 2 * un + (unsigned long)(*ptr - '0');
ptr++;
}
} else if ((pre == '0') || (dooct > 1)) {
// octal
while ('0' <= *ptr && *ptr <= '7') {
un = 8 * un + (unsigned long)(*ptr - '0');
ptr++;
}
} else if ((hex != 0) || (dohex > 1)) {
} else if (pre != 0 || dohex > 1) {
// hex
if (pre != 0) {
n += 2; // skip over "0x"
}
while (ascii_isxdigit(*ptr)) {
un = 16 * un + (unsigned long)hex2nr(*ptr);
ptr++;
@ -1808,8 +1866,8 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
}
}
if (hexp != NULL) {
*hexp = hex;
if (prep != NULL) {
*prep = pre;
}
if (len != NULL) {

View File

@ -1113,19 +1113,17 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd)
}
/*
* Call some vimL function and return the result in "*rettv".
* Uses argv[argc] for the function arguments. Only Number and String
* arguments are currently supported.
* Returns OK or FAIL.
*/
int
call_vim_function (
// Call some vimL function and return the result in "*rettv".
// Uses argv[argc] for the function arguments. Only Number and String
// arguments are currently supported.
//
// Return OK or FAIL.
int call_vim_function(
char_u *func,
int argc,
char_u **argv,
int safe, /* use the sandbox */
int str_arg_only, /* all arguments are strings */
int safe, // use the sandbox
int str_arg_only, // all arguments are strings
typval_T *rettv
)
{
@ -1138,18 +1136,19 @@ call_vim_function (
typval_T *argvars = xmalloc((argc + 1) * sizeof(typval_T));
for (int i = 0; i < argc; i++) {
/* Pass a NULL or empty argument as an empty string */
// Pass a NULL or empty argument as an empty string
if (argv[i] == NULL || *argv[i] == NUL) {
argvars[i].v_type = VAR_STRING;
argvars[i].vval.v_string = (char_u *)"";
continue;
}
if (str_arg_only)
if (str_arg_only) {
len = 0;
else
/* Recognize a number argument, the others must be strings. */
vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL);
} else {
// Recognize a number argument, the others must be strings.
vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL);
}
if (len != 0 && len == (int)STRLEN(argv[i])) {
argvars[i].v_type = VAR_NUMBER;
argvars[i].vval.v_number = n;
@ -1166,16 +1165,17 @@ call_vim_function (
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, TRUE, NULL);
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL);
if (safe) {
--sandbox;
restore_funccal(save_funccalp);
}
xfree(argvars);
if (ret == FAIL)
if (ret == FAIL) {
clear_tv(rettv);
}
return ret;
}
@ -4025,38 +4025,35 @@ eval6 (
return OK;
}
/*
* Handle sixth level expression:
* number number constant
* "string" string constant
* 'string' literal string constant
* &option-name option value
* @r register contents
* identifier variable value
* function() function call
* $VAR environment variable
* (expression) nested expression
* [expr, expr] List
* {key: val, key: val} Dictionary
*
* Also handle:
* ! in front logical NOT
* - in front unary minus
* + in front unary plus (ignored)
* trailing [] subscript in String or List
* trailing .name entry in Dictionary
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
*
* Return OK or FAIL.
*/
static int
eval7 (
// Handle sixth level expression:
// number number constant
// "string" string constant
// 'string' literal string constant
// &option-name option value
// @r register contents
// identifier variable value
// function() function call
// $VAR environment variable
// (expression) nested expression
// [expr, expr] List
// {key: val, key: val} Dictionary
//
// Also handle:
// ! in front logical NOT
// - in front unary minus
// + in front unary plus (ignored)
// trailing [] subscript in String or List
// trailing .name entry in Dictionary
//
// "arg" must point to the first non-white of the expression.
// "arg" is advanced to the next non-white after the recognized expression.
//
// Return OK or FAIL.
static int eval7(
char_u **arg,
typval_T *rettv,
int evaluate,
int want_string /* after "." operator */
int want_string // after "." operator
)
{
long n;
@ -4066,24 +4063,19 @@ eval7 (
int ret = OK;
char_u *alias;
/*
* Initialise variable so that clear_tv() can't mistake this for a
* string and free a string that isn't there.
*/
// Initialise variable so that clear_tv() can't mistake this for a
// string and free a string that isn't there.
rettv->v_type = VAR_UNKNOWN;
/*
* Skip '!' and '-' characters. They are handled later.
*/
// Skip '!' and '-' characters. They are handled later.
start_leader = *arg;
while (**arg == '!' || **arg == '-' || **arg == '+')
while (**arg == '!' || **arg == '-' || **arg == '+') {
*arg = skipwhite(*arg + 1);
}
end_leader = *arg;
switch (**arg) {
/*
* Number constant.
*/
// Number constant.
case '0':
case '1':
case '2':
@ -4096,27 +4088,30 @@ eval7 (
case '9':
{
char_u *p = skipdigits(*arg + 1);
int get_float = FALSE;
int get_float = false;
/* We accept a float when the format matches
* "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
* strict to avoid backwards compatibility problems.
* Don't look for a float after the "." operator, so that
* ":let vers = 1.2.3" doesn't fail. */
// We accept a float when the format matches
// "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
// strict to avoid backwards compatibility problems.
// Don't look for a float after the "." operator, so that
// ":let vers = 1.2.3" doesn't fail.
if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
get_float = TRUE;
get_float = true;
p = skipdigits(p + 2);
if (*p == 'e' || *p == 'E') {
++p;
if (*p == '-' || *p == '+')
if (*p == '-' || *p == '+') {
++p;
if (!ascii_isdigit(*p))
get_float = FALSE;
else
}
if (!ascii_isdigit(*p)) {
get_float = false;
} else {
p = skipdigits(p + 1);
}
}
if (ASCII_ISALPHA(*p) || *p == '.') {
get_float = false;
}
if (ASCII_ISALPHA(*p) || *p == '.')
get_float = FALSE;
}
if (get_float) {
float_T f;
@ -4127,7 +4122,7 @@ eval7 (
rettv->vval.v_float = f;
}
} else {
vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL);
vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL);
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@ -4137,62 +4132,47 @@ eval7 (
break;
}
/*
* String constant: "string".
*/
// String constant: "string".
case '"': ret = get_string_tv(arg, rettv, evaluate);
break;
/*
* Literal string constant: 'str''ing'.
*/
// Literal string constant: 'str''ing'.
case '\'': ret = get_lit_string_tv(arg, rettv, evaluate);
break;
/*
* List: [expr, expr]
*/
// List: [expr, expr]
case '[': ret = get_list_tv(arg, rettv, evaluate);
break;
/*
* Dictionary: {key: val, key: val}
*/
// Dictionary: {key: val, key: val}
case '{': ret = get_dict_tv(arg, rettv, evaluate);
break;
/*
* Option value: &name
*/
// Option value: &name
case '&': ret = get_option_tv(arg, rettv, evaluate);
break;
/*
* Environment variable: $VAR.
*/
// Environment variable: $VAR.
case '$': ret = get_env_tv(arg, rettv, evaluate);
break;
/*
* Register contents: @r.
*/
// Register contents: @r.
case '@': ++*arg;
if (evaluate) {
rettv->v_type = VAR_STRING;
rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc);
}
if (**arg != NUL)
if (**arg != NUL) {
++*arg;
}
break;
/*
* nested expression: (expression).
*/
// nested expression: (expression).
case '(': *arg = skipwhite(*arg + 1);
ret = eval1(arg, rettv, evaluate); /* recursive! */
if (**arg == ')')
ret = eval1(arg, rettv, evaluate); // recursive!
if (**arg == ')') {
++*arg;
else if (ret == OK) {
} else if (ret == OK) {
EMSG(_("E110: Missing ')'"));
clear_tv(rettv);
ret = FAIL;
@ -4204,71 +4184,72 @@ eval7 (
}
if (ret == NOTDONE) {
/*
* Must be a variable or function name.
* Can also be a curly-braces kind of name: {expr}.
*/
// Must be a variable or function name.
// Can also be a curly-braces kind of name: {expr}.
s = *arg;
len = get_name_len(arg, &alias, evaluate, TRUE);
if (alias != NULL)
len = get_name_len(arg, &alias, evaluate, true);
if (alias != NULL) {
s = alias;
}
if (len <= 0)
if (len <= 0) {
ret = FAIL;
else {
if (**arg == '(') { /* recursive! */
/* If "s" is the name of a variable of type VAR_FUNC
* use its contents. */
} else {
if (**arg == '(') { // recursive!
// If "s" is the name of a variable of type VAR_FUNC
// use its contents.
s = deref_func_name(s, &len, !evaluate);
/* Invoke the function. */
// Invoke the function.
ret = get_func_tv(s, len, rettv, arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, NULL);
/* If evaluate is FALSE rettv->v_type was not set in
* get_func_tv, but it's needed in handle_subscript() to parse
* what follows. So set it here. */
// If evaluate is false rettv->v_type was not set in
// get_func_tv, but it's needed in handle_subscript() to parse
// what follows. So set it here.
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
rettv->vval.v_string = empty_string;
rettv->v_type = VAR_FUNC;
}
/* Stop the expression evaluation when immediately
* aborting on error, or when an interrupt occurred or
* an exception was thrown but not caught. */
// Stop the expression evaluation when immediately
// aborting on error, or when an interrupt occurred or
// an exception was thrown but not caught.
if (aborting()) {
if (ret == OK)
if (ret == OK) {
clear_tv(rettv);
}
ret = FAIL;
}
} else if (evaluate)
ret = get_var_tv(s, len, rettv, TRUE, FALSE);
else
} else if (evaluate) {
ret = get_var_tv(s, len, rettv, true, false);
} else {
ret = OK;
}
}
xfree(alias);
}
*arg = skipwhite(*arg);
/* Handle following '[', '(' and '.' for expr[expr], expr.name,
* expr(expr). */
if (ret == OK)
ret = handle_subscript(arg, rettv, evaluate, TRUE);
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr).
if (ret == OK) {
ret = handle_subscript(arg, rettv, evaluate, true);
}
/*
* Apply logical NOT and unary '-', from right to left, ignore '+'.
*/
// Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
int error = FALSE;
int error = false;
int val = 0;
float_T f = 0.0;
if (rettv->v_type == VAR_FLOAT)
if (rettv->v_type == VAR_FLOAT) {
f = rettv->vval.v_float;
else
} else {
val = get_tv_number_chk(rettv, &error);
}
if (error) {
clear_tv(rettv);
ret = FAIL;
@ -4276,15 +4257,17 @@ eval7 (
while (end_leader > start_leader) {
--end_leader;
if (*end_leader == '!') {
if (rettv->v_type == VAR_FLOAT)
if (rettv->v_type == VAR_FLOAT) {
f = !f;
else
} else {
val = !val;
}
} else if (*end_leader == '-') {
if (rettv->v_type == VAR_FLOAT)
if (rettv->v_type == VAR_FLOAT) {
f = -f;
else
} else {
val = -val;
}
}
}
if (rettv->v_type == VAR_FLOAT) {
@ -15998,9 +15981,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_FLOAT;
}
/*
* "str2nr()" function
*/
// "str2nr()" function
static void f_str2nr(typval_T *argvars, typval_T *rettv)
{
int base = 10;
@ -16009,16 +15990,21 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN) {
base = get_tv_number(&argvars[1]);
if (base != 8 && base != 10 && base != 16) {
if (base != 2 && base != 8 && base != 10 && base != 16) {
EMSG(_(e_invarg));
return;
}
}
p = skipwhite(get_tv_string(&argvars[0]));
if (*p == '+')
if (*p == '+') {
p = skipwhite(p + 1);
vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL);
}
vim_str2nr(p, NULL, NULL,
base == 2 ? 2 : 0,
base == 8 ? 2 : 0,
base == 16 ? 2 : 0,
&n, NULL);
rettv->vval.v_number = n;
}
@ -18298,9 +18284,10 @@ long get_tv_number_chk(typval_T *varp, int *denote)
EMSG(_("E703: Using a Funcref as a Number"));
break;
case VAR_STRING:
if (varp->vval.v_string != NULL)
if (varp->vval.v_string != NULL) {
vim_str2nr(varp->vval.v_string, NULL, NULL,
TRUE, TRUE, &n, NULL);
true, true, true, &n, NULL);
}
return n;
case VAR_LIST:
EMSG(_("E745: Using a List as a Number"));
@ -18312,10 +18299,12 @@ long get_tv_number_chk(typval_T *varp, int *denote)
EMSG2(_(e_intern2), "get_tv_number()");
break;
}
if (denote == NULL) /* useful for values that must be unsigned */
if (denote == NULL) {
// useful for values that must be unsigned
n = -1;
else
*denote = TRUE;
} else {
*denote = true;
}
return n;
}

View File

@ -329,9 +329,7 @@ static int sort_compare(const void *s1, const void *s2)
return result;
}
/*
* ":sort".
*/
// ":sort".
void ex_sort(exarg_T *eap)
{
regmatch_T regmatch;
@ -343,17 +341,19 @@ void ex_sort(exarg_T *eap)
char_u *p;
char_u *s;
char_u *s2;
char_u c; /* temporary character storage */
int unique = FALSE;
char_u c; // temporary character storage
int unique = false;
long deleted;
colnr_T start_col;
colnr_T end_col;
int sort_oct; /* sort on octal number */
int sort_hex; /* sort on hex number */
int sort_bin; // sort on bin number
int sort_oct; // sort on octal number
int sort_hex; // sort on hex number
/* Sorting one line is really quick! */
if (count <= 1)
// Sorting one line is really quick!
if (count <= 1) {
return;
}
if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
return;
@ -362,47 +362,51 @@ void ex_sort(exarg_T *eap)
regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;
sort_abort = sort_ic = sort_rx = sort_nr = sort_bin = sort_oct = sort_hex = 0;
for (p = eap->arg; *p != NUL; ++p) {
if (ascii_iswhite(*p))
;
else if (*p == 'i')
sort_ic = TRUE;
else if (*p == 'r')
sort_rx = TRUE;
else if (*p == 'n')
if (ascii_iswhite(*p)) {
} else if (*p == 'i') {
sort_ic = true;
} else if (*p == 'r') {
sort_rx = true;
} else if (*p == 'n') {
sort_nr = 2;
else if (*p == 'o')
} else if (*p == 'b') {
sort_bin = 2;
} else if (*p == 'o') {
sort_oct = 2;
else if (*p == 'x')
} else if (*p == 'x') {
sort_hex = 2;
else if (*p == 'u')
unique = TRUE;
else if (*p == '"') /* comment start */
} else if (*p == 'u') {
unique = true;
} else if (*p == '"') {
// comment start
break;
else if (check_nextcmd(p) != NULL) {
} else if (check_nextcmd(p) != NULL) {
eap->nextcmd = check_nextcmd(p);
break;
} else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) {
s = skip_regexp(p + 1, *p, TRUE, NULL);
s = skip_regexp(p + 1, *p, true, NULL);
if (*s != *p) {
EMSG(_(e_invalpat));
goto sortend;
}
*s = NUL;
/* Use last search pattern if sort pattern is empty. */
// Use last search pattern if sort pattern is empty.
if (s == p + 1) {
if (last_search_pat() == NULL) {
EMSG(_(e_noprevre));
goto sortend;
}
regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
} else
} else {
regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
if (regmatch.regprog == NULL)
}
if (regmatch.regprog == NULL) {
goto sortend;
p = s; /* continue after the regexp */
}
p = s; // continue after the regexp
regmatch.rm_ic = p_ic;
} else {
EMSG2(_(e_invarg2), p);
@ -410,28 +414,27 @@ void ex_sort(exarg_T *eap)
}
}
/* Can only have one of 'n', 'o' and 'x'. */
if (sort_nr + sort_oct + sort_hex > 2) {
// Can only have one of 'n', 'b', 'o' and 'x'.
if (sort_nr + sort_bin + sort_oct + sort_hex > 2) {
EMSG(_(e_invarg));
goto sortend;
}
/* From here on "sort_nr" is used as a flag for any number sorting. */
sort_nr += sort_oct + sort_hex;
// From here on "sort_nr" is used as a flag for any number sorting.
sort_nr += sort_bin + sort_oct + sort_hex;
/*
* Make an array with all line numbers. This avoids having to copy all
* the lines into allocated memory.
* When sorting on strings "start_col_nr" is the offset in the line, for
* numbers sorting it's the number to sort on. This means the pattern
* matching and number conversion only has to be done once per line.
* Also get the longest line length for allocating "sortbuf".
*/
// Make an array with all line numbers. This avoids having to copy all
// the lines into allocated memory.
// When sorting on strings "start_col_nr" is the offset in the line, for
// numbers sorting it's the number to sort on. This means the pattern
// matching and number conversion only has to be done once per line.
// Also get the longest line length for allocating "sortbuf".
for (lnum = eap->line1; lnum <= eap->line2; ++lnum) {
s = ml_get(lnum);
len = (int)STRLEN(s);
if (maxlen < len)
if (maxlen < len) {
maxlen = len;
}
start_col = 0;
end_col = len;
@ -439,34 +442,41 @@ void ex_sort(exarg_T *eap)
if (sort_rx) {
start_col = (colnr_T)(regmatch.startp[0] - s);
end_col = (colnr_T)(regmatch.endp[0] - s);
} else
} else {
start_col = (colnr_T)(regmatch.endp[0] - s);
} else if (regmatch.regprog != NULL)
}
} else if (regmatch.regprog != NULL) {
end_col = 0;
}
if (sort_nr) {
/* Make sure vim_str2nr doesn't read any digits past the end
* of the match, by temporarily terminating the string there */
// Make sure vim_str2nr doesn't read any digits past the end
// of the match, by temporarily terminating the string there
s2 = s + end_col;
c = *s2;
*s2 = NUL;
/* Sorting on number: Store the number itself. */
// Sorting on number: Store the number itself.
p = s + start_col;
if (sort_hex)
if (sort_hex) {
s = skiptohex(p);
else
} else if (sort_bin) {
s = (char_u*) skiptobin((char*) p);
} else {
s = skiptodigit(p);
if (s > p && s[-1] == '-')
--s; /* include preceding negative sign */
if (*s == NUL)
/* empty line should sort before any number */
}
if (s > p && s[-1] == '-') {
--s; // include preceding negative sign
}
if (*s == NUL) {
// empty line should sort before any number
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
else
vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,
&nrs[lnum - eap->line1].start_col_nr, NULL);
} else {
vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex,
&nrs[lnum - eap->line1].start_col_nr, NULL);
}
*s2 = c;
} else {
/* Store the column to sort at. */
// Store the column to sort at.
nrs[lnum - eap->line1].start_col_nr = start_col;
nrs[lnum - eap->line1].end_col_nr = end_col;
}
@ -479,17 +489,17 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
/* Allocate a buffer that can hold the longest line. */
// Allocate a buffer that can hold the longest line.
sortbuf1 = xmalloc(maxlen + 1);
sortbuf2 = xmalloc(maxlen + 1);
/* Sort the array of line numbers. Note: can't be interrupted! */
// Sort the array of line numbers. Note: can't be interrupted!
qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
if (sort_abort)
goto sortend;
/* Insert the lines in the sorted order below the last one. */
// Insert the lines in the sorted order below the last one.
lnum = eap->line2;
for (i = 0; i < count; ++i) {
s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum);
@ -507,19 +517,22 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
/* delete the original lines if appending worked */
if (i == count)
for (i = 0; i < count; ++i)
ml_delete(eap->line1, FALSE);
else
// delete the original lines if appending worked
if (i == count) {
for (i = 0; i < count; ++i) {
ml_delete(eap->line1, false);
}
} else {
count = 0;
}
/* Adjust marks for deleted (or added) lines and prepare for displaying. */
// Adjust marks for deleted (or added) lines and prepare for displaying.
deleted = (long)(count - (lnum - eap->line2));
if (deleted > 0)
if (deleted > 0) {
mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
else if (deleted < 0)
} else if (deleted < 0) {
mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
}
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
curwin->w_cursor.lnum = eap->line1;
@ -530,8 +543,9 @@ sortend:
xfree(sortbuf1);
xfree(sortbuf2);
vim_regfree(regmatch.regprog);
if (got_int)
if (got_int) {
EMSG(_(e_interr));
}
}
/*

View File

@ -4767,35 +4767,40 @@ int del_history_idx(int histype, int idx)
return TRUE;
}
/*
* Get indices "num1,num2" that specify a range within a list (not a range of
* text lines in a buffer!) from a string. Used for ":history" and ":clist".
* Returns OK if parsed successfully, otherwise FAIL.
*/
/// Get indices that specify a range within a list (not a range of text lines
/// in a buffer!) from a string. Used for ":history" and ":clist".
///
/// @param str string to parse range from
/// @param num1 from
/// @param num2 to
///
/// @return OK if parsed successfully, otherwise FAIL.
int get_list_range(char_u **str, int *num1, int *num2)
{
int len;
int first = FALSE;
int first = false;
long num;
*str = skipwhite(*str);
if (**str == '-' || ascii_isdigit(**str)) { /* parse "from" part of range */
vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
*str += len;
*num1 = (int)num;
first = TRUE;
first = true;
}
*str = skipwhite(*str);
if (**str == ',') { /* parse "to" part of range */
if (**str == ',') { // parse "to" part of range
*str = skipwhite(*str + 1);
vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
if (len > 0) {
*num2 = (int)num;
*str = skipwhite(*str + len);
} else if (!first) /* no number given at all */
} else if (!first) { // no number given at all
return FAIL;
} else if (first) /* only one number given */
}
} else if (first) { // only one number given
*num2 = *num1;
}
return OK;
}

View File

@ -531,17 +531,14 @@ trans_special (
return dlen;
}
/*
* Try translating a <> name at (*srcp)[], return the key and modifiers.
* srcp is advanced to after the <> name.
* returns 0 if there is no match.
*/
int
find_special_key (
// Try translating a <> name at (*srcp)[], return the key and modifiers.
// srcp is advanced to after the <> name.
// returns 0 if there is no match.
int find_special_key(
char_u **srcp,
int *modp,
int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
int keep_x_key /* don't translate xHome to Home key */
int keycode, // prefer key code, e.g. K_DEL instead of DEL
int keep_x_key // don't translate xHome to Home key
)
{
char_u *last_dash;
@ -558,24 +555,26 @@ find_special_key (
if (src[0] != '<')
return 0;
/* Find end of modifier list */
// Find end of modifier list
last_dash = src;
for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
if (*bp == '-') {
last_dash = bp;
if (bp[1] != NUL) {
if (has_mbyte)
if (has_mbyte) {
l = mb_ptr2len(bp + 1);
else
} else {
l = 1;
if (bp[l + 1] == '>')
bp += l; /* anything accepted, like <C-?> */
}
if (bp[l + 1] == '>') {
bp += l; // anything accepted, like <C-?>
}
}
}
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
bp += 3; /* skip t_xx, xx may be '-' or '>' */
else if (STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL);
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
bp += 3; // skip t_xx, xx may be '-' or '>'
} else if (STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL);
bp += l + 5;
break;
}
@ -589,55 +588,53 @@ find_special_key (
for (bp = src + 1; bp < last_dash; bp++) {
if (*bp != '-') {
bit = name_to_mod_mask(*bp);
if (bit == 0x0)
break; /* Illegal modifier name */
if (bit == 0x0) {
break; // Illegal modifier name
}
modifiers |= bit;
}
}
/*
* Legal modifier name.
*/
// 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, TRUE, TRUE, NULL, &n);
// <Char-123> or <Char-033> or <Char-0x33>
vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n);
key = (int)n;
} else {
/*
* Modifier with single letter, or special key name.
*/
if (has_mbyte)
if (has_mbyte) {
l = mb_ptr2len(last_dash + 1);
else
} else {
l = 1;
if (modifiers != 0 && last_dash[l + 1] == '>')
}
if (modifiers != 0 && last_dash[l + 1] == '>') {
key = PTR2CHAR(last_dash + 1);
else {
} else {
key = get_special_key_code(last_dash + 1);
if (!keep_x_key)
if (!keep_x_key) {
key = handle_x_keys(key);
}
}
}
/*
* get_special_key_code() may return NUL for invalid
* special key name.
*/
// 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.
*/
// 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)
// don't want keycode, use single byte code
if (key == K_BS) {
key = BS;
else if (key == K_DEL || key == K_KDEL)
} else if (key == K_DEL || key == K_KDEL) {
key = DEL;
}
}
// Normal Key with modifier:

View File

@ -3037,7 +3037,7 @@ static double tv_float(typval_T *tvs, int *idxp)
* http://www.ijs.si/software/snprintf/
*
* This snprintf() only supports the following conversion specifiers:
* s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
* s, c, b, B, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
* with flags: '-', '+', ' ', '0' and '#'.
* An asterisk is supported for field width as well as precision.
*
@ -3103,8 +3103,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
char *p = fmt;
int arg_idx = 1;
if (!p)
if (!p) {
p = "";
}
while (*p) {
if (*p != '%') {
// copy up to the next '%' or NUL without any changes
@ -3176,9 +3177,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (*p == '*') {
p++;
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
if (j >= 0)
if (j >= 0) {
min_field_width = j;
else {
} else {
min_field_width = -j;
justify_left = 1;
}
@ -3187,8 +3188,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// argument like common implementations do
unsigned int uj = *p++ - '0';
while (ascii_isdigit((int)(*p)))
while (ascii_isdigit((int)(*p))) {
uj = 10 * uj + (unsigned int)(*p++ - '0');
}
min_field_width = uj;
}
@ -3199,9 +3201,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (*p == '*') {
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
p++;
if (j >= 0)
if (j >= 0) {
precision = j;
else {
} else {
precision_specified = 0;
precision = 0;
}
@ -3210,8 +3212,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// treat argument like common implementations do
unsigned int uj = *p++ - '0';
while (ascii_isdigit((int)(*p)))
while (ascii_isdigit((int)(*p))) {
uj = 10 * uj + (unsigned int)(*p++ - '0');
}
precision = uj;
}
}
@ -3262,14 +3265,13 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (!str_arg) {
str_arg = "[NULL]";
str_arg_l = 6;
}
// make sure not to address string beyond the specified precision
else if (!precision_specified)
} else if (!precision_specified) {
// make sure not to address string beyond the specified precision
str_arg_l = strlen(str_arg);
// truncate string if necessary as requested by precision
else if (precision == 0)
} else if (precision == 0) {
// truncate string if necessary as requested by precision
str_arg_l = 0;
else {
} else {
// memchr on HP does not like n > 2^31
// TODO(elmart): check if this still holds / is relevant
str_arg_l = (size_t)((char *)xmemscan(str_arg,
@ -3283,8 +3285,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
- mb_string2cells((char_u *) str_arg);
if (precision) {
char_u *p1 = (char_u *)str_arg;
for (size_t i = 0; i < precision && *p1; i++)
for (size_t i = 0; i < precision && *p1; i++) {
p1 += mb_ptr2len(p1);
}
str_arg_l = precision = p1 - (char_u *)str_arg;
}
}
@ -3295,9 +3298,14 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
}
break;
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
// u, o, x, X and p conversion specifiers imply the value is unsigned;
// d implies a signed value
case 'd':
case 'u':
case 'b': case 'B':
case 'o':
case 'x': case 'X':
case 'p': {
// u, b, B, o, x, X and p conversion specifiers imply
// the value is unsigned; d implies a signed value
// 0 if numeric argument is zero (or if pointer is NULL for 'p'),
// +1 if greater than zero (or non NULL for 'p'),
@ -3325,8 +3333,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (fmt_spec == 'p') {
length_modifier = '\0';
ptr_arg = tvs ? (void *)tv_str(tvs, &arg_idx) : va_arg(ap, void *);
if (ptr_arg)
if (ptr_arg) {
arg_sign = 1;
}
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
@ -3334,25 +3343,28 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case 'h':
// char and short arguments are passed as int
int_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
if (int_arg > 0)
if (int_arg > 0) {
arg_sign = 1;
else if (int_arg < 0)
} else if (int_arg < 0) {
arg_sign = -1;
}
break;
case 'l':
long_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, long int);
if (long_arg > 0)
if (long_arg > 0) {
arg_sign = 1;
else if (long_arg < 0)
} else if (long_arg < 0) {
arg_sign = -1;
}
break;
case '2':
long_long_arg = tvs ? tv_nr(tvs, &arg_idx)
: va_arg(ap, long long int);
if (long_long_arg > 0)
: va_arg(ap, long long int); // NOLINT (runtime/int)
if (long_long_arg > 0) {
arg_sign = 1;
else if (long_long_arg < 0)
} else if (long_long_arg < 0) {
arg_sign = -1;
}
break;
}
} else {
@ -3362,24 +3374,23 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case 'h':
uint_arg = tvs ? (unsigned)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int);
if (uint_arg != 0)
arg_sign = 1;
if (uint_arg != 0) { arg_sign = 1; }
break;
case 'l':
ulong_arg = tvs ? (unsigned long)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned long int);
if (ulong_arg != 0)
arg_sign = 1;
if (ulong_arg != 0) { arg_sign = 1; }
break;
case '2':
ulong_long_arg = tvs ? (unsigned long long)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned long long int);
if (ulong_long_arg) arg_sign = 1;
ulong_long_arg = tvs
? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int)
: va_arg(ap, unsigned long long int); // NOLINT (runtime/int)
if (ulong_long_arg) { arg_sign = 1; }
break;
case 'z':
size_t_arg = tvs ? (size_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, size_t);
if (size_t_arg) arg_sign = 1;
if (size_t_arg) { arg_sign = 1; }
break;
}
}
@ -3390,16 +3401,19 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// For d, i, u, o, x, and X conversions, if precision is specified,
// '0' flag should be ignored. This is so with Solaris 2.6, Digital UNIX
// 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
if (precision_specified)
if (precision_specified) {
zero_padding = 0;
}
if (fmt_spec == 'd') {
if (force_sign && arg_sign >= 0)
if (force_sign && arg_sign >= 0) {
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
}
// leave negative numbers for sprintf to handle, to
// avoid handling tricky cases like (short int)-32768
} else if (alternate_form) {
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) {
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' ||
fmt_spec == 'b' || fmt_spec == 'B')) {
tmp[str_arg_l++] = '0';
tmp[str_arg_l++] = fmt_spec;
}
@ -3407,20 +3421,20 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
}
zero_padding_insertion_ind = str_arg_l;
if (!precision_specified)
if (!precision_specified) {
precision = 1; // default precision is 1
}
if (precision == 0 && arg_sign == 0) {
// when zero value is formatted with an explicit precision 0,
// resulting formatted string is empty (d, i, u, o, x, X, p)
// resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
} else {
char f[5];
int f_l = 0;
// construct a simple format string for sprintf
f[f_l++] = '%';
if (!length_modifier)
;
else if (length_modifier == '2') {
if (!length_modifier) {
} else if (length_modifier == '2') {
f[f_l++] = 'l';
f[f_l++] = 'l';
} else
@ -3441,6 +3455,41 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case '2': str_arg_l += sprintf(tmp + str_arg_l, f, long_long_arg);
break;
}
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
// binary
size_t bits = 0;
switch (length_modifier) {
case '\0':
case 'h': for (bits = sizeof(unsigned) * 8; bits > 0; bits--) {
if ((uint_arg >> (bits - 1)) & 0x1) { break; } }
while (bits > 0) {
tmp[str_arg_l++] =
((uint_arg >> --bits) & 0x1) ? '1' : '0'; }
break;
case 'l': for (bits = sizeof(unsigned long) * 8; bits > 0; bits--) {
if ((ulong_arg >> (bits - 1)) & 0x1) { break; } }
while (bits > 0) {
tmp[str_arg_l++] =
((ulong_arg >> --bits) & 0x1) ? '1' : '0'; }
break;
case '2': for (bits = sizeof(unsigned long long) * 8; // NOLINT (runtime/int)
bits > 0; bits--) {
if ((ulong_long_arg >> (bits - 1)) & 0x1) { break; } }
while (bits > 0) {
tmp[str_arg_l++] =
((ulong_long_arg >> --bits) & 0x1) ? '1' : '0'; }
break;
case 'z': for (bits = sizeof(size_t) * 8; bits > 0; bits--) {
if ((size_t_arg >> (bits - 1)) & 0x1) { break; } }
while (bits > 0) {
tmp[str_arg_l++] =
((size_t_arg >> --bits) & 0x1) ? '1' : '0'; }
break;
}
} else {
// unsigned
switch (length_modifier) {
@ -3464,7 +3513,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (zero_padding_insertion_ind + 1 < str_arg_l
&& tmp[zero_padding_insertion_ind] == '0'
&& (tmp[zero_padding_insertion_ind + 1] == 'x'
|| tmp[zero_padding_insertion_ind + 1] == 'X'))
|| tmp[zero_padding_insertion_ind + 1] == 'X'
|| tmp[zero_padding_insertion_ind + 1] == 'b'
|| tmp[zero_padding_insertion_ind + 1] == 'B'))
zero_padding_insertion_ind += 2;
}
@ -3507,7 +3558,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// floating point
char format[40];
int l;
int remove_trailing_zeroes = FALSE;
int remove_trailing_zeroes = false;
double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
double abs_f = f < 0 ? -f : f;
@ -3518,7 +3569,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
fmt_spec = 'f';
else
fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
remove_trailing_zeroes = TRUE;
remove_trailing_zeroes = true;
}
if (fmt_spec == 'f' && abs_f > 1.0e307) {

View File

@ -4186,75 +4186,102 @@ static void reverse_line(char_u *s)
# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
/*
* add or subtract 'Prenum1' from a number in a line
* 'command' is CTRL-A for add, CTRL-X for subtract
*
* return FAIL for failure, OK otherwise
*/
/// Add or subtract from a number in a line.
///
/// @param command CTRL-A for add, CTRL-X for subtract
// @param Prenum1 number to add or subtract
///
/// @return FAIL for failure, OK otherwise
int do_addsub(int command, linenr_T Prenum1)
{
int col;
char_u *buf1;
char_u buf2[NUMBUFLEN];
int hex; /* 'X' or 'x': hex; '0': octal */
static int hexupper = FALSE; /* 0xABC */
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
static int hexupper = false; // 0xABC
unsigned long n, oldn;
char_u *ptr;
int c;
int length = 0; /* character length of the number */
int length = 0; // character length of the number
int todel;
int dohex;
int dooct;
int dobin;
int doalp;
int firstdigit;
int negative;
int subtract;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
ptr = get_cursor_line_ptr();
RLADDSUBFIX(ptr);
/*
* First check if we are on a hexadecimal number, after the "0x".
*/
// First check if we are on a hexadecimal number, after the "0x".
col = curwin->w_cursor.col;
if (dohex)
while (col > 0 && ascii_isxdigit(ptr[col]))
--col;
if ( dohex
&& col > 0
&& (ptr[col] == 'X'
|| ptr[col] == 'x')
&& ptr[col - 1] == '0'
&& ascii_isxdigit(ptr[col + 1])) {
/*
* Found hexadecimal number, move to its start.
*/
--col;
if (dobin) {
while (col > 0 && ascii_isbdigit(ptr[col])) {
col--;
}
}
if (dohex) {
while (col > 0 && ascii_isxdigit(ptr[col])) {
col--;
}
}
if (dobin
&& dohex
&& !((col > 0
&& (ptr[col] == 'X' ||
ptr[col] == 'x')
&& ptr[col - 1] == '0'
&& ascii_isxdigit(ptr[col + 1])))) {
// In case of binary/hexadecimal pattern overlap match, rescan
col = curwin->w_cursor.col;
while (col > 0 && ascii_isdigit(ptr[col])) {
col--;
}
}
if ((dohex
&& col > 0
&& (ptr[col] == 'X'
|| ptr[col] == 'x')
&& ptr[col - 1] == '0'
&& ascii_isxdigit(ptr[col + 1])) ||
(dobin
&& col > 0
&& (ptr[col] == 'B'
|| ptr[col] == 'b')
&& ptr[col - 1] == '0'
&& ascii_isbdigit(ptr[col + 1]))) {
// Found hexadecimal or binary number, move to its start.
col--;
} else {
/*
* Search forward and then backward to find the start of number.
*/
// Search forward and then backward to find the start of number.
col = curwin->w_cursor.col;
while (ptr[col] != NUL
&& !ascii_isdigit(ptr[col])
&& !(doalp && ASCII_ISALPHA(ptr[col])))
++col;
&& !(doalp && ASCII_ISALPHA(ptr[col]))) {
col++;
}
while (col > 0
&& ascii_isdigit(ptr[col - 1])
&& !(doalp && ASCII_ISALPHA(ptr[col])))
--col;
&& !(doalp && ASCII_ISALPHA(ptr[col]))) {
col--;
}
}
/*
* If a number was found, and saving for undo works, replace the number.
*/
// If a number was found, and saving for undo works, replace the number.
firstdigit = ptr[col];
RLADDSUBFIX(ptr);
if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
@ -4263,152 +4290,170 @@ int do_addsub(int command, linenr_T Prenum1)
return FAIL;
}
/* get ptr again, because u_save() may have changed it */
// get ptr again, because u_save() may have changed it
ptr = get_cursor_line_ptr();
RLADDSUBFIX(ptr);
if (doalp && ASCII_ISALPHA(firstdigit)) {
/* decrement or increment alphabetic character */
// decrement or increment alphabetic character
if (command == Ctrl_X) {
if (CharOrd(firstdigit) < Prenum1) {
if (isupper(firstdigit))
if (isupper(firstdigit)) {
firstdigit = 'A';
else
} else {
firstdigit = 'a';
} else
}
} else {
firstdigit -= Prenum1;
}
} else {
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
if (isupper(firstdigit))
if (isupper(firstdigit)) {
firstdigit = 'Z';
else
} else {
firstdigit = 'z';
} else
}
} else {
firstdigit += Prenum1;
}
}
curwin->w_cursor.col = col;
(void)del_char(FALSE);
(void)del_char(false);
ins_char(firstdigit);
} else {
negative = FALSE;
if (col > 0 && ptr[col - 1] == '-') { /* negative number */
negative = false;
if (col > 0 && ptr[col - 1] == '-') { // negative number
--col;
negative = TRUE;
negative = true;
}
/* get the number value (unsigned) */
vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
// get the number value (unsigned)
vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n);
/* ignore leading '-' for hex and octal numbers */
if (hex && negative) {
// ignore leading '-' for hex, octal and bin numbers
if (pre && negative) {
++col;
--length;
negative = FALSE;
negative = false;
}
/* add or subtract */
subtract = FALSE;
if (command == Ctrl_X)
subtract ^= TRUE;
if (negative)
subtract ^= TRUE;
// add or subtract
subtract = false;
if (command == Ctrl_X) {
subtract ^= true;
}
if (negative) {
subtract ^= true;
}
oldn = n;
if (subtract)
n -= (unsigned long)Prenum1;
else
n += (unsigned long)Prenum1;
/* handle wraparound for decimal numbers */
if (!hex) {
n = subtract ? n - (unsigned long) Prenum1
: n + (unsigned long) Prenum1;
// handle wraparound for decimal numbers
if (!pre) {
if (subtract) {
if (n > oldn) {
n = 1 + (n ^ (unsigned long)-1);
negative ^= TRUE;
negative ^= true;
}
} else { /* add */
if (n < oldn) {
n = (n ^ (unsigned long)-1);
negative ^= TRUE;
negative ^= true;
}
}
if (n == 0)
negative = FALSE;
if (n == 0) {
negative = false;
}
}
/*
* Delete the old number.
*/
// Delete the old number.
curwin->w_cursor.col = col;
todel = length;
c = gchar_cursor();
/*
* Don't include the '-' in the length, only the length of the part
* after it is kept the same.
*/
if (c == '-')
// Don't include the '-' in the length, only the length of the part
// after it is kept the same.
if (c == '-') {
--length;
}
while (todel-- > 0) {
if (c < 0x100 && isalpha(c)) {
if (isupper(c))
hexupper = TRUE;
else
hexupper = FALSE;
if (isupper(c)) {
hexupper = true;
} else {
hexupper = false;
}
}
/* del_char() will mark line needing displaying */
(void)del_char(FALSE);
// del_char() will mark line needing displaying
(void)del_char(false);
c = gchar_cursor();
}
/*
* Prepare the leading characters in buf1[].
* When there are many leading zeros it could be very long. Allocate
* a bit too much.
*/
// Prepare the leading characters in buf1[].
// When there are many leading zeros it could be very long. Allocate
// a bit too much.
buf1 = xmalloc(length + NUMBUFLEN);
ptr = buf1;
if (negative) {
*ptr++ = '-';
}
if (hex) {
if (pre) {
*ptr++ = '0';
--length;
}
if (hex == 'x' || hex == 'X') {
*ptr++ = hex;
if (pre == 'b' || pre == 'B' ||
pre == 'x' || pre == 'X') {
*ptr++ = pre;
--length;
}
/*
* Put the number characters in buf2[].
*/
if (hex == 0)
sprintf((char *)buf2, "%" PRIu64, (uint64_t)n);
else if (hex == '0')
sprintf((char *)buf2, "%" PRIo64, (uint64_t)n);
else if (hex && hexupper)
sprintf((char *)buf2, "%" PRIX64, (uint64_t)n);
else
sprintf((char *)buf2, "%" PRIx64, (uint64_t)n);
// Put the number characters in buf2[].
if (pre == 'b' || pre == 'B') {
size_t bits = 0;
size_t pos = 0;
// leading zeros
for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) {
if ((n >> (bits - 1)) & 0x1) { break; }
}
while (bits > 0) {
buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0';
}
buf2[pos] = '\0';
} else if (pre == 0) {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n);
} else if (pre && hexupper) {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n);
} else {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n);
}
length -= (int)STRLEN(buf2);
/*
* Adjust number of zeros to the new number of digits, so the
* total length of the number remains the same.
* Don't do this when
* the result may look like an octal number.
*/
if (firstdigit == '0' && !(dooct && hex == 0))
while (length-- > 0)
// Adjust number of zeros to the new number of digits, so the
// total length of the number remains the same.
// Don't do this when
// the result may look like an octal number.
if (firstdigit == '0' && !(dooct && pre == 0)) {
while (length-- > 0) {
*ptr++ = '0';
}
}
*ptr = NUL;
STRCAT(buf1, buf2);
ins_str(buf1); /* insert the new number */
xfree(buf1);
}
--curwin->w_cursor.col;
curwin->w_set_curswant = TRUE;
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
curwin->w_set_curswant = true;
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
RLADDSUBFIX(ptr);
return OK;
}

View File

@ -258,30 +258,31 @@ typedef struct vimoption {
#define PARAM_COUNT ARRAY_SIZE(options)
static char *(p_ambw_values[]) = {"single", "double", NULL};
static char *(p_bg_values[]) = {"light", "dark", NULL};
static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
static char *(p_wop_values[]) = {"tagfile", NULL};
static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
static char *(p_mousem_values[]) =
{"extend", "popup", "popup_setpos", "mac", NULL};
static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
static char *(p_buftype_values[]) =
{"nofile", "nowrite", "quickfix", "help", "acwrite", "terminal", NULL};
static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
"diff",
NULL};
static char *(p_fcl_values[]) = {"all", NULL};
static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
"noinsert", "noselect", NULL};
static char *(p_ambw_values[]) = { "single", "double", NULL };
static char *(p_bg_values[]) = { "light", "dark", NULL };
static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL };
static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
static char *(p_wop_values[]) = { "tagfile", NULL };
static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",
"mac", NULL };
static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
"help", "acwrite", "terminal", NULL };
static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
"wipe", NULL };
static char *(p_bs_values[]) = { "indent", "eol", "start", NULL };
static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
"syntax", "diff", NULL };
static char *(p_fcl_values[]) = { "all", NULL };
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
"noinsert", "noselect", NULL };
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.c.generated.h"
@ -1431,7 +1432,7 @@ do_set (
} else if (*arg == '-' || ascii_isdigit(*arg)) {
// Allow negative (for 'undolevels'), octal and
// hex numbers.
vim_str2nr(arg, NULL, &i, true, true, &value, NULL);
vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg;
goto skip;

View File

@ -1599,7 +1599,7 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_nf',
defaults={if_true={vi="octal,hex", vim="hex"}}
defaults={if_true={vi="bin,octal,hex", vim="bin,hex"}}
},
{
full_name='number', abbreviation='nu',

View File

@ -1063,8 +1063,7 @@ static char_u *repl_to = NULL;
//
// Returns the length of the word in bytes, also when it's OK, so that the
// caller can skip over the word.
size_t
spell_check (
size_t spell_check(
win_T *wp, // current window
char_u *ptr,
hlf_T *attrp,
@ -1082,12 +1081,14 @@ spell_check (
// A word never starts at a space or a control character. Return quickly
// then, skipping over the character.
if (*ptr <= ' ')
if (*ptr <= ' ') {
return 1;
}
// Return here when loading language files failed.
if (GA_EMPTY(&wp->w_s->b_langp))
if (GA_EMPTY(&wp->w_s->b_langp)) {
return 1;
}
memset(&mi, 0, sizeof(matchinf_T));
@ -1095,10 +1096,13 @@ spell_check (
// 0X99FF. But always do check spelling to find "3GPP" and "11
// julifeest".
if (*ptr >= '0' && *ptr <= '9') {
if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) {
mi.mi_end = (char_u*) skipbin((char*) ptr + 2);
} else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
mi.mi_end = skiphex(ptr + 2);
else
} else {
mi.mi_end = skipdigits(ptr);
}
nrlen = (size_t)(mi.mi_end - ptr);
}
@ -1113,12 +1117,14 @@ spell_check (
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) {
// Check word starting with capital letter.
c = PTR2CHAR(ptr);
if (!SPELL_ISUPPER(c))
if (!SPELL_ISUPPER(c)) {
wrongcaplen = (size_t)(mi.mi_fend - ptr);
}
}
}
if (capcol != NULL)
if (capcol != NULL) {
*capcol = -1;
}
// We always use the characters up to the next non-word character,
// also for bad words.
@ -1131,8 +1137,9 @@ spell_check (
// case-fold the word with one non-word character, so that we can check
// for the word end.
if (*mi.mi_fend != NUL)
if (*mi.mi_fend != NUL) {
mb_ptr_adv(mi.mi_fend);
}
(void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1);
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
@ -1149,8 +1156,9 @@ spell_check (
// If reloading fails the language is still in the list but everything
// has been cleared.
if (mi.mi_lp->lp_slang->sl_fidxs == NULL)
if (mi.mi_lp->lp_slang->sl_fidxs == NULL) {
continue;
}
// Check for a matching word in case-folded words.
find_word(&mi, FIND_FOLDWORD);
@ -1181,18 +1189,18 @@ spell_check (
// If we found a number skip over it. Allows for "42nd". Do flag
// rare and local words, e.g., "3GPP".
if (nrlen > 0) {
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
return nrlen;
}
}
} else if (!spell_iswordp_nmw(ptr, wp)) {
// When we are at a non-word character there is no error, just
// skip over the character (try looking for a word after it).
else if (!spell_iswordp_nmw(ptr, wp)) {
if (capcol != NULL && wp->w_s->b_cap_prog != NULL) {
regmatch_T regmatch;
// Check for end of sentence.
regmatch.regprog = wp->w_s->b_cap_prog;
regmatch.rm_ic = FALSE;
regmatch.rm_ic = false;
int r = vim_regexec(&regmatch, ptr, 0);
wp->w_s->b_cap_prog = regmatch.regprog;
if (r) {
@ -1204,12 +1212,12 @@ spell_check (
return (size_t)(*mb_ptr2len)(ptr);
}
return 1;
} else if (mi.mi_end == ptr)
} else if (mi.mi_end == ptr) {
// Always include at least one character. Required for when there
// is a mixup in "midword".
mb_ptr_adv(mi.mi_end);
else if (mi.mi_result == SP_BAD
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
} else if (mi.mi_result == SP_BAD
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
char_u *p, *fp;
int save_result = mi.mi_result;
@ -1219,11 +1227,12 @@ spell_check (
if (mi.mi_lp->lp_slang->sl_fidxs != NULL) {
p = mi.mi_word;
fp = mi.mi_fword;
for (;; ) {
for (;;) {
mb_ptr_adv(p);
mb_ptr_adv(fp);
if (p >= mi.mi_end)
if (p >= mi.mi_end) {
break;
}
mi.mi_compoff = (int)(fp - mi.mi_fword);
find_word(&mi, FIND_COMPOUND);
if (mi.mi_result != SP_BAD) {
@ -1235,12 +1244,13 @@ spell_check (
}
}
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
*attrp = HLF_SPB;
else if (mi.mi_result == SP_RARE)
} else if (mi.mi_result == SP_RARE) {
*attrp = HLF_SPR;
else
} else {
*attrp = HLF_SPL;
}
}
if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE)) {

View File

@ -35,7 +35,7 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os/os_defs.h" /* bring lots of system header files */
#define NUMBUFLEN 30 /* length of a buffer to store a number in ASCII */
#define NUMBUFLEN 65 // length of a buffer to store a number in ASCII
#define MAX_TYPENR 65535

View File

@ -0,0 +1,58 @@
local helpers = require('test.functional.helpers')
local clear = helpers.clear
local eq = helpers.eq
local funcs = helpers.funcs
local exc_exec = helpers.exc_exec
describe('printf()', function()
it('works with zero and %b', function()
eq('0', funcs.printf('%lb', 0))
eq('0', funcs.printf('%llb', 0))
eq('0', funcs.printf('%zb', 0))
end)
it('works with one and %b', function()
eq('1', funcs.printf('%b', 1))
eq('1', funcs.printf('%lb', 1))
eq('1', funcs.printf('%llb', 1))
eq('1', funcs.printf('%zb', 1))
end)
it('works with 0xff and %b', function()
eq('11111111', funcs.printf('%b', 0xff))
eq('11111111', funcs.printf('%lb', 0xff))
eq('11111111', funcs.printf('%llb', 0xff))
eq('11111111', funcs.printf('%zb', 0xff))
end)
it('accepts width modifier with %b', function()
eq(' 1', funcs.printf('%3b', 1))
end)
it('accepts prefix modifier with %b', function()
eq('0b1', funcs.printf('%#b', 1))
end)
it('writes capital B with %B', function()
eq('0B1', funcs.printf('%#B', 1))
end)
it('accepts prefix, zero-fill and width modifiers with %b', function()
eq('0b001', funcs.printf('%#05b', 1))
end)
it('accepts prefix and width modifiers with %b', function()
eq(' 0b1', funcs.printf('%#5b', 1))
end)
it('does not write prefix for zero with prefix and width modifier used with %b', function()
eq(' 0', funcs.printf('%#5b', 0))
end)
it('accepts precision modifier with %b', function()
eq('00000', funcs.printf('%.5b', 0))
end)
it('accepts all modifiers with %b at once', function()
-- zero-fill modifier is ignored when used with left-align
-- force-sign and add-blank are ignored
-- use-grouping-characters modifier is ignored always
eq('0b00011 ', funcs.printf('% \'+#0-10.5b', 3))
end)
it('errors out when %b modifier is used for a list', function()
eq('Vim(call):E745: Using a List as a Number', exc_exec('call printf("%b", [])'))
end)
it('errors out when %b modifier is used for a float', function()
eq('Vim(call):E805: Using a Float as a Number', exc_exec('call printf("%b", 3.1415926535)'))
end)
end)

View File

@ -11,34 +11,40 @@ describe('increment and decrement commands', function()
it('should work', function()
-- Insert some numbers in various bases.
insert([[
100 0x100 077 0
100 0x100 077
0b101 100 0x100 077 0
0b101 100 0x100 077
100 0x100 077 0xfF 0xFf
100 0x100 077]])
100 0x100 077
0x0b101 0b1101]])
-- Increment and decrement numbers in the first row, interpreting the
-- numbers as decimal, octal or hexadecimal.
execute('set nrformats=octal,hex', '1')
feed('102ll64128$')
execute('set nrformats=bin,octal,hex', '1')
feed('63l102ll64128$')
-- For the second row, treat the numbers as decimal or octal.
-- 0x100 should be interpreted as decimal 0, the character x, and decimal 100.
execute('set nrformats=octal', '2')
feed('0102l2w65129blx6lD')
feed('0w102l2w65129blx6lD')
-- For the third row, treat the numbers as decimal or hexadecimal.
-- 077 should be interpreted as decimal 77.
execute('set nrformats=hex', '3')
feed('0101l257Txldt   ')
-- For the last row, interpret all numbers as decimal.
-- For the fourth row, interpret all numbers as decimal.
execute('set nrformats=', '4')
feed('0200l100w78')
-- For the last row, interpret as binary and hexadecimal.
execute('set nrformats=bin,hex', '5')
feed('010065l6432')
expect([[
0 0x0ff 0000 -1
0 1x100 0777777
0b011 0 0x0ff 0000 -1
1b101 0 1x100 0777777
-1 0x0 078 0xFE 0xfe
-100 -100x100 000]])
-100 -100x100 000
0x0b0de 0b0101101]])
end)
end)

View File

@ -600,4 +600,39 @@ describe(':sort', function()
eq('Vim(sort):E474: Invalid argument', eval('tmpvar'))
expect(text)
end)
it('binary', function()
insert([[
0b111000
0b101100
0b101001
0b101001
0b101000
0b000000
0b001000
0b010000
0b101000
0b100000
0b101010
0b100010
0b100100
0b100010]])
execute([[sort b]])
expect([[
0b000000
0b001000
0b010000
0b100000
0b100010
0b100010
0b100100
0b101000
0b101000
0b101001
0b101001
0b101010
0b101100
0b111000]])
end)
end)