Coverage Report

Created: 2025-01-11 06:55

/src/mupdf/thirdparty/mujs/jsrepr.c
Line
Count
Source (jump to first uncovered line)
1
#include "jsi.h"
2
#include "utf.h"
3
4
static void reprvalue(js_State *J, js_Buffer **sb);
5
6
static void reprnum(js_State *J, js_Buffer **sb, double n)
7
0
{
8
0
  char buf[40];
9
0
  if (n == 0 && signbit(n))
10
0
    js_puts(J, sb, "-0");
11
0
  else
12
0
    js_puts(J, sb, jsV_numbertostring(J, buf, n));
13
0
}
14
15
static void reprstr(js_State *J, js_Buffer **sb, const char *s)
16
0
{
17
0
  static const char *HEX = "0123456789ABCDEF";
18
0
  int i, n;
19
0
  Rune c;
20
0
  js_putc(J, sb, '"');
21
0
  while (*s) {
22
0
    n = chartorune(&c, s);
23
0
    switch (c) {
24
0
    case '"': js_puts(J, sb, "\\\""); break;
25
0
    case '\\': js_puts(J, sb, "\\\\"); break;
26
0
    case '\b': js_puts(J, sb, "\\b"); break;
27
0
    case '\f': js_puts(J, sb, "\\f"); break;
28
0
    case '\n': js_puts(J, sb, "\\n"); break;
29
0
    case '\r': js_puts(J, sb, "\\r"); break;
30
0
    case '\t': js_puts(J, sb, "\\t"); break;
31
0
    default:
32
0
      if (c < ' ') {
33
0
        js_putc(J, sb, '\\');
34
0
        js_putc(J, sb, 'x');
35
0
        js_putc(J, sb, HEX[(c>>4)&15]);
36
0
        js_putc(J, sb, HEX[c&15]);
37
0
      } else if (c < 128) {
38
0
        js_putc(J, sb, c);
39
0
      } else if (c < 0x10000) {
40
0
        js_putc(J, sb, '\\');
41
0
        js_putc(J, sb, 'u');
42
0
        js_putc(J, sb, HEX[(c>>12)&15]);
43
0
        js_putc(J, sb, HEX[(c>>8)&15]);
44
0
        js_putc(J, sb, HEX[(c>>4)&15]);
45
0
        js_putc(J, sb, HEX[c&15]);
46
0
      } else {
47
0
        for (i = 0; i < n; ++i)
48
0
          js_putc(J, sb, s[i]);
49
0
      }
50
0
      break;
51
0
    }
52
0
    s += n;
53
0
  }
54
0
  js_putc(J, sb, '"');
55
0
}
56
57
#ifndef isalpha
58
#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
59
#endif
60
#ifndef isdigit
61
#define isdigit(c) (c >= '0' && c <= '9')
62
#endif
63
64
static void reprident(js_State *J, js_Buffer **sb, const char *name)
65
0
{
66
0
  const char *p = name;
67
0
  if (isdigit(*p))
68
0
    while (isdigit(*p))
69
0
      ++p;
70
0
  else if (isalpha(*p) || *p == '_')
71
0
    while (isdigit(*p) || isalpha(*p) || *p == '_')
72
0
      ++p;
73
0
  if (p > name && *p == 0)
74
0
    js_puts(J, sb, name);
75
0
  else
76
0
    reprstr(J, sb, name);
77
0
}
78
79
static void reprobject(js_State *J, js_Buffer **sb)
80
0
{
81
0
  const char *key;
82
0
  int i, n;
83
84
0
  n = js_gettop(J) - 1;
85
0
  for (i = 0; i < n; ++i) {
86
0
    if (js_isobject(J, i)) {
87
0
      if (js_toobject(J, i) == js_toobject(J, -1)) {
88
0
        js_puts(J, sb, "{}");
89
0
        return;
90
0
      }
91
0
    }
92
0
  }
93
94
0
  n = 0;
95
0
  js_putc(J, sb, '{');
96
0
  js_pushiterator(J, -1, 1);
97
0
  while ((key = js_nextiterator(J, -1))) {
98
0
    if (n++ > 0)
99
0
      js_puts(J, sb, ", ");
100
0
    reprident(J, sb, key);
101
0
    js_puts(J, sb, ": ");
102
0
    js_getproperty(J, -2, key);
103
0
    reprvalue(J, sb);
104
0
    js_pop(J, 1);
105
0
  }
106
0
  js_pop(J, 1);
107
0
  js_putc(J, sb, '}');
108
0
}
109
110
static void reprarray(js_State *J, js_Buffer **sb)
111
0
{
112
0
  int n, i;
113
114
0
  n = js_gettop(J) - 1;
115
0
  for (i = 0; i < n; ++i) {
116
0
    if (js_isobject(J, i)) {
117
0
      if (js_toobject(J, i) == js_toobject(J, -1)) {
118
0
        js_puts(J, sb, "[]");
119
0
        return;
120
0
      }
121
0
    }
122
0
  }
123
124
0
  js_putc(J, sb, '[');
125
0
  n = js_getlength(J, -1);
126
0
  for (i = 0; i < n; ++i) {
127
0
    if (i > 0)
128
0
      js_puts(J, sb, ", ");
129
0
    if (js_hasindex(J, -1, i)) {
130
0
      reprvalue(J, sb);
131
0
      js_pop(J, 1);
132
0
    }
133
0
  }
134
0
  js_putc(J, sb, ']');
135
0
}
136
137
static void reprfun(js_State *J, js_Buffer **sb, js_Function *fun)
138
0
{
139
0
  int i;
140
0
  js_puts(J, sb, "function ");
141
0
  js_puts(J, sb, fun->name);
142
0
  js_putc(J, sb, '(');
143
0
  for (i = 0; i < fun->numparams; ++i) {
144
0
    if (i > 0)
145
0
      js_puts(J, sb, ", ");
146
0
    js_puts(J, sb, fun->vartab[i]);
147
0
  }
148
0
  js_puts(J, sb, ") { [byte code] }");
149
0
}
150
151
static void reprvalue(js_State *J, js_Buffer **sb)
152
0
{
153
0
  if (js_isundefined(J, -1))
154
0
    js_puts(J, sb, "undefined");
155
0
  else if (js_isnull(J, -1))
156
0
    js_puts(J, sb, "null");
157
0
  else if (js_isboolean(J, -1))
158
0
    js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");
159
0
  else if (js_isnumber(J, -1))
160
0
    reprnum(J, sb, js_tonumber(J, -1));
161
0
  else if (js_isstring(J, -1))
162
0
    reprstr(J, sb, js_tostring(J, -1));
163
0
  else if (js_isobject(J, -1)) {
164
0
    js_Object *obj = js_toobject(J, -1);
165
0
    switch (obj->type) {
166
0
    default:
167
0
      reprobject(J, sb);
168
0
      break;
169
0
    case JS_CARRAY:
170
0
      reprarray(J, sb);
171
0
      break;
172
0
    case JS_CFUNCTION:
173
0
    case JS_CSCRIPT:
174
0
      reprfun(J, sb, obj->u.f.function);
175
0
      break;
176
0
    case JS_CCFUNCTION:
177
0
      js_puts(J, sb, "function ");
178
0
      js_puts(J, sb, obj->u.c.name);
179
0
      js_puts(J, sb, "() { [native code] }");
180
0
      break;
181
0
    case JS_CBOOLEAN:
182
0
      js_puts(J, sb, "(new Boolean(");
183
0
      js_puts(J, sb, obj->u.boolean ? "true" : "false");
184
0
      js_puts(J, sb, "))");
185
0
      break;
186
0
    case JS_CNUMBER:
187
0
      js_puts(J, sb, "(new Number(");
188
0
      reprnum(J, sb, obj->u.number);
189
0
      js_puts(J, sb, "))");
190
0
      break;
191
0
    case JS_CSTRING:
192
0
      js_puts(J, sb, "(new String(");
193
0
      reprstr(J, sb, obj->u.s.string);
194
0
      js_puts(J, sb, "))");
195
0
      break;
196
0
    case JS_CREGEXP:
197
0
      js_putc(J, sb, '/');
198
0
      js_puts(J, sb, obj->u.r.source);
199
0
      js_putc(J, sb, '/');
200
0
      if (obj->u.r.flags & JS_REGEXP_G) js_putc(J, sb, 'g');
201
0
      if (obj->u.r.flags & JS_REGEXP_I) js_putc(J, sb, 'i');
202
0
      if (obj->u.r.flags & JS_REGEXP_M) js_putc(J, sb, 'm');
203
0
      break;
204
0
    case JS_CDATE:
205
0
      {
206
0
        char buf[40];
207
0
        js_puts(J, sb, "(new Date(");
208
0
        js_puts(J, sb, jsV_numbertostring(J, buf, obj->u.number));
209
0
        js_puts(J, sb, "))");
210
0
      }
211
0
      break;
212
0
    case JS_CERROR:
213
0
      js_puts(J, sb, "(new ");
214
0
      js_getproperty(J, -1, "name");
215
0
      js_puts(J, sb, js_tostring(J, -1));
216
0
      js_pop(J, 1);
217
0
      js_putc(J, sb, '(');
218
0
      if (js_hasproperty(J, -1, "message")) {
219
0
        reprvalue(J, sb);
220
0
        js_pop(J, 1);
221
0
      }
222
0
      js_puts(J, sb, "))");
223
0
      break;
224
0
    case JS_CMATH:
225
0
      js_puts(J, sb, "Math");
226
0
      break;
227
0
    case JS_CJSON:
228
0
      js_puts(J, sb, "JSON");
229
0
      break;
230
0
    case JS_CITERATOR:
231
0
      js_puts(J, sb, "[iterator ");
232
0
      break;
233
0
    case JS_CUSERDATA:
234
0
      js_puts(J, sb, "[userdata ");
235
0
      js_puts(J, sb, obj->u.user.tag);
236
0
      js_putc(J, sb, ']');
237
0
      break;
238
0
    }
239
0
  }
240
0
}
241
242
void js_repr(js_State *J, int idx)
243
0
{
244
0
  js_Buffer *sb = NULL;
245
0
  int savebot;
246
247
0
  if (js_try(J)) {
248
0
    js_free(J, sb);
249
0
    js_throw(J);
250
0
  }
251
252
0
  js_copy(J, idx);
253
254
0
  savebot = J->bot;
255
0
  J->bot = J->top - 1;
256
0
  reprvalue(J, &sb);
257
0
  J->bot = savebot;
258
259
0
  js_pop(J, 1);
260
261
0
  js_putc(J, &sb, 0);
262
0
  js_pushstring(J, sb ? sb->s : "undefined");
263
264
0
  js_endtry(J);
265
0
  js_free(J, sb);
266
0
}
267
268
const char *js_torepr(js_State *J, int idx)
269
0
{
270
0
  js_repr(J, idx);
271
0
  js_replace(J, idx < 0 ? idx-1 : idx);
272
0
  return js_tostring(J, idx);
273
0
}
274
275
const char *js_tryrepr(js_State *J, int idx, const char *error)
276
0
{
277
0
  const char *s;
278
0
  if (js_try(J)) {
279
0
    js_pop(J, 1);
280
0
    return error;
281
0
  }
282
0
  s = js_torepr(J, idx);
283
0
  js_endtry(J);
284
0
  return s;
285
0
}