1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <stdarg.h>
18#include <linux/types.h>
19#include <linux/string.h>
20#include <linux/ctype.h>
21#include <linux/kernel.h>
22
23#include <asm/div64.h>
24
25
26
27
28
29
30
31unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
32{
33 unsigned long result = 0,value;
34
35 if (!base) {
36 base = 10;
37 if (*cp == '0') {
38 base = 8;
39 cp++;
40 if ((*cp == 'x') && isxdigit(cp[1])) {
41 cp++;
42 base = 16;
43 }
44 }
45 }
46 while (isxdigit(*cp) &&
47 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
48 result = result*base + value;
49 cp++;
50 }
51 if (endp)
52 *endp = (char *)cp;
53 return result;
54}
55
56
57
58
59
60
61
62long simple_strtol(const char *cp,char **endp,unsigned int base)
63{
64 if(*cp=='-')
65 return -simple_strtoul(cp+1,endp,base);
66 return simple_strtoul(cp,endp,base);
67}
68
69
70
71
72
73
74
75unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
76{
77 unsigned long long result = 0,value;
78
79 if (!base) {
80 base = 10;
81 if (*cp == '0') {
82 base = 8;
83 cp++;
84 if ((*cp == 'x') && isxdigit(cp[1])) {
85 cp++;
86 base = 16;
87 }
88 }
89 }
90 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
91 ? toupper(*cp) : *cp)-'A'+10) < base) {
92 result = result*base + value;
93 cp++;
94 }
95 if (endp)
96 *endp = (char *)cp;
97 return result;
98}
99
100
101
102
103
104
105
106long long simple_strtoll(const char *cp,char **endp,unsigned int base)
107{
108 if(*cp=='-')
109 return -simple_strtoull(cp+1,endp,base);
110 return simple_strtoull(cp,endp,base);
111}
112
113static int skip_atoi(const char **s)
114{
115 int i=0;
116
117 while (isdigit(**s))
118 i = i*10 + *((*s)++) - '0';
119 return i;
120}
121
122#define ZEROPAD 1
123#define SIGN 2
124#define PLUS 4
125#define SPACE 8
126#define LEFT 16
127#define SPECIAL 32
128#define LARGE 64
129
130static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
131{
132 char c,sign,tmp[66];
133 const char *digits;
134 const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
135 const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
136 int i;
137
138 digits = (type & LARGE) ? large_digits : small_digits;
139 if (type & LEFT)
140 type &= ~ZEROPAD;
141 if (base < 2 || base > 36)
142 return 0;
143 c = (type & ZEROPAD) ? '0' : ' ';
144 sign = 0;
145 if (type & SIGN) {
146 if (num < 0) {
147 sign = '-';
148 num = -num;
149 size--;
150 } else if (type & PLUS) {
151 sign = '+';
152 size--;
153 } else if (type & SPACE) {
154 sign = ' ';
155 size--;
156 }
157 }
158 if (type & SPECIAL) {
159 if (base == 16)
160 size -= 2;
161 else if (base == 8)
162 size--;
163 }
164 i = 0;
165 if (num == 0)
166 tmp[i++]='0';
167 else while (num != 0)
168 tmp[i++] = digits[do_div(num,base)];
169 if (i > precision)
170 precision = i;
171 size -= precision;
172 if (!(type&(ZEROPAD+LEFT))) {
173 while(size-->0) {
174 if (buf <= end)
175 *buf = ' ';
176 ++buf;
177 }
178 }
179 if (sign) {
180 if (buf <= end)
181 *buf = sign;
182 ++buf;
183 }
184 if (type & SPECIAL) {
185 if (base==8) {
186 if (buf <= end)
187 *buf = '0';
188 ++buf;
189 } else if (base==16) {
190 if (buf <= end)
191 *buf = '0';
192 ++buf;
193 if (buf <= end)
194 *buf = digits[33];
195 ++buf;
196 }
197 }
198 if (!(type & LEFT)) {
199 while (size-- > 0) {
200 if (buf <= end)
201 *buf = c;
202 ++buf;
203 }
204 }
205 while (i < precision--) {
206 if (buf <= end)
207 *buf = '0';
208 ++buf;
209 }
210 while (i-- > 0) {
211 if (buf <= end)
212 *buf = tmp[i];
213 ++buf;
214 }
215 while (size-- > 0) {
216 if (buf <= end)
217 *buf = ' ';
218 ++buf;
219 }
220 return buf;
221}
222
223
224
225
226
227
228
229
230
231
232
233int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
234{
235 int len;
236 unsigned long long num;
237 int i, base;
238 char *str, *end, c;
239 const char *s;
240
241 int flags;
242
243 int field_width;
244 int precision;
245
246 int qualifier;
247
248
249
250 str = buf;
251 end = buf + size - 1;
252
253 if (end < buf - 1) {
254 end = ((void *) -1);
255 size = end - buf + 1;
256 }
257
258 for (; *fmt ; ++fmt) {
259 if (*fmt != '%') {
260 if (str <= end)
261 *str = *fmt;
262 ++str;
263 continue;
264 }
265
266
267 flags = 0;
268 repeat:
269 ++fmt;
270 switch (*fmt) {
271 case '-': flags |= LEFT; goto repeat;
272 case '+': flags |= PLUS; goto repeat;
273 case ' ': flags |= SPACE; goto repeat;
274 case '#': flags |= SPECIAL; goto repeat;
275 case '0': flags |= ZEROPAD; goto repeat;
276 }
277
278
279 field_width = -1;
280 if (isdigit(*fmt))
281 field_width = skip_atoi(&fmt);
282 else if (*fmt == '*') {
283 ++fmt;
284
285 field_width = va_arg(args, int);
286 if (field_width < 0) {
287 field_width = -field_width;
288 flags |= LEFT;
289 }
290 }
291
292
293 precision = -1;
294 if (*fmt == '.') {
295 ++fmt;
296 if (isdigit(*fmt))
297 precision = skip_atoi(&fmt);
298 else if (*fmt == '*') {
299 ++fmt;
300
301 precision = va_arg(args, int);
302 }
303 if (precision < 0)
304 precision = 0;
305 }
306
307
308 qualifier = -1;
309 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
310 qualifier = *fmt;
311 ++fmt;
312 if (qualifier == 'l' && *fmt == 'l') {
313 qualifier = 'L';
314 ++fmt;
315 }
316 }
317
318
319 base = 10;
320
321 switch (*fmt) {
322 case 'c':
323 if (!(flags & LEFT)) {
324 while (--field_width > 0) {
325 if (str <= end)
326 *str = ' ';
327 ++str;
328 }
329 }
330 c = (unsigned char) va_arg(args, int);
331 if (str <= end)
332 *str = c;
333 ++str;
334 while (--field_width > 0) {
335 if (str <= end)
336 *str = ' ';
337 ++str;
338 }
339 continue;
340
341 case 's':
342 s = va_arg(args, char *);
343 if (!s)
344 s = "<NULL>";
345
346 len = strnlen(s, precision);
347
348 if (!(flags & LEFT)) {
349 while (len < field_width--) {
350 if (str <= end)
351 *str = ' ';
352 ++str;
353 }
354 }
355 for (i = 0; i < len; ++i) {
356 if (str <= end)
357 *str = *s;
358 ++str; ++s;
359 }
360 while (len < field_width--) {
361 if (str <= end)
362 *str = ' ';
363 ++str;
364 }
365 continue;
366
367 case 'p':
368 if (field_width == -1) {
369 field_width = 2*sizeof(void *);
370 flags |= ZEROPAD;
371 }
372 str = number(str, end,
373 (unsigned long) va_arg(args, void *),
374 16, field_width, precision, flags);
375 continue;
376
377
378 case 'n':
379
380
381 if (qualifier == 'l') {
382 long * ip = va_arg(args, long *);
383 *ip = (str - buf);
384 } else if (qualifier == 'Z') {
385 size_t * ip = va_arg(args, size_t *);
386 *ip = (str - buf);
387 } else {
388 int * ip = va_arg(args, int *);
389 *ip = (str - buf);
390 }
391 continue;
392
393 case '%':
394 if (str <= end)
395 *str = '%';
396 ++str;
397 continue;
398
399
400 case 'o':
401 base = 8;
402 break;
403
404 case 'X':
405 flags |= LARGE;
406 case 'x':
407 base = 16;
408 break;
409
410 case 'd':
411 case 'i':
412 flags |= SIGN;
413 case 'u':
414 break;
415
416 default:
417 if (str <= end)
418 *str = '%';
419 ++str;
420 if (*fmt) {
421 if (str <= end)
422 *str = *fmt;
423 ++str;
424 } else {
425 --fmt;
426 }
427 continue;
428 }
429 if (qualifier == 'L')
430 num = va_arg(args, long long);
431 else if (qualifier == 'l') {
432 num = va_arg(args, unsigned long);
433 if (flags & SIGN)
434 num = (signed long) num;
435 } else if (qualifier == 'Z') {
436 num = va_arg(args, size_t);
437 } else if (qualifier == 'h') {
438 num = (unsigned short) va_arg(args, int);
439 if (flags & SIGN)
440 num = (signed short) num;
441 } else {
442 num = va_arg(args, unsigned int);
443 if (flags & SIGN)
444 num = (signed int) num;
445 }
446 str = number(str, end, num, base,
447 field_width, precision, flags);
448 }
449 if (str <= end)
450 *str = '\0';
451 else if (size > 0)
452
453 *end = '\0';
454
455
456
457 return str-buf;
458}
459
460
461
462
463
464
465
466
467int snprintf(char * buf, size_t size, const char *fmt, ...)
468{
469 va_list args;
470 int i;
471
472 va_start(args, fmt);
473 i=vsnprintf(buf,size,fmt,args);
474 va_end(args);
475 return i;
476}
477
478
479
480
481
482
483
484
485
486
487int vsprintf(char *buf, const char *fmt, va_list args)
488{
489 return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
490}
491
492
493
494
495
496
497
498
499int sprintf(char * buf, const char *fmt, ...)
500{
501 va_list args;
502 int i;
503
504 va_start(args, fmt);
505 i=vsprintf(buf,fmt,args);
506 va_end(args);
507 return i;
508}
509
510
511
512
513
514
515
516int vsscanf(const char * buf, const char * fmt, va_list args)
517{
518 const char *str = buf;
519 char *next;
520 int num = 0;
521 int qualifier;
522 int base;
523 int field_width = -1;
524 int is_sign = 0;
525
526 while(*fmt && *str) {
527
528
529
530
531 if (isspace(*fmt)) {
532 while (isspace(*fmt))
533 ++fmt;
534 while (isspace(*str))
535 ++str;
536 }
537
538
539 if (*fmt != '%' && *fmt) {
540 if (*fmt++ != *str++)
541 break;
542 continue;
543 }
544
545 if (!*fmt)
546 break;
547 ++fmt;
548
549
550
551
552 if (*fmt == '*') {
553 while (!isspace(*fmt) && *fmt)
554 fmt++;
555 while (!isspace(*str) && *str)
556 str++;
557 continue;
558 }
559
560
561 if (isdigit(*fmt))
562 field_width = skip_atoi(&fmt);
563
564
565 qualifier = -1;
566 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') {
567 qualifier = *fmt;
568 fmt++;
569 }
570 base = 10;
571 is_sign = 0;
572
573 if (!*fmt || !*str)
574 break;
575
576 switch(*fmt++) {
577 case 'c':
578 {
579 char *s = (char *) va_arg(args,char*);
580 if (field_width == -1)
581 field_width = 1;
582 do {
583 *s++ = *str++;
584 } while(field_width-- > 0 && *str);
585 num++;
586 }
587 continue;
588 case 's':
589 {
590 char *s = (char *) va_arg(args, char *);
591 if(field_width == -1)
592 field_width = INT_MAX;
593
594 while (isspace(*str))
595 str++;
596
597
598 while (*str && !isspace(*str) && field_width--) {
599 *s++ = *str++;
600 }
601 *s = '\0';
602 num++;
603 }
604 continue;
605 case 'n':
606
607 {
608 int *i = (int *)va_arg(args,int*);
609 *i = str - buf;
610 }
611 continue;
612 case 'o':
613 base = 8;
614 break;
615 case 'x':
616 case 'X':
617 base = 16;
618 break;
619 case 'd':
620 case 'i':
621 is_sign = 1;
622 case 'u':
623 break;
624 case '%':
625
626 if (*str++ != '%')
627 return num;
628 continue;
629 default:
630
631 return num;
632 }
633
634
635
636
637 while (isspace(*str))
638 str++;
639
640 if (!*str || !isdigit(*str))
641 break;
642
643 switch(qualifier) {
644 case 'h':
645 if (is_sign) {
646 short *s = (short *) va_arg(args,short *);
647 *s = (short) simple_strtol(str,&next,base);
648 } else {
649 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
650 *s = (unsigned short) simple_strtoul(str, &next, base);
651 }
652 break;
653 case 'l':
654 if (is_sign) {
655 long *l = (long *) va_arg(args,long *);
656 *l = simple_strtol(str,&next,base);
657 } else {
658 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
659 *l = simple_strtoul(str,&next,base);
660 }
661 break;
662 case 'L':
663 if (is_sign) {
664 long long *l = (long long*) va_arg(args,long long *);
665 *l = simple_strtoll(str,&next,base);
666 } else {
667 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
668 *l = simple_strtoull(str,&next,base);
669 }
670 break;
671 case 'Z':
672 {
673 size_t *s = (size_t*) va_arg(args,size_t*);
674 *s = (size_t) simple_strtoul(str,&next,base);
675 }
676 break;
677 default:
678 if (is_sign) {
679 int *i = (int *) va_arg(args, int*);
680 *i = (int) simple_strtol(str,&next,base);
681 } else {
682 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
683 *i = (unsigned int) simple_strtoul(str,&next,base);
684 }
685 break;
686 }
687 num++;
688
689 if (!next)
690 break;
691 str = next;
692 }
693 return num;
694}
695
696
697
698
699
700
701
702int sscanf(const char * buf, const char * fmt, ...)
703{
704 va_list args;
705 int i;
706
707 va_start(args,fmt);
708 i = vsscanf(buf,fmt,args);
709 va_end(args);
710 return i;
711}
712