| /* |
| * 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; |
| } |
| |