home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / lib / vsprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-02  |  5.8 KB  |  307 lines

  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. #include <stdarg.h>
  13. #include <linux/types.h>
  14. #include <linux/string.h>
  15. #include <linux/ctype.h>
  16.  
  17. unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
  18. {
  19.     unsigned long result = 0,value;
  20.  
  21.     if (!base) {
  22.         base = 10;
  23.         if (*cp == '0') {
  24.             base = 8;
  25.             cp++;
  26.             if ((*cp == 'x') && isxdigit(cp[1])) {
  27.                 cp++;
  28.                 base = 16;
  29.             }
  30.         }
  31.     }
  32.     while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
  33.         ? toupper(*cp) : *cp)-'A'+10) < base) {
  34.         result = result*base + value;
  35.         cp++;
  36.     }
  37.     if (endp)
  38.         *endp = (char *)cp;
  39.     return result;
  40. }
  41.  
  42. /* we use this so that we can do without the ctype library */
  43. #define is_digit(c)    ((c) >= '0' && (c) <= '9')
  44.  
  45. static int skip_atoi(const char **s)
  46. {
  47.     int i=0;
  48.  
  49.     while (is_digit(**s))
  50.         i = i*10 + *((*s)++) - '0';
  51.     return i;
  52. }
  53.  
  54. #define ZEROPAD    1        /* pad with zero */
  55. #define SIGN    2        /* unsigned/signed long */
  56. #define PLUS    4        /* show plus */
  57. #define SPACE    8        /* space if plus */
  58. #define LEFT    16        /* left justified */
  59. #define SPECIAL    32        /* 0x */
  60. #define LARGE    64        /* use 'ABCDEF' instead of 'abcdef' */
  61.  
  62. #define do_div(n,base) ({ \
  63. int __res; \
  64. __res = ((unsigned long) n) % (unsigned) base; \
  65. n = ((unsigned long) n) / (unsigned) base; \
  66. __res; })
  67.  
  68. static char * number(char * str, long num, int base, int size, int precision
  69.     ,int type)
  70. {
  71.     char c,sign,tmp[66];
  72.     const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
  73.     int i;
  74.  
  75.     if (type & LARGE)
  76.         digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  77.     if (type & LEFT)
  78.         type &= ~ZEROPAD;
  79.     if (base < 2 || base > 36)
  80.         return 0;
  81.     c = (type & ZEROPAD) ? '0' : ' ';
  82.     sign = 0;
  83.     if (type & SIGN) {
  84.         if (num < 0) {
  85.             sign = '-';
  86.             num = -num;
  87.             size--;
  88.         } else if (type & PLUS) {
  89.             sign = '+';
  90.             size--;
  91.         } else if (type & SPACE) {
  92.             sign = ' ';
  93.             size--;
  94.         }
  95.     }
  96.     if (type & SPECIAL) {
  97.         if (base == 16)
  98.             size -= 2;
  99.         else if (base == 8)
  100.             size--;
  101.     }
  102.     i = 0;
  103.     if (num == 0)
  104.         tmp[i++]='0';
  105.     else while (num != 0)
  106.         tmp[i++] = digits[do_div(num,base)];
  107.     if (i > precision)
  108.         precision = i;
  109.     size -= precision;
  110.     if (!(type&(ZEROPAD+LEFT)))
  111.         while(size-->0)
  112.             *str++ = ' ';
  113.     if (sign)
  114.         *str++ = sign;
  115.     if (type & SPECIAL)
  116.         if (base==8)
  117.             *str++ = '0';
  118.         else if (base==16) {
  119.             *str++ = '0';
  120.             *str++ = digits[33];
  121.         }
  122.     if (!(type & LEFT))
  123.         while (size-- > 0)
  124.             *str++ = c;
  125.     while (i < precision--)
  126.         *str++ = '0';
  127.     while (i-- > 0)
  128.         *str++ = tmp[i];
  129.     while (size-- > 0)
  130.         *str++ = ' ';
  131.     return str;
  132. }
  133.  
  134. int vsprintf(char *buf, const char *fmt, va_list args)
  135. {
  136.     int len;
  137.     unsigned long num;
  138.     int i, base;
  139.     char * str;
  140.     char *s;
  141.  
  142.     int flags;        /* flags to number() */
  143.  
  144.     int field_width;    /* width of output field */
  145.     int precision;        /* min. # of digits for integers; max
  146.                    number of chars for from string */
  147.     int qualifier;        /* 'h', 'l', or 'L' for integer fields */
  148.  
  149.     for (str=buf ; *fmt ; ++fmt) {
  150.         if (*fmt != '%') {
  151.             *str++ = *fmt;
  152.             continue;
  153.         }
  154.             
  155.         /* process flags */
  156.         flags = 0;
  157.         repeat:
  158.             ++fmt;        /* this also skips first '%' */
  159.             switch (*fmt) {
  160.                 case '-': flags |= LEFT; goto repeat;
  161.                 case '+': flags |= PLUS; goto repeat;
  162.                 case ' ': flags |= SPACE; goto repeat;
  163.                 case '#': flags |= SPECIAL; goto repeat;
  164.                 case '0': flags |= ZEROPAD; goto repeat;
  165.                 }
  166.         
  167.         /* get field width */
  168.         field_width = -1;
  169.         if (is_digit(*fmt))
  170.             field_width = skip_atoi(&fmt);
  171.         else if (*fmt == '*') {
  172.             ++fmt;
  173.             /* it's the next argument */
  174.             field_width = va_arg(args, int);
  175.             if (field_width < 0) {
  176.                 field_width = -field_width;
  177.                 flags |= LEFT;
  178.             }
  179.         }
  180.  
  181.         /* get the precision */
  182.         precision = -1;
  183.         if (*fmt == '.') {
  184.             ++fmt;    
  185.             if (is_digit(*fmt))
  186.                 precision = skip_atoi(&fmt);
  187.             else if (*fmt == '*') {
  188.                 ++fmt;
  189.                 /* it's the next argument */
  190.                 precision = va_arg(args, int);
  191.             }
  192.             if (precision < 0)
  193.                 precision = 0;
  194.         }
  195.  
  196.         /* get the conversion qualifier */
  197.         qualifier = -1;
  198.         if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
  199.             qualifier = *fmt;
  200.             ++fmt;
  201.         }
  202.  
  203.         /* default base */
  204.         base = 10;
  205.  
  206.         switch (*fmt) {
  207.         case 'c':
  208.             if (!(flags & LEFT))
  209.                 while (--field_width > 0)
  210.                     *str++ = ' ';
  211.             *str++ = (unsigned char) va_arg(args, int);
  212.             while (--field_width > 0)
  213.                 *str++ = ' ';
  214.             continue;
  215.  
  216.         case 's':
  217.             s = va_arg(args, char *);
  218.             if (!s)
  219.                 s = "<NULL>";
  220.  
  221.             len = strnlen(s, precision);
  222.  
  223.             if (!(flags & LEFT))
  224.                 while (len < field_width--)
  225.                     *str++ = ' ';
  226.             for (i = 0; i < len; ++i)
  227.                 *str++ = *s++;
  228.             while (len < field_width--)
  229.                 *str++ = ' ';
  230.             continue;
  231.  
  232.         case 'p':
  233.             if (field_width == -1) {
  234.                 field_width = 2*sizeof(void *);
  235.                 flags |= ZEROPAD;
  236.             }
  237.             str = number(str,
  238.                 (unsigned long) va_arg(args, void *), 16,
  239.                 field_width, precision, flags);
  240.             continue;
  241.  
  242.  
  243.         case 'n':
  244.             if (qualifier == 'l') {
  245.                 long * ip = va_arg(args, long *);
  246.                 *ip = (str - buf);
  247.             } else {
  248.                 int * ip = va_arg(args, int *);
  249.                 *ip = (str - buf);
  250.             }
  251.             continue;
  252.  
  253.         /* integer number formats - set up the flags and "break" */
  254.         case 'o':
  255.             base = 8;
  256.             break;
  257.  
  258.         case 'X':
  259.             flags |= LARGE;
  260.         case 'x':
  261.             base = 16;
  262.             break;
  263.  
  264.         case 'd':
  265.         case 'i':
  266.             flags |= SIGN;
  267.         case 'u':
  268.             break;
  269.  
  270.         default:
  271.             if (*fmt != '%')
  272.                 *str++ = '%';
  273.             if (*fmt)
  274.                 *str++ = *fmt;
  275.             else
  276.                 --fmt;
  277.             continue;
  278.         }
  279.         if (qualifier == 'l')
  280.             num = va_arg(args, unsigned long);
  281.         else if (qualifier == 'h')
  282.             if (flags & SIGN)
  283.                 num = va_arg(args, short);
  284.             else
  285.                 num = va_arg(args, unsigned short);
  286.         else if (flags & SIGN)
  287.             num = va_arg(args, int);
  288.         else
  289.             num = va_arg(args, unsigned int);
  290.         str = number(str, num, base, field_width, precision, flags);
  291.     }
  292.     *str = '\0';
  293.     return str-buf;
  294. }
  295.  
  296. int sprintf(char * buf, const char *fmt, ...)
  297. {
  298.     va_list args;
  299.     int i;
  300.  
  301.     va_start(args, fmt);
  302.     i=vsprintf(buf,fmt,args);
  303.     va_end(args);
  304.     return i;
  305. }
  306.  
  307.