]> git.buserror.net Git - polintos/scott/priv.git/commitdiff
fixes/cleanup
authorScott Wood <scott@thor.buserror.net>
Tue, 14 Aug 2007 13:09:30 +0000 (08:09 -0500)
committerScott Wood <scott@thor.buserror.net>
Tue, 14 Aug 2007 13:09:30 +0000 (08:09 -0500)
Makefile.head
Makefile.target
kernel/io/console/misc.cc
kernel/io/console/vga.cc
lib/c++/orb.cc
lib/c/freestanding/Makefile
lib/c/freestanding/sprintf.c [deleted file]
lib/c/freestanding/sprintf.cc [new file with mode: 0644]

index da2bc1da75a78090603ee4348d735b330039e151..61456a0c08b845611b431800d73877bf48c6e740 100644 (file)
@@ -51,7 +51,7 @@ OPT += -O2
 DEBUG += -g3
 ABI += -freg-struct-return
 
 DEBUG += -g3
 ABI += -freg-struct-return
 
-CXXFLAGS += $(CXXINCS) $(DEFS) $(CXXWARN) $(OPT) $(DEBUG) $(ABI)
+CXXFLAGS += $(DEFS) $(CXXINCS) $(CXXWARN) $(OPT) $(DEBUG) $(ABI)
 BUILDCXXFLAGS += $(BUILDDEFS) $(CXXWARN) $(OPT) $(DEBUG)
 
 CFLAGS += $(CINCS) $(DEFS) $(CWARN) $(OPT) $(DEBUG) $(ABI)
 BUILDCXXFLAGS += $(BUILDDEFS) $(CXXWARN) $(OPT) $(DEBUG)
 
 CFLAGS += $(CINCS) $(DEFS) $(CWARN) $(OPT) $(DEBUG) $(ABI)
index 2943437f1e0a2bb2be031846471da2ead3f10059..6da0ecfa4bb439066142467200e5696ba2ce1e8b 100644 (file)
@@ -85,6 +85,7 @@ STRIP := $(CROSS)strip
 DEFS += -D_LL_ARCH_$(ARCH) -D_LL_ARCH=$(ARCH)
 MKDIR := mkdir -p
 MV := mv
 DEFS += -D_LL_ARCH_$(ARCH) -D_LL_ARCH=$(ARCH)
 MKDIR := mkdir -p
 MV := mv
+OBJCOPY := $(CROSS)objcopy
 RANLIB := $(CROSS)ranlib
 RM := rm -f
 RMDIR := rm -rf
 RANLIB := $(CROSS)ranlib
 RM := rm -f
 RMDIR := rm -rf
index 09f8623edf1eb0f6097a82341bb503cb61c2d0d9..7da03244e01d4bfbafd0f560fdf15fbde6e45315 100644 (file)
@@ -41,8 +41,6 @@ Lock::SpinLock printf_lock;
 // happens.  If you really need that, you'll need to call snprintf
 // and primary_console->write yourself.
 
 // happens.  If you really need that, you'll need to call snprintf
 // and primary_console->write yourself.
 
-void vga_write(uint8_t *buf, u64 len);
-
 size_t printf(const char *str, ...)
 {
        Lock::AutoSpinLockRecIRQ autolock(printf_lock);
 size_t printf(const char *str, ...)
 {
        Lock::AutoSpinLockRecIRQ autolock(printf_lock);
index d0c044ecba87c1817946fd1d6c8963a9d3ab55d2..7c5250361698cfdad1b8a708841bc8dd54f9d432 100644 (file)
@@ -21,8 +21,6 @@
 #include <kern/addrs.h>
 #include <util/lock.h>
 
 #include <kern/addrs.h>
 #include <util/lock.h>
 
-void vga_write(char *str);
-
 namespace IO {
 namespace Console {
        class VGA : public Console {
 namespace IO {
 namespace Console {
        class VGA : public Console {
index a62e91f6b1f43160764e0439311609e175fc6e22..8533f52347146f677a142a539cca850b675819e3 100644 (file)
@@ -57,7 +57,7 @@ namespace RunTime {
                };
 
                typedef ::Util::RadixTree<Object, ID, 6> ObjTable;
                };
 
                typedef ::Util::RadixTree<Object, ID, 6> ObjTable;
-               ObjTable objtable;
+//             ObjTable objtable;
 
                unsigned long get_pc()
                {
 
                unsigned long get_pc()
                {
index 0257e46c2d09bf01edeaf7e2ca071c9155786597..27c18e8624f23e0c07f0bb216144a4bfdc67e6e2 100644 (file)
@@ -1,10 +1,10 @@
 DIR := c/freestanding/
 DIRS += $(DIR)
 
 DIR := c/freestanding/
 DIRS += $(DIR)
 
-RAW_CFILES := sprintf string
+RAW_CFILES := string
 CFILES += $(RAW_CFILES:%=$(DIR)%)
 
 CFILES += $(RAW_CFILES:%=$(DIR)%)
 
-RAW_CXXFILES :=
+RAW_CXXFILES := sprintf
 CXXFILES += $(RAW_CXXFILES:%=$(DIR)%)
 
 TARGETS += $(BUILDDIR)/c/libfreestanding.a
 CXXFILES += $(RAW_CXXFILES:%=$(DIR)%)
 
 TARGETS += $(BUILDDIR)/c/libfreestanding.a
diff --git a/lib/c/freestanding/sprintf.c b/lib/c/freestanding/sprintf.c
deleted file mode 100644 (file)
index a7aa115..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-// 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;
-}
diff --git a/lib/c/freestanding/sprintf.cc b/lib/c/freestanding/sprintf.cc
new file mode 100644 (file)
index 0000000..acfbaff
--- /dev/null
@@ -0,0 +1,434 @@
+// 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 - 1)
+                               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 - 1, 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 - 1, arg, radix,
+                                                  fieldwidth, precision, flags);
+                                       state = 0;
+                                       break;
+                               }
+                               
+                               case 'c':
+                                       if (opos < size - 1)
+                                               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 - 1, arg, len);
+                                       state = 0;
+                                       break;
+                               }
+                               
+                               case 'p': {
+                                       const void *arg = va_arg(args, const void *);
+
+                                       printf_num(buf, opos, size - 1, (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 - 1)
+                                               buf[opos] = str[pos];
+                                       
+                                       opos++;
+                                       state = 0;
+                                       break;
+                       }
+       }
+
+       if (opos < size)
+               buf[opos] = 0;
+       else if (size > 0)
+               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;
+}