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 }