blob: b3d4cd778141660246caf24d090f7920c7f7498d [file] [log] [blame]
/*
* Copyright (c) 2020 MediaTek Inc.
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <assert.h>
#include <ctype.h>
#include <debug.h>
#include <limits.h>
#include <platform/debug.h>
#include <printf.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <trace.h>
#define LOCAL_TRACE 0
#define FLAG_SHORT (0x1 << 2)
#define FLAG_INT (0x1 << 3)
static int xchar_to_int(char c)
{
if (isdigit(c))
return c - '0';
else if (c >= 'a' && c <= 'f')
return 10 + c - 'a';
else if (c >= 'A' && c <= 'F')
return 10 + c - 'A';
else
return 0; // not xdigit: return 0!
}
static int get_int(const char **buf, int *val)
{
const char *p = *buf;
int i = 0;
int err = -1;
int sign = 0;
// ignore blank
while (isspace(*p)) {
++p;
}
if (*p == '+')
++p;
else if (*p == '-') {
sign = 1;
++p;
}
while (1) {
char c = *p;
if (isdigit(c)) {
i = i * 10 + (c - '0');
err = 0; // find at least one digit
LTRACEF("buf:%s, i:%d, c:%c\n", p, i, c);
++p;
continue;
} else {
if (err == -1)
return -1;
*buf = p;
*val = sign ? -i : i;
break;
}
}
return 0;
}
static int get_hex_int(const char **buf)
{
const char *p = *buf;
int i = 0;
int err = -1;
int found_hex_prefix = 0, ignore_hex_prefix = 0;
// ignore blank
while (isspace(*p)) {
++p;
}
while (1) {
char c = *p;
if (isspace(c)) {
*buf = p;
break;
}
// hex prefix
if (!ignore_hex_prefix && !found_hex_prefix && c == '0') {
c = *++p;
if (c == 'x' || c == 'X') {
found_hex_prefix = 1;
ignore_hex_prefix = 1;
++p;
continue;
} else if (isxdigit(c)) {
i = i * 16 + (xchar_to_int(c));
ignore_hex_prefix = 1;
++p;
} else
goto error;
}
if (isxdigit(c)) {
i = i * 16 + xchar_to_int(c);
ignore_hex_prefix = 1;
err = 0; // find at least one digit
LTRACEF("buf:%s, i:0x%x, c:%c\n", p, i, c);
++p;
continue;
} else if (err == 0)
break;
else
goto error;
}
if (err == 0)
*buf = p;
return i;
error:
return -1;
}
/* support interger scanf */
static int vsscanf(const char *buf, const char *fmt, va_list ap)
{
int err = 0;
char c;
size_t item;
int n;
int *p;
char *pch;
short *psh;
int flag;
item = 0;
flag = FLAG_INT;
for (;;) {
while ((c = *fmt++) != 0) {
if (isspace(c))
continue;
if (c == '%')
break;
else {
while (isspace(*buf)) {
++buf;
}
if (c != *buf)
return 0;
++buf;
}
}
/* make sure we haven't just hit the end of the string */
if (c == 0)
break;
c = *fmt++;
if (c == 0)
break;
format_continue:
switch (c) {
case 'h': /* short interger: %hd */
flag = FLAG_SHORT;
c = *fmt++;
goto format_continue;
case 'd': /* interger: %d */
if (flag == FLAG_SHORT)
psh = va_arg(ap, short *);
else
p = va_arg(ap, int *);
err = get_int(&buf, &n);
if (err < 0)
goto exit;
if (flag == FLAG_SHORT)
*psh = n;
else
*p = n;
item++;
break;
case 'x': /* hex interger */
case 'X':
p = va_arg(ap, int *);
n = get_hex_int(&buf);
if (n < 0)
goto exit;
*p = n;
item++;
break;
default:
err = -1;
break;
}
continue;
}
exit:
return (err < 0) ? 0 : (int)item;
}
// a simple sscanf: %d, %x
int sscanf(const char *buf, const char *fmt, ...)
{
va_list ap;
int err;
va_start(ap, fmt);
err = vsscanf(buf, fmt, ap);
va_end(ap);
return err;
}