63 lines
		
	
	
	
		
			1.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			63 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);
 | |
| }
 |