baseconv/baseconv.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);
}