From 9bf28debd8617bbc5b8e42c9a47a3eb8c78ef43d Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Sat, 13 Feb 2010 14:41:00 +0000 Subject: 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 --- apps/plugins/lua/SOURCES | 1 + apps/plugins/lua/fscanf.c | 290 ++++++++++++++++++++++++++++++++++++++++++++ apps/plugins/lua/liolib.c | 15 +-- apps/plugins/lua/rocklibc.h | 4 + 4 files changed, 297 insertions(+), 13 deletions(-) create mode 100644 apps/plugins/lua/fscanf.c (limited to 'apps/plugins') diff --git a/apps/plugins/lua/SOURCES b/apps/plugins/lua/SOURCES index d475783c7a..7354fdc821 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 0000000000..25058af7da --- /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 eea40c0d02..e50524ae89 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 78b83a6c18..9b68f429d2 100644 --- a/apps/plugins/lua/rocklibc.h +++ b/apps/plugins/lua/rocklibc.h @@ -28,10 +28,12 @@ #ifdef SIMULATOR #include +#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_ */ -- cgit v1.2.3