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