libfreestanding.
extern "C" {
#endif
+void *memcpy(void *dest, const void *src, size_t len);
void *memset(void *block, int count, size_t len);
int memcmp(const void *b1, const void *b2, size_t len);
size_t strlen(const char *s);
include tests/Makefile
TARGETS := $(BUILDDIR)/kernel $(BUILDDIR)/kernel.stripped
+RAW_LIBS := c/libfreestanding.a
+LIBS += $(RAW_LIBS:%=$(ARCHBUILDDIR)/user/lib/%)
.PHONY: symlinks
symlinks:
DIR := arch/x86/
CXXFLAGS += -fno-omit-frame-pointer -march=i686
-$(BUILDDIR)/kernel: $(OBJS) $(DIR)linker-script
+$(BUILDDIR)/kernel: $(OBJS) $(LIBS) $(DIR)linker-script
@echo $(COMP): Linking kernel: $@
@$(MKDIR) $(dir $@)
- @$(CXX) $(OBJS) -lgcc -lsupc++ -nostdlib -o "$@" -Wl,-T$(DIR)linker-script
+ @$(CXX) $(OBJS) $(LIBS) -lgcc -lsupc++ -nostdlib -o "$@" -Wl,-T$(DIR)linker-script
# GRUB refuses to use the addresses in the multiboot header if it
# finds a valid ELF header, so the dd hacks a zero into the high byte
#include <kern/types.h>
#include <stdarg.h>
-size_t vsnprintf(char *buf, size_t size, const char *str, va_list args);
-size_t snprintf(char *buf, size_t size, const char *str, ...)
-__attribute__((format(printf, 3, 4)));
-size_t sprintf(char *buf, const char *str, ...)
-__attribute__((format(printf, 2, 3)));
-size_t printf(const char *str, ...)
-__attribute__((format(printf, 1, 2)));
-
-// These are C-ABI so libgcc and libsupc++ can use them.
extern "C" {
+ size_t vsnprintf(char *buf, size_t size, const char *str, va_list args);
+ size_t snprintf(char *buf, size_t size, const char *str, ...)
+ __attribute__((format(printf, 3, 4)));
+ size_t sprintf(char *buf, const char *str, ...)
+ __attribute__((format(printf, 2, 3)));
+ size_t printf(const char *str, ...)
+ __attribute__((format(printf, 1, 2)));
+
// FIXME: template/alignof versions
void *memcpy(void *dest, const void *src, size_t len);
void *memmove(void *dest, const void *src, size_t len);
#include <stdarg.h>
#include <limits.h>
-// FIXME: Move printf to lib/kernel
-
-static const int alt_form = 0x0001;
-static const int zero_pad = 0x0002;
-static const int neg_field = 0x0004;
-static const int leave_blank = 0x0008;
-static const int always_sign = 0x0010;
-static const int group_thousands = 0x0020; // FIXME -- unimplemented
-static const int long_arg = 0x0040;
-static const int long_long_arg = 0x0080;
-static const int short_arg = 0x0100;
-static const int short_short_arg = 0x0200;
-static const int intmax_arg = 0x0400;
-static const int ptrdiff_arg = 0x0800;
-static const int size_t_arg = 0x1000;
-static const int capital_hex = 0x2000;
-static const int num_signed = 0x4000;
-static const int has_precision = 0x8000;
-
-static void printf_string(char *buf, size_t &opos, size_t limit,
- const char *src, size_t len)
-{
- if (opos < limit) {
- size_t olen = opos + len <= limit ? len : limit - opos;
- memcpy(buf + opos, src, olen);
- }
-
- opos += len;
-}
-
-static void printf_fill(char *buf, size_t &opos, size_t limit,
- char ch, int len)
-{
- if (opos < limit) {
- size_t olen = opos + len <= limit ? len : limit - opos;
- memset(buf + opos, ch, olen);
- }
-
- opos += len;
-}
-
-static void printf_num(char *obuf, size_t &opos, size_t limit,
- s64 value, long radix, int fieldwidth,
- int precision, int flags)
-{
- char buf[65];
- int pos = 64;
- int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10;
- u64 uval;
-
- if (flags & num_signed)
- uval = value < 0 ? -value : value;
- else
- uval = value;
-
- // An explicit precision of 0 suppresses all output if the value
- // is zero. Otherwise, the output size is not limited by precision
- // or field width.
-
- if (uval != 0 || !(flags & has_precision) || precision != 0) do {
- int ch = uval % radix;
-
- if (ch < 10)
- buf[pos] = ch + '0';
- else
- buf[pos] = ch + letter;
-
- uval /= radix;
- pos--;
- } while (uval);
-
- int len = 64 - pos;
-
- // length which counts against fieldwidth but not precision
- int extralen = 0;
-
- if (flags & num_signed) {
- if (value < 0) {
- printf_fill(obuf, opos, limit, '-', 1);
- extralen += 1;
- } else if (flags & always_sign) {
- printf_fill(obuf, opos, limit, '+', 1);
- extralen += 1;
- } else if (flags & leave_blank) {
- printf_fill(obuf, opos, limit, ' ', 1);
- extralen += 1;
- }
- }
-
- if ((flags & alt_form) && value != 0) {
- if (radix == 8 && (!(flags & has_precision) || precision <= len)) {
- flags |= has_precision;
- precision = len + 1;
- }
-
- if (radix == 16) {
- printf_string(obuf, opos, limit, "0x", 2);
- extralen += 2;
- }
- }
-
- if ((flags & has_precision) && len < precision) {
- precision -= len;
- len += precision;
- } else {
- precision = 0;
- }
-
- len += extralen;
-
- if (!(flags & neg_field) && len < fieldwidth) {
- char padchar = (flags & zero_pad) ? '0' : ' ';
- printf_fill(obuf, opos, limit, padchar, fieldwidth - len);
- len = fieldwidth;
- }
-
- if (precision != 0) {
- printf_fill(obuf, opos, limit, '0', precision);
- len += precision;
- }
-
- printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos);
-
- if ((flags & neg_field) && len < fieldwidth)
- printf_fill(obuf, opos, limit, ' ', fieldwidth - len);
-}
-
-size_t vsnprintf(char *buf, size_t size, const char *str, va_list args)
-{
- size_t opos = 0; // position in the output string
- unsigned int flags = 0;
- int radix = 10;
- int state = 0;
- int fieldwidth = 0;
- int precision = 0;
-
- for (size_t pos = 0; str[pos]; pos++) switch (state) {
- case 0:
- if (str[pos] == '%') {
- flags = 0;
- radix = 10;
- state = 1;
- fieldwidth = 0;
- precision = 0;
- break;
- }
-
- if (opos < size)
- buf[opos] = str[pos];
-
- opos++;
- break;
-
- case 1: // A percent has been seen; read in format characters
- switch (str[pos]) {
- case '#':
- flags |= alt_form;
- break;
-
- case '0':
- if (!(flags & has_precision)) {
- flags |= zero_pad;
- break;
- }
-
- // else fall through
-
- case '1' ... '9':
- if (flags & has_precision)
- goto default_case;
-
- do {
- fieldwidth *= 10;
- fieldwidth += str[pos++] - '0';
- } while (str[pos] >= '0' && str[pos] <= '9');
-
- pos--;
- break;
-
- case '*':
- if (fieldwidth || (flags & has_precision))
- goto default_case;
-
- fieldwidth = va_arg(args, int);
- break;
-
- case '.':
- flags |= has_precision;
-
- if (str[pos + 1] == '*') {
- pos++;
- precision = va_arg(args, int);
- } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') {
- precision *= 10;
- precision += str[++pos] - '0';
- }
-
- break;
-
- case '-':
- flags |= neg_field;
- break;
-
- case ' ':
- flags |= leave_blank;
- break;
-
- case '+':
- flags |= always_sign;
- break;
-
- case '\'':
- flags |= group_thousands;
- break;
-
- case 'l':
- if (flags & long_arg)
- flags |= long_long_arg;
- else
- flags |= long_arg;
-
- break;
-
- case 'h':
- if (flags & long_arg)
- flags |= short_short_arg;
- else
- flags |= short_arg;
-
- break;
-
- case 'j':
- flags |= intmax_arg;
- break;
-
- case 't':
- flags |= ptrdiff_arg;
- break;
-
- // Note that %z and other such "new" format characters are
- // basically useless because some GCC coder actually went out
- // of their way to make the compiler reject C99 format
- // strings in C++ code, with no way of overriding it that I
- // can find (the source code comments suggest the checking is
- // only when using -pedantic, but I wasn't using -pedantic).
- //
- // Thus, we have the choice of either avoiding %z and friends
- // (and possibly needing to insert hackish casts to silence
- // the compiler's warnings if different architectures define
- // types like size_t in different ways), or not using the
- // format warnings at all.
- //
- // To mitigate this, 32-bit architectures should define
- // pointer-sized special types as "long" rather than "int",
- // so that %lx/%ld can always be used with them. Fixed-size
- // 32-bit types should be declared as "int" rather than
- // "long" for the same reason.
-
- case 'z':
- flags |= size_t_arg;
- break;
-
- case 'd':
- case 'i': {
- s64 arg;
-
- if ((flags & intmax_arg) || (flags & long_long_arg))
- arg = va_arg(args, long long);
- else if (flags & size_t_arg)
- arg = va_arg(args, ssize_t);
- else if (flags & ptrdiff_arg)
- arg = va_arg(args, ptrdiff_t);
- else if (flags & long_arg)
- arg = va_arg(args, long);
- else if (flags & short_short_arg)
- arg = (signed char)va_arg(args, int);
- else if (flags & short_arg)
- arg = (short)va_arg(args, int);
- else
- arg = va_arg(args, int);
-
- flags |= num_signed;
- printf_num(buf, opos, size, arg, 10,
- fieldwidth, precision, flags);
- state = 0;
- break;
- }
-
- case 'X':
- flags |= capital_hex;
- // fall-through
-
- case 'x':
- radix = 18;
- // fall-through
-
- case 'o':
- radix -= 2;
- // fall-through
-
- case 'u': {
- u64 arg;
-
- if ((flags & intmax_arg) || (flags & long_long_arg))
- arg = va_arg(args, unsigned long long);
- else if (flags & size_t_arg)
- arg = va_arg(args, size_t);
- else if (flags & ptrdiff_arg)
- arg = va_arg(args, intptr_t);
- else if (flags & long_arg)
- arg = va_arg(args, unsigned long);
- else if (flags & short_short_arg)
- arg = (unsigned char)va_arg(args, unsigned int);
- else if (flags & short_arg)
- arg = (unsigned short)va_arg(args, unsigned int);
- else if (flags & short_short_arg)
- arg = (signed char)va_arg(args, int);
- else if (flags & short_arg)
- arg = (short)va_arg(args, int);
- else
- arg = va_arg(args, unsigned int);
-
- printf_num(buf, opos, size, arg, radix,
- fieldwidth, precision, flags);
- state = 0;
- break;
- }
-
- case 'c':
- if (opos < size)
- buf[opos] = va_arg(args, int);
-
- opos++;
- state = 0;
- break;
-
- case 's': {
- const char *arg = va_arg(args, const char *);
-
- if (!arg)
- arg = "(null)";
-
- size_t len = strlen(arg);
- printf_string(buf, opos, size, arg, len);
- state = 0;
- break;
- }
-
- case 'p': {
- const void *arg = va_arg(args, const void *);
-
- printf_num(buf, opos, size, (ulong)arg, 16,
- fieldwidth, precision, flags);
-
- state = 0;
- break;
- }
-
- case 'n': {
- if ((flags & intmax_arg) || (flags & long_long_arg))
- *va_arg(args, unsigned long long *) = opos;
- else if (flags & size_t_arg)
- *va_arg(args, ssize_t *) = opos;
- else if (flags & ptrdiff_arg)
- *va_arg(args, ptrdiff_t *) = opos;
- else if (flags & long_arg)
- *va_arg(args, long *) = opos;
- else if (flags & short_short_arg)
- *va_arg(args, signed char *) = opos;
- else if (flags & short_arg)
- *va_arg(args, short *) = opos;
- else
- *va_arg(args, int *) = opos;
-
- state = 0;
- break;
- }
-
- default_case: // label for goto
- default:
- if (opos < size)
- buf[opos] = str[pos];
-
- opos++;
- state = 0;
- break;
- }
- }
-
- if (size > 0 && opos >= size)
- buf[size - 1] = 0;
-
- return opos;
-}
-
-size_t snprintf(char *buf, size_t size, const char *str, ...)
-{
- va_list args;
- va_start(args, str);
- int ret = vsnprintf(buf, size, str, args);
- va_end(args);
- return ret;
-}
-
-size_t sprintf(char *buf, const char *str, ...)
-{
- va_list args;
- va_start(args, str);
- int ret = vsnprintf(buf, ULONG_MAX, str, args);
- va_end(args);
- return ret;
-}
-
-void *memcpy(void *dest, const void *src, size_t len)
-{
- const char *cs = static_cast<const char *>(src);
- char *cd = static_cast<char *>(dest);
-
- for (size_t i = 0; i < len; i++)
- cd[i] = cs[i];
-
- return dest;
-}
-
-void *memmove(void *dest, const void *src, size_t len)
-{
- if (dest < src)
- return memcpy(dest, src, len);
-
- const char *cs = static_cast<const char *>(src);
- char *cd = static_cast<char *>(dest);
-
- for (size_t i = len - 1; i >= 0; i--)
- cd[i] = cs[i];
-
- return dest;
-}
-
-int memcmp(const void *b1, const void *b2, size_t len)
-{
- size_t pos;
- const char *c1 = static_cast<const char *>(b1);
- const char *c2 = static_cast<const char *>(b2);
-
- for (pos = 0; pos < len; pos++) {
- if (c1[pos] != c2[pos])
- return c1[pos] - c2[pos];
-
- pos++;
- }
-
- return 0;
-}
-
-size_t strnlen(const char *s, size_t n)
-{
- size_t pos = 0;
- while (pos < n && *s++)
- pos++;
- return pos;
-}
-
-size_t strlen(const char *s)
-{
- size_t pos = 0;
- while (*s++)
- pos++;
- return pos;
-}
-
-char *strcpy(char *dest, const char *src)
-{
- char *orig = dest;
-
- do {
- *dest = *src++;
- } while (*dest++);
-
- return orig;
-}
-
-char *strncpy(char *dest, const char *src, size_t len)
-{
- char *orig = dest;
-
- while (len--) {
- *dest = *src++;
-
- if (!*dest++)
- break;
- }
-
- bzero(dest, len);
- return orig;
-}
-
-char *strcat(char *dest, const char *src)
-{
- char *orig = dest;
- dest += strlen(dest);
-
- do {
- *dest = *src++;
- } while (*dest++);
-
- return orig;
-}
-
-char *strncat(char *dest, const char *src, size_t len)
-{
- char *orig = dest;
- int orig_len = strlen(dest);
-
- len -= orig_len;
- dest += orig_len;
-
- while (len--) {
- *dest = *src++;
-
- if (!*dest++)
- break;
- }
-
- bzero(dest, len);
- return orig;
-}
-
void bzero(void *b, size_t len)
{
char *c = static_cast<char *>(b);
*c++ = 0;
}
-void *memset(void *b, int ch, size_t len)
-{
- char *c = static_cast<char *>(b);
-
- while (len--)
- *c++ = ch;
-
- return b;
-}
-
#include <kern/pagealloc.h>
// Temporary hack until slab allocator is added
COMP := lib
include ../Makefile.head
+TARGETS := objs
+
include c++/Makefile
include c/Makefile
-TARGETS := objs
-
include ../Makefile.tail
+include c/Makefile.final
objs: $(OBJS)
-DIR := c/
-DIRS += $(DIR)
-
-RAW_CXXFILES :=
-CXXFILES += $(RAW_CXXFILES:%=$(DIR)%)
+include c/freestanding/Makefile
--- /dev/null
+include c/freestanding/Makefile.final
--- /dev/null
+DIR := c/freestanding/
+DIRS += $(DIR)
+
+RAW_CFILES := sprintf string
+CFILES += $(RAW_CFILES:%=$(DIR)%)
+
+RAW_CXXFILES :=
+CXXFILES += $(RAW_CXXFILES:%=$(DIR)%)
+
+TARGETS += $(BUILDDIR)/c/libfreestanding.a
--- /dev/null
+MYOBJS := $(filter $(BUILDDIR)/c/freestanding/%,$(OBJS))
+
+$(BUILDDIR)/c/libfreestanding.a: $(MYOBJS)
+ @echo $(COMP): Linking c/libfreestanding.a
+ @$(MKDIR) $(dir $@)
+ @$(RM) $@
+ @$(AR) rc $@ $(MYOBJS)
+ @$(RANLIB) $@
--- /dev/null
+// sprintf() and related functions.
+//
+// This software is copyright (c) 2007 Scott Wood <scott@buserror.net>.
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors or contributors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is hereby granted to everyone, free of charge, to use, copy,
+// modify, prepare derivative works of, publish, distribute, perform,
+// sublicense, and/or sell copies of the Software, provided that the above
+// copyright notice and disclaimer of warranty be included in all copies or
+// substantial portions of this software.
+
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+
+enum {
+ alt_form = 0x0001,
+ zero_pad = 0x0002,
+ neg_field = 0x0004,
+ leave_blank = 0x0008,
+ always_sign = 0x0010,
+ group_thousands = 0x0020, // FIXME -- unimplemented
+ long_arg = 0x0040,
+ long_long_arg = 0x0080,
+ short_arg = 0x0100,
+ short_short_arg = 0x0200,
+ intmax_arg = 0x0400,
+ ptrdiff_arg = 0x0800,
+ size_t_arg = 0x1000,
+ capital_hex = 0x2000,
+ num_signed = 0x4000,
+ has_precision = 0x8000,
+};
+
+static void printf_string(char *buf, size_t &opos, size_t limit,
+ const char *src, size_t len)
+{
+ if (opos < limit) {
+ size_t olen = opos + len <= limit ? len : limit - opos;
+ memcpy(buf + opos, src, olen);
+ }
+
+ opos += len;
+}
+
+static void printf_fill(char *buf, size_t &opos, size_t limit,
+ char ch, int len)
+{
+ if (opos < limit) {
+ size_t olen = opos + len <= limit ? len : limit - opos;
+ memset(buf + opos, ch, olen);
+ }
+
+ opos += len;
+}
+
+static void printf_num(char *obuf, size_t &opos, size_t limit,
+ int64_t value, long radix, int fieldwidth,
+ int precision, int flags)
+{
+ char buf[65];
+ int pos = 64;
+ int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10;
+ uint64_t uval;
+
+ if (flags & num_signed)
+ uval = value < 0 ? -value : value;
+ else
+ uval = value;
+
+ // An explicit precision of 0 suppresses all output if the value
+ // is zero. Otherwise, the output size is not limited by precision
+ // or field width.
+
+ if (uval != 0 || !(flags & has_precision) || precision != 0) do {
+ int ch = uval % radix;
+
+ if (ch < 10)
+ buf[pos] = ch + '0';
+ else
+ buf[pos] = ch + letter;
+
+ uval /= radix;
+ pos--;
+ } while (uval);
+
+ int len = 64 - pos;
+
+ // length which counts against fieldwidth but not precision
+ int extralen = 0;
+
+ if (flags & num_signed) {
+ if (value < 0) {
+ printf_fill(obuf, opos, limit, '-', 1);
+ extralen += 1;
+ } else if (flags & always_sign) {
+ printf_fill(obuf, opos, limit, '+', 1);
+ extralen += 1;
+ } else if (flags & leave_blank) {
+ printf_fill(obuf, opos, limit, ' ', 1);
+ extralen += 1;
+ }
+ }
+
+ if ((flags & alt_form) && value != 0) {
+ if (radix == 8 && (!(flags & has_precision) || precision <= len)) {
+ flags |= has_precision;
+ precision = len + 1;
+ }
+
+ if (radix == 16) {
+ printf_string(obuf, opos, limit, "0x", 2);
+ extralen += 2;
+ }
+ }
+
+ if ((flags & has_precision) && len < precision) {
+ precision -= len;
+ len += precision;
+ } else {
+ precision = 0;
+ }
+
+ len += extralen;
+
+ if (!(flags & neg_field) && len < fieldwidth) {
+ char padchar = (flags & zero_pad) ? '0' : ' ';
+ printf_fill(obuf, opos, limit, padchar, fieldwidth - len);
+ len = fieldwidth;
+ }
+
+ if (precision != 0) {
+ printf_fill(obuf, opos, limit, '0', precision);
+ len += precision;
+ }
+
+ printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos);
+
+ if ((flags & neg_field) && len < fieldwidth)
+ printf_fill(obuf, opos, limit, ' ', fieldwidth - len);
+}
+
+extern "C" size_t vsnprintf(char *buf, size_t size,
+ const char *str, va_list args)
+{
+ size_t opos = 0; // position in the output string
+ unsigned int flags = 0;
+ int radix = 10;
+ int state = 0;
+ int fieldwidth = 0;
+ int precision = 0;
+
+ for (size_t pos = 0; str[pos]; pos++) switch (state) {
+ case 0:
+ if (str[pos] == '%') {
+ flags = 0;
+ radix = 10;
+ state = 1;
+ fieldwidth = 0;
+ precision = 0;
+ break;
+ }
+
+ if (opos < size)
+ buf[opos] = str[pos];
+
+ opos++;
+ break;
+
+ case 1: // A percent has been seen; read in format characters
+ switch (str[pos]) {
+ case '#':
+ flags |= alt_form;
+ break;
+
+ case '0':
+ if (!(flags & has_precision)) {
+ flags |= zero_pad;
+ break;
+ }
+
+ // else fall through
+
+ case '1' ... '9':
+ if (flags & has_precision)
+ goto default_case;
+
+ do {
+ fieldwidth *= 10;
+ fieldwidth += str[pos++] - '0';
+ } while (str[pos] >= '0' && str[pos] <= '9');
+
+ pos--;
+ break;
+
+ case '*':
+ if (fieldwidth || (flags & has_precision))
+ goto default_case;
+
+ fieldwidth = va_arg(args, int);
+ break;
+
+ case '.':
+ flags |= has_precision;
+
+ if (str[pos + 1] == '*') {
+ pos++;
+ precision = va_arg(args, int);
+ } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') {
+ precision *= 10;
+ precision += str[++pos] - '0';
+ }
+
+ break;
+
+ case '-':
+ flags |= neg_field;
+ break;
+
+ case ' ':
+ flags |= leave_blank;
+ break;
+
+ case '+':
+ flags |= always_sign;
+ break;
+
+ case '\'':
+ flags |= group_thousands;
+ break;
+
+ case 'l':
+ if (flags & long_arg)
+ flags |= long_long_arg;
+ else
+ flags |= long_arg;
+
+ break;
+
+ case 'h':
+ if (flags & long_arg)
+ flags |= short_short_arg;
+ else
+ flags |= short_arg;
+
+ break;
+
+ case 'j':
+ flags |= intmax_arg;
+ break;
+
+ case 't':
+ flags |= ptrdiff_arg;
+ break;
+
+ // Note that %z and other such "new" format characters are
+ // basically useless because some GCC coder actually went out
+ // of their way to make the compiler reject C99 format
+ // strings in C++ code, with no way of overriding it that I
+ // can find (the source code comments suggest the checking is
+ // only when using -pedantic, but I wasn't using -pedantic).
+ //
+ // Thus, we have the choice of either avoiding %z and friends
+ // (and possibly needing to insert hackish casts to silence
+ // the compiler's warnings if different architectures define
+ // types like size_t in different ways), or not using the
+ // format warnings at all.
+ //
+ // To mitigate this, 32-bit architectures should define
+ // pointer-sized special types as "long" rather than "int",
+ // so that %lx/%ld can always be used with them. Fixed-size
+ // 32-bit types should be declared as "int" rather than
+ // "long" for the same reason.
+
+ case 'z':
+ flags |= size_t_arg;
+ break;
+
+ case 'd':
+ case 'i': {
+ int64_t arg;
+
+ if ((flags & intmax_arg) || (flags & long_long_arg))
+ arg = va_arg(args, long long);
+ else if (flags & size_t_arg)
+ arg = va_arg(args, ssize_t);
+ else if (flags & ptrdiff_arg)
+ arg = va_arg(args, ptrdiff_t);
+ else if (flags & long_arg)
+ arg = va_arg(args, long);
+ else if (flags & short_short_arg)
+ arg = (signed char)va_arg(args, int);
+ else if (flags & short_arg)
+ arg = (short)va_arg(args, int);
+ else
+ arg = va_arg(args, int);
+
+ flags |= num_signed;
+ printf_num(buf, opos, size, arg, 10,
+ fieldwidth, precision, flags);
+ state = 0;
+ break;
+ }
+
+ case 'X':
+ flags |= capital_hex;
+ // fall-through
+
+ case 'x':
+ radix = 18;
+ // fall-through
+
+ case 'o':
+ radix -= 2;
+ // fall-through
+
+ case 'u': {
+ uint64_t arg;
+
+ if ((flags & intmax_arg) || (flags & long_long_arg))
+ arg = va_arg(args, unsigned long long);
+ else if (flags & size_t_arg)
+ arg = va_arg(args, size_t);
+ else if (flags & ptrdiff_arg)
+ arg = va_arg(args, intptr_t);
+ else if (flags & long_arg)
+ arg = va_arg(args, unsigned long);
+ else if (flags & short_short_arg)
+ arg = (unsigned char)va_arg(args, unsigned int);
+ else if (flags & short_arg)
+ arg = (unsigned short)va_arg(args, unsigned int);
+ else if (flags & short_short_arg)
+ arg = (signed char)va_arg(args, int);
+ else if (flags & short_arg)
+ arg = (short)va_arg(args, int);
+ else
+ arg = va_arg(args, unsigned int);
+
+ printf_num(buf, opos, size, arg, radix,
+ fieldwidth, precision, flags);
+ state = 0;
+ break;
+ }
+
+ case 'c':
+ if (opos < size)
+ buf[opos] = va_arg(args, int);
+
+ opos++;
+ state = 0;
+ break;
+
+ case 's': {
+ const char *arg = va_arg(args, const char *);
+
+ if (!arg)
+ arg = "(null)";
+
+ size_t len = strlen(arg);
+ printf_string(buf, opos, size, arg, len);
+ state = 0;
+ break;
+ }
+
+ case 'p': {
+ const void *arg = va_arg(args, const void *);
+
+ printf_num(buf, opos, size, (unsigned long)arg, 16,
+ fieldwidth, precision, flags);
+
+ state = 0;
+ break;
+ }
+
+ case 'n': {
+ if ((flags & intmax_arg) || (flags & long_long_arg))
+ *va_arg(args, unsigned long long *) = opos;
+ else if (flags & size_t_arg)
+ *va_arg(args, ssize_t *) = opos;
+ else if (flags & ptrdiff_arg)
+ *va_arg(args, ptrdiff_t *) = opos;
+ else if (flags & long_arg)
+ *va_arg(args, long *) = opos;
+ else if (flags & short_short_arg)
+ *va_arg(args, signed char *) = opos;
+ else if (flags & short_arg)
+ *va_arg(args, short *) = opos;
+ else
+ *va_arg(args, int *) = opos;
+
+ state = 0;
+ break;
+ }
+
+ default_case: // label for goto
+ default:
+ if (opos < size)
+ buf[opos] = str[pos];
+
+ opos++;
+ state = 0;
+ break;
+ }
+ }
+
+ if (size > 0 && opos >= size)
+ buf[size - 1] = 0;
+
+ return opos;
+}
+
+extern "C" size_t snprintf(char *buf, size_t size, const char *str, ...)
+{
+ va_list args;
+ va_start(args, str);
+ int ret = vsnprintf(buf, size, str, args);
+ va_end(args);
+ return ret;
+}
+
+extern "C" size_t sprintf(char *buf, const char *str, ...)
+{
+ va_list args;
+ va_start(args, str);
+ int ret = vsnprintf(buf, ULONG_MAX, str, args);
+ va_end(args);
+ return ret;
+}
--- /dev/null
+// string and memory functions.
+//
+// This software is copyright (c) 2007 Scott Wood <scott@buserror.net>.
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors or contributors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is hereby granted to everyone, free of charge, to use, copy,
+// modify, prepare derivative works of, publish, distribute, perform,
+// sublicense, and/or sell copies of the Software, provided that the above
+// copyright notice and disclaimer of warranty be included in all copies or
+// substantial portions of this software.
+
+#include <stdint.h>
+#include <string.h>
+
+void *memcpy(void *dest, const void *src, size_t len)
+{
+ const char *cs = static_cast<const char *>(src);
+ char *cd = static_cast<char *>(dest);
+
+ for (size_t i = 0; i < len; i++)
+ cd[i] = cs[i];
+
+ return dest;
+}
+
+void *memmove(void *dest, const void *src, size_t len)
+{
+ if (dest < src)
+ return memcpy(dest, src, len);
+
+ const char *cs = static_cast<const char *>(src);
+ char *cd = static_cast<char *>(dest);
+
+ for (size_t i = len - 1; i >= 0; i--)
+ cd[i] = cs[i];
+
+ return dest;
+}
+
+int memcmp(const void *b1, const void *b2, size_t len)
+{
+ size_t pos;
+ const char *c1 = static_cast<const char *>(b1);
+ const char *c2 = static_cast<const char *>(b2);
+
+ for (pos = 0; pos < len; pos++) {
+ if (c1[pos] != c2[pos])
+ return c1[pos] - c2[pos];
+
+ pos++;
+ }
+
+ return 0;
+}
+
+size_t strnlen(const char *s, size_t n)
+{
+ size_t pos = 0;
+ while (pos < n && *s++)
+ pos++;
+ return pos;
+}
+
+size_t strlen(const char *s)
+{
+ size_t pos = 0;
+ while (*s++)
+ pos++;
+ return pos;
+}
+
+char *strcpy(char *dest, const char *src)
+{
+ char *orig = dest;
+
+ do {
+ *dest = *src++;
+ } while (*dest++);
+
+ return orig;
+}
+
+char *strncpy(char *dest, const char *src, size_t len)
+{
+ char *orig = dest;
+
+ while (len--) {
+ *dest = *src++;
+
+ if (!*dest++)
+ break;
+ }
+
+ memset(dest, 0, len);
+ return orig;
+}
+
+char *strcat(char *dest, const char *src)
+{
+ char *orig = dest;
+ dest += strlen(dest);
+
+ do {
+ *dest = *src++;
+ } while (*dest++);
+
+ return orig;
+}
+
+char *strncat(char *dest, const char *src, size_t len)
+{
+ char *orig = dest;
+ int orig_len = strlen(dest);
+
+ len -= orig_len;
+ dest += orig_len;
+
+ while (len--) {
+ *dest = *src++;
+
+ if (!*dest++)
+ break;
+ }
+
+ memset(dest, 0, len);
+ return orig;
+}
+
+void *memset(void *b, int ch, size_t len)
+{
+ char *c = static_cast<char *>(b);
+
+ while (len--)
+ *c++ = ch;
+
+ return b;
+}