blob: b3d4cd778141660246caf24d090f7920c7f7498d [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2020 MediaTek Inc.
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9#include <assert.h>
10#include <ctype.h>
11#include <debug.h>
12#include <limits.h>
13#include <platform/debug.h>
14#include <printf.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <string.h>
18#include <sys/types.h>
19#include <trace.h>
20
21#define LOCAL_TRACE 0
22
23#define FLAG_SHORT (0x1 << 2)
24#define FLAG_INT (0x1 << 3)
25
26static int xchar_to_int(char c)
27{
28 if (isdigit(c))
29 return c - '0';
30 else if (c >= 'a' && c <= 'f')
31 return 10 + c - 'a';
32 else if (c >= 'A' && c <= 'F')
33 return 10 + c - 'A';
34 else
35 return 0; // not xdigit: return 0!
36}
37
38static int get_int(const char **buf, int *val)
39{
40 const char *p = *buf;
41 int i = 0;
42 int err = -1;
43 int sign = 0;
44
45 // ignore blank
46 while (isspace(*p)) {
47 ++p;
48 }
49
50 if (*p == '+')
51 ++p;
52 else if (*p == '-') {
53 sign = 1;
54 ++p;
55 }
56
57 while (1) {
58 char c = *p;
59
60 if (isdigit(c)) {
61 i = i * 10 + (c - '0');
62 err = 0; // find at least one digit
63
64 LTRACEF("buf:%s, i:%d, c:%c\n", p, i, c);
65
66 ++p;
67 continue;
68 } else {
69 if (err == -1)
70 return -1;
71
72 *buf = p;
73
74 *val = sign ? -i : i;
75 break;
76 }
77 }
78
79 return 0;
80}
81
82static int get_hex_int(const char **buf)
83{
84 const char *p = *buf;
85 int i = 0;
86 int err = -1;
87 int found_hex_prefix = 0, ignore_hex_prefix = 0;
88
89 // ignore blank
90 while (isspace(*p)) {
91 ++p;
92 }
93
94 while (1) {
95 char c = *p;
96
97 if (isspace(c)) {
98 *buf = p;
99 break;
100 }
101
102 // hex prefix
103 if (!ignore_hex_prefix && !found_hex_prefix && c == '0') {
104 c = *++p;
105 if (c == 'x' || c == 'X') {
106 found_hex_prefix = 1;
107 ignore_hex_prefix = 1;
108 ++p;
109 continue;
110 } else if (isxdigit(c)) {
111 i = i * 16 + (xchar_to_int(c));
112 ignore_hex_prefix = 1;
113 ++p;
114 } else
115 goto error;
116 }
117
118 if (isxdigit(c)) {
119 i = i * 16 + xchar_to_int(c);
120 ignore_hex_prefix = 1;
121 err = 0; // find at least one digit
122
123 LTRACEF("buf:%s, i:0x%x, c:%c\n", p, i, c);
124
125 ++p;
126 continue;
127 } else if (err == 0)
128 break;
129 else
130 goto error;
131 }
132
133 if (err == 0)
134 *buf = p;
135 return i;
136
137error:
138 return -1;
139}
140
141/* support interger scanf */
142static int vsscanf(const char *buf, const char *fmt, va_list ap)
143{
144 int err = 0;
145 char c;
146 size_t item;
147 int n;
148 int *p;
149 char *pch;
150 short *psh;
151 int flag;
152
153 item = 0;
154 flag = FLAG_INT;
155
156 for (;;) {
157 while ((c = *fmt++) != 0) {
158 if (isspace(c))
159 continue;
160
161 if (c == '%')
162 break;
163 else {
164 while (isspace(*buf)) {
165 ++buf;
166 }
167 if (c != *buf)
168 return 0;
169
170 ++buf;
171 }
172 }
173
174 /* make sure we haven't just hit the end of the string */
175 if (c == 0)
176 break;
177
178 c = *fmt++;
179 if (c == 0)
180 break;
181
182format_continue:
183 switch (c) {
184 case 'h': /* short interger: %hd */
185 flag = FLAG_SHORT;
186 c = *fmt++;
187 goto format_continue;
188 case 'd': /* interger: %d */
189 if (flag == FLAG_SHORT)
190 psh = va_arg(ap, short *);
191 else
192 p = va_arg(ap, int *);
193
194 err = get_int(&buf, &n);
195
196 if (err < 0)
197 goto exit;
198
199 if (flag == FLAG_SHORT)
200 *psh = n;
201 else
202 *p = n;
203 item++;
204 break;
205
206 case 'x': /* hex interger */
207 case 'X':
208 p = va_arg(ap, int *);
209
210 n = get_hex_int(&buf);
211
212 if (n < 0)
213 goto exit;
214
215 *p = n;
216 item++;
217 break;
218
219 default:
220 err = -1;
221 break;
222 }
223
224 continue;
225 }
226
227exit:
228 return (err < 0) ? 0 : (int)item;
229}
230
231// a simple sscanf: %d, %x
232int sscanf(const char *buf, const char *fmt, ...)
233{
234 va_list ap;
235 int err;
236
237 va_start(ap, fmt);
238 err = vsscanf(buf, fmt, ap);
239 va_end(ap);
240
241 return err;
242}
243