home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / kernel / vsprintf.c < prev   
Encoding:
C/C++ Source or Header  |  1994-06-05  |  5.9 KB  |  294 lines

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