changeset 7447:ad432f8f68fb v7.4.1027

commit https://github.com/vim/vim/commit/887c1fea4a114e7170091942d0446c8882701b5b Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jan 2 17:56:35 2016 +0100 patch 7.4.1027 Problem: No support for binary numbers. Solution: Add "bin" to nrformats. (Jason Schulz)
author Christian Brabandt <cb@256bit.org>
date Sat, 02 Jan 2016 18:00:05 +0100
parents a67ee44e5848
children 7f446cc997d2
files runtime/doc/change.txt runtime/doc/version7.txt src/charset.c src/eval.c src/ex_cmds.c src/ex_getln.c src/misc2.c src/ops.c src/option.c src/proto/charset.pro src/spell.c src/testdir/test57.in src/testdir/test57.ok src/testdir/test58.in src/testdir/test58.ok src/testdir/test_increment.in src/testdir/test_increment.ok src/version.c src/vim.h
diffstat 19 files changed, 490 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -416,9 +416,14 @@ CTRL-X			Subtract [count] from the numbe
 			additional [count] (so effectively creating a [count]
 			decrementing sequence).  {not in Vi}
 
-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.
+The CTRL-A and CTRL-X commands can work for:
+- signed and unsigned decimal numbers
+- unsigned binary, octal and hexadecimal numbers
+- alphabetic characters
+
+This depends on the 'nrformats' option:
+- When 'nrformats' includes "bin", Vim assumes numbers starting with '0b' or
+  '0B' are 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.
@@ -447,6 +452,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.
 
@@ -1736,7 +1745,7 @@ Vim has a sorting function and a sorting
 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.
 
@@ -1756,6 +1765,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
--- a/runtime/doc/version7.txt
+++ b/runtime/doc/version7.txt
@@ -931,7 +931,7 @@ New and extended functions: ~
 |spellbadword()|	get a badly spelled word
 |spellsuggest()|	get suggestions for correct spelling
 |split()|		split a String into a List
-|str2nr()|		convert a string to a number, base 8, 10 or 16
+|str2nr()|		convert a string to a number, base 2, 8, 10 or 16
 |stridx()|		extra argument: start position
 |strridx()|		extra argument: start position
 |string()|		string representation of a List or Dictionary
--- a/src/charset.c
+++ b/src/charset.c
@@ -1570,6 +1570,20 @@ skipdigits(q)
 
 #if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO)
 /*
+ * skip over binary digits
+ */
+    char_u *
+skipbin(q)
+    char_u	*q;
+{
+    char_u	*p = q;
+
+    while (vim_isbdigit(*p))	/* skip to next non-digit */
+	++p;
+    return p;
+}
+
+/*
  * skip over digits and hex characters
  */
     char_u *
@@ -1586,6 +1600,20 @@ skiphex(q)
 
 #if defined(FEAT_EX_EXTRA) || defined(PROTO)
 /*
+ * skip to bin digit (or NUL after the string)
+ */
+    char_u *
+skiptobin(q)
+    char_u	*q;
+{
+    char_u	*p = q;
+
+    while (*p != NUL && !vim_isbdigit(*p))	/* skip to next digit */
+	++p;
+    return p;
+}
+
+/*
  * skip to digit (or NUL after the string)
  */
     char_u *
@@ -1641,6 +1669,17 @@ vim_isxdigit(c)
 	|| (c >= 'A' && c <= 'F');
 }
 
+/*
+ * Corollary of vim_isdigit and vim_isxdigit() that can handle
+ * characters > 0x100.
+ */
+    int
+vim_isbdigit(c)
+    int		c;
+{
+    return (c == '0' || c == '1');
+}
+
 #if defined(FEAT_MBYTE) || defined(PROTO)
 /*
  * Vim's own character class functions.  These exist because many library
@@ -1822,35 +1861,37 @@ vim_isblankline(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 "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.
+ * If "what" contains STR2NR_BIN recognize binary numbers
+ * If "what" contains STR2NR_OCT recognize octal numbers
+ * If "what" contains STR2NR_HEX recognize hex numbers
+ * If "what" contains STR2NR_FORCE always assume bin/oct/hex.
  * If maxlen > 0, check at a maximum maxlen chars
  */
     void
-vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen)
+vim_str2nr(start, prep, len, what, nptr, unptr, maxlen)
     char_u		*start;
-    int			*hexp;	    /* return: type of number 0 = decimal, 'x'
-				       or 'X' is hex, '0' = octal */
+    int			*prep;	    /* return: type of number 0 = decimal, 'x'
+				       or 'X' is hex, '0' = octal, 'b' or 'B'
+				       is bin */
     int			*len;	    /* return: detected length of number */
-    int			dooct;	    /* recognize octal number */
-    int			dohex;	    /* recognize hex number */
+    int			what;	    /* what numbers to recognize */
     long		*nptr;	    /* return: signed result */
     unsigned long	*unptr;	    /* return: unsigned result */
     int			maxlen;     /* max length of string to check */
 {
     char_u	    *ptr = start;
-    int		    hex = 0;		/* default is decimal */
+    int		    pre = 0;		/* default is decimal */
     int		    negative = FALSE;
     unsigned long   un = 0;
     int		    n;
@@ -1861,29 +1902,37 @@ vim_str2nr(start, hexp, len, dooct, dohe
 	++ptr;
     }
 
-    /* Recognize hex and octal. */
+    /* Recognize hex, octal, and bin. */
     if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9'
 					       && (maxlen == 0 || maxlen > 1))
     {
-	hex = ptr[1];
-	if (dohex && (hex == 'X' || hex == 'x') && vim_isxdigit(ptr[2])
-					       && (maxlen == 0 || maxlen > 2))
-	    ptr += 2;			/* hexadecimal */
+	pre = ptr[1];
+	if ((what & STR2NR_HEX)
+		&& (pre == 'X' || pre == 'x') && vim_isxdigit(ptr[2])
+		&& (maxlen == 0 || maxlen > 2))
+	    /* hexadecimal */
+	    ptr += 2;
+	else if ((what & STR2NR_BIN)
+		&& (pre == 'B' || pre == 'b') && vim_isbdigit(ptr[2])
+		&& (maxlen == 0 || maxlen > 2))
+	    /* binary */
+	    ptr += 2;
 	else
 	{
-	    hex = 0;			/* default is decimal */
-	    if (dooct)
+	    /* decimal or octal, default is decimal */
+	    pre = 0;
+	    if (what & STR2NR_OCT)
 	    {
 		/* Don't interpret "0", "08" or "0129" as octal. */
 		for (n = 1; VIM_ISDIGIT(ptr[n]); ++n)
 		{
 		    if (ptr[n] > '7')
 		    {
-			hex = 0;	/* can't be octal */
+			pre = 0;	/* can't be octal */
 			break;
 		    }
 		    if (ptr[n] >= '0')
-			hex = '0';	/* assume octal */
+			pre = '0';	/* assume octal */
 		    if (n == maxlen)
 			break;
 		}
@@ -1892,10 +1941,23 @@ vim_str2nr(start, hexp, len, dooct, dohe
     }
 
     /*
-     * Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
-     */
+    * Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
+    */
     n = 1;
-    if (hex == '0' || dooct > 1)
+    if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE)
+    {
+	/* bin */
+	if (pre != 0)
+	    n += 2;	    /* skip over "0b" */
+	while ('0' <= *ptr && *ptr <= '1')
+	{
+	    un = 2 * un + (unsigned long)(*ptr - '0');
+	    ++ptr;
+	    if (n++ == maxlen)
+		break;
+	}
+    }
+    else if (pre == '0' || what == STR2NR_OCT + STR2NR_FORCE)
     {
 	/* octal */
 	while ('0' <= *ptr && *ptr <= '7')
@@ -1906,10 +1968,10 @@ vim_str2nr(start, hexp, len, dooct, dohe
 		break;
 	}
     }
-    else if (hex != 0 || dohex > 1)
+    else if (pre != 0 || what == STR2NR_HEX + STR2NR_FORCE)
     {
 	/* hex */
-	if (hex != 0)
+	if (pre != 0)
 	    n += 2;	    /* skip over "0x" */
 	while (vim_isxdigit(*ptr))
 	{
@@ -1931,8 +1993,8 @@ vim_str2nr(start, hexp, len, dooct, dohe
 	}
     }
 
-    if (hexp != NULL)
-	*hexp = hex;
+    if (prep != NULL)
+	*prep = pre;
     if (len != NULL)
 	*len = (int)(ptr - start);
     if (nptr != NULL)
--- a/src/eval.c
+++ b/src/eval.c
@@ -1625,7 +1625,7 @@ call_vim_function(func, argc, argv, safe
 	    len = 0;
 	else
 	    /* Recognize a number argument, the others must be strings. */
-	    vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL, 0);
+	    vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
 	if (len != 0 && len == (int)STRLEN(argv[i]))
 	{
 	    argvars[i].v_type = VAR_NUMBER;
@@ -5139,7 +5139,7 @@ eval7(arg, rettv, evaluate, want_string)
 		else
 #endif
 		{
-		    vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL, 0);
+		    vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
 		    *arg += len;
 		    if (evaluate)
 		    {
@@ -18529,11 +18529,12 @@ f_str2nr(argvars, rettv)
     int		base = 10;
     char_u	*p;
     long	n;
+    int		what;
 
     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;
@@ -18543,7 +18544,14 @@ f_str2nr(argvars, rettv)
     p = skipwhite(get_tv_string(&argvars[0]));
     if (*p == '+')
 	p = skipwhite(p + 1);
-    vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL, 0);
+    switch (base)
+    {
+	case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
+	case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
+	case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
+	default: what = 0;
+    }
+    vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
     rettv->vval.v_number = n;
 }
 
@@ -21349,7 +21357,7 @@ get_tv_number_chk(varp, denote)
 	case VAR_STRING:
 	    if (varp->vval.v_string != NULL)
 		vim_str2nr(varp->vval.v_string, NULL, NULL,
-						    TRUE, TRUE, &n, NULL, 0);
+						    STR2NR_ALL, &n, NULL, 0);
 	    return n;
 	case VAR_LIST:
 	    EMSG(_("E745: Using a List as a Number"));
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -365,8 +365,8 @@ ex_sort(eap)
     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_what = 0;
+    int		format_found = 0;
 
     /* Sorting one line is really quick! */
     if (count <= 1)
@@ -381,7 +381,7 @@ ex_sort(eap)
     if (nrs == NULL)
 	goto sortend;
 
-    sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;
+    sort_abort = sort_ic = sort_rx = sort_nr = 0;
 
     for (p = eap->arg; *p != NUL; ++p)
     {
@@ -392,11 +392,25 @@ ex_sort(eap)
 	else if (*p == 'r')
 	    sort_rx = TRUE;
 	else if (*p == 'n')
+	{
 	    sort_nr = 2;
+	    ++format_found;
+	}
+	else if (*p == 'b')
+	{
+	    sort_what = STR2NR_BIN + STR2NR_FORCE;
+	    ++format_found;
+	}
 	else if (*p == 'o')
-	    sort_oct = 2;
+	{
+	    sort_what = STR2NR_OCT + STR2NR_FORCE;
+	    ++format_found;
+	}
 	else if (*p == 'x')
-	    sort_hex = 2;
+	{
+	    sort_what = STR2NR_HEX + STR2NR_FORCE;
+	    ++format_found;
+	}
 	else if (*p == 'u')
 	    unique = TRUE;
 	else if (*p == '"')	/* comment start */
@@ -439,15 +453,15 @@ ex_sort(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 (format_found > 1)
     {
 	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;
+    sort_nr += sort_what;
 
     /*
      * Make an array with all line numbers.  This avoids having to copy all
@@ -489,8 +503,10 @@ ex_sort(eap)
 	    *s2 = NUL;
 	    /* Sorting on number: Store the number itself. */
 	    p = s + start_col;
-	    if (sort_hex)
+	    if (sort_what & STR2NR_HEX)
 		s = skiptohex(p);
+	    else if (sort_what & STR2NR_BIN)
+		s = skiptobin(p);
 	    else
 		s = skiptodigit(p);
 	    if (s > p && s[-1] == '-')
@@ -499,8 +515,8 @@ ex_sort(eap)
 		/* 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, 0);
+		vim_str2nr(s, NULL, NULL, sort_what,
+			       &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
 	    *s2 = c;
 	}
 	else
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -5935,7 +5935,7 @@ get_list_range(str, num1, num2)
     *str = skipwhite(*str);
     if (**str == '-' || vim_isdigit(**str))  /* parse "from" part of range */
     {
-	vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL, 0);
+	vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
 	*str += len;
 	*num1 = (int)num;
 	first = TRUE;
@@ -5944,7 +5944,7 @@ get_list_range(str, num1, num2)
     if (**str == ',')			/* parse "to" part of range */
     {
 	*str = skipwhite(*str + 1);
-	vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL, 0);
+	vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
 	if (len > 0)
 	{
 	    *num2 = (int)num;
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -2780,7 +2780,7 @@ find_special_key(srcp, modp, keycode, ke
 	    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, 0);
+	    vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
 	    bp += l + 5;
 	    break;
 	}
@@ -2812,7 +2812,7 @@ find_special_key(srcp, modp, keycode, ke
 						 && VIM_ISDIGIT(last_dash[6]))
 	    {
 		/* <Char-123> or <Char-033> or <Char-0x33> */
-		vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n, 0);
+		vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
 		key = (int)n;
 	    }
 	    else
--- a/src/ops.c
+++ b/src/ops.c
@@ -5379,7 +5379,7 @@ do_addsub(command, Prenum1, g_cmd)
     int		col;
     char_u	*buf1;
     char_u	buf2[NUMBUFLEN];
-    int		hex;		/* 'X' or 'x': hex; '0': octal */
+    int		pre;		/* 'X'/'x': hex; '0': octal; 'B'/'b': bin */
     static int	hexupper = FALSE;	/* 0xABC */
     unsigned long n;
     unsigned long offset = 0;		/* line offset for Ctrl_V mode */
@@ -5390,6 +5390,7 @@ do_addsub(command, Prenum1, g_cmd)
     int		todel;
     int		dohex;
     int		dooct;
+    int		dobin;
     int		doalp;
     int		firstdigit;
     int		subtract;
@@ -5403,9 +5404,13 @@ do_addsub(command, Prenum1, g_cmd)
     int		did_change = FALSE;
     pos_T	t = curwin->w_cursor;
     int		maxlen = 0;
+    int		pos = 0;
+    int		bit = 0;
+    int		bits = sizeof(unsigned long) * 8;
 
     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" */
 
     /*
@@ -5454,17 +5459,45 @@ do_addsub(command, Prenum1, g_cmd)
 	ptr = ml_get_curline();
 	RLADDSUBFIX(ptr);
 
+	if (dobin)
+	    while (col > 0 && vim_isbdigit(ptr[col]))
+		--col;
+
 	if (dohex)
 	    while (col > 0 && vim_isxdigit(ptr[col]))
 		--col;
-	if (       dohex
+
+	if (       dobin
+		&& dohex
+		&& ! ((col > 0
+		    && (ptr[col] == 'X'
+			|| ptr[col] == 'x')
+		    && ptr[col - 1] == '0'
+		    && vim_isxdigit(ptr[col + 1]))))
+	{
+
+	    /* In case of binary/hexadecimal pattern overlap match, rescan */
+
+	    col = curwin->w_cursor.col;
+
+	    while (col > 0 && vim_isdigit(ptr[col]))
+		col--;
+	}
+
+	if ((       dohex
 		&& col > 0
 		&& (ptr[col] == 'X'
 		    || ptr[col] == 'x')
 		&& ptr[col - 1] == '0'
-		&& vim_isxdigit(ptr[col + 1]))
+		&& vim_isxdigit(ptr[col + 1])) ||
+	    (       dobin
+		&& col > 0
+		&& (ptr[col] == 'B'
+		    || ptr[col] == 'b')
+		&& ptr[col - 1] == '0'
+		&& vim_isbdigit(ptr[col + 1])))
 	{
-	    /* Found hexadecimal number, move to its start. */
+	    /* Found hexadecimal or binary number, move to its start. */
 	    --col;
 	}
 	else
@@ -5609,11 +5642,14 @@ do_addsub(command, Prenum1, g_cmd)
 					: curwin->w_cursor.col - col + 1);
 	    }
 
-	    vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n,
-								      maxlen);
-
-	    /* ignore leading '-' for hex and octal numbers */
-	    if (hex && negative)
+	    vim_str2nr(ptr + col, &pre, &length,
+		    0 + (dobin ? STR2NR_BIN : 0)
+		      + (dooct ? STR2NR_OCT : 0)
+		      + (dohex ? STR2NR_HEX : 0),
+		    NULL, &n, maxlen);
+
+	    /* ignore leading '-' for hex and octal and bin numbers */
+	    if (pre && negative)
 	    {
 		++col;
 		--length;
@@ -5634,7 +5670,7 @@ do_addsub(command, Prenum1, g_cmd)
 		n += (unsigned long)Prenum1;
 
 	    /* handle wraparound for decimal numbers */
-	    if (!hex)
+	    if (!pre)
 	    {
 		if (subtract)
 		{
@@ -5706,25 +5742,37 @@ do_addsub(command, Prenum1, g_cmd)
 	    {
 		*ptr++ = '-';
 	    }
-	    if (hex)
+	    if (pre)
 	    {
 		*ptr++ = '0';
 		--length;
 	    }
-	    if (hex == 'x' || hex == 'X')
+	    if (pre == 'b' || pre == 'B' || 
+		pre == 'x' || pre == 'X')
 	    {
-		*ptr++ = hex;
+		*ptr++ = pre;
 		--length;
 	    }
 
 	    /*
 	     * Put the number characters in buf2[].
 	     */
-	    if (hex == 0)
+	    if (pre == 'b' || pre == 'B')
+	    {
+		/* leading zeros */
+		for (bit = bits; bit > 0; bit--)
+		    if ((n >> (bit - 1)) & 0x1) break;
+
+		for (pos = 0; bit > 0; bit--)
+		    buf2[pos++] = ((n >> (bit - 1)) & 0x1) ? '1' : '0';
+
+		buf2[pos] = '\0';
+	    }
+	    else if (pre == 0)
 		sprintf((char *)buf2, "%lu", n);
-	    else if (hex == '0')
+	    else if (pre == '0')
 		sprintf((char *)buf2, "%lo", n);
-	    else if (hex && hexupper)
+	    else if (pre && hexupper)
 		sprintf((char *)buf2, "%lX", n);
 	    else
 		sprintf((char *)buf2, "%lx", n);
@@ -5736,7 +5784,7 @@ do_addsub(command, Prenum1, g_cmd)
 	     * Don't do this when
 	     * the result may look like an octal number.
 	     */
-	    if (firstdigit == '0' && !(dooct && hex == 0))
+	    if (firstdigit == '0' && !(dooct && pre == 0))
 		while (length-- > 0)
 		    *ptr++ = '0';
 	    *ptr = NUL;
@@ -6359,7 +6407,7 @@ get_reg_type(regname, reglen)
 #endif
 
     if (regname != NUL && !valid_yank_reg(regname, FALSE))
-        return MAUTO;
+	return MAUTO;
 
     get_yank_register(regname, FALSE);
 
--- a/src/option.c
+++ b/src/option.c
@@ -1940,7 +1940,7 @@ static struct vimoption
 			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
     {"nrformats",   "nf",   P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
 			    (char_u *)&p_nf, PV_NF,
-			    {(char_u *)"octal,hex", (char_u *)0L}
+			    {(char_u *)"bin,octal,hex", (char_u *)0L}
 			    SCRIPTID_INIT},
     {"number",	    "nu",   P_BOOL|P_VI_DEF|P_RWIN,
 			    (char_u *)VAR_WIN, PV_NU,
@@ -3031,7 +3031,7 @@ static struct vimoption
 static char *(p_ambw_values[]) = {"single", "double", NULL};
 #endif
 static char *(p_bg_values[]) = {"light", "dark", NULL};
-static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
+static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", NULL};
 static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
 #ifdef FEAT_CRYPT
 static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
@@ -4579,7 +4579,8 @@ do_set(arg, opt_flags)
 			{
 			    /* Allow negative (for 'undolevels'), octal and
 			     * hex numbers. */
-			    vim_str2nr(arg, NULL, &i, TRUE, TRUE, &value, NULL, 0);
+			    vim_str2nr(arg, NULL, &i, STR2NR_ALL,
+							     &value, NULL, 0);
 			    if (arg[i] != NUL && !vim_iswhite(arg[i]))
 			    {
 				errmsg = e_invarg;
--- a/src/proto/charset.pro
+++ b/src/proto/charset.pro
@@ -36,11 +36,14 @@ void getvvcol __ARGS((win_T *wp, pos_T *
 void getvcols __ARGS((win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right));
 char_u *skipwhite __ARGS((char_u *q));
 char_u *skipdigits __ARGS((char_u *q));
+char_u *skipbin __ARGS((char_u *q));
 char_u *skiphex __ARGS((char_u *q));
+char_u *skiptobin __ARGS((char_u *q));
 char_u *skiptodigit __ARGS((char_u *q));
 char_u *skiptohex __ARGS((char_u *q));
 int vim_isdigit __ARGS((int c));
 int vim_isxdigit __ARGS((int c));
+int vim_isbdigit __ARGS((int c));
 int vim_islower __ARGS((int c));
 int vim_isupper __ARGS((int c));
 int vim_toupper __ARGS((int c));
@@ -49,7 +52,7 @@ char_u *skiptowhite __ARGS((char_u *p));
 char_u *skiptowhite_esc __ARGS((char_u *p));
 long getdigits __ARGS((char_u **pp));
 int vim_isblankline __ARGS((char_u *lbuf));
-void vim_str2nr __ARGS((char_u *start, int *hexp, int *len, int dooct, int dohex, long *nptr, unsigned long *unptr, int strlen));
+void vim_str2nr __ARGS((char_u *start, int *prep, int *len, int what, long *nptr, unsigned long *unptr, int maxlen));
 int hex2nr __ARGS((int c));
 int hexhex2nr __ARGS((char_u *p));
 int rem_backslash __ARGS((char_u *str));
--- a/src/spell.c
+++ b/src/spell.c
@@ -1047,7 +1047,9 @@ spell_check(wp, ptr, attrp, capcol, doco
      * 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 = skipbin(ptr + 2);
+	else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
 	    mi.mi_end = skiphex(ptr + 2);
 	else
 	    mi.mi_end = skipdigits(ptr);
@@ -15612,7 +15614,7 @@ ex_spelldump(eap)
 
     /* enable spelling locally in the new window */
     set_option_value((char_u*)"spell", TRUE, (char_u*)"", OPT_LOCAL);
-    set_option_value((char_u*)"spl",  dummy,         spl, OPT_LOCAL);
+    set_option_value((char_u*)"spl",  dummy, spl, OPT_LOCAL);
     vim_free(spl);
 
     if (!bufempty() || !buf_valid(curbuf))
--- a/src/testdir/test57.in
+++ b/src/testdir/test57.in
@@ -30,6 +30,8 @@ STARTTEST
 :/^t25:/+1,/^t26/-1sort/\d\d/rn
 :/^t26:/+1,/^t27/-1sort/\d\d/rx
 :/^t27:/+1,/^t28/-1sort no
+:/^t28:/+1,/^t29/-1sort b
+:/^t29:/+1,/^t30/-1sort b
 :/^t01:/,$wq! test.out
 ENDTEST
 
@@ -494,7 +496,38 @@ c321d
 b322b
 b321
 b321b
+t28: binary
 
 
-t28: done
+0b111000
+0b101100
+0b101001
+0b101001
+0b101000
+0b000000
+0b001000
+0b010000
+0b101000
+0b100000
+0b101010
+0b100010
+0b100100
+0b100010
+t29: binary with leading characters
 
+
+0b100010
+0b010000
+ 0b101001
+b0b101100
+0b100010
+ 0b100100
+a0b001000
+0b101000
+0b101000
+a0b101001
+ab0b100000
+0b101010
+0b000000
+b0b111000
+t30: done
--- a/src/testdir/test57.ok
+++ b/src/testdir/test57.ok
@@ -453,7 +453,38 @@ c321d
 b322b
 b321
 b321b
+t28: binary
 
 
-t28: done
+0b000000
+0b001000
+0b010000
+0b100000
+0b100010
+0b100010
+0b100100
+0b101000
+0b101000
+0b101001
+0b101001
+0b101010
+0b101100
+0b111000
+t29: binary with leading characters
 
+
+0b000000
+a0b001000
+0b010000
+ab0b100000
+0b100010
+0b100010
+ 0b100100
+0b101000
+0b101000
+ 0b101001
+a0b101001
+0b101010
+b0b101100
+b0b111000
+t30: done
--- a/src/testdir/test58.in
+++ b/src/testdir/test58.in
@@ -104,6 +104,8 @@ gg:/^addstart/+1,/^addend/-1w! Xtest.lat
 :"
 :" NOSLITSUGS
 :call TestOne('8', '8')
+:" Numbers
+:call TestOne('9', '9')
 :"
 :" clean up for valgrind
 :delfunc TestOne
@@ -636,4 +638,19 @@ bad: foobar barfoo
 badend
 
 
+Test Numbers
+
+9affstart
+9affend
+
+9dicstart
+1234
+foo
+bar
+9dicend
+
+9good: 0b1011 0777 1234 0x01ff
+badend
+
+
 test output:
--- a/src/testdir/test58.ok
+++ b/src/testdir/test58.ok
@@ -281,3 +281,9 @@ foobar
 ['faabar', 'foo bar', 'bar']
 barfoo
 ['bar foo', 'bar', 'foo']
+
+test 9-9
+# file: Xtest.latin1.spl
+bar
+foo
+-------
--- a/src/testdir/test_increment.in
+++ b/src/testdir/test_increment.in
@@ -286,6 +286,49 @@ 0x123456
   1) Ctrl-V f3 <ctrl-a>
 0x124456
 
+22) Block increment on 0b0
+Text:
+0b1
+0b1
+    Expected:
+    1) Ctrl-A on visually block selected region (cursor at beginning):
+    0b10
+    0b10
+    2) Ctrl-A on visually block selected region (cursor at end)
+    0b10
+    0b10
+
+23) block-wise increment on part of binary
+Text:
+0b1001
+
+  Expected:
+  1) Ctrl-V 5l <ctrl-a>
+0b1011
+
+24) increment hexadecimal
+Text:
+0x0b1001
+
+  Expected:
+  1) <ctrl-a>
+0x0b1002
+
+25) increment binary with nrformats including alpha
+Text:
+0b1001a
+
+  Expected:
+  1) <ctrl-a>
+0b1010a
+
+26) increment binary with 64 bits
+Text:
+0b1111111111111111111111111111111111111111111111111111111111111110
+
+  Expected:
+  1) <ctrl-a>
+0b1111111111111111111111111111111111111111111111111111111111111111
 
 
 STARTTEST
@@ -415,6 +458,38 @@ V3kg..
 :set nrformats&vim
 f3
 
+:" Test 22
+:/^S22=/+,/^E22=/-y a
+:/^E22=/+put a
+kj$j:.+put a
+k$+
+
+:" Test 23
+:/^S23=/+,/^E23=/-y a
+:/^E23=/+put a
+:set nrformats&vim
+4l
+
+:" Test 24
+:/^S24=/+,/^E24=/-y a
+:/^E24=/+put a
+:set nrformats&vim
+$
+
+:" Test 25
+:set nrformats+=alpha
+:/^S25=/+,/^E25=/-y a
+:/^E25=/+put a
+k$
+:set nrformats&vim
+
+:" Test 26
+:set nrformats+=alpha
+:/^S26=/+,/^E26=/-y a
+:/^E26=/+put a
+k$
+:set nrformats&vim
+
 :" Save the report
 :/^# Test 1/,$w! test.out
 :qa!
@@ -615,6 +690,45 @@ E21====
 
 
 
+# Test 22
+S22====
+0b1
+0b1
+E22====
+
+
+
+
+# Test 23
+S23====
+0b1001
+E23====
+
+
+
+
+# Test 24
+S24====
+0x0b1001
+E24====
+
+
+
+
+# Test 25
+S25====
+0b1001a
+E25====
+
+
+
+
+# Test 26
+S26====
+0b1111111111111111111111111111111111111111111111111111111111111110
+E26====
+
+
 
 ENDTEST
 
--- a/src/testdir/test_increment.ok
+++ b/src/testdir/test_increment.ok
@@ -288,6 +288,53 @@ E21====
 0x124456
 
 
+# Test 22
+S22====
+0b1
+0b1
+E22====
+
+0b10
+0b10
+
+0b10
+0b10
+
+
+# Test 23
+S23====
+0b1001
+E23====
+
+0b1011
+
+
+
+# Test 24
+S24====
+0x0b1001
+E24====
+
+0x0b1002
+
+
+
+# Test 25
+S25====
+0b1001a
+E25====
+
+0b1010a
+
+
+
+# Test 26
+S26====
+0b1111111111111111111111111111111111111111111111111111111111111110
+E26====
+
+0b1111111111111111111111111111111111111111111111111111111111111111
+
 
 ENDTEST
 
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1027,
+/**/
     1026,
 /**/
     1025,
--- a/src/vim.h
+++ b/src/vim.h
@@ -392,7 +392,15 @@
 # endif
 #endif
 
-#define NUMBUFLEN 30	    /* length of a buffer to store a number in ASCII */
+/* length of a buffer to store a number in ASCII (64 bits binary + NUL) */
+#define NUMBUFLEN 65
+
+/* flags for vim_str2nr() */
+#define STR2NR_BIN 1
+#define STR2NR_OCT 2
+#define STR2NR_HEX 4
+#define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
+#define STR2NR_FORCE 8 /* only when ONE of the above is used */
 
 /*
  * Shorthand for unsigned variables. Many systems, but not all, have u_char