Skip to content

Commit 887c1fe

Browse files
committed
patch 7.4.1027
Problem: No support for binary numbers. Solution: Add "bin" to nrformats. (Jason Schulz)
1 parent acf92d2 commit 887c1fe

19 files changed

Lines changed: 495 additions & 85 deletions

runtime/doc/change.txt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,14 @@ CTRL-X Subtract [count] from the number or alphabetic
416416
additional [count] (so effectively creating a [count]
417417
decrementing sequence). {not in Vi}
418418

419-
The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
420-
octal and hexadecimal numbers and alphabetic characters. This depends on the
421-
'nrformats' option.
419+
The CTRL-A and CTRL-X commands can work for:
420+
- signed and unsigned decimal numbers
421+
- unsigned binary, octal and hexadecimal numbers
422+
- alphabetic characters
423+
424+
This depends on the 'nrformats' option:
425+
- When 'nrformats' includes "bin", Vim assumes numbers starting with '0b' or
426+
'0B' are binary.
422427
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
423428
to be octal, unless the number includes a '8' or '9'. Other numbers are
424429
decimal and may have a preceding minus sign.
@@ -447,6 +452,10 @@ octal number.
447452
Note that when 'nrformats' includes "octal", decimal numbers with leading
448453
zeros cause mistakes, because they can be confused with octal numbers.
449454

455+
Note similarly, when 'nrformats' includes "bin", binary numbers with a leading
456+
'0x' or '0X' can be interpreted as hexadecimal rather than binary since '0b'
457+
are valid hexadecimal digits.
458+
450459
The CTRL-A command is very useful in a macro. Example: Use the following
451460
steps to make a numbered list.
452461

@@ -1736,7 +1745,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
17361745
found here: |sort()|, |uniq()|.
17371746

17381747
*:sor* *:sort*
1739-
:[range]sor[t][!] [i][u][r][n][x][o] [/{pattern}/]
1748+
:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
17401749
Sort lines in [range]. When no range is given all
17411750
lines are sorted.
17421751

@@ -1756,6 +1765,9 @@ found here: |sort()|, |uniq()|.
17561765
With [o] sorting is done on the first octal number in
17571766
the line (after or inside a {pattern} match).
17581767

1768+
With [b] sorting is done on the first binary number in
1769+
the line (after or inside a {pattern} match).
1770+
17591771
With [u] only keep the first of a sequence of
17601772
identical lines (ignoring case when [i] is used).
17611773
Without this flag, a sequence of identical lines

runtime/doc/version7.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ New and extended functions: ~
931931
|spellbadword()| get a badly spelled word
932932
|spellsuggest()| get suggestions for correct spelling
933933
|split()| split a String into a List
934-
|str2nr()| convert a string to a number, base 8, 10 or 16
934+
|str2nr()| convert a string to a number, base 2, 8, 10 or 16
935935
|stridx()| extra argument: start position
936936
|strridx()| extra argument: start position
937937
|string()| string representation of a List or Dictionary

src/charset.c

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,20 @@ skipdigits(q)
15691569
}
15701570

15711571
#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO)
1572+
/*
1573+
* skip over binary digits
1574+
*/
1575+
char_u *
1576+
skipbin(q)
1577+
char_u *q;
1578+
{
1579+
char_u *p = q;
1580+
1581+
while (vim_isbdigit(*p)) /* skip to next non-digit */
1582+
++p;
1583+
return p;
1584+
}
1585+
15721586
/*
15731587
* skip over digits and hex characters
15741588
*/
@@ -1585,6 +1599,20 @@ skiphex(q)
15851599
#endif
15861600

15871601
#if defined(FEAT_EX_EXTRA) || defined(PROTO)
1602+
/*
1603+
* skip to bin digit (or NUL after the string)
1604+
*/
1605+
char_u *
1606+
skiptobin(q)
1607+
char_u *q;
1608+
{
1609+
char_u *p = q;
1610+
1611+
while (*p != NUL && !vim_isbdigit(*p)) /* skip to next digit */
1612+
++p;
1613+
return p;
1614+
}
1615+
15881616
/*
15891617
* skip to digit (or NUL after the string)
15901618
*/
@@ -1641,6 +1669,17 @@ vim_isxdigit(c)
16411669
|| (c >= 'A' && c <= 'F');
16421670
}
16431671

1672+
/*
1673+
* Corollary of vim_isdigit and vim_isxdigit() that can handle
1674+
* characters > 0x100.
1675+
*/
1676+
int
1677+
vim_isbdigit(c)
1678+
int c;
1679+
{
1680+
return (c == '0' || c == '1');
1681+
}
1682+
16441683
#if defined(FEAT_MBYTE) || defined(PROTO)
16451684
/*
16461685
* Vim's own character class functions. These exist because many library
@@ -1822,35 +1861,37 @@ vim_isblankline(lbuf)
18221861

18231862
/*
18241863
* Convert a string into a long and/or unsigned long, taking care of
1825-
* hexadecimal and octal numbers. Accepts a '-' sign.
1826-
* If "hexp" is not NULL, returns a flag to indicate the type of the number:
1864+
* hexadecimal, octal, and binary numbers. Accepts a '-' sign.
1865+
* If "prep" is not NULL, returns a flag to indicate the type of the number:
18271866
* 0 decimal
18281867
* '0' octal
1868+
* 'B' bin
1869+
* 'b' bin
18291870
* 'X' hex
18301871
* 'x' hex
18311872
* If "len" is not NULL, the length of the number in characters is returned.
18321873
* If "nptr" is not NULL, the signed result is returned in it.
18331874
* If "unptr" is not NULL, the unsigned result is returned in it.
1834-
* If "dooct" is non-zero recognize octal numbers, when > 1 always assume
1835-
* octal number.
1836-
* If "dohex" is non-zero recognize hex numbers, when > 1 always assume
1837-
* hex number.
1875+
* If "what" contains STR2NR_BIN recognize binary numbers
1876+
* If "what" contains STR2NR_OCT recognize octal numbers
1877+
* If "what" contains STR2NR_HEX recognize hex numbers
1878+
* If "what" contains STR2NR_FORCE always assume bin/oct/hex.
18381879
* If maxlen > 0, check at a maximum maxlen chars
18391880
*/
18401881
void
1841-
vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
1882+
vim_str2nr(start, prep, len, what, nptr, unptr, maxlen)
18421883
char_u *start;
1843-
int *hexp; /* return: type of number 0 = decimal, 'x'
1844-
or 'X' is hex, '0' = octal */
1884+
int *prep; /* return: type of number 0 = decimal, 'x'
1885+
or 'X' is hex, '0' = octal, 'b' or 'B'
1886+
is bin */
18451887
int *len; /* return: detected length of number */
1846-
int dooct; /* recognize octal number */
1847-
int dohex; /* recognize hex number */
1888+
int what; /* what numbers to recognize */
18481889
long *nptr; /* return: signed result */
18491890
unsigned long *unptr; /* return: unsigned result */
18501891
int maxlen; /* max length of string to check */
18511892
{
18521893
char_u *ptr = start;
1853-
int hex = 0; /* default is decimal */
1894+
int pre = 0; /* default is decimal */
18541895
int negative = FALSE;
18551896
unsigned long un = 0;
18561897
int n;
@@ -1861,29 +1902,37 @@ vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
18611902
++ptr;
18621903
}
18631904

1864-
/* Recognize hex and octal. */
1905+
/* Recognize hex, octal, and bin. */
18651906
if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9'
18661907
&& (maxlen == 0 || maxlen > 1))
18671908
{
1868-
hex = ptr[1];
1869-
if (dohex && (hex == 'X' || hex == 'x') && vim_isxdigit(ptr[2])
1870-
&& (maxlen == 0 || maxlen > 2))
1871-
ptr += 2; /* hexadecimal */
1909+
pre = ptr[1];
1910+
if ((what & STR2NR_HEX)
1911+
&& (pre == 'X' || pre == 'x') && vim_isxdigit(ptr[2])
1912+
&& (maxlen == 0 || maxlen > 2))
1913+
/* hexadecimal */
1914+
ptr += 2;
1915+
else if ((what & STR2NR_BIN)
1916+
&& (pre == 'B' || pre == 'b') && vim_isbdigit(ptr[2])
1917+
&& (maxlen == 0 || maxlen > 2))
1918+
/* binary */
1919+
ptr += 2;
18721920
else
18731921
{
1874-
hex = 0; /* default is decimal */
1875-
if (dooct)
1922+
/* decimal or octal, default is decimal */
1923+
pre = 0;
1924+
if (what & STR2NR_OCT)
18761925
{
18771926
/* Don't interpret "0", "08" or "0129" as octal. */
18781927
for (n = 1; VIM_ISDIGIT(ptr[n]); ++n)
18791928
{
18801929
if (ptr[n] > '7')
18811930
{
1882-
hex = 0; /* can't be octal */
1931+
pre = 0; /* can't be octal */
18831932
break;
18841933
}
18851934
if (ptr[n] >= '0')
1886-
hex = '0'; /* assume octal */
1935+
pre = '0'; /* assume octal */
18871936
if (n == maxlen)
18881937
break;
18891938
}
@@ -1892,10 +1941,23 @@ vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
18921941
}
18931942

18941943
/*
1895-
* Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
1896-
*/
1944+
* Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
1945+
*/
18971946
n = 1;
1898-
if (hex == '0' || dooct > 1)
1947+
if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE)
1948+
{
1949+
/* bin */
1950+
if (pre != 0)
1951+
n += 2; /* skip over "0b" */
1952+
while ('0' <= *ptr && *ptr <= '1')
1953+
{
1954+
un = 2 * un + (unsigned long)(*ptr - '0');
1955+
++ptr;
1956+
if (n++ == maxlen)
1957+
break;
1958+
}
1959+
}
1960+
else if (pre == '0' || what == STR2NR_OCT + STR2NR_FORCE)
18991961
{
19001962
/* octal */
19011963
while ('0' <= *ptr && *ptr <= '7')
@@ -1906,10 +1968,10 @@ vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
19061968
break;
19071969
}
19081970
}
1909-
else if (hex != 0 || dohex > 1)
1971+
else if (pre != 0 || what == STR2NR_HEX + STR2NR_FORCE)
19101972
{
19111973
/* hex */
1912-
if (hex != 0)
1974+
if (pre != 0)
19131975
n += 2; /* skip over "0x" */
19141976
while (vim_isxdigit(*ptr))
19151977
{
@@ -1931,8 +1993,8 @@ vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
19311993
}
19321994
}
19331995

1934-
if (hexp != NULL)
1935-
*hexp = hex;
1996+
if (prep != NULL)
1997+
*prep = pre;
19361998
if (len != NULL)
19371999
*len = (int)(ptr - start);
19382000
if (nptr != NULL)

src/eval.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,7 @@ call_vim_function(func, argc, argv, safe, str_arg_only, rettv)
16251625
len = 0;
16261626
else
16271627
/* Recognize a number argument, the others must be strings. */
1628-
vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL, 0);
1628+
vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
16291629
if (len != 0 && len == (int)STRLEN(argv[i]))
16301630
{
16311631
argvars[i].v_type = VAR_NUMBER;
@@ -5139,7 +5139,7 @@ eval7(arg, rettv, evaluate, want_string)
51395139
else
51405140
#endif
51415141
{
5142-
vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL, 0);
5142+
vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
51435143
*arg += len;
51445144
if (evaluate)
51455145
{
@@ -18529,11 +18529,12 @@ f_str2nr(argvars, rettv)
1852918529
int base = 10;
1853018530
char_u *p;
1853118531
long n;
18532+
int what;
1853218533

1853318534
if (argvars[1].v_type != VAR_UNKNOWN)
1853418535
{
1853518536
base = get_tv_number(&argvars[1]);
18536-
if (base != 8 && base != 10 && base != 16)
18537+
if (base != 2 && base != 8 && base != 10 && base != 16)
1853718538
{
1853818539
EMSG(_(e_invarg));
1853918540
return;
@@ -18543,7 +18544,14 @@ f_str2nr(argvars, rettv)
1854318544
p = skipwhite(get_tv_string(&argvars[0]));
1854418545
if (*p == '+')
1854518546
p = skipwhite(p + 1);
18546-
vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL, 0);
18547+
switch (base)
18548+
{
18549+
case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
18550+
case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
18551+
case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
18552+
default: what = 0;
18553+
}
18554+
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
1854718555
rettv->vval.v_number = n;
1854818556
}
1854918557

@@ -21349,7 +21357,7 @@ get_tv_number_chk(varp, denote)
2134921357
case VAR_STRING:
2135021358
if (varp->vval.v_string != NULL)
2135121359
vim_str2nr(varp->vval.v_string, NULL, NULL,
21352-
TRUE, TRUE, &n, NULL, 0);
21360+
STR2NR_ALL, &n, NULL, 0);
2135321361
return n;
2135421362
case VAR_LIST:
2135521363
EMSG(_("E745: Using a List as a Number"));

0 commit comments

Comments
 (0)