summaryrefslogtreecommitdiff
path: root/apps/plugins/lua
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2010-02-13 14:41:00 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2010-02-13 14:41:00 +0000
commit9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d (patch)
treee70216b99f6366b47df34c955a9650227b7ddf82 /apps/plugins/lua
parent4c658f74a775bcccadbc682e2a173a9a452ee2a2 (diff)
downloadrockbox-9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d.zip
rockbox-9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d.tar.gz
rockbox-9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d.tar.bz2
rockbox-9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d.tar.xz
Fix FS#11007: Lua didn't parse negative numbers correct when reading from files
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24632 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/lua')
-rw-r--r--apps/plugins/lua/SOURCES1
-rw-r--r--apps/plugins/lua/fscanf.c290
-rw-r--r--apps/plugins/lua/liolib.c15
-rw-r--r--apps/plugins/lua/rocklibc.h4
4 files changed, 297 insertions, 13 deletions
diff --git a/apps/plugins/lua/SOURCES b/apps/plugins/lua/SOURCES
index d475783..7354fdc 100644
--- a/apps/plugins/lua/SOURCES
+++ b/apps/plugins/lua/SOURCES
@@ -29,6 +29,7 @@ lzio.c
rockaux.c
rocklib.c
rockmalloc.c
+fscanf.c
gmtime.c
strcspn.c
strftime.c
diff --git a/apps/plugins/lua/fscanf.c b/apps/plugins/lua/fscanf.c
new file mode 100644
index 0000000..25058af
--- /dev/null
+++ b/apps/plugins/lua/fscanf.c
@@ -0,0 +1,290 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copied from firmware/common/sscanf.c
+ * Original author: Tomasz Malesinski
+ *
+ * Copyright (C) 2010 Maurus Cuelenaere
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "rocklibc.h"
+
+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 argument */
+ {
+ 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 fspeek(void *userp)
+{
+ int fd = (int) userp;
+ char buf = 0;
+ if(rb->read(fd, &buf, 1) == 1)
+ rb->lseek(fd, -1, SEEK_CUR);
+ return buf;
+}
+
+static void fspop(void *userp)
+{
+ rb->lseek((int) userp, 1, SEEK_CUR);
+}
+
+int PREFIX(fscanf)(int fd, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+
+ va_start(ap, fmt);
+ r = scan(fspeek, fspop, (void*) fd, fmt, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/apps/plugins/lua/liolib.c b/apps/plugins/lua/liolib.c
index eea40c0..e50524a 100644
--- a/apps/plugins/lua/liolib.c
+++ b/apps/plugins/lua/liolib.c
@@ -245,24 +245,13 @@ static int io_lines (lua_State *L) {
** =======================================================
*/
-
static int read_number (lua_State *L, int *f) {
- char buf[10]; /* Maximum uint32 value is 10 chars long */
lua_Number d;
- int i = 0;
- /* Rather hackish, but we don't have fscanf.
- Was: fscanf(f, LUA_NUMBER_SCAN, &d); */
- memset(buf, 0, 10);
- rb->read(*f, buf, 10);
- while(isdigit(buf[i]) && i < 10)
- i++;
- if(i == 0) return 0;
- else {
- rb->lseek(*f, i-10, SEEK_CUR);
- d = rb->atoi(buf);
+ if (PREFIX(fscanf)(*f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
+ else return 0; /* read fails */
}
diff --git a/apps/plugins/lua/rocklibc.h b/apps/plugins/lua/rocklibc.h
index 78b83a6..9b68f42 100644
--- a/apps/plugins/lua/rocklibc.h
+++ b/apps/plugins/lua/rocklibc.h
@@ -28,10 +28,12 @@
#ifdef SIMULATOR
#include <errno.h>
+#define PREFIX(_x_) sim_ ## _x_
#else
extern int errno;
#define EINVAL 22 /* Invalid argument */
#define ERANGE 34 /* Math result not representable */
+#define PREFIX
#endif
#define __likely LIKELY
@@ -41,5 +43,7 @@ extern int errno;
#define memcmp rb->memcmp
#define strlen rb->strlen
+extern int PREFIX(fscanf)(int fd, const char *fmt, ...);
+
#endif /* _ROCKLIBC_H_ */