Added functionality in libskb to store and retrieve caps.
authorGerd Zellweger <mail@gerdzellweger.com>
Thu, 20 Apr 2017 15:13:25 +0000 (17:13 +0200)
committerGerd Zellweger <mail@gerdzellweger.com>
Thu, 20 Apr 2017 15:15:53 +0000 (17:15 +0200)
This uses a custom scanf and snprintf implementation
that has an additional format specifier (%Q) to
transparently load and store caps from and in the SKB.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>

lib/skb/Hakefile
lib/skb/skb.c
lib/skb/skb_functions.c
lib/skb/skb_internal.h [moved from lib/skb/skb_debug.h with 62% similarity]
lib/skb/skb_snprintf.c [new file with mode: 0644]
lib/skb/skb_sscanf.c [new file with mode: 0644]

index c2c942e..2684f72 100644 (file)
@@ -7,12 +7,14 @@
 -- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
 --
 -- Hakefile for lib/skb
--- 
+--
 --------------------------------------------------------------------------
 
 [ build library { target = "skb",
-                  cFiles = [ "skb.c", "skb_functions.c", "helper.c" ],
+                  cFiles = [ "skb.c", "skb_functions.c", "skb_snprintf.c", "skb_sscanf.c", "helper.c" ],
                   flounderBindings = [ "skb" ],
-                  flounderExtraBindings = [ ("skb", ["rpcclient"]) ]
+                  flounderExtraBindings = [ ("skb", ["rpcclient"]) ],
+                  addLibraries = ["octopus"],
+                  addCFlags = ["-Wno-char-subscripts"]
                 }
 ]
index 3c22a05..ef84707 100644 (file)
@@ -24,7 +24,6 @@
 static void bind_cb(void *st, errval_t err, struct skb_binding *b)
 {
     struct skb_state *skb_state = get_skb_state();
-
     if (err_is_fail(err)) {
         DEBUG_ERR(err, "bind failed");
         abort();
index 18a7dc5..0ee890b 100644 (file)
  */
 
 #include <stdio.h>
+#include <stddef.h>
 #include <string.h>
+#include <stdarg.h>
+
 #include <barrelfish/barrelfish.h>
 #include <skb/skb.h>
 #include <if/skb_defs.h>
 #include <barrelfish/core_state_arch.h>
-#include "skb_debug.h"
+#include "skb_internal.h"
 
 #define BUFFER_SIZE skb__run_call_input_MAX_ARGUMENT_SIZE
 #define OUTPUT_SIZE skb__run_response_output_MAX_ARGUMENT_SIZE
@@ -73,13 +76,15 @@ errval_t skb_execute(char *goal)
 
 errval_t skb_add_fact(char *fmt, ...)
 {
+    errval_t err;
     va_list va_l;
     va_start(va_l, fmt);
-    int len = vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
+    int len = skb_vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
     va_end(va_l);
 
     if (len >= BUFFER_SIZE) {
-        return SKB_ERR_OVERFLOW;
+        err = SKB_ERR_OVERFLOW;
+        goto out;
     }
 
     if (len > 0 && buffer[len - 1] == '.') {
@@ -88,13 +93,15 @@ errval_t skb_add_fact(char *fmt, ...)
 
     SKB_DEBUG("skb_add_fact(): %s\n", buffer);
     int assert_len = snprintf(buffer + len, BUFFER_SIZE - len,
-            "assert(%.*s).", len, buffer);
-
+                              "assert(%.*s).", len, buffer);
     if (assert_len >= BUFFER_SIZE - len) {
-        return SKB_ERR_OVERFLOW;
+        err = SKB_ERR_OVERFLOW;
+        goto out;
     }
 
-    errval_t err = skb_execute(buffer + len);
+    err = skb_execute(buffer + len);
+
+out:
     return err;
 }
 
@@ -102,9 +109,23 @@ errval_t skb_execute_query(char *fmt, ...)
 {
     va_list va_l;
     va_start(va_l, fmt);
-    int len = vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
+    int len = skb_vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
     va_end(va_l);
 
+#if 0
+    va_start(va_l, fmt);
+    char* buffer2 = malloc(BUFFER_SIZE+1);
+    len = vsnprintf(buffer2, BUFFER_SIZE, fmt, va_l);
+    va_end(va_l);
+    if (strcmp(buffer, buffer2) != 0) {
+        printf("%s:%s:%d: fmt = %s\n", __FILE__, __FUNCTION__, __LINE__, fmt);
+        printf("%s:%s:%d: skb_vsnprintf: %s\n", __FILE__, __FUNCTION__, __LINE__, buffer);
+        printf("%s:%s:%d: vsnprintf: %s\n", __FILE__, __FUNCTION__, __LINE__, buffer2);
+        USER_PANIC("skb_vsnprintf doesn't quite work!");
+    }
+    free(buffer2);
+#endif
+
     if (len >= BUFFER_SIZE) {
         return SKB_ERR_OVERFLOW;
     }
@@ -122,7 +143,7 @@ static inline int count_expected_conversions(char *s, int len)
     //count the number of single occurences of '%' to calculate the expected
     //number of conversions made by sscanf
     for (int i = 0; i < len; i++) {
-        if ((s[i] == '%') && 
+        if ((s[i] == '%') &&
             (((i + 1 < len) && (s[i + 1] != '%')) ||
             (i + 1 >= len))) {
             expected_conversions++;
@@ -131,34 +152,34 @@ static inline int count_expected_conversions(char *s, int len)
     return (expected_conversions);
 }
 
-errval_t skb_read_output_at(char *out, char *fmt, ...)
-{
-    errval_t r;
-    va_list va_l;
-    va_start(va_l, fmt);
-    r = skb_vread_output_at(out, fmt, va_l);
-    va_end(va_l);
-    return(r);
-}
-
 errval_t skb_vread_output_at(char *out, char *fmt, va_list va_l)
 {
-
     int expected_conversions = 0;
     int nr_conversions;
     int fmtlen = strlen(fmt);
     expected_conversions = count_expected_conversions(fmt, fmtlen);
-
-    nr_conversions = vsscanf(out, fmt, va_l);
+    nr_conversions = skb_vsscanf(out, fmt, va_l);
     if (nr_conversions != expected_conversions) {
-        SKB_DEBUG("skb_vread_output_at(): Could not convert the SKB's result\n");
-        SKB_DEBUG("SKB returned: %s\nSKB error: %s\n", skb_get_output(),
-                skb_get_error_output());
+        printf("skb_vread_output_at(): Could not convert the SKB's result (expected conversions=%d, got instead=%d)\n",
+               expected_conversions, nr_conversions);
+        printf("SKB returned: %s\nSKB error: %s\n", skb_get_output(), skb_get_error_output());
+        printf("%s:%s:%d: fmt = %s out = %s\n", __FILE__, __FUNCTION__, __LINE__, fmt, out);
         return SKB_ERR_CONVERSION_ERROR;
     }
     return SYS_ERR_OK;
 }
 
+errval_t skb_read_output_at(char *out, char *fmt, ...)
+{
+    errval_t r;
+    va_list va_l;
+
+    va_start(va_l, fmt);
+    r = skb_vread_output_at(out, fmt, va_l);
+    va_end(va_l);
+
+    return(r);
+}
 
 errval_t skb_read_output(char *fmt, ...)
 {
@@ -212,7 +233,6 @@ bool skb_read_list(struct list_parser_status *status, char *fmt, ...)
             count_expected_conversions(fmt, fmtlen);
     }
 
-
     //iterate over all buselements
     while (status->conv_ptr < status->s + status->len) {
         // search the beginning of the next buselement
@@ -222,7 +242,7 @@ bool skb_read_list(struct list_parser_status *status, char *fmt, ...)
                     status->conv_ptr++;
         }
         //convert the string to single elements and numbers
-        nr_conversions = vsscanf(status->conv_ptr, fmt, va_l);
+        nr_conversions = skb_vsscanf(status->conv_ptr, fmt, va_l);
         va_end(va_l);
         status->conv_ptr++;
         if (nr_conversions != status->expected_conversions) {
similarity index 62%
rename from lib/skb/skb_debug.h
rename to lib/skb/skb_internal.h
index dcf42a0..41ccb77 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * Copyright (c) 2017, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -7,12 +7,17 @@
  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
  */
 
-#ifndef SKB_DEBUG_H_
-#define SKB_DEBUG_H_
+#ifndef SKB_INTERNAL_H_
+#define SKB_INTERNAL_H_
 
 #include <barrelfish/debug.h>
 #include <skb/skb.h>
 
+int skb_vsnprintf (char *str, size_t count, const char *fmt, va_list args);
+int skb_sscanf(const char *ibuf, const char *fmt, ...);
+int skb_vsscanf(const char *str, const char *format, va_list args);
+int skb_snprintf(char *str, size_t count, const char *fmt, ...);
+
 
 /*****************************************************************
  * Debug printer:
@@ -24,8 +29,4 @@
 #define SKB_DEBUG(x...) ((void)0)
 #endif
 
-
-
-
-
-#endif // PCI_DEBUG_H_
+#endif // SKB_INTERNAL_H_
diff --git a/lib/skb/skb_snprintf.c b/lib/skb/skb_snprintf.c
new file mode 100644 (file)
index 0000000..63a96e8
--- /dev/null
@@ -0,0 +1,919 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ *
+ *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats.
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge@samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
+ * actually print args for %g and %e
+ *
+ * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally.  Fixes AIX and Solaris builds.
+ *
+ * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ *
+ * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
+ * Fix usage of va_list passed as an arg.  Use __va_copy before using it
+ * when it exists.
+ *
+ * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ *    Remove NO_CONFIG_H so that the test case can be built within a source
+ *    tree with less trouble.
+ *    Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ *    if the C library has some snprintf functions already.
+ *
+ * Damien Miller (djm@mindrot.org) Jan 2007
+ *    Fix integer overflows in return value.
+ *    Make formatting quite a bit faster by inlining dopr_outch()
+ *
+ **************************************************************/
+
+#ifdef BARRELFISH
+#include <barrelfish/barrelfish.h>
+#include <skb/skb.h>
+#include <if/skb_defs.h>
+#include <barrelfish/core_state_arch.h>
+#include <octopus/capability_storage.h>
+#include "skb_internal.h"
+#endif
+
+#define CAP_STORAGE_IDENT "cid_"
+
+
+#if defined(BROKEN_SNPRINTF)           /* For those with broken snprintf() */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdint.h>
+
+#ifdef HAVE_LONG_DOUBLE
+# define LDOUBLE long double
+#else
+# define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+# define LLONG long long
+#else
+# define LLONG long
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS     (1 << 0)
+#define DP_F_PLUS      (1 << 1)
+#define DP_F_SPACE     (1 << 2)
+#define DP_F_NUM       (1 << 3)
+#define DP_F_ZERO      (1 << 4)
+#define DP_F_UP        (1 << 5)
+#define DP_F_UNSIGNED  (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT   1
+#define DP_C_LONG    2
+#define DP_C_LDOUBLE 3
+#define DP_C_LLONG   4
+#define DP_C_SIZE    5
+#define DP_C_INTMAX  6
+#define DP_C_CHAR    7
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+#define DOPR_OUTCH(buf, pos, buflen, thechar) \
+       do { \
+               if (pos + 1 >= INT_MAX) { \
+                       errno = ERANGE; \
+                       return -1; \
+               } \
+               if (pos < buflen) \
+                       buf[pos] = thechar; \
+               (pos)++; \
+       } while (0)
+
+static int dopr(char *buffer, size_t maxlen, const char *format,
+    va_list args_in);
+static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max);
+static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    intmax_t value, int base, int min, int max, int flags);
+static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+    LDOUBLE fvalue, int min, int max, int flags);
+static int fmtcap(char *buffer, size_t *currlen, size_t maxlen, struct capref c);
+
+static int
+dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+       char ch;
+       intmax_t value;
+       LDOUBLE fvalue;
+       char *strvalue;
+       int min;
+       int max;
+       int state;
+       int flags;
+       int cflags;
+       size_t currlen;
+       va_list args;
+
+       va_copy(args, args_in);
+
+       state = DP_S_DEFAULT;
+       currlen = flags = cflags = min = 0;
+       max = -1;
+       ch = *format++;
+
+       while (state != DP_S_DONE) {
+               if (ch == '\0')
+                       state = DP_S_DONE;
+
+               switch(state) {
+               case DP_S_DEFAULT:
+                       if (ch == '%')
+                               state = DP_S_FLAGS;
+                       else
+                               DOPR_OUTCH(buffer, currlen, maxlen, ch);
+                       ch = *format++;
+                       break;
+               case DP_S_FLAGS:
+                       switch (ch) {
+                       case '-':
+                               flags |= DP_F_MINUS;
+                               ch = *format++;
+                               break;
+                       case '+':
+                               flags |= DP_F_PLUS;
+                               ch = *format++;
+                               break;
+                       case ' ':
+                               flags |= DP_F_SPACE;
+                               ch = *format++;
+                               break;
+                       case '#':
+                               flags |= DP_F_NUM;
+                               ch = *format++;
+                               break;
+                       case '0':
+                               flags |= DP_F_ZERO;
+                               ch = *format++;
+                               break;
+                       default:
+                               state = DP_S_MIN;
+                               break;
+                       }
+                       break;
+               case DP_S_MIN:
+                       if (isdigit((unsigned char)ch)) {
+                               min = 10*min + char_to_int (ch);
+                               ch = *format++;
+                       } else if (ch == '*') {
+                               min = va_arg (args, int);
+                               ch = *format++;
+                               state = DP_S_DOT;
+                       } else {
+                               state = DP_S_DOT;
+                       }
+                       break;
+               case DP_S_DOT:
+                       if (ch == '.') {
+                               state = DP_S_MAX;
+                               ch = *format++;
+                       } else {
+                               state = DP_S_MOD;
+                       }
+                       break;
+               case DP_S_MAX:
+                       if (isdigit((unsigned char)ch)) {
+                               if (max < 0)
+                                       max = 0;
+                               max = 10*max + char_to_int (ch);
+                               ch = *format++;
+                       } else if (ch == '*') {
+                               max = va_arg (args, int);
+                               ch = *format++;
+                               state = DP_S_MOD;
+                       } else {
+                               state = DP_S_MOD;
+                       }
+                       break;
+               case DP_S_MOD:
+                       switch (ch) {
+                       case 'h':
+                               cflags = DP_C_SHORT;
+                               ch = *format++;
+                if (ch == 'h') {
+                    //cflags = DP_C_SHORT;
+                    ch = *format++;
+                }
+                               break;
+                       case 'j':
+                               cflags = DP_C_INTMAX;
+                               ch = *format++;
+                               break;
+                       case 'l':
+                               cflags = DP_C_LONG;
+                               ch = *format++;
+                               if (ch == 'l') {        /* It's a long long */
+                                       cflags = DP_C_LLONG;
+                                       ch = *format++;
+                               }
+                               break;
+                       case 'L':
+                               cflags = DP_C_LDOUBLE;
+                               ch = *format++;
+                               break;
+                       case 'z':
+                               cflags = DP_C_SIZE;
+                               ch = *format++;
+                               break;
+                       default:
+                               break;
+                       }
+                       state = DP_S_CONV;
+                       break;
+               case DP_S_CONV:
+                       switch (ch) {
+                       case 'd':
+                       case 'i':
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg (args, int);
+                               else if (cflags == DP_C_LONG)
+                                       value = va_arg (args, long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = va_arg (args, LLONG);
+                               else if (cflags == DP_C_SIZE)
+                                       value = va_arg (args, ssize_t);
+                               else if (cflags == DP_C_INTMAX)
+                                       value = va_arg (args, intmax_t);
+                               else
+                                       value = va_arg (args, int);
+                               if (fmtint(buffer, &currlen, maxlen,
+                                   value, 10, min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'o':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg (args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (long)va_arg (args, unsigned LLONG);
+                               else if (cflags == DP_C_SIZE)
+                                       value = va_arg (args, size_t);
+#ifdef notyet
+                               else if (cflags == DP_C_INTMAX)
+                                       value = va_arg (args, uintmax_t);
+#endif
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   8, min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'u':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg (args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (LLONG)va_arg (args, unsigned LLONG);
+                               else if (cflags == DP_C_SIZE)
+                                       value = va_arg (args, size_t);
+#ifdef notyet
+                               else if (cflags == DP_C_INTMAX)
+                                       value = va_arg (args, uintmax_t);
+#endif
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   10, min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'X':
+                               flags |= DP_F_UP;
+                       case 'x':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg (args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (LLONG)va_arg (args, unsigned LLONG);
+                               else if (cflags == DP_C_SIZE)
+                                       value = va_arg (args, size_t);
+#ifdef notyet
+                               else if (cflags == DP_C_INTMAX)
+                                       value = va_arg (args, uintmax_t);
+#endif
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   16, min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'f':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'E':
+                               flags |= DP_F_UP;
+                       case 'e':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'G':
+                               flags |= DP_F_UP;
+                       case 'g':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'c':
+                               DOPR_OUTCH(buffer, currlen, maxlen,
+                                   va_arg (args, int));
+                               break;
+                       case 's':
+                               strvalue = va_arg (args, char *);
+                               if (!strvalue) strvalue = "(NULL)";
+                               if (max == -1) {
+                                       max = strlen(strvalue);
+                               }
+                               if (min > 0 && max >= 0 && min > max) max = min;
+                               if (fmtstr(buffer, &currlen, maxlen,
+                                   strvalue, flags, min, max) == -1)
+                                       return -1;
+                               break;
+                       case 'p':
+                               strvalue = va_arg (args, void *);
+                               if (fmtint(buffer, &currlen, maxlen,
+                                   (long) strvalue, 16, min, max, flags) == -1)
+                                       return -1;
+                               break;
+#if we_dont_want_this_in_openssh
+                       case 'n':
+                               if (cflags == DP_C_SHORT) {
+                                       short int *num;
+                                       num = va_arg (args, short int *);
+                                       *num = currlen;
+                               } else if (cflags == DP_C_LONG) {
+                                       long int *num;
+                                       num = va_arg (args, long int *);
+                                       *num = (long int)currlen;
+                               } else if (cflags == DP_C_LLONG) {
+                                       LLONG *num;
+                                       num = va_arg (args, LLONG *);
+                                       *num = (LLONG)currlen;
+                               } else if (cflags == DP_C_SIZE) {
+                                       ssize_t *num;
+                                       num = va_arg (args, ssize_t *);
+                                       *num = (ssize_t)currlen;
+                               } else if (cflags == DP_C_INTMAX) {
+                                       intmax_t *num;
+                                       num = va_arg (args, intmax_t *);
+                                       *num = (intmax_t)currlen;
+                               } else {
+                                       int *num;
+                                       num = va_arg (args, int *);
+                                       *num = currlen;
+                               }
+                               break;
+#endif
+                       case '%':
+                               DOPR_OUTCH(buffer, currlen, maxlen, ch);
+                               break;
+                       case 'w':
+                               /* not supported yet, treat as next char */
+                               ch = *format++;
+                               break;
+            case 'Q':
+                /* Barrelfish specific capref type */
+                               if (fmtcap(buffer, &currlen, maxlen, va_arg(args, struct capref)) == -1)
+                                       return -1;
+                               break;
+                       default:
+                               /* Unknown, skip */
+                               break;
+                       }
+                       ch = *format++;
+                       state = DP_S_DEFAULT;
+                       flags = cflags = min = 0;
+                       max = -1;
+                       break;
+               case DP_S_DONE:
+                       break;
+               default:
+                       /* hmm? */
+                       break; /* some picky compilers need this */
+               }
+       }
+       if (maxlen != 0) {
+               if (currlen < maxlen - 1)
+                       buffer[currlen] = '\0';
+               else if (maxlen > 0)
+                       buffer[maxlen - 1] = '\0';
+       }
+
+       return currlen < INT_MAX ? (int)currlen : -1;
+}
+
+static int
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max)
+{
+       int padlen, strln;     /* amount to pad */
+       int cnt = 0;
+
+//#define DEBUG_SNPRINTF 1
+#ifdef DEBUG_SNPRINTF
+       printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+       if (value == 0) {
+               value = "<NULL>";
+       }
+
+       for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
+       padlen = min - strln;
+       if (padlen < 0)
+               padlen = 0;
+       if (flags & DP_F_MINUS)
+               padlen = -padlen; /* Left Justify */
+
+       while ((padlen > 0) && (cnt < max)) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               --padlen;
+               ++cnt;
+       }
+       while (*value && (cnt < max)) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, *value);
+               value++;
+               ++cnt;
+       }
+       while ((padlen < 0) && (cnt < max)) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++padlen;
+               ++cnt;
+       }
+       return 0;
+}
+
+// Replaces %C with the identifers returned from oct_sput_capability
+static int fmtcap(char *buffer, size_t *currlen, size_t maxlen, struct capref c)
+{
+    char* retkey = NULL;
+    errval_t err = oct_sput_capability(CAP_STORAGE_IDENT, c, &retkey);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Can't save the cap in the storage?");
+        return -1;
+    }
+    assert(retkey != NULL);
+    //printf("Stored capability using oct_put_capability in '%s'.\n", retkey);
+
+    while (*retkey) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, *retkey);
+               retkey++;
+       }
+
+    return 0;
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static int
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    intmax_t value, int base, int min, int max, int flags)
+{
+       int signvalue = 0;
+       unsigned LLONG uvalue;
+       char convert[20];
+       int place = 0;
+       int spadlen = 0; /* amount to space pad */
+       int zpadlen = 0; /* amount to zero pad */
+       int caps = 0;
+
+       if (max < 0)
+               max = 0;
+
+       uvalue = value;
+
+       if(!(flags & DP_F_UNSIGNED)) {
+               if( value < 0 ) {
+                       signvalue = '-';
+                       uvalue = -value;
+               } else {
+                       if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+                               signvalue = '+';
+                       else if (flags & DP_F_SPACE)
+                               signvalue = ' ';
+               }
+       }
+
+       if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+       do {
+               convert[place++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")
+                       [uvalue % (unsigned)base  ];
+               uvalue = (uvalue / (unsigned)base );
+       } while(uvalue && (place < 20));
+       if (place == 20) place--;
+       convert[place] = 0;
+
+       zpadlen = max - place;
+       spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+       if (zpadlen < 0) zpadlen = 0;
+       if (spadlen < 0) spadlen = 0;
+       if (flags & DP_F_ZERO) {
+               zpadlen = MAX(zpadlen, spadlen);
+               spadlen = 0;
+       }
+       if (flags & DP_F_MINUS)
+               spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+       printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+              zpadlen, spadlen, min, max, place);
+#endif
+
+       /* Spaces */
+       while (spadlen > 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               --spadlen;
+       }
+
+       /* Sign */
+       if (signvalue)
+               DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
+
+       /* Zeros */
+       if (zpadlen > 0) {
+               while (zpadlen > 0) {
+                       DOPR_OUTCH(buffer, *currlen, maxlen, '0');
+                       --zpadlen;
+               }
+       }
+
+       /* Digits */
+       while (place > 0) {
+               --place;
+               DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]);
+       }
+
+       /* Left Justified spaces */
+       while (spadlen < 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++spadlen;
+       }
+       return 0;
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+       LDOUBLE result = value;
+
+       if (value < 0)
+               result = -value;
+
+       return result;
+}
+
+static LDOUBLE POW10(int val)
+{
+       LDOUBLE result = 1;
+
+       while (val) {
+               result *= 10;
+               val--;
+       }
+
+       return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+       LLONG intpart;
+
+       intpart = (LLONG)value;
+       value = value - intpart;
+       if (value >= 0.5) intpart++;
+
+       return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+       int i;
+       long l;
+       double x = x0;
+       double f = 1.0;
+
+       for (i=0;i<100;i++) {
+               l = (long)x;
+               if (l <= (x+1) && l >= (x-1)) break;
+               x *= 0.1;
+               f *= 10.0;
+       }
+
+       if (i == 100) {
+               /*
+                * yikes! the number is beyond what we can handle.
+                * What do we do?
+                */
+               (*iptr) = 0;
+               return 0;
+       }
+
+       if (i != 0) {
+               double i2;
+               double ret;
+
+               ret = my_modf(x0-l*f, &i2);
+               (*iptr) = l*f + i2;
+               return ret;
+       }
+
+       (*iptr) = l;
+       return x - (*iptr);
+}
+
+
+static int
+fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+    LDOUBLE fvalue, int min, int max, int flags)
+{
+       int signvalue = 0;
+       double ufvalue;
+       char iconvert[311];
+       char fconvert[311];
+       int iplace = 0;
+       int fplace = 0;
+       int padlen = 0; /* amount to pad */
+       int zpadlen = 0;
+       int caps = 0;
+       int idx;
+       double intpart;
+       double fracpart;
+       double temp;
+
+       /*
+        * AIX manpage says the default is 0, but Solaris says the default
+        * is 6, and sprintf on AIX defaults to 6
+        */
+       if (max < 0)
+               max = 6;
+
+       ufvalue = abs_val (fvalue);
+
+       if (fvalue < 0) {
+               signvalue = '-';
+       } else {
+               if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+                       signvalue = '+';
+               } else {
+                       if (flags & DP_F_SPACE)
+                               signvalue = ' ';
+               }
+       }
+
+#if 0
+       if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+        if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+       /*
+        * Sorry, we only support 16 digits past the decimal because of our
+        * conversion method
+        */
+       if (max > 16)
+               max = 16;
+
+       /* We "cheat" by converting the fractional part to integer by
+        * multiplying by a factor of 10
+        */
+
+       temp = ufvalue;
+       my_modf(temp, &intpart);
+
+       fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+       if (fracpart >= POW10(max)) {
+               intpart++;
+               fracpart -= POW10(max);
+       }
+
+       /* Convert integer part */
+       do {
+               temp = intpart*0.1;
+               my_modf(temp, &intpart);
+               idx = (int) ((temp -intpart +0.05)* 10.0);
+               /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+               /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+               iconvert[iplace++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+       } while (intpart && (iplace < 311));
+       if (iplace == 311) iplace--;
+       iconvert[iplace] = 0;
+
+       /* Convert fractional part */
+       if (fracpart)
+       {
+               do {
+                       temp = fracpart*0.1;
+                       my_modf(temp, &fracpart);
+                       idx = (int) ((temp -fracpart +0.05)* 10.0);
+                       /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+                       /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+                       fconvert[fplace++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+               } while(fracpart && (fplace < 311));
+               if (fplace == 311) fplace--;
+       }
+       fconvert[fplace] = 0;
+
+       /* -1 for decimal point, another -1 if we are printing a sign */
+       padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+       zpadlen = max - fplace;
+       if (zpadlen < 0) zpadlen = 0;
+       if (padlen < 0)
+               padlen = 0;
+       if (flags & DP_F_MINUS)
+               padlen = -padlen; /* Left Justifty */
+
+       if ((flags & DP_F_ZERO) && (padlen > 0)) {
+               if (signvalue) {
+                       DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
+                       --padlen;
+                       signvalue = 0;
+               }
+               while (padlen > 0) {
+                       DOPR_OUTCH(buffer, *currlen, maxlen, '0');
+                       --padlen;
+               }
+       }
+       while (padlen > 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               --padlen;
+       }
+       if (signvalue)
+               DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
+
+       while (iplace > 0) {
+               --iplace;
+               DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]);
+       }
+
+#ifdef DEBUG_SNPRINTF
+       printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+       /*
+        * Decimal point.  This should probably use locale to find the correct
+        * char to print out.
+        */
+       if (max > 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, '.');
+
+               while (zpadlen > 0) {
+                       DOPR_OUTCH(buffer, *currlen, maxlen, '0');
+                       --zpadlen;
+               }
+
+               while (fplace > 0) {
+                       --fplace;
+                       DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]);
+               }
+       }
+
+       while (padlen < 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++padlen;
+       }
+       return 0;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+int
+skb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+       return dopr(str, count, fmt, args);
+}
+
+int
+skb_snprintf(char *str, size_t count, const char *fmt, ...)
+{
+       size_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(str, count, fmt, ap);
+       va_end(ap);
+       return ret;
+}
diff --git a/lib/skb/skb_sscanf.c b/lib/skb/skb_sscanf.c
new file mode 100644 (file)
index 0000000..2d4ba17
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#include "skb_internal.h"
+#include <barrelfish/barrelfish.h>
+#include <octopus/capability_storage.h>
+
+#define        BUF             32      /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define        LONG            0x01    /* l: long or double */
+#define        SHORT           0x04    /* h: short */
+#define        SUPPRESS        0x08    /* *: suppress assignment */
+#define        POINTER         0x10    /* p: void * (as hex) */
+#define        NOSKIP          0x20    /* [ or c: do not skip blanks */
+#define        LONGLONG        0x400   /* ll: long long (+ deprecated q: quad) */
+#define        SHORTSHORT      0x4000  /* hh: char */
+#define        UNSIGNED        0x8000  /* %[oupxX] conversions */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+#define        SIGNOK          0x40    /* +/- is (still) legal */
+#define        NDIGITS         0x80    /* no digits detected */
+
+#define        DPTOK           0x100   /* (float) decimal point is still legal */
+#define        EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
+
+#define        PFXOK           0x100   /* 0x prefix is (still) legal */
+#define        NZDIGITS        0x200   /* no zero digits detected */
+
+/*
+ * Conversion types.
+ */
+#define        CT_CHAR         0       /* %c conversion */
+#define        CT_CCL          1       /* %[...] conversion */
+#define        CT_STRING       2       /* %s conversion */
+#define        CT_INT          3       /* %[dioupxX] conversion */
+#define CT_CAP      4   /* struct capref conversion */
+
+static const u_char *__sccl(char *, const u_char *);
+
+int
+skb_sscanf(const char *ibuf, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       ret = skb_vsscanf(ibuf, fmt, ap);
+       va_end(ap);
+       return(ret);
+}
+
+int
+skb_vsscanf(const char *inp, char const *fmt0, va_list ap)
+{
+       int inr;
+       const u_char *fmt = (const u_char *)fmt0;
+       int c;                  /* character from format, or conversion */
+       size_t width;           /* field width, or 0 */
+       char *p;                /* points into all kinds of strings */
+       int n;                  /* handy integer */
+       int flags;              /* flags as defined above */
+       char *p0;               /* saves original value of p when necessary */
+       int nassigned;          /* number of fields assigned */
+       int nconversions;       /* number of conversions */
+       int nread;              /* number of characters consumed from fp */
+       int base;               /* base argument to conversion function */
+       char ccltab[256];       /* character class table for %[...] */
+       char buf[BUF];          /* buffer for numeric conversions */
+
+       /* `basefix' is used to avoid `if' tests in the integer scanner */
+       static short basefix[17] =
+               { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+       inr = strlen(inp);
+
+       nassigned = 0;
+       nconversions = 0;
+       nread = 0;
+       base = 0;               /* XXX just to keep gcc happy */
+       for (;;) {
+               c = *fmt++;
+               if (c == 0)
+                       return (nassigned);
+               if (isspace(c)) {
+                       while (inr > 0 && isspace(*inp))
+                               nread++, inr--, inp++;
+                       continue;
+               }
+               if (c != '%')
+                       goto literal;
+               width = 0;
+               flags = 0;
+               /*
+                * switch on the format.  continue if done;
+                * break once format type is derived.
+                */
+again:         c = *fmt++;
+               switch (c) {
+               case '%':
+literal:
+                       if (inr <= 0)
+                               goto input_failure;
+                       if (*inp != c)
+                               goto match_failure;
+                       inr--, inp++;
+                       nread++;
+                       continue;
+
+               case '*':
+                       flags |= SUPPRESS;
+                       goto again;
+               case 'l':
+                       if (flags & LONG) {
+                               flags &= ~LONG;
+                               flags |= LONGLONG;
+                       } else
+                               flags |= LONG;
+                       goto again;
+               case 'q':
+                       flags |= LONGLONG;      /* not quite */
+                       goto again;
+               case 'h':
+                       if (flags & SHORT) {
+                               flags &= ~SHORT;
+                               flags |= SHORTSHORT;
+                       } else
+                               flags |= SHORT;
+                       goto again;
+
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       width = width * 10 + c - '0';
+                       goto again;
+
+               /*
+                * Conversions.
+                */
+               case 'd':
+                       c = CT_INT;
+                       base = 10;
+                       break;
+
+               case 'i':
+                       c = CT_INT;
+                       base = 0;
+                       break;
+
+               case 'o':
+                       c = CT_INT;
+                       flags |= UNSIGNED;
+                       base = 8;
+                       break;
+
+               case 'u':
+                       c = CT_INT;
+                       flags |= UNSIGNED;
+                       base = 10;
+                       break;
+
+               case 'X':
+               case 'x':
+                       flags |= PFXOK; /* enable 0x prefixing */
+                       c = CT_INT;
+                       flags |= UNSIGNED;
+                       base = 16;
+                       break;
+
+               case 's':
+                       c = CT_STRING;
+                       break;
+
+               case '[':
+                       fmt = __sccl(ccltab, fmt);
+                       flags |= NOSKIP;
+                       c = CT_CCL;
+                       break;
+
+               case 'c':
+                       flags |= NOSKIP;
+                       c = CT_CHAR;
+                       break;
+
+        case 'Q':
+                       c = CT_CAP;
+                       break;
+
+               case 'p':       /* pointer format is like hex */
+                       flags |= POINTER | PFXOK;
+                       c = CT_INT;
+                       flags |= UNSIGNED;
+                       base = 16;
+                       break;
+
+               case 'n':
+                       nconversions++;
+                       if (flags & SUPPRESS)   /* ??? */
+                               continue;
+                       if (flags & SHORTSHORT)
+                               *va_arg(ap, char *) = nread;
+                       else if (flags & SHORT)
+                               *va_arg(ap, short *) = nread;
+                       else if (flags & LONG)
+                               *va_arg(ap, long *) = nread;
+                       else if (flags & LONGLONG)
+                               *va_arg(ap, long long *) = nread;
+                       else
+                               *va_arg(ap, int *) = nread;
+                       continue;
+               }
+
+               /*
+                * We have a conversion that requires input.
+                */
+               if (inr <= 0)
+                       goto input_failure;
+
+               /*
+                * Consume leading white space, except for formats
+                * that suppress this.
+                */
+               if ((flags & NOSKIP) == 0) {
+                       while (isspace(*inp)) {
+                               nread++;
+                               if (--inr > 0)
+                                       inp++;
+                               else
+                                       goto input_failure;
+                       }
+                       /*
+                        * Note that there is at least one character in
+                        * the buffer, so conversions that do not set NOSKIP
+                        * can no longer result in an input failure.
+                        */
+               }
+
+               /*
+                * Do the conversion.
+                */
+               switch (c) {
+
+               case CT_CHAR:
+                       /* scan arbitrary characters (sets NOSKIP) */
+                       if (width == 0)
+                               width = 1;
+                       if (flags & SUPPRESS) {
+                               size_t sum = 0;
+                               for (;;) {
+                                       if ((n = inr) < (int)width) {
+                                               sum += n;
+                                               width -= n;
+                                               inp += n;
+                                               if (sum == 0)
+                                                       goto input_failure;
+                                               break;
+                                       } else {
+                                               sum += width;
+                                               inr -= width;
+                                               inp += width;
+                                               break;
+                                       }
+                               }
+                               nread += sum;
+                       } else {
+                               bcopy(inp, va_arg(ap, char *), width);
+                               inr -= width;
+                               inp += width;
+                               nread += width;
+                               nassigned++;
+                       }
+                       nconversions++;
+                       break;
+
+               case CT_CCL:
+                       /* scan a (nonempty) character class (sets NOSKIP) */
+                       if (width == 0)
+                               width = (size_t)~0;     /* `infinity' */
+                       /* take only those things in the class */
+                       if (flags & SUPPRESS) {
+                               n = 0;
+                               while (ccltab[(unsigned char)*inp]) {
+                                       n++, inr--, inp++;
+                                       if (--width == 0)
+                                               break;
+                                       if (inr <= 0) {
+                                               if (n == 0)
+                                                       goto input_failure;
+                                               break;
+                                       }
+                               }
+                               if (n == 0)
+                                       goto match_failure;
+                       } else {
+                               p0 = p = va_arg(ap, char *);
+                               while (ccltab[(unsigned char)*inp]) {
+                                       inr--;
+                                       *p++ = *inp++;
+                                       if (--width == 0)
+                                               break;
+                                       if (inr <= 0) {
+                                               if (p == p0)
+                                                       goto input_failure;
+                                               break;
+                                       }
+                               }
+                               n = p - p0;
+                               if (n == 0)
+                                       goto match_failure;
+                               *p = 0;
+                               nassigned++;
+                       }
+                       nread += n;
+                       nconversions++;
+                       break;
+
+        case CT_CAP:
+        {
+            struct capref* cap = va_arg(ap, struct capref*);
+            char cap_id_buf[513];
+
+            p0 = p = cap_id_buf;
+            while (isalnum(*inp) || *inp == '_') {
+                inr--;
+                *p++ = *inp++;
+                if (--width == 0)
+                    break;
+                if (inr <= 0)
+                    break;
+            }
+            *p = 0;
+                       nread += p - p0;
+                       nassigned++;
+
+            //printf("%s:%s:%d: ret cap for buf = %s\n", __FILE__, __FUNCTION__, __LINE__, cap_id_buf);
+            errval_t err = oct_get_capability(cap_id_buf, cap);
+            if (err_is_fail(err)) {
+                USER_PANIC_ERR(err, "Can't retrieve the cap from storage.");
+            }
+
+            nconversions++;
+            break;
+        }
+
+               case CT_STRING:
+                       /* like CCL, but zero-length string OK, & no NOSKIP */
+                       if (width == 0)
+                               width = (size_t)~0;
+                       if (flags & SUPPRESS) {
+                               n = 0;
+                               while (!isspace(*inp)) {
+                                       n++, inr--, inp++;
+                                       if (--width == 0)
+                                               break;
+                                       if (inr <= 0)
+                                               break;
+                               }
+                               nread += n;
+                       } else {
+                               p0 = p = va_arg(ap, char *);
+                               while (!isspace(*inp)) {
+                                       inr--;
+                                       *p++ = *inp++;
+                                       if (--width == 0)
+                                               break;
+                                       if (inr <= 0)
+                                               break;
+                               }
+                               *p = 0;
+                               nread += p - p0;
+                               nassigned++;
+                       }
+                       nconversions++;
+                       continue;
+
+
+               case CT_INT:
+                       /* scan an integer as if by the conversion function */
+#ifdef hardway
+                       if (width == 0 || width > sizeof(buf) - 1)
+                               width = sizeof(buf) - 1;
+#else
+                       /* size_t is unsigned, hence this optimisation */
+                       if (--width > sizeof(buf) - 2)
+                               width = sizeof(buf) - 2;
+                       width++;
+#endif
+                       flags |= SIGNOK | NDIGITS | NZDIGITS;
+                       for (p = buf; width; width--) {
+                               c = *inp;
+                               /*
+                                * Switch on the character; `goto ok'
+                                * if we accept it as a part of number.
+                                */
+                               switch (c) {
+
+                               /*
+                                * The digit 0 is always legal, but is
+                                * special.  For %i conversions, if no
+                                * digits (zero or nonzero) have been
+                                * scanned (only signs), we will have
+                                * base==0.  In that case, we should set
+                                * it to 8 and enable 0x prefixing.
+                                * Also, if we have not scanned zero digits
+                                * before this, do not turn off prefixing
+                                * (someone else will turn it off if we
+                                * have scanned any nonzero digits).
+                                */
+                               case '0':
+                                       if (base == 0) {
+                                               base = 8;
+                                               flags |= PFXOK;
+                                       }
+                                       if (flags & NZDIGITS)
+                                           flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+                                       else
+                                           flags &= ~(SIGNOK|PFXOK|NDIGITS);
+                                       goto ok;
+
+                               /* 1 through 7 always legal */
+                               case '1': case '2': case '3':
+                               case '4': case '5': case '6': case '7':
+                                       base = basefix[base];
+                                       flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                       goto ok;
+
+                               /* digits 8 and 9 ok iff decimal or hex */
+                               case '8': case '9':
+                                       base = basefix[base];
+                                       if (base <= 8)
+                                               break;  /* not legal here */
+                                       flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                       goto ok;
+
+                               /* letters ok iff hex */
+                               case 'A': case 'B': case 'C':
+                               case 'D': case 'E': case 'F':
+                               case 'a': case 'b': case 'c':
+                               case 'd': case 'e': case 'f':
+                                       /* no need to fix base here */
+                                       if (base <= 10)
+                                               break;  /* not legal here */
+                                       flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                       goto ok;
+
+                               /* sign ok only as first character */
+                               case '+': case '-':
+                                       if (flags & SIGNOK) {
+                                               flags &= ~SIGNOK;
+                                               goto ok;
+                                       }
+                                       break;
+
+                               /* x ok iff flag still set & 2nd char */
+                               case 'x': case 'X':
+                                       if (flags & PFXOK && p == buf + 1) {
+                                               base = 16;      /* if %i */
+                                               flags &= ~PFXOK;
+                                               goto ok;
+                                       }
+                                       break;
+                               }
+
+                               /*
+                                * If we got here, c is not a legal character
+                                * for a number.  Stop accumulating digits.
+                                */
+                               break;
+               ok:
+                               /*
+                                * c is legal: store it and look at the next.
+                                */
+                               *p++ = c;
+                               if (--inr > 0)
+                                       inp++;
+                               else
+                                       break;          /* end of input */
+                       }
+                       /*
+                        * If we had only a sign, it is no good; push
+                        * back the sign.  If the number ends in `x',
+                        * it was [sign] '0' 'x', so push back the x
+                        * and treat it as [sign] '0'.
+                        */
+                       if (flags & NDIGITS) {
+                               if (p > buf) {
+                                       inp--;
+                                       inr++;
+                               }
+                               goto match_failure;
+                       }
+                       c = ((u_char *)p)[-1];
+                       if (c == 'x' || c == 'X') {
+                               --p;
+                               inp--;
+                               inr++;
+                       }
+                       if ((flags & SUPPRESS) == 0) {
+                               uint64_t res;
+
+                               *p = 0;
+                               if ((flags & UNSIGNED) == 0)
+                                   res = strtoll(buf, (char **)NULL, base);
+                               else
+                                   res = strtoull(buf, (char **)NULL, base);
+                               if (flags & POINTER)
+                                       *va_arg(ap, void **) =
+                                               (void *)(uintptr_t)res;
+                               else if (flags & SHORTSHORT)
+                                       *va_arg(ap, char *) = res;
+                               else if (flags & SHORT)
+                                       *va_arg(ap, short *) = res;
+                               else if (flags & LONG)
+                                       *va_arg(ap, long *) = res;
+                               else if (flags & LONGLONG)
+                                       *va_arg(ap, long long *) = res;
+                               else
+                                       *va_arg(ap, int *) = res;
+                               nassigned++;
+                       }
+                       nread += p - buf;
+                       nconversions++;
+                       break;
+
+               }
+       }
+input_failure:
+       return (nconversions != 0 ? nassigned : -1);
+match_failure:
+       return (nassigned);
+}
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `[').  Return a pointer to the character past the
+ * closing `]'.  The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static const u_char *
+__sccl(char *tab, const u_char *fmt)
+{
+       int c, n, v;
+
+       /* first `clear' the whole table */
+       c = *fmt++;             /* first char hat => negated scanset */
+       if (c == '^') {
+               v = 1;          /* default => accept */
+               c = *fmt++;     /* get new first char */
+       } else
+               v = 0;          /* default => reject */
+
+       /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
+       (void) memset(tab, v, 256);
+
+       if (c == 0)
+               return (fmt - 1);/* format ended before closing ] */
+
+       /*
+        * Now set the entries corresponding to the actual scanset
+        * to the opposite of the above.
+        *
+        * The first character may be ']' (or '-') without being special;
+        * the last character may be '-'.
+        */
+       v = 1 - v;
+       for (;;) {
+               tab[c] = v;             /* take character c */
+doswitch:
+               n = *fmt++;             /* and examine the next */
+               switch (n) {
+
+               case 0:                 /* format ended too soon */
+                       return (fmt - 1);
+
+               case '-':
+                       /*
+                        * A scanset of the form
+                        *      [01+-]
+                        * is defined as `the digit 0, the digit 1,
+                        * the character +, the character -', but
+                        * the effect of a scanset such as
+                        *      [a-zA-Z0-9]
+                        * is implementation defined.  The V7 Unix
+                        * scanf treats `a-z' as `the letters a through
+                        * z', but treats `a-a' as `the letter a, the
+                        * character -, and the letter a'.
+                        *
+                        * For compatibility, the `-' is not considerd
+                        * to define a range if the character following
+                        * it is either a close bracket (required by ANSI)
+                        * or is not numerically greater than the character
+                        * we just stored in the table (c).
+                        */
+                       n = *fmt;
+                       if (n == ']' || n < c) {
+                               c = '-';
+                               break;  /* resume the for(;;) */
+                       }
+                       fmt++;
+                       /* fill in the range */
+                       do {
+                           tab[++c] = v;
+                       } while (c < n);
+                       c = n;
+                       /*
+                        * Alas, the V7 Unix scanf also treats formats
+                        * such as [a-c-e] as `the letters a through e'.
+                        * This too is permitted by the standard....
+                        */
+                       goto doswitch;
+                       break;
+
+               case ']':               /* end of scanset */
+                       return (fmt);
+
+               default:                /* just another character */
+                       c = n;
+                       break;
+               }
+       }
+       /* NOTREACHED */
+}