免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8574 | 回复: 0
打印 上一主题 下一主题

vsprintf源代码 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-08 11:26 |只看该作者 |倒序浏览
在查询va_list/va_args时发现的,不敢独享,公诸同好
  1. Goto sanos source index
  2. //
  3. // vsprintf.c
  4. //
  5. // Print formatting routines
  6. //
  7. // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
  8. //
  9. // Redistribution and use in source and binary forms, with or without
  10. // modification, are permitted provided that the following conditions
  11. // are met:
  12. //
  13. // 1. Redistributions of source code must retain the above copyright
  14. //    notice, this list of conditions and the following disclaimer.  
  15. // 2. Redistributions in binary form must reproduce the above copyright
  16. //    notice, this list of conditions and the following disclaimer in the
  17. //    documentation and/or other materials provided with the distribution.  
  18. // 3. Neither the name of the project nor the names of its contributors
  19. //    may be used to endorse or promote products derived from this software
  20. //    without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  23. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  26. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. // SUCH DAMAGE.
  33. //

  34. #include <sys/types.h>
  35. #include <stdarg.h>
  36. #include <string.h>

  37. #ifdef KERNEL
  38. #define NOFLOAT
  39. #endif

  40. #define ZEROPAD 1               // Pad with zero
  41. #define SIGN    2               // Unsigned/signed long
  42. #define PLUS    4               // Show plus
  43. #define SPACE   8               // Space if plus
  44. #define LEFT    16              // Left justified
  45. #define SPECIAL 32              // 0x
  46. #define LARGE   64              // Use 'ABCDEF' instead of 'abcdef'

  47. #define is_digit(c) ((c) >= '0' && (c) <= '9')

  48. static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  49. static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  50. static size_t strnlen(const char *s, size_t count)
  51. {
  52.   const char *sc;
  53.   for (sc = s; *sc != '\0' && count--; ++sc);
  54.   return sc - s;
  55. }

  56. static int skip_atoi(const char **s)
  57. {
  58.   int i = 0;
  59.   while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
  60.   return i;
  61. }

  62. static char *number(char *str, long num, int base, int size, int precision, int type)
  63. {
  64.   char c, sign, tmp[66];
  65.   char *dig = digits;
  66.   int i;

  67.   if (type & LARGE)  dig = upper_digits;
  68.   if (type & LEFT) type &= ~ZEROPAD;
  69.   if (base < 2 || base > 36) return 0;
  70.   
  71.   c = (type & ZEROPAD) ? '0' : ' ';
  72.   sign = 0;
  73.   if (type & SIGN)
  74.   {
  75.     if (num < 0)
  76.     {
  77.       sign = '-';
  78.       num = -num;
  79.       size--;
  80.     }
  81.     else if (type & PLUS)
  82.     {
  83.       sign = '+';
  84.       size--;
  85.     }
  86.     else if (type & SPACE)
  87.     {
  88.       sign = ' ';
  89.       size--;
  90.     }
  91.   }

  92.   if (type & SPECIAL)
  93.   {
  94.     if (base == 16)
  95.       size -= 2;
  96.     else if (base == 8)
  97.       size--;
  98.   }

  99.   i = 0;

  100.   if (num == 0)
  101.     tmp[i++] = '0';
  102.   else
  103.   {
  104.     while (num != 0)
  105.     {
  106.       tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
  107.       num = ((unsigned long) num) / (unsigned) base;
  108.     }
  109.   }

  110.   if (i > precision) precision = i;
  111.   size -= precision;
  112.   if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
  113.   if (sign) *str++ = sign;
  114.   
  115.   if (type & SPECIAL)
  116.   {
  117.     if (base == 8)
  118.       *str++ = '0';
  119.     else if (base == 16)
  120.     {
  121.       *str++ = '0';
  122.       *str++ = digits[33];
  123.     }
  124.   }

  125.   if (!(type & LEFT)) while (size-- > 0) *str++ = c;
  126.   while (i < precision--) *str++ = '0';
  127.   while (i-- > 0) *str++ = tmp[i];
  128.   while (size-- > 0) *str++ = ' ';

  129.   return str;
  130. }

  131. static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
  132. {
  133.   char tmp[24];
  134.   char *dig = digits;
  135.   int i, len;

  136.   if (type & LARGE)  dig = upper_digits;
  137.   len = 0;
  138.   for (i = 0; i < 6; i++)
  139.   {
  140.     if (i != 0) tmp[len++] = ':';
  141.     tmp[len++] = dig[addr[i] >> 4];
  142.     tmp[len++] = dig[addr[i] & 0x0F];
  143.   }

  144.   if (!(type & LEFT)) while (len < size--) *str++ = ' ';
  145.   for (i = 0; i < len; ++i) *str++ = tmp[i];
  146.   while (len < size--) *str++ = ' ';

  147.   return str;
  148. }

  149. static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
  150. {
  151.   char tmp[24];
  152.   int i, n, len;

  153.   len = 0;
  154.   for (i = 0; i < 4; i++)
  155.   {
  156.     if (i != 0) tmp[len++] = '.';
  157.     n = addr[i];
  158.    
  159.     if (n == 0)
  160.       tmp[len++] = digits[0];
  161.     else
  162.     {
  163.       if (n >= 100)
  164.       {
  165.         tmp[len++] = digits[n / 100];
  166.         n = n % 100;
  167.         tmp[len++] = digits[n / 10];
  168.         n = n % 10;
  169.       }
  170.       else if (n >= 10)
  171.       {
  172.         tmp[len++] = digits[n / 10];
  173.         n = n % 10;
  174.       }

  175.       tmp[len++] = digits[n];
  176.     }
  177.   }

  178.   if (!(type & LEFT)) while (len < size--) *str++ = ' ';
  179.   for (i = 0; i < len; ++i) *str++ = tmp[i];
  180.   while (len < size--) *str++ = ' ';

  181.   return str;
  182. }

  183. #ifndef NOFLOAT

  184. char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
  185. char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);

  186. static void cfltcvt(double value, char *buffer, char fmt, int precision)
  187. {
  188.   int decpt, sign, exp, pos;
  189.   char *digits = NULL;
  190.   char cvtbuf[80];
  191.   int capexp = 0;
  192.   int magnitude;

  193.   if (fmt == 'G' || fmt == 'E')
  194.   {
  195.     capexp = 1;
  196.     fmt += 'a' - 'A';
  197.   }

  198.   if (fmt == 'g')
  199.   {
  200.     digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
  201.     magnitude = decpt - 1;
  202.     if (magnitude < -4  ||  magnitude > precision - 1)
  203.     {
  204.       fmt = 'e';
  205.       precision -= 1;
  206.     }
  207.     else
  208.     {
  209.       fmt = 'f';
  210.       precision -= decpt;
  211.     }
  212.   }

  213.   if (fmt == 'e')
  214.   {
  215.     digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);

  216.     if (sign) *buffer++ = '-';
  217.     *buffer++ = *digits;
  218.     if (precision > 0) *buffer++ = '.';
  219.     memcpy(buffer, digits + 1, precision);
  220.     buffer += precision;
  221.     *buffer++ = capexp ? 'E' : 'e';

  222.     if (decpt == 0)
  223.     {
  224.       if (value == 0.0)
  225.         exp = 0;
  226.       else
  227.         exp = -1;
  228.     }
  229.     else
  230.       exp = decpt - 1;

  231.     if (exp < 0)
  232.     {
  233.       *buffer++ = '-';
  234.       exp = -exp;
  235.     }
  236.     else
  237.       *buffer++ = '+';

  238.     buffer[2] = (exp % 10) + '0';
  239.     exp = exp / 10;
  240.     buffer[1] = (exp % 10) + '0';
  241.     exp = exp / 10;
  242.     buffer[0] = (exp % 10) + '0';
  243.     buffer += 3;
  244.   }
  245.   else if (fmt == 'f')
  246.   {
  247.     digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
  248.     if (sign) *buffer++ = '-';
  249.     if (*digits)
  250.     {
  251.       if (decpt <= 0)
  252.       {
  253.         *buffer++ = '0';
  254.         *buffer++ = '.';
  255.         for (pos = 0; pos < -decpt; pos++) *buffer++ = '0';
  256.         while (*digits) *buffer++ = *digits++;
  257.       }
  258.       else
  259.       {
  260.         pos = 0;
  261.         while (*digits)
  262.         {
  263.           if (pos++ == decpt) *buffer++ = '.';
  264.           *buffer++ = *digits++;
  265.         }
  266.       }
  267.     }
  268.     else
  269.     {
  270.       *buffer++ = '0';
  271.       if (precision > 0)
  272.       {
  273.         *buffer++ = '.';
  274.         for (pos = 0; pos < precision; pos++) *buffer++ = '0';
  275.       }
  276.     }
  277.   }

  278.   *buffer = '\0';
  279. }

  280. static void forcdecpt(char *buffer)
  281. {
  282.   while (*buffer)
  283.   {
  284.     if (*buffer == '.') return;
  285.     if (*buffer == 'e' || *buffer == 'E') break;
  286.     buffer++;
  287.   }

  288.   if (*buffer)
  289.   {
  290.     int n = strlen(buffer);
  291.     while (n > 0)
  292.     {
  293.       buffer[n + 1] = buffer[n];
  294.       n--;
  295.     }

  296.     *buffer = '.';
  297.   }
  298.   else
  299.   {
  300.     *buffer++ = '.';
  301.     *buffer = '\0';
  302.   }
  303. }

  304. static void cropzeros(char *buffer)
  305. {
  306.   char *stop;

  307.   while (*buffer && *buffer != '.') buffer++;
  308.   if (*buffer++)
  309.   {
  310.     while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
  311.     stop = buffer--;
  312.     while (*buffer == '0') buffer--;
  313.     if (*buffer == '.') buffer--;
  314.     while (*++buffer = *stop++);
  315.   }
  316. }

  317. static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
  318. {
  319.   char tmp[80];
  320.   char c, sign;
  321.   int n, i;

  322.   // Left align means no zero padding
  323.   if (flags & LEFT) flags &= ~ZEROPAD;

  324.   // Determine padding and sign char
  325.   c = (flags & ZEROPAD) ? '0' : ' ';
  326.   sign = 0;
  327.   if (flags & SIGN)
  328.   {
  329.     if (num < 0.0)
  330.     {
  331.       sign = '-';
  332.       num = -num;
  333.       size--;
  334.     }
  335.     else if (flags & PLUS)
  336.     {
  337.       sign = '+';
  338.       size--;
  339.     }
  340.     else if (flags & SPACE)
  341.     {
  342.       sign = ' ';
  343.       size--;
  344.     }
  345.   }

  346.   // Compute the precision value
  347.   if (precision < 0)
  348.     precision = 6; // Default precision: 6
  349.   else if (precision == 0 && fmt == 'g')
  350.     precision = 1; // ANSI specified

  351.   // Convert floating point number to text
  352.   cfltcvt(num, tmp, fmt, precision);

  353.   // '#' and precision == 0 means force a decimal point
  354.   if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp);

  355.   // 'g' format means crop zero unless '#' given
  356.   if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp);

  357.   n = strlen(tmp);

  358.   // Output number with alignment and padding
  359.   size -= n;
  360.   if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
  361.   if (sign) *str++ = sign;
  362.   if (!(flags & LEFT)) while (size-- > 0) *str++ = c;
  363.   for (i = 0; i < n; i++) *str++ = tmp[i];
  364.   while (size-- > 0) *str++ = ' ';

  365.   return str;
  366. }

  367. #endif

  368. int vsprintf(char *buf, const char *fmt, va_list args)
  369. {
  370.   int len;
  371.   unsigned long num;
  372.   int i, base;
  373.   char *str;
  374.   char *s;

  375.   int flags;            // Flags to number()

  376.   int field_width;      // Width of output field
  377.   int precision;        // Min. # of digits for integers; max number of chars for from string
  378.   int qualifier;        // 'h', 'l', or 'L' for integer fields

  379.   for (str = buf; *fmt; fmt++)
  380.   {
  381.     if (*fmt != '%')
  382.     {
  383.       *str++ = *fmt;
  384.       continue;
  385.     }
  386.                   
  387.     // Process flags
  388.     flags = 0;
  389. repeat:
  390.     fmt++; // This also skips first '%'
  391.     switch (*fmt)
  392.     {
  393.       case '-': flags |= LEFT; goto repeat;
  394.       case '+': flags |= PLUS; goto repeat;
  395.       case ' ': flags |= SPACE; goto repeat;
  396.       case '#': flags |= SPECIAL; goto repeat;
  397.       case '0': flags |= ZEROPAD; goto repeat;
  398.     }
  399.          
  400.     // Get field width
  401.     field_width = -1;
  402.     if (is_digit(*fmt))
  403.       field_width = skip_atoi(&fmt);
  404.     else if (*fmt == '*')
  405.     {
  406.       fmt++;
  407.       field_width = va_arg(args, int);
  408.       if (field_width < 0)
  409.       {
  410.         field_width = -field_width;
  411.         flags |= LEFT;
  412.       }
  413.     }

  414.     // Get the precision
  415.     precision = -1;
  416.     if (*fmt == '.')
  417.     {
  418.       ++fmt;   
  419.       if (is_digit(*fmt))
  420.         precision = skip_atoi(&fmt);
  421.       else if (*fmt == '*')
  422.       {
  423.         ++fmt;
  424.         precision = va_arg(args, int);
  425.       }
  426.       if (precision < 0) precision = 0;
  427.     }

  428.     // Get the conversion qualifier
  429.     qualifier = -1;
  430.     if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
  431.     {
  432.       qualifier = *fmt;
  433.       fmt++;
  434.     }

  435.     // Default base
  436.     base = 10;

  437.     switch (*fmt)
  438.     {
  439.       case 'c':
  440.         if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' ';
  441.         *str++ = (unsigned char) va_arg(args, int);
  442.         while (--field_width > 0) *str++ = ' ';
  443.         continue;

  444.       case 's':
  445.         s = va_arg(args, char *);
  446.         if (!s) s = "<NULL>";
  447.         len = strnlen(s, precision);
  448.         if (!(flags & LEFT)) while (len < field_width--) *str++ = ' ';
  449.         for (i = 0; i < len; ++i) *str++ = *s++;
  450.         while (len < field_width--) *str++ = ' ';
  451.         continue;

  452.       case 'p':
  453.         if (field_width == -1)
  454.         {
  455.           field_width = 2 * sizeof(void *);
  456.           flags |= ZEROPAD;
  457.         }
  458.         str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
  459.         continue;

  460.       case 'n':
  461.         if (qualifier == 'l')
  462.         {
  463.           long *ip = va_arg(args, long *);
  464.           *ip = (str - buf);
  465.         }
  466.         else
  467.         {
  468.           int *ip = va_arg(args, int *);
  469.           *ip = (str - buf);
  470.         }
  471.         continue;

  472.       case 'A':
  473.         flags |= LARGE;

  474.       case 'a':
  475.         if (qualifier == 'l')
  476.           str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
  477.         else
  478.           str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
  479.         continue;

  480.       // Integer number formats - set up the flags and "break"
  481.       case 'o':
  482.         base = 8;
  483.         break;

  484.       case 'X':
  485.         flags |= LARGE;

  486.       case 'x':
  487.         base = 16;
  488.         break;

  489.       case 'd':
  490.       case 'i':
  491.         flags |= SIGN;

  492.       case 'u':
  493.         break;

  494. #ifndef NOFLOAT

  495.       case 'E':
  496.       case 'G':
  497.       case 'e':
  498.       case 'f':
  499.       case 'g':
  500.         str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
  501.         continue;

  502. #endif

  503.       default:
  504.         if (*fmt != '%') *str++ = '%';
  505.         if (*fmt)
  506.           *str++ = *fmt;
  507.         else
  508.           --fmt;
  509.         continue;
  510.     }

  511.     if (qualifier == 'l')
  512.       num = va_arg(args, unsigned long);
  513.     else if (qualifier == 'h')
  514.     {
  515.       if (flags & SIGN)
  516.         num = va_arg(args, short);
  517.       else
  518.         num = va_arg(args, unsigned short);
  519.     }
  520.     else if (flags & SIGN)
  521.       num = va_arg(args, int);
  522.     else
  523.       num = va_arg(args, unsigned int);

  524.     str = number(str, num, base, field_width, precision, flags);
  525.   }

  526.   *str = '\0';
  527.   return str - buf;
  528. }

  529. int sprintf(char *buf, const char *fmt, ...)
  530. {
  531.   va_list args;
  532.   int n;

  533.   va_start(args, fmt);
  534.   n = vsprintf(buf, fmt, args);
  535.   va_end(args);

  536.   return n;
  537. }


复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP