Coverage Report

Created: 2024-05-20 06:23

/src/mupdf/thirdparty/mujs/jsnumber.c
Line
Count
Source (jump to first uncovered line)
1
#include "jsi.h"
2
3
#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */
4
typedef unsigned __int64 uint64_t;
5
#else
6
#include <stdint.h>
7
#endif
8
9
static void jsB_new_Number(js_State *J)
10
0
{
11
0
  js_newnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0);
12
0
}
13
14
static void jsB_Number(js_State *J)
15
0
{
16
0
  js_pushnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0);
17
0
}
18
19
static void Np_valueOf(js_State *J)
20
0
{
21
0
  js_Object *self = js_toobject(J, 0);
22
0
  if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
23
0
  js_pushnumber(J, self->u.number);
24
0
}
25
26
static void Np_toString(js_State *J)
27
0
{
28
0
  char buf[100];
29
0
  js_Object *self = js_toobject(J, 0);
30
0
  int radix = js_isundefined(J, 1) ? 10 : js_tointeger(J, 1);
31
0
  double x = 0;
32
0
  if (self->type != JS_CNUMBER)
33
0
    js_typeerror(J, "not a number");
34
0
  x = self->u.number;
35
0
  if (radix == 10) {
36
0
    js_pushstring(J, jsV_numbertostring(J, buf, x));
37
0
    return;
38
0
  }
39
0
  if (radix < 2 || radix > 36)
40
0
    js_rangeerror(J, "invalid radix");
41
42
  /* lame number to string conversion for any radix from 2 to 36 */
43
0
  {
44
0
    static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
45
0
    double number = x;
46
0
    int sign = x < 0;
47
0
    js_Buffer *sb = NULL;
48
0
    uint64_t u, limit = ((uint64_t)1<<52);
49
50
0
    int ndigits, exp, point;
51
52
0
    if (number == 0) { js_pushstring(J, "0"); return; }
53
0
    if (isnan(number)) { js_pushstring(J, "NaN"); return; }
54
0
    if (isinf(number)) { js_pushstring(J, sign ? "-Infinity" : "Infinity"); return; }
55
56
0
    if (sign)
57
0
      number = -number;
58
59
    /* fit as many digits as we want in an int */
60
0
    exp = 0;
61
0
    while (number * pow(radix, exp) > limit)
62
0
      --exp;
63
0
    while (number * pow(radix, exp+1) < limit)
64
0
      ++exp;
65
0
    u = number * pow(radix, exp) + 0.5;
66
67
    /* trim trailing zeros */
68
0
    while (u > 0 && (u % radix) == 0) {
69
0
      u /= radix;
70
0
      --exp;
71
0
    }
72
73
    /* serialize digits */
74
0
    ndigits = 0;
75
0
    while (u > 0) {
76
0
      buf[ndigits++] = digits[u % radix];
77
0
      u /= radix;
78
0
    }
79
0
    point = ndigits - exp;
80
81
0
    if (js_try(J)) {
82
0
      js_free(J, sb);
83
0
      js_throw(J);
84
0
    }
85
86
0
    if (sign)
87
0
      js_putc(J, &sb, '-');
88
89
0
    if (point <= 0) {
90
0
      js_putc(J, &sb, '0');
91
0
      js_putc(J, &sb, '.');
92
0
      while (point++ < 0)
93
0
        js_putc(J, &sb, '0');
94
0
      while (ndigits-- > 0)
95
0
        js_putc(J, &sb, buf[ndigits]);
96
0
    } else {
97
0
      while (ndigits-- > 0) {
98
0
        js_putc(J, &sb, buf[ndigits]);
99
0
        if (--point == 0 && ndigits > 0)
100
0
          js_putc(J, &sb, '.');
101
0
      }
102
0
      while (point-- > 0)
103
0
        js_putc(J, &sb, '0');
104
0
    }
105
106
0
    js_putc(J, &sb, 0);
107
0
    js_pushstring(J, sb->s);
108
109
0
    js_endtry(J);
110
0
    js_free(J, sb);
111
0
  }
112
0
}
113
114
/* Customized ToString() on a number */
115
static void numtostr(js_State *J, const char *fmt, int w, double n)
116
0
{
117
  /* buf needs to fit printf("%.20f", 1e20) */
118
0
  char buf[50], *e;
119
0
  sprintf(buf, fmt, w, n);
120
0
  e = strchr(buf, 'e');
121
0
  if (e) {
122
0
    int exp = atoi(e+1);
123
0
    sprintf(e, "e%+d", exp);
124
0
  }
125
0
  js_pushstring(J, buf);
126
0
}
127
128
static void Np_toFixed(js_State *J)
129
0
{
130
0
  js_Object *self = js_toobject(J, 0);
131
0
  int width = js_tointeger(J, 1);
132
0
  char buf[32];
133
0
  double x;
134
0
  if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
135
0
  if (width < 0) js_rangeerror(J, "precision %d out of range", width);
136
0
  if (width > 20) js_rangeerror(J, "precision %d out of range", width);
137
0
  x = self->u.number;
138
0
  if (isnan(x) || isinf(x) || x <= -1e21 || x >= 1e21)
139
0
    js_pushstring(J, jsV_numbertostring(J, buf, x));
140
0
  else
141
0
    numtostr(J, "%.*f", width, x);
142
0
}
143
144
static void Np_toExponential(js_State *J)
145
0
{
146
0
  js_Object *self = js_toobject(J, 0);
147
0
  int width = js_tointeger(J, 1);
148
0
  char buf[32];
149
0
  double x;
150
0
  if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
151
0
  if (width < 0) js_rangeerror(J, "precision %d out of range", width);
152
0
  if (width > 20) js_rangeerror(J, "precision %d out of range", width);
153
0
  x = self->u.number;
154
0
  if (isnan(x) || isinf(x))
155
0
    js_pushstring(J, jsV_numbertostring(J, buf, x));
156
0
  else
157
0
    numtostr(J, "%.*e", width, x);
158
0
}
159
160
static void Np_toPrecision(js_State *J)
161
0
{
162
0
  js_Object *self = js_toobject(J, 0);
163
0
  int width = js_tointeger(J, 1);
164
0
  char buf[32];
165
0
  double x;
166
0
  if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
167
0
  if (width < 1) js_rangeerror(J, "precision %d out of range", width);
168
0
  if (width > 21) js_rangeerror(J, "precision %d out of range", width);
169
0
  x = self->u.number;
170
0
  if (isnan(x) || isinf(x))
171
0
    js_pushstring(J, jsV_numbertostring(J, buf, x));
172
0
  else
173
0
    numtostr(J, "%.*g", width, x);
174
0
}
175
176
void jsB_initnumber(js_State *J)
177
0
{
178
0
  J->Number_prototype->u.number = 0;
179
180
0
  js_pushobject(J, J->Number_prototype);
181
0
  {
182
0
    jsB_propf(J, "Number.prototype.valueOf", Np_valueOf, 0);
183
0
    jsB_propf(J, "Number.prototype.toString", Np_toString, 1);
184
0
    jsB_propf(J, "Number.prototype.toLocaleString", Np_toString, 0);
185
0
    jsB_propf(J, "Number.prototype.toFixed", Np_toFixed, 1);
186
0
    jsB_propf(J, "Number.prototype.toExponential", Np_toExponential, 1);
187
0
    jsB_propf(J, "Number.prototype.toPrecision", Np_toPrecision, 1);
188
0
  }
189
0
  js_newcconstructor(J, jsB_Number, jsB_new_Number, "Number", 0); /* 1 */
190
0
  {
191
0
    jsB_propn(J, "MAX_VALUE", 1.7976931348623157e+308);
192
0
    jsB_propn(J, "MIN_VALUE", 5e-324);
193
0
    jsB_propn(J, "NaN", NAN);
194
0
    jsB_propn(J, "NEGATIVE_INFINITY", -INFINITY);
195
0
    jsB_propn(J, "POSITIVE_INFINITY", INFINITY);
196
0
  }
197
0
  js_defglobal(J, "Number", JS_DONTENUM);
198
0
}