Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. FUNCTION
  3. <<ecvtbuf>>, <<fcvtbuf>>---double or float to string
  4.  
  5. INDEX
  6.         ecvtbuf
  7. INDEX
  8.         fcvtbuf
  9.  
  10. ANSI_SYNOPSIS
  11.         #include <stdio.h>
  12.  
  13.         char *ecvtbuf(double <[val]>, int <[chars]>, int *<[decpt]>,
  14.                        int *<[sgn]>, char *<[buf]>);
  15.  
  16.         char *fcvtbuf(double <[val]>, int <[decimals]>, int *<[decpt]>,
  17.                        int *<[sgn]>, char *<[buf]>);
  18.  
  19. TRAD_SYNOPSIS
  20.         #include <stdio.h>
  21.  
  22.         char *ecvtbuf(<[val]>, <[chars]>, <[decpt]>, <[sgn]>, <[buf]>);
  23.         double <[val]>;
  24.         int <[chars]>;
  25.         int *<[decpt]>;
  26.         int *<[sgn]>;
  27.         char *<[buf]>;
  28.  
  29.         char *fcvtbuf(<[val]>, <[decimals]>, <[decpt]>, <[sgn]>, <[buf]>);
  30.         double <[val]>;
  31.         int <[decimals]>;
  32.         int *<[decpt]>;
  33.         int *<[sgn]>;
  34.         char *<[buf]>;
  35.  
  36. DESCRIPTION
  37.         <<ecvtbuf>> and <<fcvtbuf>> produce (null-terminated) strings
  38.         of digits representating the <<double>> number <[val]>.
  39.  
  40.         The only difference between <<ecvtbuf>> and <<fcvtbuf>> is the
  41.         interpretation of the second argument (<[chars]> or
  42.         <[decimals]>). For <<ecvtbuf>>, the second argument <[chars]>
  43.         specifies the total number of characters to write (which is
  44.         also the number of significant digits in the formatted string,
  45.         since these two functions write only digits). For <<fcvtbuf>>,
  46.         the second argument <[decimals]> specifies the number of
  47.         characters to write after the decimal point; all digits for
  48.         the integer part of <[val]> are always included.
  49.  
  50.         Since <<ecvtbuf>> and <<fcvtbuf>> write only digits in the
  51.         output string, they record the location of the decimal point
  52.         in <<*<[decpt]>>>, and the sign of the number in <<*<[sgn]>>>.
  53.         After formatting a number, <<*<[decpt]>>> contains the number
  54.         of digits to the left of the decimal point.  <<*<[sgn]>>>
  55.         contains <<0>> if the number is positive, and <<1>> if it is
  56.         negative.  For both functions, you supply a pointer <[buf]> to
  57.         an area of memory to hold the converted string.
  58.  
  59. RETURNS
  60.         Both functions return a pointer to <[buf]>, the string
  61.         containing a character representation of <[val]>.
  62.  
  63. PORTABILITY
  64.         Neither function is ANSI C.
  65.  
  66. Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
  67. <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
  68. */
  69.  
  70. #include <_ansi.h>
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <reent.h>
  74. #include "mprec.h"
  75. #include "local.h"
  76.  
  77. static void
  78. _DEFUN (print_f, (ptr, buf, invalue, ndigit, type, dot, mode),
  79.         struct _reent *ptr _AND
  80.         char *buf _AND
  81.         double invalue _AND
  82.         int ndigit _AND
  83.         char type _AND
  84.         int dot _AND
  85.         int mode)
  86. {
  87.   int decpt;
  88.   int sign;
  89.   char *p, *start, *end;
  90.  
  91.   start = p = _dtoa_r (ptr, invalue, mode, ndigit, &decpt, &sign, &end);
  92.  
  93.   if (decpt == 9999)
  94.     {
  95.       strcpy (buf, p);
  96.       return;
  97.     }
  98.   while (*p && decpt > 0)
  99.     {
  100.       *buf++ = *p++;
  101.       decpt--;
  102.     }
  103.   /* Even if not in buffer */
  104.   while (decpt > 0)
  105.     {
  106.       *buf++ = '0';
  107.       decpt--;
  108.     }
  109.  
  110.   if (dot || *p)
  111.     {
  112.       if (p == start)
  113.         *buf++ = '0';
  114.       *buf++ = '.';
  115.       while (decpt < 0 && ndigit > 0)
  116.         {
  117.           *buf++ = '0';
  118.           decpt++;
  119.           ndigit--;
  120.         }
  121.  
  122.       /* Print rest of stuff */
  123.       while (*p && ndigit > 0)
  124.         {
  125.           *buf++ = *p++;
  126.           ndigit--;
  127.         }
  128.       /* And trailing zeros */
  129.       while (ndigit > 0)
  130.         {
  131.           *buf++ = '0';
  132.           ndigit--;
  133.         }
  134.     }
  135.   *buf++ = 0;
  136. }
  137.  
  138. /* Print number in e format with width chars after.
  139.  
  140.    TYPE is one of 'e' or 'E'.  It may also be one of 'g' or 'G' indicating
  141.    that _gcvt is calling us and we should remove trailing zeroes.
  142.  
  143.    WIDTH is the number of digits of precision after the decimal point.  */
  144.  
  145. static void
  146. _DEFUN (print_e, (ptr, buf, invalue, width, type, dot),
  147.         struct _reent *ptr _AND
  148.         char *buf _AND
  149.         double invalue _AND
  150.         int width _AND
  151.         char type _AND
  152.         int dot)
  153. {
  154.   int sign;
  155.   char *end;
  156.   char *p;
  157.   int decpt;
  158.   int top;
  159.   int ndigit = width;
  160.  
  161.   p = _dtoa_r (ptr, invalue, 2, width + 1, &decpt, &sign, &end);
  162.  
  163.   if (decpt == 9999)
  164.     {
  165.       strcpy (buf, p);
  166.       return;
  167.     }
  168.  
  169.   *buf++ = *p++;
  170.   if (dot || ndigit != 0)
  171.     *buf++ = '.';
  172.  
  173.   while (*p && ndigit > 0)
  174.     {
  175.       *buf++ = *p++;
  176.       ndigit--;
  177.     }
  178.  
  179.   /* Add trailing zeroes to fill out to ndigits unless this is 'g' format.
  180.      Also, convert g/G to e/E.  */
  181.  
  182.   if (type == 'g')
  183.     type = 'e';
  184.   else if (type == 'G')
  185.     type = 'E';
  186.   else
  187.     {
  188.       while (ndigit > 0)
  189.         {
  190.           *buf++ = '0';
  191.           ndigit--;
  192.         }
  193.     }
  194.  
  195.   /* Add the exponent.  */
  196.  
  197.   *buf++ = type;
  198.   decpt--;
  199.   if (decpt < 0)
  200.     {
  201.       *buf++ = '-';
  202.       decpt = -decpt;
  203.     }
  204.   else
  205.     {
  206.       *buf++ = '+';
  207.     }
  208.   if (decpt > 99)
  209.     {
  210.       int top = decpt / 100;
  211.       *buf++ = top + '0';
  212.       decpt -= top * 100;
  213.     }
  214.   top = decpt / 10;
  215.   *buf++ = top + '0';
  216.   decpt -= top * 10;
  217.   *buf++ = decpt + '0';
  218.  
  219.   *buf++ = 0;
  220. }
  221.  
  222. #ifndef _REENT_ONLY
  223.  
  224. /* Undocumented behaviour: when given NULL as a buffer, return a
  225.    pointer to static space in the rent structure.  This is only to
  226.    support ecvt and fcvt, which aren't ANSI anyway.  */
  227.  
  228. char *
  229. _DEFUN (fcvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf),
  230.         double invalue _AND
  231.         int ndigit _AND
  232.         int *decpt _AND
  233.         int *sign _AND
  234.         char *fcvt_buf)
  235. {
  236.   struct _reent *reent = _REENT;
  237.   char *save;
  238.   char *p;
  239.   char *end;
  240.   int done = 0;
  241.  
  242.   if (fcvt_buf == NULL)
  243.     {
  244.       if (reent->_cvtlen <= ndigit + 35)
  245.         {
  246.           if ((fcvt_buf = (char *) _realloc_r (reent, reent->_cvtbuf,
  247.                                                ndigit + 36)) == NULL)
  248.             return NULL;
  249.           reent->_cvtlen = ndigit + 36;
  250.           reent->_cvtbuf = fcvt_buf;
  251.         }
  252.  
  253.       fcvt_buf = reent->_cvtbuf ;
  254.     }
  255.  
  256.   save = fcvt_buf;
  257.  
  258.   if (invalue < 1.0 && invalue > -1.0)
  259.     {
  260.       p = _dtoa_r (reent, invalue, 2, ndigit, decpt, sign, &end);
  261.     }
  262.   else
  263.     {
  264.       p = _dtoa_r (reent, invalue, 3, ndigit, decpt, sign, &end);
  265.     }
  266.  
  267.   /* Now copy */
  268.  
  269.   done = -*decpt;
  270.   while (p < end)
  271.     {
  272.       *fcvt_buf++ = *p++;
  273.       done++;
  274.     }
  275.   /* And unsuppress the trailing zeroes */
  276.   while (done < ndigit)
  277.     {
  278.       *fcvt_buf++ = '0';
  279.       done++;
  280.     }
  281.   *fcvt_buf++ = 0;
  282.   return save;
  283. }
  284.  
  285. char *
  286. _DEFUN (ecvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf),
  287.         double invalue _AND
  288.         int ndigit _AND
  289.         int *decpt _AND
  290.         int *sign _AND
  291.         char *fcvt_buf)
  292. {
  293.   struct _reent *reent = _REENT;
  294.   char *save;
  295.   char *p;
  296.   char *end;
  297.   int done = 0;
  298.  
  299.   if (fcvt_buf == NULL)
  300.     {
  301.       if (reent->_cvtlen <= ndigit)
  302.         {
  303.           if ((fcvt_buf = (char *) _realloc_r (reent, reent->_cvtbuf,
  304.                                                ndigit + 1)) == NULL)
  305.             return NULL;
  306.           reent->_cvtlen = ndigit + 1;
  307.           reent->_cvtbuf = fcvt_buf;
  308.         }
  309.  
  310.       fcvt_buf = reent->_cvtbuf ;
  311.     }
  312.  
  313.   save = fcvt_buf;
  314.  
  315.   p = _dtoa_r (reent, invalue, 2, ndigit, decpt, sign, &end);
  316.  
  317.   /* Now copy */
  318.  
  319.   while (p < end)
  320.     {
  321.       *fcvt_buf++ = *p++;
  322.       done++;
  323.     }
  324.   /* And unsuppress the trailing zeroes */
  325.   while (done < ndigit)
  326.     {
  327.       *fcvt_buf++ = '0';
  328.       done++;
  329.     }
  330.   *fcvt_buf++ = 0;
  331.   return save;
  332. }
  333.  
  334. #endif
  335.  
  336. char *
  337. _DEFUN (_gcvt, (ptr, invalue, ndigit, buf, type, dot),
  338.         struct _reent *ptr _AND
  339.         double invalue _AND
  340.         int ndigit _AND
  341.         char *buf _AND
  342.         char type _AND
  343.         int dot)
  344. {
  345.   char *save = buf;
  346.  
  347.   if (invalue < 0)
  348.     {
  349.       invalue = -invalue;
  350.     }
  351.  
  352.   if (invalue == 0)
  353.     {
  354.       *buf++ = '0';
  355.       *buf = '\0';
  356.     }
  357.   else
  358.     /* Which one to print ?
  359.        ANSI says that anything with more that 4 zeros after the . or more
  360.        than precision digits before is printed in e with the qualification
  361.        that trailing zeroes are removed from the fraction portion.  */
  362.  
  363.   if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit))
  364.     {
  365.       /* We subtract 1 from ndigit because in the 'e' format the precision is
  366.          the number of digits after the . but in 'g' format it is the number
  367.          of significant digits.
  368.  
  369.          We defer changing type to e/E so that print_e() can know it's us
  370.          calling and thus should remove trailing zeroes.  */
  371.  
  372.       print_e (ptr, buf, invalue, ndigit - 1, type, dot);
  373.     }
  374.   else
  375.     {
  376.       int decpt;
  377.       int sign;
  378.       char *end;
  379.       char *p;
  380.  
  381.       if (invalue < 1.0)
  382.         {
  383.           /* what we want is ndigits after the point */
  384.           p = _dtoa_r (ptr, invalue, 3, ndigit, &decpt, &sign, &end);
  385.         }
  386.       else
  387.         {
  388.           p = _dtoa_r (ptr, invalue, 2, ndigit, &decpt, &sign, &end);
  389.         }
  390.  
  391.       if (decpt == 9999)
  392.         {
  393.           strcpy (buf, p);
  394.           return save;
  395.         }
  396.       while (*p && decpt > 0)
  397.         {
  398.           *buf++ = *p++;
  399.           decpt--;
  400.           ndigit--;
  401.         }
  402.       /* Even if not in buffer */
  403.       while (decpt > 0 && ndigit > 0)
  404.         {
  405.           *buf++ = '0';
  406.           decpt--;
  407.           ndigit--;
  408.         }
  409.  
  410.       if (dot || *p)
  411.         {
  412.           if (buf == save)
  413.             *buf++ = '0';
  414.           *buf++ = '.';
  415.           while (decpt < 0 && ndigit > 0)
  416.             {
  417.               *buf++ = '0';
  418.               decpt++;
  419.               ndigit--;
  420.             }
  421.  
  422.           /* Print rest of stuff */
  423.           while (*p && ndigit > 0)
  424.             {
  425.               *buf++ = *p++;
  426.               ndigit--;
  427.             }
  428.           /* And trailing zeros */
  429.           if (dot)
  430.             {
  431.               while (ndigit > 0)
  432.                 {
  433.                   *buf++ = '0';
  434.                   ndigit--;
  435.                 }
  436.             }
  437.         }
  438.       *buf++ = 0;
  439.     }
  440.  
  441.   return save;
  442. }
  443.  
  444. char *
  445. _DEFUN (_dcvt, (ptr, buffer, invalue, precision, width, type, dot),
  446.         struct _reent *ptr _AND
  447.         char *buffer _AND
  448.         double invalue _AND
  449.         int precision _AND
  450.         int width _AND
  451.         char type _AND
  452.         int dot)
  453. {
  454.   switch (type)
  455.     {
  456.     case 'f':
  457.     case 'F':
  458.       print_f (ptr, buffer, invalue, precision, type, precision == 0 ? dot : 1, 3);
  459.       break;
  460.     case 'g':
  461.     case 'G':
  462.       if (precision == 0)
  463.         precision = 1;
  464.       _gcvt (ptr, invalue, precision, buffer, type, dot);
  465.       break;
  466.     case 'e':
  467.     case 'E':
  468.       print_e (ptr, buffer, invalue, precision, type, dot);
  469.     }
  470.   return buffer;
  471. }
  472.