summaryrefslogtreecommitdiff
path: root/firmware/libc/sscanf.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-05-06 21:04:40 +0000
committerThomas Martitz <kugel@rockbox.org>2010-05-06 21:04:40 +0000
commit50a6ca39ad4ed01922aa4f755f0ca579788226cf (patch)
treec7881b015b220558167310345b162324c96be15a /firmware/libc/sscanf.c
parentadb506df14aded06ed6e9ebf8540e6fd383ffd6a (diff)
downloadrockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.zip
rockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.tar.gz
rockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.tar.bz2
rockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.tar.xz
Move c/h files implementing/defining standard library stuff into a new libc directory, also standard'ify some parts of the code base (almost entirely #include fixes).
This is to a) to cleanup firmware/common and firmware/include a bit, but also b) for Rockbox as an application which should use the host system's c library and headers, separating makes it easy to exclude our files from the build. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25850 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/libc/sscanf.c')
-rw-r--r--firmware/libc/sscanf.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/firmware/libc/sscanf.c b/firmware/libc/sscanf.c
new file mode 100644
index 0000000..5fbe81f
--- /dev/null
+++ b/firmware/libc/sscanf.c
@@ -0,0 +1,282 @@
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+
+static inline bool isspace(char c)
+{
+ return (c == ' ') || (c == '\t') || (c == '\n');
+}
+
+static inline bool isdigit(char c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+static inline bool isxdigit(char c)
+{
+ return ((c >= '0') && (c <= '9'))
+ || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
+}
+
+static int parse_dec(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ long *vp)
+{
+ long v = 0;
+ int n = 0;
+ int minus = 0;
+ char ch;
+
+ if ((*peek)(userp) == '-')
+ {
+ (*pop)(userp);
+ n++;
+ minus = 1;
+ }
+
+ ch = (*peek)(userp);
+ if (!isdigit(ch))
+ return -1;
+
+ do
+ {
+ v = v * 10 + ch - '0';
+ (*pop)(userp);
+ n++;
+ ch = (*peek)(userp);
+ } while (isdigit(ch));
+
+ *vp = minus ? -v : v;
+ return n;
+}
+
+static int parse_chars(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ char *vp,
+ bool fake)
+{
+ int n = 0;
+
+ char *pt=vp;
+
+ while (!isspace((*peek)(userp)))
+ {
+ if(fake==false)
+ *(pt++) = (*peek)(userp);
+
+ n++;
+ (*pop)(userp);
+ }
+
+ if(fake==false)
+ (*pt)='\0';
+
+ return n;
+}
+
+static int parse_hex(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ unsigned long *vp)
+{
+ unsigned long v = 0;
+ int n = 0;
+ char ch;
+
+ ch = (*peek)(userp);
+ if (!isxdigit(ch))
+ return -1;
+
+ do
+ {
+ if (ch >= 'a')
+ ch = ch - 'a' + 10;
+ else if (ch >= 'A')
+ ch = ch - 'A' + 10;
+ else
+ ch = ch - '0';
+ v = v * 16 + ch;
+ (*pop)(userp);
+ n++;
+ ch = (*peek)(userp);
+ } while (isxdigit(ch));
+
+ *vp = v;
+ return n;
+}
+
+static int skip_spaces(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp)
+{
+ int n = 0;
+ while (isspace((*peek)(userp))) {
+ n++;
+ (*pop)(userp);
+ }
+ return n;
+}
+
+static int scan(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ const char *fmt,
+ va_list ap)
+{
+ char ch;
+ int n = 0;
+ int n_chars = 0;
+ int r;
+ long lval;
+ bool skip=false;
+ unsigned long ulval;
+
+ while ((ch = *fmt++) != '\0')
+ {
+ bool literal = false;
+
+ if (ch == '%')
+ {
+ ch = *fmt++;
+
+ if(ch== '*') /* We should process this, but not store it in an arguement */
+ {
+ ch=*fmt++;
+ skip=true;
+ }
+ else
+ {
+ skip=false;
+ }
+
+ switch (ch)
+ {
+ case 'x':
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, unsigned int *)) = ulval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'd':
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, int *)) = lval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'n':
+ if(skip==false)
+ {
+ *(va_arg(ap, int *)) = n_chars;
+ n++;
+ }
+ break;
+ case 'l':
+ n_chars += skip_spaces(peek, pop, userp);
+ ch = *fmt++;
+ switch (ch)
+ {
+ case 'x':
+ if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, unsigned long *)) = ulval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'd':
+ if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, long *)) = lval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case '\0':
+ return n;
+ default:
+ literal = true;
+ break;
+ }
+ break;
+ case 's':
+ n_chars += skip_spaces(peek, pop, userp);
+ n_chars += parse_chars(peek,pop, userp,skip?0:va_arg(ap, char *), skip );
+ if(skip==false)
+ {
+ n++;
+ }
+ break;
+ case '\0':
+ return n;
+ default:
+ literal = true;
+ break;
+ }
+ } else
+ literal = true;
+
+ if (literal)
+ {
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((*peek)(userp) != ch)
+ continue;
+ else
+ {
+ (*pop)(userp);
+ n_chars++;
+ }
+ }
+ }
+ return n;
+}
+
+static int sspeek(void *userp)
+{
+ return **((char **)userp);
+}
+
+static void sspop(void *userp)
+{
+ (*((char **)userp))++;
+}
+
+int sscanf(const char *s, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+ const char *p;
+
+ p = s;
+ va_start(ap, fmt);
+ r = scan(sspeek, sspop, &p, fmt, ap);
+ va_end(ap);
+ return r;
+}