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