forked from len0rd/rockbox
Simple sscanf implementation
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8444 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0868ac8cb2
commit
e8e0b241bd
2 changed files with 246 additions and 0 deletions
216
firmware/common/sscanf.c
Normal file
216
firmware/common/sscanf.c
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
#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_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 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;
|
||||
unsigned long ulval;
|
||||
|
||||
while ((ch = *fmt++) != '\0')
|
||||
{
|
||||
bool literal = false;
|
||||
|
||||
if (ch == '%')
|
||||
{
|
||||
ch = *fmt++;
|
||||
|
||||
while (isspace((*peek)(userp))) {
|
||||
n_chars++;
|
||||
(*pop)(userp);
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case 'x':
|
||||
if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
|
||||
{
|
||||
*(va_arg(ap, unsigned int *)) = ulval;
|
||||
n++;
|
||||
n_chars += r;
|
||||
}
|
||||
else
|
||||
return n;
|
||||
break;
|
||||
case 'd':
|
||||
if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
|
||||
{
|
||||
*(va_arg(ap, int *)) = lval;
|
||||
n++;
|
||||
n_chars += r;
|
||||
}
|
||||
else
|
||||
return n;
|
||||
break;
|
||||
case 'n':
|
||||
*(va_arg(ap, int *)) = n_chars;
|
||||
n++;
|
||||
break;
|
||||
case 'l':
|
||||
ch = *fmt++;
|
||||
switch (ch)
|
||||
{
|
||||
case 'x':
|
||||
if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
|
||||
{
|
||||
*(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)
|
||||
{
|
||||
*(va_arg(ap, long *)) = lval;
|
||||
n++;
|
||||
n_chars += r;
|
||||
}
|
||||
else
|
||||
return n;
|
||||
break;
|
||||
case '\0':
|
||||
return n;
|
||||
default:
|
||||
literal = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
return n;
|
||||
default:
|
||||
literal = true;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
literal = true;
|
||||
|
||||
if (literal)
|
||||
{
|
||||
while (isspace((*peek)(userp))) {
|
||||
(*pop)(userp);
|
||||
n_chars++;
|
||||
}
|
||||
if ((*peek)(userp) != ch)
|
||||
return n;
|
||||
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;
|
||||
}
|
||||
30
firmware/include/sscanf.h
Normal file
30
firmware/include/sscanf.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 by Tomasz Malesinski
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __SSCANF_H__
|
||||
#define __SSCANF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <_ansi.h>
|
||||
|
||||
int sscanf(const char *s, const char *fmt, ...)
|
||||
ATTRIBUTE_SCANF(2, 3);
|
||||
|
||||
#endif /* __SSCANF_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue