| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* Because I don't know how to use sv_setref_pv() correctly. */ |
|
2
|
|
|
|
|
|
|
|
|
3
|
82
|
|
|
|
|
|
static SV *fu_selfobj_(pTHX_ SV **self, void *obj, const char *klass) { |
|
4
|
82
|
|
|
|
|
|
*self = newSViv(PTR2IV(obj)); |
|
5
|
82
|
|
|
|
|
|
return sv_bless(sv_2mortal(newRV_noinc(*self)), gv_stashpv(klass, GV_ADD)); |
|
6
|
|
|
|
|
|
|
} |
|
7
|
|
|
|
|
|
|
/* Write a blessed SV to obj->self and returns a mortal ref to it */ |
|
8
|
|
|
|
|
|
|
#define fu_selfobj(obj, klass) fu_selfobj_(aTHX_ &((obj)->self), obj, klass) |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
/* Return an SV to use for croak_sv() with a HV object. |
|
13
|
|
|
|
|
|
|
* Adds a "full_message" field including stack trace. */ |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
__attribute__((format (printf, 3, 4))) |
|
16
|
0
|
|
|
|
|
|
static SV *fu_croak_hv(HV *hv, const char *klass, const char *message, ...) { |
|
17
|
|
|
|
|
|
|
va_list args; |
|
18
|
|
|
|
|
|
|
SV *sv; |
|
19
|
|
|
|
|
|
|
dTHX; |
|
20
|
0
|
|
|
|
|
|
dSP; |
|
21
|
|
|
|
|
|
|
|
|
22
|
0
|
|
|
|
|
|
va_start(args, message); |
|
23
|
0
|
|
|
|
|
|
sv = vnewSVpvf(message, &args); |
|
24
|
0
|
|
|
|
|
|
va_end(args); |
|
25
|
|
|
|
|
|
|
|
|
26
|
0
|
|
|
|
|
|
ENTER; |
|
27
|
0
|
|
|
|
|
|
SAVETMPS; |
|
28
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
29
|
0
|
0
|
|
|
|
|
mXPUSHs(sv); |
|
30
|
0
|
|
|
|
|
|
PUTBACK; |
|
31
|
0
|
|
|
|
|
|
call_pv("Carp::longmess", G_SCALAR); |
|
32
|
0
|
|
|
|
|
|
hv_stores(hv, "full_message", SvREFCNT_inc(POPs)); |
|
33
|
0
|
0
|
|
|
|
|
FREETMPS; |
|
34
|
0
|
|
|
|
|
|
LEAVE; |
|
35
|
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
|
return sv_bless(sv_2mortal(newRV_noinc((SV *)hv)), gv_stashpv(klass, GV_ADD)); |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
__attribute__((noreturn, format (printf, 1, 2))) |
|
40
|
17
|
|
|
|
|
|
static void fu_confess(const char *message, ...) { |
|
41
|
|
|
|
|
|
|
va_list args; |
|
42
|
|
|
|
|
|
|
SV *sv; |
|
43
|
|
|
|
|
|
|
dTHX; |
|
44
|
17
|
|
|
|
|
|
dSP; |
|
45
|
|
|
|
|
|
|
|
|
46
|
17
|
|
|
|
|
|
va_start(args, message); |
|
47
|
17
|
|
|
|
|
|
sv = vnewSVpvf(message, &args); |
|
48
|
17
|
|
|
|
|
|
va_end(args); |
|
49
|
|
|
|
|
|
|
|
|
50
|
17
|
|
|
|
|
|
ENTER; |
|
51
|
17
|
|
|
|
|
|
SAVETMPS; |
|
52
|
17
|
50
|
|
|
|
|
PUSHMARK(SP); |
|
53
|
17
|
50
|
|
|
|
|
mXPUSHs(sv); |
|
54
|
17
|
|
|
|
|
|
PUTBACK; |
|
55
|
17
|
|
|
|
|
|
call_pv("Carp::confess", G_DISCARD); |
|
56
|
|
|
|
|
|
|
/* Won't happen, but a safe fallback */ |
|
57
|
0
|
|
|
|
|
|
croak("%s", SvPV_nolen(sv)); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
/* Custom string builder, should be slightly faster than using Sv* macros directly. */ |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
typedef struct { |
|
65
|
|
|
|
|
|
|
SV *sv; |
|
66
|
|
|
|
|
|
|
SV *mortal; |
|
67
|
|
|
|
|
|
|
char *cur; |
|
68
|
|
|
|
|
|
|
char *end; |
|
69
|
|
|
|
|
|
|
size_t maxlen; |
|
70
|
|
|
|
|
|
|
int setutf8; |
|
71
|
|
|
|
|
|
|
char sbuf[4096]; |
|
72
|
|
|
|
|
|
|
} fustr; |
|
73
|
|
|
|
|
|
|
|
|
74
|
5936
|
|
|
|
|
|
static void fustr_init_(pTHX_ fustr *s, SV *mortal, size_t maxlen) { |
|
75
|
5936
|
|
|
|
|
|
s->sv = NULL; |
|
76
|
5936
|
|
|
|
|
|
s->cur = s->sbuf; |
|
77
|
5936
|
|
|
|
|
|
s->end = s->sbuf + (maxlen > sizeof s->sbuf ? sizeof s->sbuf : maxlen); |
|
78
|
5936
|
|
|
|
|
|
s->maxlen = maxlen; |
|
79
|
5936
|
|
|
|
|
|
s->mortal = mortal; |
|
80
|
5936
|
|
|
|
|
|
s->setutf8 = 0; |
|
81
|
5936
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
#define fustr_start(s) (((s)->sv ? SvPVX((s)->sv) : (s)->sbuf)) |
|
84
|
|
|
|
|
|
|
#define fustr_len(s) ((s)->cur - fustr_start(s)) |
|
85
|
|
|
|
|
|
|
|
|
86
|
1046
|
|
|
|
|
|
static void fustr_grow(pTHX_ fustr *s, size_t add) { |
|
87
|
1046
|
100
|
|
|
|
|
size_t off = fustr_len(s); |
|
88
|
1046
|
|
|
|
|
|
size_t newlen = sizeof s->sbuf; |
|
89
|
|
|
|
|
|
|
char *buf; |
|
90
|
1046
|
|
|
|
|
|
add += off; |
|
91
|
1046
|
100
|
|
|
|
|
if (add > s->maxlen) croak("maximum string length exceeded"); |
|
92
|
|
|
|
|
|
|
/* Increment to next power of two; SvGROW's default strategy is slow */ |
|
93
|
2554
|
100
|
|
|
|
|
while (newlen < add) newlen <<= 1; |
|
94
|
1045
|
50
|
|
|
|
|
if (newlen > s->maxlen) newlen = s->maxlen; |
|
95
|
1045
|
100
|
|
|
|
|
if (s->sv) { |
|
96
|
224
|
50
|
|
|
|
|
buf = SvGROW(s->sv, newlen); |
|
|
|
50
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
} else { |
|
98
|
821
|
100
|
|
|
|
|
if (s->mortal) { |
|
99
|
410
|
|
|
|
|
|
s->sv = s->mortal; |
|
100
|
410
|
|
|
|
|
|
sv_setpv_bufsize(s->sv, off, newlen); |
|
101
|
|
|
|
|
|
|
} else { |
|
102
|
411
|
|
|
|
|
|
s->sv = newSV(newlen); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
821
|
|
|
|
|
|
SvPOK_only(s->sv); |
|
105
|
821
|
|
|
|
|
|
buf = SvPVX(s->sv); |
|
106
|
821
|
|
|
|
|
|
memcpy(buf, s->sbuf, off); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
1045
|
|
|
|
|
|
s->cur = buf + off; |
|
109
|
1045
|
|
|
|
|
|
s->end = buf + (SvLEN(s->sv) > s->maxlen ? s->maxlen : SvLEN(s->sv)); |
|
110
|
1045
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
4760908
|
|
|
|
|
|
static inline void fustr_reserve_(pTHX_ fustr *s, size_t add) { |
|
113
|
4760908
|
100
|
|
|
|
|
if (UNLIKELY(s->end < s->cur + add)) fustr_grow(aTHX_ s, add); |
|
114
|
4760907
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
4951
|
|
|
|
|
|
static inline void fustr_write_(pTHX_ fustr *s, const char *str, size_t n) { |
|
117
|
4951
|
|
|
|
|
|
fustr_reserve_(aTHX_ s, n); |
|
118
|
4951
|
|
|
|
|
|
memcpy(s->cur, str, n); |
|
119
|
4951
|
|
|
|
|
|
s->cur += n; |
|
120
|
4951
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
5196
|
|
|
|
|
|
static inline void fustr_write_ch_(pTHX_ fustr *s, char x) { |
|
123
|
5196
|
|
|
|
|
|
fustr_reserve_(aTHX_ s, 1); |
|
124
|
5196
|
|
|
|
|
|
*(s->cur++) = x; |
|
125
|
5196
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
/* Adds n uninitialized bytes to the string and returns a buffer to write the data to */ |
|
128
|
31
|
|
|
|
|
|
static inline char *fustr_write_buf_(pTHX_ fustr *s, size_t n) { |
|
129
|
31
|
|
|
|
|
|
fustr_reserve_(aTHX_ s, n); |
|
130
|
31
|
|
|
|
|
|
char *buf = s->cur; |
|
131
|
31
|
|
|
|
|
|
s->cur += n; |
|
132
|
31
|
|
|
|
|
|
return buf; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
5370
|
|
|
|
|
|
static SV *fustr_done_(pTHX_ fustr *s) { |
|
136
|
5370
|
|
|
|
|
|
fustr_reserve_(aTHX_ s, 1); |
|
137
|
5370
|
|
|
|
|
|
*s->cur = 0; |
|
138
|
5370
|
100
|
|
|
|
|
if (s->sv) { |
|
139
|
821
|
|
|
|
|
|
SvCUR_set(s->sv, s->cur - SvPVX(s->sv)); |
|
140
|
|
|
|
|
|
|
// TODO: SvPV_shrink_to_cur? |
|
141
|
|
|
|
|
|
|
} else { |
|
142
|
4549
|
100
|
|
|
|
|
s->sv = newSVpvn_flags(s->sbuf, s->cur - s->sbuf, s->mortal ? SVs_TEMP : 0); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
5370
|
100
|
|
|
|
|
if (s->setutf8) SvUTF8_on(s->sv); |
|
145
|
5370
|
|
|
|
|
|
return s->sv; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
#define fustr_init(a,b,c) fustr_init_(aTHX_ a,b,c) |
|
149
|
|
|
|
|
|
|
#define fustr_reserve(a,b) fustr_reserve_(aTHX_ a,b) |
|
150
|
|
|
|
|
|
|
#define fustr_write(a,b,c) fustr_write_(aTHX_ a,b,c) |
|
151
|
|
|
|
|
|
|
#define fustr_write_ch(a,b) fustr_write_ch_(aTHX_ a,b) |
|
152
|
|
|
|
|
|
|
#define fustr_write_buf(a,b) fustr_write_buf_(aTHX_ a,b) |
|
153
|
|
|
|
|
|
|
#define fustr_done(a) fustr_done_(aTHX_ a) |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
|
157
|
|
|
|
|
|
|
#define fu_bswap(bits, out, in) ({ U##bits tmpswap; memcpy(&tmpswap, in, bits>>3); tmpswap = __builtin_bswap##bits(tmpswap); memcpy(out, &tmpswap, bits>>3); }) |
|
158
|
|
|
|
|
|
|
#else |
|
159
|
|
|
|
|
|
|
#define fu_bswap(bits, out, in) memcpy(out, in, bits>>3) |
|
160
|
|
|
|
|
|
|
#endif |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
#define fu_frombeT(T, bits, buf) ({ T tmpval; fu_bswap(bits, &tmpval, buf); tmpval; }) |
|
163
|
|
|
|
|
|
|
#define fu_frombeI(bits, buf) fu_frombeT(I##bits, bits, buf) |
|
164
|
|
|
|
|
|
|
#define fu_frombeU(bits, buf) fu_frombeT(U##bits, bits, buf) |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
#define fu_tobeT(T, bits, out, in) ({ T tmpval = in; fu_bswap(bits, out, &tmpval); }) |
|
167
|
|
|
|
|
|
|
#define fu_tobeI(bits, out, in) fu_tobeT(I##bits, bits, out, in) |
|
168
|
|
|
|
|
|
|
#define fu_tobeU(bits, out, in) fu_tobeT(U##bits, bits, out, in) |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
#define fustr_writebeT(T, bits, s, in) fu_tobeT(T, bits, fustr_write_buf(s, bits>>3), in) |
|
171
|
|
|
|
|
|
|
#define fustr_writebeI(bits, s, in) fustr_writebeT(I##bits, bits, s, in) |
|
172
|
|
|
|
|
|
|
#define fustr_writebeU(bits, s, in) fustr_writebeT(U##bits, bits, s, in) |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
/* Return the difference between two struct timespecs as fractional seconds. */ |
|
176
|
0
|
|
|
|
|
|
static double fu_timediff(const struct timespec *a, const struct timespec *b) { |
|
177
|
0
|
|
|
|
|
|
return ((double)(a->tv_sec - b->tv_sec)) + (double)(a->tv_nsec - b->tv_nsec) / 1000000000.0; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
|
181
|
72
|
|
|
|
|
|
static int fu_hexdig(char x) { |
|
182
|
72
|
50
|
|
|
|
|
return x >= '0' && x <= '9' ? x-'0' : x >= 'A' && x <= 'F' ? x-'A'+10 : x >= 'a' && x <= 'f' ? x-'a'+10 : 0x10000; |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
/* -1 if arg is not a bool, 0 on false, 1 on true */ |
|
188
|
5876
|
|
|
|
|
|
static int fu_2bool(pTHX_ SV *val) { |
|
189
|
5876
|
100
|
|
|
|
|
if (SvIsBOOL(val)) return BOOL_INTERNALS_sv_isbool_true(val) ? 1 : 0; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
190
|
5855
|
100
|
|
|
|
|
if (!SvROK(val)) return -1; |
|
191
|
1074
|
|
|
|
|
|
SV *rv = SvRV(val); |
|
192
|
|
|
|
|
|
|
|
|
193
|
1074
|
100
|
|
|
|
|
if (SvOBJECT(rv)) { |
|
194
|
14
|
|
|
|
|
|
HV *stash = SvSTASH(rv); |
|
195
|
|
|
|
|
|
|
/* Historical: "JSON::XS::Boolean", not used by JSON::XS since 3.0 in 2013 */ |
|
196
|
14
|
100
|
|
|
|
|
if (stash == gv_stashpvs("JSON::PP::Boolean", 0) /* Also covers Types::Serialiser::Boolean and used by a bunch of other modules */ |
|
197
|
12
|
100
|
|
|
|
|
|| stash == gv_stashpvs("boolean", 0) |
|
198
|
10
|
50
|
|
|
|
|
|| stash == gv_stashpvs("Mojo::JSON::_Bool", 0) |
|
199
|
10
|
50
|
|
|
|
|
|| stash == gv_stashpvs("JSON::Tiny::_Bool", 0)) |
|
200
|
4
|
|
|
|
|
|
return !!SvIV(rv); |
|
201
|
10
|
|
|
|
|
|
return -1; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
/* \0 or \1 */ |
|
205
|
1060
|
100
|
|
|
|
|
if (SvTYPE(rv) < SVt_PVAV) { |
|
206
|
8
|
100
|
|
|
|
|
if (SvIOK(rv)) { |
|
207
|
6
|
|
|
|
|
|
IV iv = SvIV(rv); |
|
208
|
6
|
100
|
|
|
|
|
return iv == 0 ? 0 : iv == 1 ? 1 : -1; |
|
|
|
100
|
|
|
|
|
|
|
209
|
2
|
50
|
|
|
|
|
} else if (SvOK(rv)) { |
|
210
|
|
|
|
|
|
|
STRLEN len; |
|
211
|
2
|
|
|
|
|
|
char *str = SvPV_nomg(rv, len); |
|
212
|
2
|
50
|
|
|
|
|
return len != 1 ? -1 : *str == '0' ? 0 : *str == '1' ? 1 : -1; |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
} |
|
215
|
1052
|
|
|
|
|
|
return -1; |
|
216
|
|
|
|
|
|
|
} |