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