Add support for binary numbers

This commit is contained in:
Jason Schulz
2015-12-29 15:17:16 -08:00
parent dddbf9c5fa
commit 7ad3f077dc
17 changed files with 350 additions and 95 deletions

View File

@@ -1454,6 +1454,20 @@ char_u* skipdigits(char_u *q)
return p;
}
/// skip over binary digits
///
/// @param q
///
/// @return Pointer to the character after the skipped digits.
char_u* skipbin(char_u *q)
{
char_u *p = q;
while (ascii_isbdigit(*p)) /* skip to next non-digit */
++p;
return p;
}
/// skip over digits and hex characters
///
/// @param q
@@ -1485,6 +1499,20 @@ char_u* skiptodigit(char_u *q)
return p;
}
/// skip to binary character (or NUL after the string)
///
/// @param q
///
/// @return Pointer to the binary character or (NUL after the string).
char_u* skiptobin(char_u *q)
{
char_u *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,33 +1748,38 @@ 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 pre = 0; // default is decimal
int negative = FALSE;
unsigned long un = 0;
int n;
@@ -1756,31 +1789,35 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
++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,28 +1825,38 @@ 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++;
++ptr;
}
} else {
// decimal
while (ascii_isdigit(*ptr)) {
un = 10 * un + (unsigned long)(*ptr - '0');
ptr++;
++ptr;
}
}
if (hexp != NULL) {
*hexp = hex;
if (prep != NULL) {
*prep = pre;
}
if (len != NULL) {