Adds sscanf()
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 24 Feb 2015 21:23:53 +0000 (16:23 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sun, 1 Mar 2015 14:37:08 +0000 (09:37 -0500)
From Linux, including ctype.{c,h}.

kern/include/ctype.h [new file with mode: 0644]
kern/include/stdio.h
kern/src/Kbuild
kern/src/ctype.c [new file with mode: 0644]
kern/src/vsprintf.c [new file with mode: 0644]

diff --git a/kern/include/ctype.h b/kern/include/ctype.h
new file mode 100644 (file)
index 0000000..653589e
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U     0x01    /* upper */
+#define _L     0x02    /* lower */
+#define _D     0x04    /* digit */
+#define _C     0x08    /* cntrl */
+#define _P     0x10    /* punct */
+#define _S     0x20    /* white space (space/lf/tab) */
+#define _X     0x40    /* hex digit */
+#define _SP    0x80    /* hard space (0x20) */
+
+extern const unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c)     ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c)     ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c)     ((__ismask(c)&(_C)) != 0)
+#define isdigit(c)     ((__ismask(c)&(_D)) != 0)
+#define isgraph(c)     ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c)     ((__ismask(c)&(_L)) != 0)
+#define isprint(c)     ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c)     ((__ismask(c)&(_P)) != 0)
+/* Note: isspace() must return false for %NUL-terminator */
+#define isspace(c)     ((__ismask(c)&(_S)) != 0)
+#define isupper(c)     ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c)    ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+       if (isupper(c))
+               c -= 'A'-'a';
+       return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+       if (islower(c))
+               c -= 'a'-'A';
+       return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+/*
+ * Fast implementation of tolower() for internal usage. Do not use in your
+ * code.
+ */
+static inline char _tolower(const char c)
+{
+       return c | 0x20;
+}
+
+/* Fast check for octal digit */
+static inline int isodigit(const char c)
+{
+       return c >= '0' && c <= '7';
+}
+
+#endif
index 2b8fe00..90ae337 100644 (file)
@@ -62,4 +62,8 @@ void printipv4(void (*putch)(int, void**), void **putdat, uint8_t *ip);
 /* #K */
 void trace_printk(const char *fmt, ...);
 
+/* vsprintf.c (linux) */
+int vsscanf(const char *buf, const char *fmt, va_list args);
+int sscanf(const char *buf, const char *fmt, ...);
+
 #endif /* !ROS_INC_STDIO_H */
index 57b5d5c..bce074d 100644 (file)
@@ -6,6 +6,7 @@ obj-y                                           += bitmap.o
 obj-y                                          += blockdev.o
 obj-y                                          += colored_caches.o
 obj-y                                          += console.o
+obj-y                                          += ctype.o
 obj-y                                          += devfs.o
 obj-y                                          += elf.o
 obj-y                                          += env.o
@@ -56,3 +57,4 @@ obj-y                                         += trap.o
 obj-y                                          += ucq.o
 obj-y                                          += umem.o
 obj-y                                          += vfs.o
+obj-y                                          += vsprintf.o
diff --git a/kern/src/ctype.c b/kern/src/ctype.c
new file mode 100644 (file)
index 0000000..6d983b5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <ctype.h>
+
+const unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,                               /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                        /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,                               /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,                               /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,                           /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,                               /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,                               /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,                               /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,             /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,                               /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,                               /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,                               /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,             /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,                               /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,                               /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,                               /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                       /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                       /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
diff --git a/kern/src/vsprintf.c b/kern/src/vsprintf.c
new file mode 100644 (file)
index 0000000..f8a44b0
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/*
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+/* (trimmed to just scanf for Akaros).  grep AKAROS_PORT for dirty hacks */
+
+#include <ros/common.h>
+#include <error.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ns.h>
+#include <ctype.h>
+
+#define unlikely(x) (x)
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+static char *skip_spaces(const char *str)
+{
+       while (isspace(*str))
+               ++str;
+       return (char *)str;
+}
+
+static int skip_atoi(const char **s)
+{
+       int i = 0;
+
+       while (isdigit(**s))
+               i = i*10 + *((*s)++) - '0';
+
+       return i;
+}
+
+const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
+{
+       if (*base == 0) {
+               if (s[0] == '0') {
+                       if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
+                               *base = 16;
+                       else
+                               *base = 8;
+               } else
+                       *base = 10;
+       }
+       if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
+               s += 2;
+       return s;
+}
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       format of buffer
+ * @args:      arguments
+ */
+int vsscanf(const char *buf, const char *fmt, va_list args)
+{
+       const char *str = buf;
+       char *next;
+       char digit;
+       int num = 0;
+       uint8_t qualifier;
+       unsigned int base;
+       union {
+               long long s;
+               unsigned long long u;
+       } val;
+       int16_t field_width;
+       bool is_sign;
+
+       while (*fmt) {
+               /* skip any white space in format */
+               /* white space in format matchs any amount of
+                * white space, including none, in the input.
+                */
+               if (isspace(*fmt)) {
+                       fmt = skip_spaces(++fmt);
+                       str = skip_spaces(str);
+               }
+
+               /* anything that is not a conversion must match exactly */
+               if (*fmt != '%' && *fmt) {
+                       if (*fmt++ != *str++)
+                               break;
+                       continue;
+               }
+
+               if (!*fmt)
+                       break;
+               ++fmt;
+
+               /* skip this conversion.
+                * advance both strings to next white space
+                */
+               if (*fmt == '*') {
+                       if (!*str)
+                               break;
+                       while (!isspace(*fmt) && *fmt != '%' && *fmt)
+                               fmt++;
+                       while (!isspace(*str) && *str)
+                               str++;
+                       continue;
+               }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt)) {
+                       field_width = skip_atoi(&fmt);
+                       if (field_width <= 0)
+                               break;
+               }
+
+               /* get conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
+                   _tolower(*fmt) == 'z') {
+                       qualifier = *fmt++;
+                       if (unlikely(qualifier == *fmt)) {
+                               if (qualifier == 'h') {
+                                       qualifier = 'H';
+                                       fmt++;
+                               } else if (qualifier == 'l') {
+                                       qualifier = 'L';
+                                       fmt++;
+                               }
+                       }
+               }
+
+               if (!*fmt)
+                       break;
+
+               if (*fmt == 'n') {
+                       /* return number of characters read so far */
+                       *va_arg(args, int *) = str - buf;
+                       ++fmt;
+                       continue;
+               }
+
+               if (!*str)
+                       break;
+
+               base = 10;
+               is_sign = false;
+
+               switch (*fmt++) {
+               case 'c':
+               {
+                       char *s = (char *)va_arg(args, char*);
+                       if (field_width == -1)
+                               field_width = 1;
+                       do {
+                               *s++ = *str++;
+                       } while (--field_width > 0 && *str);
+                       num++;
+               }
+               continue;
+               case 's':
+               {
+                       char *s = (char *)va_arg(args, char *);
+                       if (field_width == -1)
+                               field_width = INT16_MAX;
+                       /* first, skip leading white space in buffer */
+                       str = skip_spaces(str);
+
+                       /* now copy until next white space */
+                       while (*str && !isspace(*str) && field_width--)
+                               *s++ = *str++;
+                       *s = '\0';
+                       num++;
+               }
+               continue;
+               case 'o':
+                       base = 8;
+                       break;
+               case 'x':
+               case 'X':
+                       base = 16;
+                       break;
+               case 'i':
+                       base = 0;
+               case 'd':
+                       is_sign = true;
+               case 'u':
+                       break;
+               case '%':
+                       /* looking for '%' in str */
+                       if (*str++ != '%')
+                               return num;
+                       continue;
+               default:
+                       /* invalid format; stop here */
+                       return num;
+               }
+
+               /* have some sort of integer conversion.
+                * first, skip white space in buffer.
+                */
+               str = skip_spaces(str);
+
+               digit = *str;
+               if (is_sign && digit == '-')
+                       digit = *(str + 1);
+
+               if (!digit
+                   || (base == 16 && !isxdigit(digit))
+                   || (base == 10 && !isdigit(digit))
+                   || (base == 8 && (!isdigit(digit) || digit > '7'))
+                   || (base == 0 && !isdigit(digit)))
+                       break;
+
+               if (is_sign)
+#if 0 // AKAROS_PORT
+                       val.s = qualifier != 'L' ?
+                               strtol(str, &next, base) :
+                               strtoll(str, &next, base);
+#else
+                       val.s = strtol(str, &next, base);
+#endif
+               else
+#if 0 // AKAROS_PORT
+                       val.u = qualifier != 'L' ?
+                               strtoul(str, &next, base) :
+                               strtoull(str, &next, base);
+#else
+                       val.s = strtoul(str, &next, base);
+#endif
+
+               if (field_width > 0 && next - str > field_width) {
+                       if (base == 0)
+                               _parse_integer_fixup_radix(str, &base);
+                       while (next - str > field_width) {
+                               if (is_sign)    // AKAROS_PORT
+                                       val.s = (int64_t)(val.s / base);
+                               else
+                                       val.u = (uint64_t)(val.u / base);
+                               --next;
+                       }
+               }
+
+               switch (qualifier) {
+               case 'H':       /* that's 'hh' in format */
+                       if (is_sign)
+                               *va_arg(args, signed char *) = val.s;
+                       else
+                               *va_arg(args, unsigned char *) = val.u;
+                       break;
+               case 'h':
+                       if (is_sign)
+                               *va_arg(args, short *) = val.s;
+                       else
+                               *va_arg(args, unsigned short *) = val.u;
+                       break;
+               case 'l':
+                       if (is_sign)
+                               *va_arg(args, long *) = val.s;
+                       else
+                               *va_arg(args, unsigned long *) = val.u;
+                       break;
+               case 'L':
+                       if (is_sign)
+                               *va_arg(args, long long *) = val.s;
+                       else
+                               *va_arg(args, unsigned long long *) = val.u;
+                       break;
+               case 'Z':
+               case 'z':
+                       *va_arg(args, size_t *) = val.u;
+                       break;
+               default:
+                       if (is_sign)
+                               *va_arg(args, int *) = val.s;
+                       else
+                               *va_arg(args, unsigned int *) = val.u;
+                       break;
+               }
+               num++;
+
+               if (!next)
+                       break;
+               str = next;
+       }
+
+       return num;
+}
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       formatting of buffer
+ * @...:       resulting arguments
+ */
+int sscanf(const char *buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vsscanf(buf, fmt, args);
+       va_end(args);
+
+       return i;
+}