Skip to content
Snippets Groups Projects
Commit 6cc5216c authored by Peter Limkilde Svendsen's avatar Peter Limkilde Svendsen Committed by jD91mZM2
Browse files

Implement l64a()

parent e35f22b3
No related branches found
No related tags found
No related merge requests found
......@@ -35,6 +35,7 @@ pub const MB_CUR_MAX: c_int = 4;
pub const MB_LEN_MAX: c_int = 4;
static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
static mut L64A_BUFFER: [c_char; 7] = [0; 7]; // up to 6 digits plus null terminator
static mut RNG: Option<XorShiftRng> = None;
lazy_static! {
......@@ -51,26 +52,27 @@ pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long {
if s.is_null() {
return 0;
}
let mut l: c_long = 0;
// POSIX says only the low-order 32 bits are used.
let mut l: i32 = 0;
// a64l does not support more than 6 characters at once
for x in 0..6 {
let c = *s.offset(x);
if c == 0 {
// string is null terminated
return l;
return c_long::from(l);
}
// ASCII to base64 conversion:
let mut bits: c_long = if c < 58 {
(c - 46) as c_long // ./0123456789
let mut bits: i32 = if c < 58 {
(c - 46) as i32 // ./0123456789
} else if c < 91 {
(c - 53) as c_long // A-Z
(c - 53) as i32 // A-Z
} else {
(c - 59) as c_long // a-z
(c - 59) as i32 // a-z
};
bits <<= 6 * x;
l |= bits;
}
l
c_long::from(l)
}
#[no_mangle]
......@@ -368,9 +370,37 @@ pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long {
lcg48::int32_from_x(new_xi)
}
// #[no_mangle]
pub extern "C" fn l64a(value: c_long) -> *mut c_char {
unimplemented!();
#[no_mangle]
pub unsafe extern "C" fn l64a(value: c_long) -> *mut c_char {
// POSIX says we should only consider the lower 32 bits of value.
let value_as_i32 = value as i32;
/* If we pretend to extend the 32-bit value with 4 binary zeros, we
* would get a 36-bit integer. The number of base-64 digits to be
* left unused can then be found by taking the number of leading
* zeros, dividing by 6 and rounding down (i.e. using integer
* division). */
let num_output_digits = 6 - (value_as_i32.leading_zeros() + 4) / 6;
// Reset buffer (and have null terminator in place for any result)
L64A_BUFFER = [0; 7];
for i in 0..num_output_digits as usize {
let digit_value = ((value_as_i32 >> 6 * i) & 63) as c_char;
if digit_value < 12 {
// ./0123456789 for values 0 to 11. b'.' == 46
L64A_BUFFER[i] = 46 + digit_value;
} else if digit_value < 38 {
// A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
L64A_BUFFER[i] = 53 + digit_value;
} else {
// a-z for values 38 to 63. b'a' == 97, 97-38 == 59
L64A_BUFFER[i] = 59 + digit_value;
}
}
L64A_BUFFER.as_mut_ptr()
}
#[no_mangle]
......
Correct a64l: azAZ9. = 194301926
Correct a64l: azA = 53222
l64a(0):
l64a(1): /
l64a(2): 0
l64a(11): 9
l64a(12): A
l64a(37): Z
l64a(38): a
l64a(63): z
l64a(64): ./
l64a(65): //
l64a(4095): zz
l64a(4096): ../
l64a(262143): zzz
l64a(262144): .../
l64a(16777215): zzzz
l64a(16777216): ..../
l64a(1073741823): zzzzz
l64a(1073741824): ...../
l64a(2147483647): zzzzz/
a64l(l64a(0)): 0
a64l(l64a(1)): 1
a64l(l64a(2)): 2
a64l(l64a(11)): 11
a64l(l64a(12)): 12
a64l(l64a(37)): 37
a64l(l64a(38)): 38
a64l(l64a(63)): 63
a64l(l64a(64)): 64
a64l(l64a(65)): 65
a64l(l64a(4095)): 4095
a64l(l64a(4096)): 4096
a64l(l64a(262143)): 262143
a64l(l64a(262144)): 262144
a64l(l64a(16777215)): 16777215
a64l(l64a(16777216)): 16777216
a64l(l64a(1073741823)): 1073741823
a64l(l64a(1073741824)): 1073741824
a64l(l64a(2147483647)): 2147483647
l64a(x) (lower 32 bits of x are 1985229328): E61Jq/
a64l(l64a(x)) (lower 32 bits of x are 1985229328): 1985229328
......@@ -20,4 +20,34 @@ int main(void) {
exit(EXIT_FAILURE);
}
printf("Correct a64l: %s = %ld\n", s, l);
/* Test near boundaries of digit character mapping, and near
* boundaries for number of digits */
long l64a_test_values[] = {0, 1, 2, 11, 12, 37, \
38, 63, \
64, 65, 4095, \
4096, 262143, \
262144, 16777215, \
16777216, 1073741823, \
1073741824, 2147483647};
// l64a tests
for (size_t i = 0; i < sizeof(l64a_test_values)/sizeof(long); i++) {
printf("l64a(%ld): %s\n", l64a_test_values[i], l64a(l64a_test_values[i]));
}
// a64l(l64a(x)) round-trip tests
for (size_t i = 0; i < sizeof(l64a_test_values)/sizeof(long); i++) {
printf("a64l(l64a(%ld)): %ld\n", l64a_test_values[i], a64l(l64a(l64a_test_values[i])));
}
/* For testing 32-bit truncation behavior (for platforms where long
* is larger than 32 bits). Note that the behavior for a64l() and
* l64a() is unspecified for negative values. */
int64_t test_value_64bit = 0x7edcba9876543210;
printf("l64a(x) (lower 32 bits of x are %ld): %s\n", ((long)test_value_64bit) & 0xffffffff, l64a((long)test_value_64bit));
/* Test for trunctation in l64a(a64(x)) round trip (POSIX says the
* result of that is "x in the low-order 32-bits". */
printf("a64l(l64a(x)) (lower 32 bits of x are %ld): %ld\n", ((long)test_value_64bit) & 0xffffffff, a64l(l64a((long)test_value_64bit)));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment