• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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