1 /*
2 * Copyright (c) 2021 GOODIX.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <stdarg.h>
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #define INDEX_0 0
23 #define INDEX_1 1
24 #define INDEX_2 2
25 #define BASE_8 9
26 #define BASE_2 2
27 #define BASE_0 0
28 #define BASE_10 10
29 #define BASE_16 16
30 #define is_digit(c) ((c) >= '0' && (c) <= '9')
31 #define likely(x) __builtin_expect((x), 1)
32 #define unlikely(x) __builtin_expect((x), 0)
33 #define KSTRTOX_OVERFLOW 0
34
35 /* Convert a character to lower case */
tolower_re(char char_c)36 inline static char tolower_re(char char_c)
37 {
38 char c = char_c;
39
40 if ((c >= 'A') && (c <= 'Z')) {
41 c = (c - 'A') + 'a';
42 }
43 return c;
44 }
45
46 // div_u64_rem
div_u64_rem(unsigned long long dividend,unsigned int divisor,unsigned int * remainder)47 static inline unsigned long long div_u64_rem(unsigned long long dividend, unsigned int divisor, unsigned int *remainder)
48 {
49 unsigned long long ret = 0;
50
51 if (divisor == 0) {
52 return ret;
53 }
54 *remainder = dividend % divisor;
55 return dividend / divisor;
56 }
57
div_u64(unsigned long long dividend,unsigned int divisor)58 static inline unsigned long long div_u64(unsigned long long dividend, unsigned int divisor)
59 {
60 unsigned int remainder;
61 return div_u64_rem(dividend, divisor, &remainder);
62 }
63
64 // lib/kstrtox.c, line 23
_parse_integer_fixup_radix(const char * str,unsigned int * base)65 const char *_parse_integer_fixup_radix(const char *str, unsigned int *base)
66 {
67 const char *s = str;
68
69 if (*base == BASE_0) {
70 if (s[BASE_0] == '0') {
71 if (tolower_re(s[INDEX_1]) == 'x' && isxdigit(s[INDEX_2])) {
72 *base = BASE_16;
73 } else {
74 *base = BASE_8;
75 }
76 } else {
77 *base = BASE_10;
78 }
79 }
80 if (*base == BASE_16 && s[INDEX_0] == '0' && tolower_re(s[INDEX_1]) == 'x') {
81 s += BASE_2;
82 }
83 return s;
84 }
85
_parse_integer(const char * str,unsigned int base,unsigned long long * p)86 unsigned int _parse_integer(const char *str, unsigned int base, unsigned long long *p)
87 {
88 unsigned long long res;
89 unsigned int rv;
90 int overflow;
91 const char *s = str;
92
93 res = 0;
94 rv = 0;
95 overflow = 0;
96 while (*s) {
97 unsigned int val;
98
99 if (*s >= '0' && *s <= '9') {
100 val = *s - '0';
101 } else if (tolower_re(*s) >= 'a' && tolower_re(*s) <= 'f') {
102 val = tolower_re(*s) - 'a' + BASE_10;
103 } else {
104 break;
105 }
106 if (val >= base) {
107 break;
108 }
109 /*
110 * Check for overflow only if we are within range of
111 * it in the max base we support (16)
112 */
113 if (unlikely(res & (~0ull << 60))) {
114 if (res > div_u64(ULLONG_MAX - val, base)) {
115 overflow = 1;
116 }
117 }
118 res = res * base + val;
119 rv++;
120 s++;
121 }
122 *p = res;
123 if (overflow) {
124 rv |= KSTRTOX_OVERFLOW;
125 }
126 return rv;
127 }
128
isspace_re(int x)129 int isspace_re(int x)
130 {
131 if (x==' '||x=='/t'||x=='/n'||x=='/f'||x=='/b'||x=='/r') {
132 return 1;
133 } else {
134 return 0;
135 }
136 }
137
skip_spaces(const char * str)138 char* skip_spaces(const char * str)
139 {
140 const char* str_temp = str;
141
142 while (isspace_re(*str_temp)) {
143 ++str_temp;
144 }
145 return (char *)str_temp;
146 }
147
148 // simple_strtoull - convert a string to an unsigned long long
simple_strtoull(const char * cp_temp,char ** endp,unsigned int base)149 unsigned long long simple_strtoull(const char *cp_temp, char **endp, unsigned int base)
150 {
151 unsigned long long result;
152 unsigned int rv;
153 const char *cp = cp_temp;
154
155 cp = _parse_integer_fixup_radix(cp, &base);
156 rv = _parse_integer(cp, base, &result);
157
158 cp += (rv & ~KSTRTOX_OVERFLOW);
159
160 if (endp) {
161 *endp = (char *)cp;
162 }
163 return result;
164 }
165
skip_atoi(const char ** s)166 static int skip_atoi(const char **s)
167 {
168 int i = 0;
169 while (is_digit(**s)) {
170 i = i*BASE_10 + *((*s)++) - '0';
171 }
172 return i;
173 }
174
simple_strtoul(const char * cp,char ** endp,unsigned int base)175 unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
176 {
177 return simple_strtoull(cp, endp, base);
178 }
179
180 /**
181 * simple_strtoll - convert a string to a signed long long
182 * @cp: The start of the string
183 * @endp: A pointer to the end of the parsed string will be placed here
184 * @base: The number base to use
185 */
simple_strtoll(const char * cp,char ** endp,unsigned int base)186 long long simple_strtoll(const char *cp, char **endp, unsigned int base)
187 {
188 if (*cp == '-') {
189 return -simple_strtoull(cp + 1, endp, base);
190 }
191 return simple_strtoull(cp, endp, base);
192 }
193
simple_strtol(const char * cp,char ** endp,unsigned int base)194 long simple_strtol(const char *cp, char **endp, unsigned int base)
195 {
196 if (*cp == '-') {
197 return -simple_strtoul(cp + 1, endp, base);
198 }
199 return simple_strtoul(cp, endp, base);
200 }
201
202 /**
203 * vsscanf - Unformat a buffer into a list of arguments
204 * @buf: input buffer
205 * @fmt: format of buffer
206 * @args: arguments
207 */
pre_vsscanf(const char * __restrict __s,const char * __restrict __format,va_list arg)208 int pre_vsscanf(const char *__restrict __s, const char *__restrict __format, va_list arg)
209 {
210 const char *str = __s;
211 char *next;
212 char digit;
213 int num = 0;
214 unsigned char qualifier;
215 unsigned char base;
216 short field_width;
217 char is_sign;
218 const char *fmt = __format;
219
220 while (*fmt && *str) {
221 /* skip any white space in format */
222 /* white space in format matchs any amount of
223 * white space, including none, in the input.
224 */
225 if (isspace_re(*fmt)) {
226 ++fmt;
227 fmt = skip_spaces(fmt);
228 str = skip_spaces(str);
229 }
230
231 /* anything that is not a conversion must match exactly */
232 if (*fmt != '%' && *fmt) {
233 if (*fmt++ != *str++) {
234 break;
235 }
236 continue;
237 }
238
239 if (!*fmt) {
240 break;
241 }
242 ++fmt;
243
244 /* skip this conversion.
245 * advance both strings to next white space
246 */
247 if (*fmt == '*') {
248 while (!isspace_re(*fmt) && *fmt != '%' && *fmt) {
249 fmt++;
250 }
251 while (!isspace_re(*str) && *str) {
252 str++;
253 }
254 continue;
255 }
256
257 /* get field width */
258 field_width = -1;
259 if (is_digit(*fmt)) {
260 field_width = skip_atoi(&fmt);
261 }
262
263 /* get conversion qualifier */
264 qualifier = -1;
265 if (*fmt == 'h' || tolower_re(*fmt) == 'l' ||
266 tolower_re(*fmt) == 'z') {
267 qualifier = *fmt++;
268 if (likely(qualifier == *fmt)) {
269 break;
270 }
271 if (qualifier == 'h') {
272 qualifier = 'H';
273 fmt++;
274 } else if (qualifier == 'l') {
275 qualifier = 'L';
276 fmt++;
277 }
278 }
279
280 if (!*fmt || !*str) {
281 break;
282 }
283
284 base = BASE_10;
285 is_sign = 0;
286
287 switch (*fmt++) {
288 case 'c': {
289 char *s = (char *)va_arg(arg, char *);
290 if (field_width == -1) {
291 field_width = 1;
292 }
293 do {
294 *s++ = *str++;
295 } while (--field_width > 0 && *str);
296 num++;
297 }
298 continue;
299 case 's': {
300 char *s = (char *)va_arg(arg, char *);
301 if (field_width == -1) {
302 field_width = SHRT_MAX;
303 }
304 /* first, skip leading white space in buffer */
305 str = skip_spaces(str);
306
307 /* now copy until next white space */
308 while (*str && !isspace_re(*str) && field_width--) {
309 *s++ = *str++;
310 }
311 *s = '\0';
312 num++;
313 }
314 continue;
315 case 'n':
316 /* return number of characters read so far */
317 {
318 int *i = (int *)va_arg(arg, int *);
319 *i = str - __s;
320 }
321 continue;
322 case 'o':
323 base = BASE_8;
324 break;
325 case 'x':
326 case 'X':
327 base = BASE_16;
328 break;
329 case 'i':
330 base = 0;
331 case 'd':
332 is_sign = 1;
333 case 'u':
334 break;
335 case '%':
336 /* looking for '%' in str */
337 if (*str++ != '%') {
338 return num;
339 }
340 continue;
341 default:
342 /* invalid format; stop here */
343 return num;
344 }
345
346 /* have some sort of integer conversion.
347 * first, skip white space in buffer.
348 */
349 str = skip_spaces(str);
350
351 digit = *str;
352 if (is_sign && digit == '-') {
353 digit = *(str + 1);
354 }
355 if (!digit|| (base == BASE_16 && !isxdigit(digit))
356 || (base == BASE_10 && !isdigit(digit))
357 || (base == BASE_8 && (!isdigit(digit) || digit > '7'))
358 || (base == BASE_0 && !isdigit(digit))) {
359 break;
360 }
361 switch (qualifier) {
362 case 'H': /* that's 'hh' in format */
363 if (is_sign) {
364 signed char *s = (signed char *)va_arg(arg, signed char *);
365 *s = (signed char)simple_strtol(str, &next, base);
366 } else {
367 unsigned char *s = (unsigned char *)va_arg(arg, unsigned char *);
368 *s = (unsigned char)simple_strtoul(str, &next, base);
369 }
370 break;
371 case 'h':
372 if (is_sign) {
373 short *s = (short *)va_arg(arg, short *);
374 *s = (short)simple_strtol(str, &next, base);
375 } else {
376 unsigned short *s = (unsigned short *)va_arg(arg, unsigned short *);
377 *s = (unsigned short)simple_strtoul(str, &next, base);
378 }
379 break;
380 case 'l':
381 if (is_sign) {
382 long *l = (long *)va_arg(arg, long *);
383 *l = simple_strtol(str, &next, base);
384 } else {
385 unsigned long *l = (unsigned long *)va_arg(arg, unsigned long *);
386 *l = simple_strtoul(str, &next, base);
387 }
388 break;
389 case 'L':
390 if (is_sign) {
391 long long *l = (long long *)va_arg(arg, long long *);
392 *l = simple_strtoll(str, &next, base);
393 } else {
394 unsigned long long *l = (unsigned long long *)va_arg(arg, unsigned long long *);
395 *l = simple_strtoull(str, &next, base);
396 }
397 break;
398 case 'Z':
399 case 'z': {
400 size_t *s = (size_t *)va_arg(arg, size_t *);
401 *s = (size_t)simple_strtoul(str, &next, base);
402 }
403 break;
404 default:
405 if (is_sign) {
406 int *i = (int *)va_arg(arg, int *);
407 *i = (int)simple_strtol(str, &next, base);
408 } else {
409 unsigned int *i = (unsigned int *)va_arg(arg, unsigned int*);
410 *i = (unsigned int)simple_strtoul(str, &next, base);
411 }
412 break;
413 }
414 num++;
415
416 if (!next) {
417 break;
418 }
419 str = next;
420 }
421
422 /*
423 * Now we've come all the way through so either the input string or the
424 * format ended. In the former case, there can be a %n at the current
425 * position in the format that needs to be filled.
426 */
427 if (*fmt == '%' && *(fmt + 1) == 'n') {
428 int *p = (int *)va_arg(arg, int *);
429 *p = str - __s;
430 }
431
432 return num;
433 }
434 /**
435 * sscanf - Unformat a buffer into a list of arguments
436 * @__s: input buffer
437 * @__format: formatting of buffer
438 * @...: resulting arguments
439 */
sscanf(const char * __restrict __s,const char * __restrict __format,...)440 int sscanf(const char *__restrict __s, const char *__restrict __format, ...)
441 {
442 va_list args;
443 int i;
444
445 va_start(args, __format);
446 i = pre_vsscanf(__s, __format, args);
447 va_end(args);
448
449 return i;
450 }
451
strcpy(char * __restrict __dest,const char * __restrict __src)452 char *strcpy(char *__restrict __dest, const char *__restrict __src)
453 {
454 __stpcpy(__dest, __src);
455 return __dest;
456 }
457
458