1 #ifndef MRB_WITHOUT_FLOAT
2 #ifdef MRB_DISABLE_STDIO
3 /*
4 
5 Most code in this file originates from musl (src/stdio/vfprintf.c)
6 which, just like mruby itself, is licensed under the MIT license.
7 
8 Copyright (c) 2005-2014 Rich Felker, et al.
9 
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17 
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 
29 */
30 
31 #include <limits.h>
32 #include <string.h>
33 #include <stdint.h>
34 #include <math.h>
35 #include <float.h>
36 #include <ctype.h>
37 
38 #include <mruby.h>
39 #include <mruby/string.h>
40 
41 struct fmt_args {
42   mrb_state *mrb;
43   mrb_value str;
44 };
45 
46 #define MAX(a,b) ((a)>(b) ? (a) : (b))
47 #define MIN(a,b) ((a)<(b) ? (a) : (b))
48 
49 /* Convenient bit representation for modifier flags, which all fall
50  * within 31 codepoints of the space character. */
51 
52 #define ALT_FORM   (1U<<('#'-' '))
53 #define ZERO_PAD   (1U<<('0'-' '))
54 #define LEFT_ADJ   (1U<<('-'-' '))
55 #define PAD_POS    (1U<<(' '-' '))
56 #define MARK_POS   (1U<<('+'-' '))
57 
58 static void
out(struct fmt_args * f,const char * s,size_t l)59 out(struct fmt_args *f, const char *s, size_t l)
60 {
61   mrb_str_cat(f->mrb, f->str, s, l);
62 }
63 
64 #define PAD_SIZE 256
65 static void
pad(struct fmt_args * f,char c,ptrdiff_t w,ptrdiff_t l,uint8_t fl)66 pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint8_t fl)
67 {
68   char pad[PAD_SIZE];
69   if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
70   l = w - l;
71   memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l);
72   for (; l >= PAD_SIZE; l -= PAD_SIZE)
73     out(f, pad, PAD_SIZE);
74   out(f, pad, l);
75 }
76 
77 static const char xdigits[16] = {
78   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
79 };
80 
81 static char*
fmt_u(uint32_t x,char * s)82 fmt_u(uint32_t x, char *s)
83 {
84   for (; x; x /= 10) *--s = '0' + x % 10;
85   return s;
86 }
87 
88 /* Do not override this check. The floating point printing code below
89  * depends on the float.h constants being right. If they are wrong, it
90  * may overflow the stack. */
91 #if LDBL_MANT_DIG == 53
92 typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
93 #endif
94 
95 static int
fmt_fp(struct fmt_args * f,long double y,ptrdiff_t p,uint8_t fl,int t)96 fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t)
97 {
98   uint32_t big[(LDBL_MANT_DIG+28)/29 + 1          // mantissa expansion
99     + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
100   uint32_t *a, *d, *r, *z;
101   uint32_t i;
102   int e2=0, e, j;
103   ptrdiff_t l;
104   char buf[9+LDBL_MANT_DIG/4], *s;
105   const char *prefix="-0X+0X 0X-0x+0x 0x";
106   ptrdiff_t pl;
107   char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
108 
109   pl=1;
110   if (signbit(y)) {
111     y=-y;
112   } else if (fl & MARK_POS) {
113     prefix+=3;
114   } else if (fl & PAD_POS) {
115     prefix+=6;
116   } else prefix++, pl=0;
117 
118   if (!isfinite(y)) {
119     const char *ss = (t&32)?"inf":"INF";
120     if (y!=y) ss=(t&32)?"nan":"NAN";
121     pad(f, ' ', 0, 3+pl, fl&~ZERO_PAD);
122     out(f, prefix, pl);
123     out(f, ss, 3);
124     pad(f, ' ', 0, 3+pl, fl^LEFT_ADJ);
125     return 3+(int)pl;
126   }
127 
128   y = frexp((double)y, &e2) * 2;
129   if (y) e2--;
130 
131   if ((t|32)=='a') {
132     long double round = 8.0;
133     ptrdiff_t re;
134 
135     if (t&32) prefix += 9;
136     pl += 2;
137 
138     if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
139     else re=LDBL_MANT_DIG/4-1-p;
140 
141     if (re) {
142       while (re--) round*=16;
143       if (*prefix=='-') {
144         y=-y;
145         y-=round;
146         y+=round;
147         y=-y;
148       }
149       else {
150         y+=round;
151         y-=round;
152       }
153     }
154 
155     estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
156     if (estr==ebuf) *--estr='0';
157     *--estr = (e2<0 ? '-' : '+');
158     *--estr = t+('p'-'a');
159 
160     s=buf;
161     do {
162       int x=(int)y;
163       *s++=xdigits[x]|(t&32);
164       y=16*(y-x);
165       if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
166     } while (y);
167 
168     if (p && s-buf-2 < p)
169       l = (p+2) + (ebuf-estr);
170     else
171       l = (s-buf) + (ebuf-estr);
172 
173     pad(f, ' ', 0, pl+l, fl);
174     out(f, prefix, pl);
175     pad(f, '0', 0, pl+l, fl^ZERO_PAD);
176     out(f, buf, s-buf);
177     pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
178     out(f, estr, ebuf-estr);
179     pad(f, ' ', 0, pl+l, fl^LEFT_ADJ);
180     return (int)pl+(int)l;
181   }
182   if (p<0) p=6;
183 
184   if (y) y *= 268435456.0, e2-=28;
185 
186   if (e2<0) a=r=z=big;
187   else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
188 
189   do {
190     *z = (uint32_t)y;
191     y = 1000000000*(y-*z++);
192   } while (y);
193 
194   while (e2>0) {
195     uint32_t carry=0;
196     int sh=MIN(29,e2);
197     for (d=z-1; d>=a; d--) {
198       uint64_t x = ((uint64_t)*d<<sh)+carry;
199       *d = x % 1000000000;
200       carry = (uint32_t)(x / 1000000000);
201     }
202     if (carry) *--a = carry;
203     while (z>a && !z[-1]) z--;
204     e2-=sh;
205   }
206   while (e2<0) {
207     uint32_t carry=0, *b;
208     int sh=MIN(9,-e2), need=1+((int)p+LDBL_MANT_DIG/3+8)/9;
209     for (d=a; d<z; d++) {
210       uint32_t rm = *d & ((1<<sh)-1);
211       *d = (*d>>sh) + carry;
212       carry = (1000000000>>sh) * rm;
213     }
214     if (!*a) a++;
215     if (carry) *z++ = carry;
216     /* Avoid (slow!) computation past requested precision */
217     b = (t|32)=='f' ? r : a;
218     if (z-b > need) z = b+need;
219     e2+=sh;
220   }
221 
222   if (a<z) for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
223   else e=0;
224 
225   /* Perform rounding: j is precision after the radix (possibly neg) */
226   j = (int)p - ((t|32)!='f')*e - ((t|32)=='g' && p);
227   if (j < 9*(z-r-1)) {
228     uint32_t x;
229     /* We avoid C's broken division of negative numbers */
230     d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
231     j += 9*LDBL_MAX_EXP;
232     j %= 9;
233     for (i=10, j++; j<9; i*=10, j++);
234     x = *d % i;
235     /* Are there any significant digits past j? */
236     if (x || d+1!=z) {
237       long double round = 2/LDBL_EPSILON;
238       long double small;
239       if (*d/i & 1) round += 2;
240       if (x<i/2) small=0.5;
241       else if (x==i/2 && d+1==z) small=1.0;
242       else small=1.5;
243       if (pl && *prefix=='-') round*=-1, small*=-1;
244       *d -= x;
245       /* Decide whether to round by probing round+small */
246       if (round+small != round) {
247         *d = *d + i;
248         while (*d > 999999999) {
249           *d--=0;
250           if (d<a) *--a=0;
251           (*d)++;
252         }
253         for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
254       }
255     }
256     if (z>d+1) z=d+1;
257   }
258   for (; z>a && !z[-1]; z--);
259 
260   if ((t|32)=='g') {
261     if (!p) p++;
262     if (p>e && e>=-4) {
263       t--;
264       p-=e+1;
265     }
266     else {
267       t-=2;
268       p--;
269     }
270     if (!(fl&ALT_FORM)) {
271       /* Count trailing zeros in last place */
272       if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
273       else j=9;
274       if ((t|32)=='f')
275         p = MIN(p,MAX(0,9*(z-r-1)-j));
276       else
277         p = MIN(p,MAX(0,9*(z-r-1)+e-j));
278     }
279   }
280   l = 1 + p + (p || (fl&ALT_FORM));
281   if ((t|32)=='f') {
282     if (e>0) l+=e;
283   }
284   else {
285     estr=fmt_u(e<0 ? -e : e, ebuf);
286     while(ebuf-estr<2) *--estr='0';
287     *--estr = (e<0 ? '-' : '+');
288     *--estr = t;
289     l += ebuf-estr;
290   }
291 
292   pad(f, ' ', 0, pl+l, fl);
293   out(f, prefix, pl);
294   pad(f, '0', 0, pl+l, fl^ZERO_PAD);
295 
296   if ((t|32)=='f') {
297     if (a>r) a=r;
298     for (d=a; d<=r; d++) {
299       char *ss = fmt_u(*d, buf+9);
300       if (d!=a) while (ss>buf) *--ss='0';
301       else if (ss==buf+9) *--ss='0';
302       out(f, ss, buf+9-ss);
303     }
304     if (p || (fl&ALT_FORM)) out(f, ".", 1);
305     for (; d<z && p>0; d++, p-=9) {
306       char *ss = fmt_u(*d, buf+9);
307       while (ss>buf) *--ss='0';
308       out(f, ss, MIN(9,p));
309     }
310     pad(f, '0', p+9, 9, 0);
311   }
312   else {
313     if (z<=a) z=a+1;
314     for (d=a; d<z && p>=0; d++) {
315       char *ss = fmt_u(*d, buf+9);
316       if (ss==buf+9) *--ss='0';
317       if (d!=a) while (ss>buf) *--ss='0';
318       else {
319         out(f, ss++, 1);
320         if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
321       }
322       out(f, ss, MIN(buf+9-ss, p));
323       p -= (int)(buf+9-ss);
324     }
325     pad(f, '0', p+18, 18, 0);
326     out(f, estr, ebuf-estr);
327   }
328 
329   pad(f, ' ', 0, pl+l, fl^LEFT_ADJ);
330 
331   return (int)pl+(int)l;
332 }
333 
334 static int
fmt_core(struct fmt_args * f,const char * fmt,mrb_float flo)335 fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo)
336 {
337   ptrdiff_t p;
338 
339   if (*fmt != '%') {
340     return -1;
341   }
342   ++fmt;
343 
344   if (*fmt == '.') {
345     ++fmt;
346     for (p = 0; ISDIGIT(*fmt); ++fmt) {
347       p = 10 * p + (*fmt - '0');
348     }
349   }
350   else {
351     p = -1;
352   }
353 
354   switch (*fmt) {
355   case 'e': case 'f': case 'g': case 'a':
356   case 'E': case 'F': case 'G': case 'A':
357     return fmt_fp(f, flo, p, 0, *fmt);
358   default:
359     return -1;
360   }
361 }
362 
363 mrb_value
mrb_float_to_str(mrb_state * mrb,mrb_value flo,const char * fmt)364 mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
365 {
366   struct fmt_args f;
367 
368   f.mrb = mrb;
369   f.str = mrb_str_new_capa(mrb, 24);
370   if (fmt_core(&f, fmt, mrb_float(flo)) < 0) {
371     mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string");
372   }
373   return f.str;
374 }
375 #else   /* MRB_DISABLE_STDIO */
376 #include <mruby.h>
377 #include <stdio.h>
378 
379 mrb_value
mrb_float_to_str(mrb_state * mrb,mrb_value flo,const char * fmt)380 mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
381 {
382   char buf[25];
383 
384   snprintf(buf, sizeof(buf), fmt, mrb_float(flo));
385   return mrb_str_new_cstr(mrb, buf);
386 }
387 #endif  /* MRB_DISABLE_STDIO */
388 #endif
389