-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathperl-jsonsl.h
339 lines (286 loc) · 8.37 KB
/
perl-jsonsl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#ifndef PERL_JSONSL_H_
#define PERL_JSONSL_H_
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <limits.h>
/**
* Default depth limit to use, if none supplied
*/
#define PLJSONSL_MAX_DEFAULT 512
/**
* Key names for the information returned by
* JSONpointer results
*/
#define PLJSONSL_INFO_KEY_PATH "Path"
#define PLJSONSL_INFO_KEY_VALUE "Value"
#define PLJSONSL_INFO_KEY_QUERY "JSONPointer"
/**
* Names of various perl globs
*/
#define PLJSONSL_CLASS_NAME "JSON::SL"
#define PLJSONSL_BOOLEAN_NAME "JSON::SL::Boolean"
#define PLJSONSL_PLACEHOLDER_NAME "JSON::SL::Placeholder"
#define PLTUBA_CLASS_NAME "JSON::SL::Tuba"
#define PLTUBA_HKEY_NAME "_TUBA"
#if PERL_VERSION >= 10
#define PLJSONSL_HAVE_HV_COMMON
#else
#warning "You are using a Perl from the stone age. This code might work.."
#endif /* 5.10.0 */
/**
* Extended fields for a stack state
* sv: the raw SV (never a reference)
* u_loc.idx / u_loc.key: the numerical index or the HE key, depending
* on parent type.
* matchres: the result of the last match
* matchjpr: the jsonsl_jpr_t object (assuming a successful match [COMPLETE] )
*/
#define JSONSL_STATE_USER_FIELDS \
SV *sv; \
union { \
int idx; \
HE *key; \
} u_loc; \
int matchres; \
int uescapes; \
jsonsl_jpr_t matchjpr;
/**
* We take advantage of the JSONSL_API and make all symbols
* non-exportable
*/
#define JSONSL_API static
#include "jsonsl/jsonsl.h"
#include "jsonsl/jsonsl.c"
/**
* For threaded perls, this stores the THX/my_perl context
* inside the object's pl_thx field. For non threaded perls,
* this is a nop.
*/
#ifndef tTHX
#define tTHX PerlInterpreter*
#endif
#ifdef PERL_IMPLICIT_CONTEXT
#define PLJSONSL_dTHX(pjsn) \
pTHX = (tTHX)pjsn->pl_thx
#define PLJSONSL_mkTHX(pjsn) \
pjsn->pl_thx = my_perl;
#else
#define PLJSONSL_dTHX(pjsn)
#define PLJSONSL_mkTHX(pjsn)
#endif /* PERL_IMPLICIT_CONTEXT */
/*
* This is the 'abstract base class' for both JSON::SL and JSON::SL::Tuba
*/
#define PLJSONSL_COMMON_FIELDS \
/* The lexer */ \
jsonsl_t jsn; \
/* Input buffer */ \
SV *buf; \
/* Start position of the buffer (relative to input stream) */ \
size_t pos_min_valid; \
/* Position of the beginning of the earlist of (SPECIAL,STRINGY) */ \
size_t keep_pos; \
/* Context for threaded Perls */ \
void *pl_thx; \
/* Stash for booleans */ \
HV *stash_boolean; \
/* Escape table */ \
int escape_table[0x80];
/* These are the escapes we care about: */
#define PLJSONSL_ESCTBL_INIT(tbl) \
memset(ESCTBL, 0, sizeof(ESCTBL)); \
tbl['"'] = 1; \
tbl['\\'] = 1; \
tbl['/'] = 1; \
tbl['b'] = 1; \
tbl['n'] = 1; \
tbl['r'] = 1; \
tbl['f'] = 1; \
tbl['u'] = 1; \
tbl['t'] = 1;
typedef struct {
PLJSONSL_COMMON_FIELDS
/* Root perl data structure. This is either an HV* or AV* */
SV *root;
/**
* "current" hash key. This is always a pointer to an HE* of an existing
* hash entry, and thus should never be freed/destroyed directly.
* This variable should only be non-null during until the next PUSH
* callback
*/
HE *curhk;
#ifndef PLJSONSL_HAVE_HV_COMMON
/**
* For older perls not exposing hv_common, we need a key sv.
* make this as efficient as possible. Instead of instantiating a new
* SV each time for hv_fetch_ent, we keep one cached, and change its
* PV slot as needed. I am able to do this because I have looked at 5.8's
* implementation for the hv_* methods in hv.c and unless the hash is magical,
* the behavior is to simply extract the PV from the SV in the beginning
* anyway.
*/
SV *ksv;
char *ksv_origpv;
#endif
struct {
int utf8; /** Set the SvUTF8 flag */
int nopath; /** Don't include path context in results */
int noqstr; /** Don't include original query string in results */
int max_size; /** maximum input size (from JSON::XS) */
/* ignore the jsonpointer settings and allow an 'iv-drip' of
* objects to be returned via feed */
int object_drip;
/** Callback to invoke when root object is about to be destroyed */
SV *root_callback;
} options;
/**
* Private options
*/
struct {
/* whether this is the 'global' JSON::SL object used
* for decode_json()
*/
int is_global;
} priv_global;
/**
* If we allocate a bunch of JPR objects, keep a reference to
* them here in order to destroy them along with ourselves.
*/
jsonsl_jpr_t *jprs;
size_t njprs;
/**
* This is the 'result stack'
*/
AV *results;
/**
* Escape preferences
*/
} PLJSONSL;
#define PLTUBA_XCALLBACK \
JSONSL_XTYPE \
X(DATA, 'c') \
X(ERROR, '!') \
X(JSON, 'D') \
X(NUMBER, '=') \
X(BOOLEAN, '?') \
X(NULL, '~') \
X(ANY, '.') \
typedef enum {
#define X(o,c) \
PLTUBA_CALLBACK_##o = c,
PLTUBA_XCALLBACK
#undef X
PLTUBA_CALLBACK_blah
} pltuba_callback_type;
#define PLTUBA_ACTION_ON '>'
#define PLTUBA_DEFINE_XMETHGV
#include "srcout/tuba_dispatch_getmeth.h"
#undef PLTUBA_DEFINE_XMETHGV
/* These are stringified as the 'Info' keys */
#define PLTUBA_XPARAMS \
X(Escaped) \
X(Key) \
X(Type) \
X(Mode) \
X(Value) \
X(Index)
/**
* This can be considered to be a 'subset' of the
* PLJSONSL structure, but with some slight subtleties and
* differences.
*/
struct pltuba_param_entry_st {
HE *he;
SV *sv;
};
typedef struct {
PLJSONSL_COMMON_FIELDS
/* When we invoke a callback, instead of re-creating the
* mortalized rv each time, we just keep a static reference
* to ourselves
*/
SV *selfrv;
/* This is last known stash for our methods.
* In the rare event that someone decides to rebless
* us into a different class, we compare and swap out
* in favor of the new one (SvSTASH(SvRV(tuba->selfrv)));
*/
HV *last_stash;
/* set by hkey and string callbacks */
int shift_quote;
/* Options */
struct {
int utf8;
int no_cache_mro;
int accum_kv;
int cb_unified;
int allow_unhandled;
} options;
#define PLTUBA_METHGV_STRUCT
#include "srcout/tuba_dispatch_getmeth.h"
#undef PLTUBA_METHGV_STRUCT
/* The accumulators */
SV *accum;
SV *kaccum;
/**
* The following structures contain registers for the
* HEs which are hash entries for the info hash, and the
* corresponding SVs which they contain.
*/
struct {
#define X(vname) \
struct pltuba_param_entry_st pe_##vname;
PLTUBA_XPARAMS
#undef X
} p_ents;
/* Our info hash, and its reference */
HV *paramhv;
SV *paramhvrv;
/* Table of various callbacks to invoke */
int accum_options[0x100];
} PLTUBA;
/**
* These macros manipulate the static entries within the hash
* which is passed into callbacks.
* There are two primary variables to work with:
* 1) The actual static SV which contains the value
* 2) The HE which points to the SV
*
* And three operations
* 1) Assigning the value to the SV
* 2) Tying the HE with the SV, so a lookup on the hash
* entry yields the SV
* 3) Decoupling the HE and the SV, so the SV remains allocated
* but the HE will now point to &PL_sv_placeholder and not yield
* a result.
*/
#define PLTUBA_PARAM_FIELD(tuba, b) \
(tuba->p_ents.pe_##b)
/**
* Assign an SV to the named field. The HE is made to point to the SV
*/
#define PLTUBA_SET_PARAMFIELDS_sv(tuba, field, sv) \
HeVAL(PLTUBA_PARAM_FIELD(tuba,field).he) = sv;
/**
* Convenience macro which assigns the SV to the HE, and then sets
* the IVX slot.
*/
#define PLTUBA_SET_PARAMFIELDS_iv(tuba, field, iv) \
/* assign the IV */ \
assert(PLTUBA_PARAM_FIELD(tuba,field).sv); \
assert(SvIOK(PLTUBA_PARAM_FIELD(tuba,field).sv)); \
SvIVX(PLTUBA_PARAM_FIELD(tuba, field).sv) = iv; \
/* set the he's value to the just-assigned sv */ \
PLTUBA_SET_PARAMFIELDS_sv(tuba, field, PLTUBA_PARAM_FIELD(tuba,field).sv)
#define PLTUBA_SET_PARAMFIELDS_dv(tuba, field, c) \
PLTUBA_SET_PARAMFIELDS_iv(tuba, field, c); \
*SvPVX(PLTUBA_PARAM_FIELD(tuba,field).sv) = (char)c; \
/**
* Sets the HE to point to &PL_sv_placeholder.
*/
#define PLTUBA_RESET_PARAMFIELD(tuba, field) \
HeVAL(PLTUBA_PARAM_FIELD(tuba, field).he) = &PL_sv_placeholder;
#endif /* PERL_JSONSL_H_ */