line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* Type for adding whitespace. */ |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
typedef struct json_s { |
4
|
|
|
|
|
|
|
SV * sv; |
5
|
|
|
|
|
|
|
char * s; |
6
|
|
|
|
|
|
|
STRLEN sl; |
7
|
|
|
|
|
|
|
} |
8
|
|
|
|
|
|
|
json_s_t; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
typedef struct json_ws { |
11
|
|
|
|
|
|
|
SV * news; |
12
|
|
|
|
|
|
|
SV * olds; |
13
|
|
|
|
|
|
|
/* Length of original string. */ |
14
|
|
|
|
|
|
|
STRLEN olds_l; |
15
|
|
|
|
|
|
|
/* Length of new string. */ |
16
|
|
|
|
|
|
|
unsigned int news_l; |
17
|
|
|
|
|
|
|
/* Copy point. */ |
18
|
|
|
|
|
|
|
char * q; |
19
|
|
|
|
|
|
|
/* Origin */ |
20
|
|
|
|
|
|
|
char * p; |
21
|
|
|
|
|
|
|
/* Top of token tree. */ |
22
|
|
|
|
|
|
|
json_token_t * t; |
23
|
|
|
|
|
|
|
/* Token under examination now. */ |
24
|
|
|
|
|
|
|
json_token_t * next; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
/* Whitespace to add before and after. */ |
27
|
|
|
|
|
|
|
char * before[n_json_tokens]; |
28
|
|
|
|
|
|
|
char * after[n_json_tokens]; |
29
|
|
|
|
|
|
|
int array_depth; |
30
|
|
|
|
|
|
|
int object_depth; |
31
|
|
|
|
|
|
|
char * array_indent; |
32
|
|
|
|
|
|
|
char * object_indent; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
json_ws_t; |
35
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
|
static void copy_whitespace (json_ws_t * ws, char * w) |
37
|
|
|
|
|
|
|
{ |
38
|
|
|
|
|
|
|
char * q; |
39
|
0
|
|
|
|
|
|
q = ws->q; |
40
|
0
|
0
|
|
|
|
|
while (*w) { |
41
|
0
|
|
|
|
|
|
*q++ = *w++; |
42
|
|
|
|
|
|
|
} |
43
|
0
|
|
|
|
|
|
ws->q = q; |
44
|
0
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
static INLINE int whitespace_json (json_ws_t * ws) |
47
|
|
|
|
|
|
|
{ |
48
|
|
|
|
|
|
|
/* Copy place. */ |
49
|
|
|
|
|
|
|
char * c; |
50
|
|
|
|
|
|
|
/* Value of q at entry to this routine, used to calculate added |
51
|
|
|
|
|
|
|
length. */ |
52
|
|
|
|
|
|
|
char * qorig; |
53
|
|
|
|
|
|
|
json_token_t * next; |
54
|
|
|
|
|
|
|
char * q; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
q = ws->q; |
57
|
|
|
|
|
|
|
qorig = q; |
58
|
|
|
|
|
|
|
next = ws->next; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
while (next) { |
61
|
|
|
|
|
|
|
/* Copy start of string. */ |
62
|
|
|
|
|
|
|
copy_whitespace (ws, ws->before[next->type]); |
63
|
|
|
|
|
|
|
switch (next->type) { |
64
|
|
|
|
|
|
|
case json_token_object: |
65
|
|
|
|
|
|
|
*q++ = '{'; |
66
|
|
|
|
|
|
|
ws->object_depth++; |
67
|
|
|
|
|
|
|
ws->q = q; |
68
|
|
|
|
|
|
|
q += whitespace_json (ws); |
69
|
|
|
|
|
|
|
ws->object_depth--; |
70
|
|
|
|
|
|
|
*q++ = '}'; |
71
|
|
|
|
|
|
|
break; |
72
|
|
|
|
|
|
|
case json_token_array: |
73
|
|
|
|
|
|
|
*q++ = '['; |
74
|
|
|
|
|
|
|
ws->array_depth++; |
75
|
|
|
|
|
|
|
ws->q = q; |
76
|
|
|
|
|
|
|
q += whitespace_json (ws); |
77
|
|
|
|
|
|
|
ws->object_depth--; |
78
|
|
|
|
|
|
|
*q++ = ']'; |
79
|
|
|
|
|
|
|
break; |
80
|
|
|
|
|
|
|
case json_token_string: |
81
|
|
|
|
|
|
|
case json_token_key: |
82
|
|
|
|
|
|
|
case json_token_literal: |
83
|
|
|
|
|
|
|
case json_token_number: |
84
|
|
|
|
|
|
|
for (c = ws->p + next->start; c <= ws->p + next->end; c++) { |
85
|
|
|
|
|
|
|
*q++ = *c; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
break; |
88
|
|
|
|
|
|
|
case json_token_comma: |
89
|
|
|
|
|
|
|
*q++ = ','; |
90
|
|
|
|
|
|
|
break; |
91
|
|
|
|
|
|
|
case json_token_colon: |
92
|
|
|
|
|
|
|
*q++ = ':'; |
93
|
|
|
|
|
|
|
break; |
94
|
|
|
|
|
|
|
default: |
95
|
|
|
|
|
|
|
croak ("unhandled token type %d", next->type); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
/* Copy end of string. */ |
98
|
|
|
|
|
|
|
c = ws->after[next->type]; |
99
|
|
|
|
|
|
|
while (*c) { |
100
|
|
|
|
|
|
|
*q++ = *c++; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
next = next->next; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
return q - qorig; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
6
|
|
|
|
|
|
static int copy_json (char * p, char * q, json_token_t * t) |
108
|
|
|
|
|
|
|
{ |
109
|
|
|
|
|
|
|
/* Loop variable. */ |
110
|
|
|
|
|
|
|
json_token_t * next; |
111
|
|
|
|
|
|
|
/* Copy place. */ |
112
|
|
|
|
|
|
|
char * c; |
113
|
|
|
|
|
|
|
/* Value of q at entry to this routine, used to calculate added |
114
|
|
|
|
|
|
|
length. */ |
115
|
|
|
|
|
|
|
char * qorig; |
116
|
|
|
|
|
|
|
|
117
|
6
|
|
|
|
|
|
next = t; |
118
|
6
|
|
|
|
|
|
qorig = q; |
119
|
86
|
100
|
|
|
|
|
while (next) { |
120
|
80
|
|
|
|
|
|
switch (next->type) { |
121
|
|
|
|
|
|
|
case json_token_object: |
122
|
5
|
|
|
|
|
|
*q++ = '{'; |
123
|
5
|
|
|
|
|
|
q += copy_json (p, q, next->child); |
124
|
5
|
|
|
|
|
|
*q++ = '}'; |
125
|
5
|
|
|
|
|
|
break; |
126
|
|
|
|
|
|
|
case json_token_array: |
127
|
0
|
|
|
|
|
|
*q++ = '['; |
128
|
0
|
|
|
|
|
|
q += copy_json (p, q, next->child); |
129
|
0
|
|
|
|
|
|
*q++ = ']'; |
130
|
0
|
|
|
|
|
|
break; |
131
|
|
|
|
|
|
|
case json_token_string: |
132
|
|
|
|
|
|
|
case json_token_key: |
133
|
|
|
|
|
|
|
case json_token_literal: |
134
|
|
|
|
|
|
|
case json_token_number: |
135
|
244
|
100
|
|
|
|
|
for (c = p + next->start; c < p + next->end; c++) { |
136
|
206
|
|
|
|
|
|
*q++ = *c; |
137
|
|
|
|
|
|
|
} |
138
|
38
|
|
|
|
|
|
break; |
139
|
|
|
|
|
|
|
case json_token_comma: |
140
|
16
|
|
|
|
|
|
*q++ = ','; |
141
|
16
|
|
|
|
|
|
break; |
142
|
|
|
|
|
|
|
case json_token_colon: |
143
|
21
|
|
|
|
|
|
*q++ = ':'; |
144
|
21
|
|
|
|
|
|
break; |
145
|
|
|
|
|
|
|
default: |
146
|
0
|
|
|
|
|
|
croak ("unhandled token type %d", next->type); |
147
|
|
|
|
|
|
|
} |
148
|
80
|
|
|
|
|
|
next = next->next; |
149
|
|
|
|
|
|
|
} |
150
|
6
|
|
|
|
|
|
return q - qorig; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
/* Remove all the whitespace. */ |
154
|
|
|
|
|
|
|
|
155
|
1
|
|
|
|
|
|
static SV * strip_whitespace (json_token_t * tokens, SV * json) |
156
|
|
|
|
|
|
|
{ |
157
|
|
|
|
|
|
|
SV * stripped; |
158
|
|
|
|
|
|
|
char * p; |
159
|
|
|
|
|
|
|
char * q; |
160
|
|
|
|
|
|
|
/* Original length. */ |
161
|
|
|
|
|
|
|
STRLEN l; |
162
|
|
|
|
|
|
|
/* Length of output. */ |
163
|
|
|
|
|
|
|
unsigned int m; |
164
|
1
|
50
|
|
|
|
|
p = SvPV (json, l); |
165
|
1
|
|
|
|
|
|
stripped = newSV (l); |
166
|
|
|
|
|
|
|
/* Tell Perl it's a string. */ |
167
|
1
|
|
|
|
|
|
SvPOK_on (stripped); |
168
|
|
|
|
|
|
|
/* Set UTF-8 if necessary. */ |
169
|
1
|
50
|
|
|
|
|
if (SvUTF8 (json)) { |
170
|
1
|
|
|
|
|
|
SvUTF8_on (stripped); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
/* Get a pointer to the string inside "stripped". */ |
173
|
1
|
|
|
|
|
|
q = SvPVX (stripped); |
174
|
1
|
|
|
|
|
|
m = copy_json (p, q, tokens); |
175
|
|
|
|
|
|
|
/* Set the length. */ |
176
|
1
|
|
|
|
|
|
SvCUR_set (stripped, m); |
177
|
1
|
|
|
|
|
|
return stripped; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
|
static SV * indent (json_token_t * tokens, SV * json) |
181
|
|
|
|
|
|
|
{ |
182
|
|
|
|
|
|
|
int i; |
183
|
0
|
|
|
|
|
|
json_ws_t j = {0}; |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
j.olds = json; |
186
|
0
|
0
|
|
|
|
|
j.p = SvPV (j.olds, j.olds_l); |
187
|
0
|
|
|
|
|
|
j.t = tokens; |
188
|
0
|
|
|
|
|
|
j.next = tokens; |
189
|
0
|
0
|
|
|
|
|
for (i = 0; i < n_json_tokens; i++) { |
190
|
0
|
|
|
|
|
|
j.before[i] = ""; |
191
|
0
|
|
|
|
|
|
j.after[i] = ""; |
192
|
|
|
|
|
|
|
} |
193
|
0
|
|
|
|
|
|
j.after[json_token_comma] = "\n"; |
194
|
0
|
|
|
|
|
|
j.after[json_token_object] = "\n"; |
195
|
0
|
|
|
|
|
|
j.after[json_token_array] = "\n"; |
196
|
0
|
|
|
|
|
|
return &PL_sv_undef; |
197
|
|
|
|
|
|
|
} |