commit 12f8b73077b8b1587cc91e7dc23ee147d4177bd0 Author: Juhani Krekelä Date: Sun Nov 20 06:52:54 2022 +0200 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae0b819 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +baseconv_example diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9608fdd --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +BIN = baseconv_example +OBJS = baseconv.o main.o + +all: $(BIN) + +$(BIN): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) + +main.o: baseconv.h + +clean: + rm -f $(BIN) $(OBJS) + +distclean: clean + +.PHONY: all clean distclean diff --git a/baseconv.c b/baseconv.c new file mode 100644 index 0000000..33ecad4 --- /dev/null +++ b/baseconv.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +bool baseconv(char outbuf[], size_t bufsize, unsigned base, uintmax_t num) { + // Supported bases are 2 to 36 inclusive (though it could be higher + // if our digits string was longer + if (base < 2 || base > 36) + 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; +} diff --git a/baseconv.h b/baseconv.h new file mode 100644 index 0000000..72f5df1 --- /dev/null +++ b/baseconv.h @@ -0,0 +1 @@ +bool baseconv(char outbuf[], size_t bufsize, unsigned base, uintmax_t num); diff --git a/main.c b/main.c new file mode 100644 index 0000000..826fbc1 --- /dev/null +++ b/main.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include + +#include "baseconv.h" + +int main(void) { + uintmax_t num; + printf("Number? "); + if (scanf("%ju", &num) != 1) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + unsigned base; + printf("Base? "); + if (scanf("%u", &base) != 1) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + size_t bufsize; + printf("Buffer size? "); + if (scanf("%zu", &bufsize) != 1) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + char *buf = malloc(bufsize); + if (!buf) { + fprintf(stderr, "Failed to allocate %zu bytes\n", bufsize); + return 1; + } + + if (!baseconv(buf, bufsize, base, num)) { + fprintf(stderr, "Conversion error\n"); + free(buf); + return 1; + } + + printf("%s\n", buf); + + free(buf); +}