The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/vsprintf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/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  * simple_strtoul - convert a string to an unsigned long
   27  * @cp: The start of the string
   28  * @endp: A pointer to the end of the parsed string will be placed here
   29  * @base: The number base to use
   30  */
   31 unsigned 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 == '') {
   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-'' : 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  * simple_strtol - convert a string to a signed long
   58  * @cp: The start of the string
   59  * @endp: A pointer to the end of the parsed string will be placed here
   60  * @base: The number base to use
   61  */
   62 long 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  * simple_strtoull - convert a string to an unsigned long long
   71  * @cp: The start of the string
   72  * @endp: A pointer to the end of the parsed string will be placed here
   73  * @base: The number base to use
   74  */
   75 unsigned 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 == '') {
   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-'' : (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  * simple_strtoll - convert a string to a signed long long
  102  * @cp: The start of the string
  103  * @endp: A pointer to the end of the parsed string will be placed here
  104  * @base: The number base to use
  105  */
  106 long 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 
  113 static int skip_atoi(const char **s)
  114 {
  115         int i=0;
  116 
  117         while (isdigit(**s))
  118                 i = i*10 + *((*s)++) - '';
  119         return i;
  120 }
  121 
  122 #define ZEROPAD 1               /* pad with zero */
  123 #define SIGN    2               /* unsigned/signed long */
  124 #define PLUS    4               /* show plus */
  125 #define SPACE   8               /* space if plus */
  126 #define LEFT    16              /* left justified */
  127 #define SPECIAL 32              /* 0x */
  128 #define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
  129 
  130 static 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         static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  135         static 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) ? '' : ' ';
  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++]='';
  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 = '';
  188                         ++buf;
  189                 } else if (base==16) {
  190                         if (buf <= end)
  191                                 *buf = '';
  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 = '';
  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 * vsnprintf - Format a string and place it in a buffer
  225 * @buf: The buffer to place the result into
  226 * @size: The size of the buffer, including the trailing null space
  227 * @fmt: The format string to use
  228 * @args: Arguments for the format string
  229 *
  230 * Call this function if you are already dealing with a va_list.
  231 * You probably want snprintf instead.
  232  */
  233 int 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;              /* flags to number() */
  242 
  243         int field_width;        /* width of output field */
  244         int precision;          /* min. # of digits for integers; max
  245                                    number of chars for from string */
  246         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
  247                                 /* 'z' support added 23/7/1999 S.H.    */
  248                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
  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                 /* process flags */
  267                 flags = 0;
  268                 repeat:
  269                         ++fmt;          /* this also skips first '%' */
  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 '': flags |= ZEROPAD; goto repeat;
  276                         }
  277 
  278                 /* get field width */
  279                 field_width = -1;
  280                 if (isdigit(*fmt))
  281                         field_width = skip_atoi(&fmt);
  282                 else if (*fmt == '*') {
  283                         ++fmt;
  284                         /* it's the next argument */
  285                         field_width = va_arg(args, int);
  286                         if (field_width < 0) {
  287                                 field_width = -field_width;
  288                                 flags |= LEFT;
  289                         }
  290                 }
  291 
  292                 /* get the precision */
  293                 precision = -1;
  294                 if (*fmt == '.') {
  295                         ++fmt;  
  296                         if (isdigit(*fmt))
  297                                 precision = skip_atoi(&fmt);
  298                         else if (*fmt == '*') {
  299                                 ++fmt;
  300                                 /* it's the next argument */
  301                                 precision = va_arg(args, int);
  302                         }
  303                         if (precision < 0)
  304                                 precision = 0;
  305                 }
  306 
  307                 /* get the conversion qualifier */
  308                 qualifier = -1;
  309                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
  310                     *fmt =='Z' || *fmt == 'z') {
  311                         qualifier = *fmt;
  312                         ++fmt;
  313                         if (qualifier == 'l' && *fmt == 'l') {
  314                                 qualifier = 'L';
  315                                 ++fmt;
  316                         }
  317                 }
  318 
  319                 /* default base */
  320                 base = 10;
  321 
  322                 switch (*fmt) {
  323                         case 'c':
  324                                 if (!(flags & LEFT)) {
  325                                         while (--field_width > 0) {
  326                                                 if (str <= end)
  327                                                         *str = ' ';
  328                                                 ++str;
  329                                         }
  330                                 }
  331                                 c = (unsigned char) va_arg(args, int);
  332                                 if (str <= end)
  333                                         *str = c;
  334                                 ++str;
  335                                 while (--field_width > 0) {
  336                                         if (str <= end)
  337                                                 *str = ' ';
  338                                         ++str;
  339                                 }
  340                                 continue;
  341 
  342                         case 's':
  343                                 s = va_arg(args, char *);
  344                                 if (!s)
  345                                         s = "<NULL>";
  346 
  347                                 len = strnlen(s, precision);
  348 
  349                                 if (!(flags & LEFT)) {
  350                                         while (len < field_width--) {
  351                                                 if (str <= end)
  352                                                         *str = ' ';
  353                                                 ++str;
  354                                         }
  355                                 }
  356                                 for (i = 0; i < len; ++i) {
  357                                         if (str <= end)
  358                                                 *str = *s;
  359                                         ++str; ++s;
  360                                 }
  361                                 while (len < field_width--) {
  362                                         if (str <= end)
  363                                                 *str = ' ';
  364                                         ++str;
  365                                 }
  366                                 continue;
  367 
  368                         case 'p':
  369                                 if (field_width == -1) {
  370                                         field_width = 2*sizeof(void *);
  371                                         flags |= ZEROPAD;
  372                                 }
  373                                 str = number(str, end,
  374                                                 (unsigned long) va_arg(args, void *),
  375                                                 16, field_width, precision, flags);
  376                                 continue;
  377 
  378 
  379                         case 'n':
  380                                 /* FIXME:
  381                                 * What does C99 say about the overflow case here? */
  382                                 if (qualifier == 'l') {
  383                                         long * ip = va_arg(args, long *);
  384                                         *ip = (str - buf);
  385                                 } else if (qualifier == 'Z' || qualifier == 'z') {
  386                                         size_t * ip = va_arg(args, size_t *);
  387                                         *ip = (str - buf);
  388                                 } else {
  389                                         int * ip = va_arg(args, int *);
  390                                         *ip = (str - buf);
  391                                 }
  392                                 continue;
  393 
  394                         case '%':
  395                                 if (str <= end)
  396                                         *str = '%';
  397                                 ++str;
  398                                 continue;
  399 
  400                                 /* integer number formats - set up the flags and "break" */
  401                         case 'o':
  402                                 base = 8;
  403                                 break;
  404 
  405                         case 'X':
  406                                 flags |= LARGE;
  407                         case 'x':
  408                                 base = 16;
  409                                 break;
  410 
  411                         case 'd':
  412                         case 'i':
  413                                 flags |= SIGN;
  414                         case 'u':
  415                                 break;
  416 
  417                         default:
  418                                 if (str <= end)
  419                                         *str = '%';
  420                                 ++str;
  421                                 if (*fmt) {
  422                                         if (str <= end)
  423                                                 *str = *fmt;
  424                                         ++str;
  425                                 } else {
  426                                         --fmt;
  427                                 }
  428                                 continue;
  429                 }
  430                 if (qualifier == 'L')
  431                         num = va_arg(args, long long);
  432                 else if (qualifier == 'l') {
  433                         num = va_arg(args, unsigned long);
  434                         if (flags & SIGN)
  435                                 num = (signed long) num;
  436                 } else if (qualifier == 'Z' || qualifier == 'z') {
  437                         num = va_arg(args, size_t);
  438                 } else if (qualifier == 'h') {
  439                         num = (unsigned short) va_arg(args, int);
  440                         if (flags & SIGN)
  441                                 num = (signed short) num;
  442                 } else {
  443                         num = va_arg(args, unsigned int);
  444                         if (flags & SIGN)
  445                                 num = (signed int) num;
  446                 }
  447                 str = number(str, end, num, base,
  448                                 field_width, precision, flags);
  449         }
  450         if (str <= end)
  451                 *str = '\0';
  452         else if (size > 0)
  453                 /* don't write out a null byte if the buf size is zero */
  454                 *end = '\0';
  455         /* the trailing null byte doesn't count towards the total
  456         * ++str;
  457         */
  458         return str-buf;
  459 }
  460 
  461 /**
  462  * snprintf - Format a string and place it in a buffer
  463  * @buf: The buffer to place the result into
  464  * @size: The size of the buffer, including the trailing null space
  465  * @fmt: The format string to use
  466  * @...: Arguments for the format string
  467  */
  468 int snprintf(char * buf, size_t size, const char *fmt, ...)
  469 {
  470         va_list args;
  471         int i;
  472 
  473         va_start(args, fmt);
  474         i=vsnprintf(buf,size,fmt,args);
  475         va_end(args);
  476         return i;
  477 }
  478 
  479 /**
  480  * vsprintf - Format a string and place it in a buffer
  481  * @buf: The buffer to place the result into
  482  * @fmt: The format string to use
  483  * @args: Arguments for the format string
  484  *
  485  * Call this function if you are already dealing with a va_list.
  486  * You probably want sprintf instead.
  487  */
  488 int vsprintf(char *buf, const char *fmt, va_list args)
  489 {
  490         return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
  491 }
  492 
  493 
  494 /**
  495  * sprintf - Format a string and place it in a buffer
  496  * @buf: The buffer to place the result into
  497  * @fmt: The format string to use
  498  * @...: Arguments for the format string
  499  */
  500 int sprintf(char * buf, const char *fmt, ...)
  501 {
  502         va_list args;
  503         int i;
  504 
  505         va_start(args, fmt);
  506         i=vsprintf(buf,fmt,args);
  507         va_end(args);
  508         return i;
  509 }
  510 
  511 /**
  512  * vsscanf - Unformat a buffer into a list of arguments
  513  * @buf:        input buffer
  514  * @fmt:        format of buffer
  515  * @args:       arguments
  516  */
  517 int vsscanf(const char * buf, const char * fmt, va_list args)
  518 {
  519         const char *str = buf;
  520         char *next;
  521         char digit;
  522         int num = 0;
  523         int qualifier;
  524         int base;
  525         int field_width;
  526         int is_sign = 0;
  527 
  528         while(*fmt && *str) {
  529                 /* skip any white space in format */
  530                 /* white space in format matchs any amount of
  531                  * white space, including none, in the input.
  532                  */
  533                 if (isspace(*fmt)) {
  534                         while (isspace(*fmt))
  535                                 ++fmt;
  536                         while (isspace(*str))
  537                                 ++str;
  538                 }
  539 
  540                 /* anything that is not a conversion must match exactly */
  541                 if (*fmt != '%' && *fmt) {
  542                         if (*fmt++ != *str++)
  543                                 break;
  544                         continue;
  545                 }
  546 
  547                 if (!*fmt)
  548                         break;
  549                 ++fmt;
  550                 
  551                 /* skip this conversion.
  552                  * advance both strings to next white space
  553                  */
  554                 if (*fmt == '*') {
  555                         while (!isspace(*fmt) && *fmt)
  556                                 fmt++;
  557                         while (!isspace(*str) && *str)
  558                                 str++;
  559                         continue;
  560                 }
  561 
  562                 /* get field width */
  563                 field_width = -1;
  564                 if (isdigit(*fmt))
  565                         field_width = skip_atoi(&fmt);
  566 
  567                 /* get conversion qualifier */
  568                 qualifier = -1;
  569                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
  570                     *fmt == 'Z' || *fmt == 'z') {
  571                         qualifier = *fmt;
  572                         fmt++;
  573                 }
  574                 base = 10;
  575                 is_sign = 0;
  576 
  577                 if (!*fmt || !*str)
  578                         break;
  579 
  580                 switch(*fmt++) {
  581                 case 'c':
  582                 {
  583                         char *s = (char *) va_arg(args,char*);
  584                         if (field_width == -1)
  585                                 field_width = 1;
  586                         do {
  587                                 *s++ = *str++;
  588                         } while(field_width-- > 0 && *str);
  589                         num++;
  590                 }
  591                 continue;
  592                 case 's':
  593                 {
  594                         char *s = (char *) va_arg(args, char *);
  595                         if(field_width == -1)
  596                                 field_width = INT_MAX;
  597                         /* first, skip leading white space in buffer */
  598                         while (isspace(*str))
  599                                 str++;
  600 
  601                         /* now copy until next white space */
  602                         while (*str && !isspace(*str) && field_width--) {
  603                                 *s++ = *str++;
  604                         }
  605                         *s = '\0';
  606                         num++;
  607                 }
  608                 continue;
  609                 case 'n':
  610                         /* return number of characters read so far */
  611                 {
  612                         int *i = (int *)va_arg(args,int*);
  613                         *i = str - buf;
  614                 }
  615                 continue;
  616                 case 'o':
  617                         base = 8;
  618                         break;
  619                 case 'x':
  620                 case 'X':
  621                         base = 16;
  622                         break;
  623                 case 'i':
  624                         base = 0;
  625                 case 'd':
  626                         is_sign = 1;
  627                 case 'u':
  628                         break;
  629                 case '%':
  630                         /* looking for '%' in str */
  631                         if (*str++ != '%') 
  632                                 return num;
  633                         continue;
  634                 default:
  635                         /* invalid format; stop here */
  636                         return num;
  637                 }
  638 
  639                 /* have some sort of integer conversion.
  640                  * first, skip white space in buffer.
  641                  */
  642                 while (isspace(*str))
  643                         str++;
  644 
  645                 digit = *str;
  646                 if (is_sign && digit == '-')
  647                         digit = *(str + 1);
  648 
  649                 if (!digit
  650                     || (base == 16 && !isxdigit(digit))
  651                     || (base == 10 && !isdigit(digit))
  652                     || (base == 8 && (!isdigit(digit) || digit > '7'))
  653                     || (base == 0 && !isdigit(digit)))
  654                                 break;
  655 
  656                 switch(qualifier) {
  657                 case 'h':
  658                         if (is_sign) {
  659                                 short *s = (short *) va_arg(args,short *);
  660                                 *s = (short) simple_strtol(str,&next,base);
  661                         } else {
  662                                 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
  663                                 *s = (unsigned short) simple_strtoul(str, &next, base);
  664                         }
  665                         break;
  666                 case 'l':
  667                         if (is_sign) {
  668                                 long *l = (long *) va_arg(args,long *);
  669                                 *l = simple_strtol(str,&next,base);
  670                         } else {
  671                                 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
  672                                 *l = simple_strtoul(str,&next,base);
  673                         }
  674                         break;
  675                 case 'L':
  676                         if (is_sign) {
  677                                 long long *l = (long long*) va_arg(args,long long *);
  678                                 *l = simple_strtoll(str,&next,base);
  679                         } else {
  680                                 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
  681                                 *l = simple_strtoull(str,&next,base);
  682                         }
  683                         break;
  684                 case 'Z':
  685                 case 'z':
  686                 {
  687                         size_t *s = (size_t*) va_arg(args,size_t*);
  688                         *s = (size_t) simple_strtoul(str,&next,base);
  689                 }
  690                 break;
  691                 default:
  692                         if (is_sign) {
  693                                 int *i = (int *) va_arg(args, int*);
  694                                 *i = (int) simple_strtol(str,&next,base);
  695                         } else {
  696                                 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
  697                                 *i = (unsigned int) simple_strtoul(str,&next,base);
  698                         }
  699                         break;
  700                 }
  701                 num++;
  702 
  703                 if (!next)
  704                         break;
  705                 str = next;
  706         }
  707         return num;
  708 }
  709 
  710 /**
  711  * sscanf - Unformat a buffer into a list of arguments
  712  * @buf:        input buffer
  713  * @fmt:        formatting of buffer
  714  * @...:        resulting arguments
  715  */
  716 int sscanf(const char * buf, const char * fmt, ...)
  717 {
  718         va_list args;
  719         int i;
  720 
  721         va_start(args,fmt);
  722         i = vsscanf(buf,fmt,args);
  723         va_end(args);
  724         return i;
  725 }

Cache object: 693d5bb37684c7cc98760aa72ba7805f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.