64 lines
1.6 KiB
C
64 lines
1.6 KiB
C
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
static bool baseconv_internal(
|
|
char outbuf[], size_t bufsize,
|
|
const char *digits, size_t base,
|
|
uintmax_t num
|
|
) {
|
|
// Supported bases are 2 to number of digits inclusive
|
|
if (base < 2 || base > strlen(digits))
|
|
return false;
|
|
|
|
// Longest possible converted string is base-2, where we produce one
|
|
// character per bit of input, so if we size the buffer to fit it we
|
|
// can fit any converted string
|
|
char buf[sizeof(uintmax_t) * CHAR_BIT];
|
|
|
|
// Place the digits in the buffer in a little-endian order
|
|
size_t len = 0;
|
|
while (num) {
|
|
char digit = digits[num % base];
|
|
buf[len++] = digit;
|
|
num /= base;
|
|
}
|
|
|
|
// Special case: if the original input was zero, previous loop ran
|
|
// zero times, and there is nothing in the buffer. Place a single
|
|
// zero there.
|
|
if (!len)
|
|
buf[len++] = digits[0];
|
|
|
|
// Can the output buffer hold the converted string as well as the
|
|
// null terminator?
|
|
if (!bufsize || bufsize - 1 < len)
|
|
return false;
|
|
|
|
// Copy the digits to the output buffer, reversing the order
|
|
for (size_t i = 0; i < len; i++)
|
|
outbuf[i] = buf[len - 1 - i];
|
|
|
|
// Null-terminate
|
|
outbuf[len] = '\0';
|
|
|
|
return true;
|
|
}
|
|
|
|
bool baseconv(char outbuf[], size_t bufsize, size_t base, uintmax_t num) {
|
|
const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
return baseconv_internal(outbuf, bufsize, digits, base, num);
|
|
}
|
|
|
|
bool baseconv_digits(
|
|
char outbuf[], size_t bufsize,
|
|
const char *digits,
|
|
uintmax_t num
|
|
) {
|
|
size_t base = strlen(digits);
|
|
return baseconv_internal(outbuf, bufsize, digits, base, num);
|
|
}
|