Subversion Repositories Kolibri OS

Rev

Rev 6412 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.         function for format output to the string
  3.  
  4. Siemargl update formats as http://www.cplusplus.com/reference/cstdio/printf/, no wchar though
  5. http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html  is used too
  6. %g explain https://support.microsoft.com/en-us/kb/43392
  7.  
  8. todo:
  9. -%e
  10. -simplify justifying
  11. -fix %o, %x
  12. -fix precision in %g
  13. -%a
  14. -NAN, INF
  15. -%n nothing printed
  16. -%17.18f digits maximum format
  17. %C as w_char L'x'
  18. */
  19.  
  20.  
  21. //#include <kolibrisys.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <math.h>
  26. #include <stdarg.h>
  27.  
  28. enum flags_t
  29. {
  30.         flag_unsigned   = 0x02,
  31.         flag_register   = 0x04,
  32.         flag_plus       = 0x08,
  33.         flag_left_just  = 0x10,
  34.         flag_lead_zeros = 0x20,
  35.         flag_space_plus = 0x40,
  36.         flag_hash_sign  = 0x80,
  37.         flag_point      = 0x100
  38. };
  39.  
  40. int formatted_double_to_string_scientific(long double number, int format1, int format2, char *s, int flags)
  41. {
  42.     strcpy(s, "%e not implemented yet, sorry");
  43.     return strlen(s);
  44. }
  45.  
  46. int formatted_double_to_string(long double number, int format1, int format2, char *s, int flags)
  47. {
  48.         long double     nafter, beforpointdigit;
  49.         long long       intdigit, mul;
  50.         int         div;
  51.         int     i;
  52.         char*   size;
  53.         int     fmt1;
  54.         int     fmt2;
  55.         char    buf[100], *pbuf = buf;
  56.         char    buf_low[50], *pbuf_lo = buf_low;
  57.  
  58.         if((flags & flag_point) == 0) format2 = 6;  // default prec if no point spec
  59.  
  60.         size = s;
  61.         if (number < 0) {*s++ = '-'; number = -number; }
  62.         else
  63.         {
  64.             if (flags & flag_plus) *s++ = '+';  else
  65.             if (flags & flag_space_plus) *s++ = ' ';
  66.         }
  67.  
  68.         fmt1 = 1;
  69.         fmt2 = format2;
  70.         if (fmt2 > 18) fmt2 = 18; //maximum size of long long type
  71.  
  72.         beforpointdigit = floor(number + 0.00000000000001);
  73.         nafter = number - beforpointdigit;
  74.  
  75.         //print part of number before point
  76.         mul = 1;
  77.         for(i = 0; i < sizeof buf - 1; i++)
  78.         {
  79.             mul *= 10;
  80.             if ((beforpointdigit/mul) < 1.0) { fmt1 = i + 1; break; }
  81.         }
  82.         if (i == sizeof buf - 1 || fmt1 > 17)
  83.         {
  84.             strcpy(s, "[too big number for %f, %a]");
  85.             return strlen(s);
  86.         }
  87.  
  88.         mul /= 10;
  89.         while(mul > 1)
  90.         {
  91.             div = beforpointdigit / mul;
  92.             *pbuf++ = (char)div + '0';
  93.             beforpointdigit = beforpointdigit - div * mul;
  94.             mul /= 10;
  95.         }
  96.         *pbuf++=(char)beforpointdigit + '0';
  97.  
  98.         //print part of number after point
  99.         mul = 1;
  100.         for(i = 0; i < fmt2; i++)
  101.         {
  102.             nafter = nafter*10;
  103.             mul *= 10;
  104.         }
  105.  
  106.         intdigit = roundl(nafter);
  107.  
  108.         mul /= 10;
  109.         for(i = 0; i < fmt2 - 1; i++)
  110.         {
  111.                 div = intdigit / mul;
  112.                 *pbuf_lo++=(char)div + '0';
  113.                 intdigit = intdigit - div * mul;
  114.                 mul /= 10;
  115.                 if (mul == 1) break;
  116.         }
  117.         *pbuf_lo++ = (char)intdigit + '0';
  118.  
  119.  
  120.         memcpy(s, buf, pbuf - buf);  s += pbuf - buf;
  121.         if (roundl(nafter) != 0 || fmt2 != 0)
  122.         {
  123.             *s++ = '.';
  124.             memcpy(s, buf_low, pbuf_lo - buf_low);  s += pbuf_lo - buf_low;
  125.         } else if (flags & flag_hash_sign)
  126.             *s++ = '.';
  127.  
  128.         // right justifiyng and forward zeros
  129.         div = (s - size);
  130.         if ((flags & flag_left_just) == 0 && div < format1)
  131.         {
  132.             pbuf = size;
  133.             if ((flags & flag_lead_zeros) != 0)
  134.                 if (*pbuf == '+' || *pbuf == '-' || *pbuf == ' ') { pbuf++; div--; } // sign already at place
  135.             for (i = 0; i < div; i++)
  136.                 size[format1 - i - 1] = pbuf[div - 1 - i];
  137.             for (i = 0; i < format1 - div - (pbuf - size); i++)
  138.                 if (flags & flag_lead_zeros)
  139.                     pbuf[i] = '0';
  140.                 else
  141.                     pbuf[i] = ' ';
  142.  
  143.             return format1;
  144.         }
  145.  
  146.         return s - size;
  147. }
  148.  
  149. int formatted_long_to_string(long long number, int format1, int prec, char *s, int flags)
  150. {
  151.         int         i;
  152.         int         fmt;
  153.         char*       size = s;
  154.         long long   digit;
  155.         long long   mul;
  156.         int         div;
  157.         char        buf[100], *pbuf = buf;
  158.  
  159.         if (number == -9223372036854775807LL - 1)  // overflow all our math, cant minus this
  160.         {
  161.             strcpy(buf, "9223372036854775808");
  162.             pbuf += 19;
  163.             *s++ = '-';
  164.             goto verybig;
  165.         }
  166.  
  167.         if (flags & flag_point) flags &= ~flag_lead_zeros;  // conflicting flags
  168.  
  169.         if (number < 0) {*s++ = '-'; number = -number; }
  170.         else
  171.         {
  172.             if (flags & flag_plus) *s++ = '+';  else
  173.             if (flags & flag_space_plus) *s++ = ' ';
  174.         }
  175.  
  176.         digit = number;
  177.  
  178.         mul = (digit < 0) ? -1 : 1;
  179.  
  180.         for(i = 0; i < sizeof buf - 2; i++)
  181.         {
  182.             if (digit / mul < 10) { fmt = i + 1; break; }
  183.             mul *= 10;
  184.         }
  185.  
  186.         // add leading zeros
  187.         for(i = 0; i < prec - fmt; i++) *pbuf++ = '0';
  188.  
  189.         for(i = 0; i < fmt - 1; i++)
  190.         {
  191.             div = digit / mul;
  192.             *pbuf++ = (char)div + '0';
  193.             digit = digit - div * mul;
  194.             mul /= 10;
  195.             if (mul == 1 || mul == -1) break;
  196.         }
  197.         *pbuf++ = (char)digit + '0';
  198.  
  199. verybig:
  200.         memcpy(s, buf, pbuf - buf);  s += pbuf - buf;
  201.  
  202.         // right justifiyng and forward zeros
  203.         div = (s - size);
  204.         if ((flags & flag_left_just) == 0 && div < format1)
  205.         {
  206.             pbuf = size;
  207.             if ((flags & flag_lead_zeros) != 0)
  208.                 if (*pbuf == '+' || *pbuf == '-' || *pbuf == ' ') { pbuf++; div--; } // sign already at place
  209.             for (i = 0; i < div; i++)
  210.                 size[format1 - i - 1] = pbuf[div - 1 - i];
  211.             for (i = 0; i < format1 - div - (pbuf - size); i++)
  212.                 if (flags & flag_lead_zeros)
  213.                     pbuf[i] = '0';
  214.                 else
  215.                     pbuf[i] = ' ';
  216.  
  217.             return format1;
  218.         }
  219.  
  220.         return s - size;
  221. }
  222.  
  223. int formatted_hex_to_string(long long number, int fmt1, char *s, int flags)
  224. {
  225.         long    n;
  226.         int             i,pos;
  227. //        int             fmt;
  228.         long    size;
  229.         int             difference_pos;
  230.         char            xdigs_lower[16]="0123456789abcdef";
  231.         char            xdigs_upper[16]="0123456789ABCDEF";
  232.         char            buf[200];
  233.  
  234.         n=(long)number;
  235.         size=(int)s;
  236.         if (n<0) {*s='-';s++;n=-n;}
  237.  
  238.         if (n==0) {*s='0';s++;goto end;}
  239.         for(i=0;i<200;i++) {buf[i]=0;}
  240.  
  241.         i=0;
  242.         if (flag_register==0)
  243.         {
  244.                 while (n>0)
  245.                 {
  246.                         buf[i]=xdigs_lower[n & 15];
  247.                         n=n>>4;
  248.                         i++;
  249.                 }
  250.         }
  251.         else
  252.         {
  253.                 while (n>0)
  254.                 {
  255.                         buf[i]=xdigs_upper[n & 15];
  256.                         n=n>>4;
  257.                         i++;
  258.                 }
  259.         }
  260.  
  261.         pos=i;
  262.         difference_pos=i;
  263.  
  264.         for(i=pos-1;i>=0;i--)
  265.         {
  266.                 *s=buf[i];
  267.                 s++;
  268.         }
  269.  
  270.         if (fmt1-difference_pos>0)
  271.         {
  272.                 for(i=difference_pos+1;i<=fmt1;i++)
  273.                 {
  274.                         *s=' ';
  275.                         s++;
  276.                 }
  277.         }
  278.         end:size=(int)s-size;
  279.         return(size);
  280. }
  281.  
  282. int formatted_octa_to_string(long long number, int fmt1, char *s, int flags)
  283. {
  284.         long    n;
  285.         int             i,pos;
  286. //        int             fmt;
  287.         long    size;
  288.         int             difference_pos;
  289.         char            xdigs_lower[16]="012345678";
  290.         char            buf[200];
  291.  
  292.         n=number;
  293.         size=(int)s;
  294.         if (n<0) {*s='-';s++;n=-n;}
  295.  
  296.         if (n==0) {*s='0';s++;goto end;}
  297.         for(i=0;i<200;i++) {buf[i]=0;}
  298.  
  299.         i=0;
  300.         if (flag_register==0)
  301.         {
  302.                 while (n>0)
  303.                 {
  304.                         buf[i]=xdigs_lower[n & 7];
  305.                         n=n>>3;
  306.                         i++;
  307.                 }
  308.         }
  309.  
  310.         pos=i;
  311.         difference_pos=i;
  312.  
  313.         for(i=pos-1;i>=0;i--)
  314.         {
  315.                 *s=buf[i];
  316.                 s++;
  317.         }
  318.  
  319.         if (fmt1-difference_pos>0)
  320.         {
  321.                 for(i=difference_pos+1;i<=fmt1;i++)
  322.                 {
  323.                         *s=' ';
  324.                         s++;
  325.                 }
  326.         }
  327.         end:size=(int)s-size;
  328.         return(size);
  329. }
  330.  
  331. //int vsnprintf (char * s, size_t n, const char * format, va_list arg );
  332. int format_print(char *dest, size_t maxlen, const char *fmt0, va_list argp)
  333. {
  334.     int                     i;
  335.     int                     length;
  336.     int                     fmt1, fmt2;  // width, precision
  337.     size_t                  pos, posc;
  338.     long        long            intdigit;
  339.     long        double          doubledigit;
  340. //        float                   floatdigit;
  341.     const   char            *fmt, *fmtc;  // first point to %, fmtc points to specifier
  342.     char                    *s; // pointer to current dest char
  343.     char                    *str;
  344.     char                    buf[200];  // buffer for current argument value print representation
  345.     int                     format_flag;
  346.     int                     flag_long;        // 2 = long double or long long int or wchar
  347.     int                    *point_to_n = NULL;
  348.     int                     flags;  // parsed flags
  349.  
  350.     fmt = fmt0;
  351.     s = dest;
  352.     pos = 0;
  353.     while(pos < maxlen)
  354.     {
  355.         if (*fmt != '%')  // usual char
  356.         {
  357.             if ('\0' == (*s++ = *fmt++)) break;
  358.             pos++;
  359.             continue;
  360.         }
  361.  
  362.         if (*(fmt + 1) == '%') // %%
  363.         {
  364.                 *s++ = '%'; pos++;
  365.                 fmt += 2;
  366.                 continue;
  367.         }
  368.         //checking to containg format in the string
  369.         fmtc = fmt;
  370.         posc = pos;
  371.  
  372.         flags = 0;
  373.         format_flag = 0;
  374.         flag_long = 0;  // 2 = long double or long long int or wchar
  375.  
  376.         while(*fmtc != '\0' && !format_flag)    // searching end of format
  377.         {
  378.                 fmtc++; posc++;
  379.                 switch( *fmtc )
  380.                 {
  381.                 case 'a':
  382.                     format_flag = 1;
  383.                     flags |= flag_unsigned;
  384.                     break;
  385.                 case 'A':
  386.                     format_flag = 1;
  387.                     flags |= flag_unsigned | flag_register;
  388.                     break;
  389.                 case 'c':   case 'd':   case 'i':   case 'e':   case 'f':   case 'g':   case 's':   case 'n':
  390.                     format_flag = 1;
  391.                     break;
  392.                 case 'E':   case 'F':   case 'G':
  393.                     format_flag = 1;
  394.                     flags |= flag_register;
  395.                     break;
  396.                 case 'l':
  397.                     flag_long  = flag_long ? 2 : 1;  // ll.eq.L
  398.                     break;
  399.                 case 'L':
  400.                     flag_long = 2;
  401.                     break;
  402.                 case 'o':   case 'u':   case 'x':   case 'p':
  403.                     format_flag = 1;
  404.                     flags |= flag_unsigned;
  405.                     break;
  406.                 case 'X':   case 'P':
  407.                     format_flag = 1;
  408.                     flags |= flag_unsigned | flag_register;
  409.                     break;
  410.                 case '+':
  411.                     flags |= flag_plus;
  412.                     break;
  413.                 case '-':
  414.                     flags |= flag_left_just;
  415.                     break;
  416.                 case ' ': // space
  417.                     flags |= flag_space_plus;
  418.                     break;
  419.                 case '#':
  420.                     flags |= flag_hash_sign;
  421.                     break;
  422.                 case '*':   case '.':  // just skip
  423.                     break;
  424.                 default:
  425.                     if(isdigit(*fmtc))  break;
  426.                     strncpy(dest, "print format error - in % invalid char found", maxlen);
  427.                     return -1;  // non format char found - user error
  428.                 }
  429.         }
  430.  
  431.         if (format_flag == 0)
  432.         {
  433.             strncpy(dest, "print format error - % without format specifier", maxlen);
  434.             return -1;  // format char not found - user error
  435.         }
  436.  
  437.         fmt1 = 0;
  438.         fmt2 = 0;
  439.         if (posc - pos > 1)  // try to read width, precision
  440.         {
  441.             fmt++;
  442.             for(i = pos + 1; i < posc; i++)
  443.             {
  444.                 switch(*fmt)
  445.                 {
  446.                 case '0':
  447.                     if(fmt1 == 0 && (flags & flag_point) == 0)    flags |= flag_lead_zeros;
  448.                 case '1':   case '2':   case '3':   case '4':
  449.                 case '5':   case '6':   case '7':   case '8':   case '9':
  450.                     if ((flags & flag_point) == 0)
  451.                         fmt1 = fmt1 * 10 + (*fmt -'0');
  452.                     else
  453.                         fmt2 = fmt2 * 10 + (*fmt -'0');
  454.                     break;
  455.                 case '*':
  456.                     if (flag_point == 0)
  457.                         fmt1 = va_arg(argp, int);
  458.                     else
  459.                         fmt2 = va_arg(argp, int);
  460.                     break;
  461.                 case '.':
  462.                     flags |= flag_point;
  463.                     break;
  464.                 case 'l':   case 'L':   case '+':   // valid chars - skip
  465.                 case '-':   case ' ':   case '#':
  466.                     break;
  467.                 default: // must be error
  468.                     strncpy(dest, "print format error - %width.precision", maxlen);
  469.                     return -1;  // format char not found - user error
  470.                 }
  471.                 fmt++;
  472.             }
  473.         }
  474.  
  475.         // do real work - format arguments values
  476.  
  477.         length = 0;
  478.         switch(*fmtc)
  479.         {
  480.         case 'n':
  481.             point_to_n = va_arg(argp, int*);
  482.             break;
  483.         case 'c':
  484.             if (pos + 1 <= maxlen)
  485.             {
  486.                 buf[0] = (char)va_arg(argp, int);
  487.                 length = 1;
  488.             }
  489.             break;
  490.         case 's':   // special case - without buf
  491.             str = va_arg(argp, char*);
  492.             length = strlen(str);
  493.             if ((flags & flag_point) && (length > fmt2)) length = fmt2;  // cut by precision
  494.             if (pos + length > maxlen) length = maxlen - pos;
  495.             memcpy(s, str ,length);
  496.             s += length;
  497.             pos += length;
  498.             break;
  499.         case 'd':   case 'i':   case 'u':   case 'U':
  500.             if (flag_long == 0) intdigit = va_arg(argp, int); else
  501.             if (flag_long == 1) intdigit = va_arg(argp, long); else
  502.             if (flag_long == 2) intdigit = va_arg(argp, long long);
  503.             length = formatted_long_to_string(intdigit, fmt1, fmt2, buf, flags);
  504.             break;
  505.         case 'o':
  506.             if (flag_long == 0) intdigit = va_arg(argp, int); else
  507.             if (flag_long == 1) intdigit = va_arg(argp, long); else
  508.             if (flag_long == 2) intdigit = va_arg(argp, long long);
  509.             length = formatted_octa_to_string(intdigit, fmt1, buf, flags);
  510.             break;
  511.         case 'p':   case 'P':   case 'x':   case 'X':
  512.             if (flag_long == 0) intdigit = va_arg(argp, int); else
  513.             if (flag_long == 1) intdigit = va_arg(argp, long); else
  514.             if (flag_long == 2) intdigit = va_arg(argp, long long);
  515.             length=formatted_hex_to_string(intdigit, fmt1, buf, flags);
  516.             break;
  517.         case 'a':   case 'A':   case 'f':   case 'F':
  518.             if (flag_long <= 1) doubledigit = va_arg(argp, double); else
  519.             if (flag_long == 2) doubledigit = va_arg(argp, long double);
  520.             length = formatted_double_to_string(doubledigit, fmt1, fmt2, buf, flags);
  521.             break;
  522.         case 'e':   case 'E':
  523.             if (flag_long <= 1) doubledigit = va_arg(argp, double); else
  524.             if (flag_long == 2) doubledigit = va_arg(argp, long double);
  525.             length = formatted_double_to_string_scientific(doubledigit, fmt1, fmt2, buf, flags);
  526.             break;
  527.         case 'g':   case 'G':
  528.  //prec special case, this is just workaround
  529.             if (flag_long <= 1) doubledigit = va_arg(argp, double); else
  530.             if (flag_long == 2) doubledigit = va_arg(argp, long double);
  531.             length = formatted_double_to_string(doubledigit, fmt1, fmt2, buf, flags);
  532.             i = formatted_double_to_string_scientific(doubledigit, fmt1, fmt2, buf + sizeof buf / 2, flags);
  533.             if(length > i)
  534.             {
  535.                 memcpy(buf, buf + sizeof buf / 2, i);
  536.                 length = i;
  537.             }
  538.             break;
  539.         }
  540.         if (*fmtc != 's' && length > 0) // skip multiple string copying
  541.         {
  542.             if (pos + length > maxlen)  length = maxlen - pos;
  543.             memcpy(s, buf, length);
  544.             s += length;
  545.             pos += length;
  546.         }
  547.         fmt = fmtc + 1;
  548.     }
  549.  
  550.     if (point_to_n) *point_to_n = pos;
  551.     return(pos);
  552. }
  553.