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 }