diff options
| author | Thomas Martitz <kugel@rockbox.org> | 2010-05-06 21:04:40 +0000 |
|---|---|---|
| committer | Thomas Martitz <kugel@rockbox.org> | 2010-05-06 21:04:40 +0000 |
| commit | 50a6ca39ad4ed01922aa4f755f0ca579788226cf (patch) | |
| tree | c7881b015b220558167310345b162324c96be15a /firmware/libc/sscanf.c | |
| parent | adb506df14aded06ed6e9ebf8540e6fd383ffd6a (diff) | |
| download | rockbox-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.c | 282 |
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; +} |