agoo 2.5.4 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/bin/agoo +3 -1
- data/ext/agoo/base64.h +3 -3
- data/ext/agoo/bind.c +1 -1
- data/ext/agoo/bind.h +3 -3
- data/ext/agoo/con.c +4 -2
- data/ext/agoo/con.h +3 -3
- data/ext/agoo/debug.c +7 -0
- data/ext/agoo/debug.h +13 -6
- data/ext/agoo/doc.c +159 -0
- data/ext/agoo/doc.h +34 -0
- data/ext/agoo/dtime.h +3 -3
- data/ext/agoo/err.h +3 -3
- data/ext/agoo/error_stream.h +3 -3
- data/ext/agoo/extconf.rb +1 -1
- data/ext/agoo/gqlintro.c +333 -0
- data/ext/agoo/gqlintro.h +10 -0
- data/ext/agoo/gqlvalue.c +1035 -0
- data/ext/agoo/gqlvalue.h +88 -0
- data/ext/agoo/graphql.c +1078 -0
- data/ext/agoo/graphql.h +198 -0
- data/ext/agoo/hook.c +2 -0
- data/ext/agoo/hook.h +4 -3
- data/ext/agoo/http.c +2 -1
- data/ext/agoo/http.h +3 -3
- data/ext/agoo/kinds.h +3 -3
- data/ext/agoo/log.h +3 -3
- data/ext/agoo/log_queue.h +3 -3
- data/ext/agoo/method.h +3 -3
- data/ext/agoo/page.h +3 -3
- data/ext/agoo/pub.h +3 -3
- data/ext/agoo/queue.h +3 -3
- data/ext/agoo/rack_logger.h +3 -3
- data/ext/agoo/req.c +2 -2
- data/ext/agoo/req.h +3 -3
- data/ext/agoo/request.h +3 -3
- data/ext/agoo/res.h +3 -3
- data/ext/agoo/response.h +3 -3
- data/ext/agoo/rhook.c +2 -2
- data/ext/agoo/rhook.h +4 -3
- data/ext/agoo/rlog.h +3 -3
- data/ext/agoo/rresponse.h +3 -3
- data/ext/agoo/rserver.c +64 -0
- data/ext/agoo/rserver.h +3 -3
- data/ext/agoo/rupgraded.c +1 -1
- data/ext/agoo/rupgraded.h +3 -3
- data/ext/agoo/sdl.c +334 -0
- data/ext/agoo/sdl.h +10 -0
- data/ext/agoo/seg.h +3 -3
- data/ext/agoo/server.c +3 -1
- data/ext/agoo/server.h +5 -4
- data/ext/agoo/sha1.h +3 -3
- data/ext/agoo/sse.h +3 -3
- data/ext/agoo/sub.h +3 -3
- data/ext/agoo/subject.h +3 -3
- data/ext/agoo/text.h +3 -3
- data/ext/agoo/upgraded.h +3 -3
- data/ext/agoo/websocket.h +3 -3
- data/lib/agoo/version.rb +1 -1
- data/lib/rack/handler/agoo.rb +3 -1
- metadata +12 -12
- data/ext/agoo/foo/agoo.c +0 -109
- data/ext/agoo/foo/con.c +0 -1220
- data/ext/agoo/foo/con.h +0 -65
- data/ext/agoo/foo/page.c +0 -699
- data/ext/agoo/foo/pub.c +0 -131
- data/ext/agoo/foo/pub.h +0 -40
- data/ext/agoo/foo/rserver.c +0 -1016
- data/ext/agoo/foo/server.c +0 -303
- data/ext/agoo/foo/server.h +0 -67
- data/ext/agoo/foo/upgraded.c +0 -182
data/ext/agoo/gqlintro.h
ADDED
data/ext/agoo/gqlvalue.c
ADDED
@@ -0,0 +1,1035 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <time.h>
|
7
|
+
|
8
|
+
#include "debug.h"
|
9
|
+
#include "gqlvalue.h"
|
10
|
+
#include "graphql.h"
|
11
|
+
|
12
|
+
static const char spaces[256] = "\n ";
|
13
|
+
|
14
|
+
// Int type
|
15
|
+
static Text
|
16
|
+
null_to_text(Text text, gqlValue value, int indent, int depth) {
|
17
|
+
return text_append(text, "null", 4);
|
18
|
+
}
|
19
|
+
|
20
|
+
struct _gqlType gql_null_type = {
|
21
|
+
.name = "Null",
|
22
|
+
.desc = "Null scalar.",
|
23
|
+
.kind = GQL_SCALAR,
|
24
|
+
.locked = true,
|
25
|
+
.core = true,
|
26
|
+
.coerce = NULL,
|
27
|
+
.destroy = NULL,
|
28
|
+
.to_json = null_to_text,
|
29
|
+
};
|
30
|
+
|
31
|
+
// Int type
|
32
|
+
static Text
|
33
|
+
int_to_text(Text text, gqlValue value, int indent, int depth) {
|
34
|
+
char num[32];
|
35
|
+
int cnt;
|
36
|
+
|
37
|
+
cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i);
|
38
|
+
|
39
|
+
return text_append(text, num, cnt);
|
40
|
+
}
|
41
|
+
|
42
|
+
struct _gqlType gql_int_type = {
|
43
|
+
.name = "Int",
|
44
|
+
.desc = "Int scalar.",
|
45
|
+
.kind = GQL_SCALAR,
|
46
|
+
.locked = true,
|
47
|
+
.core = true,
|
48
|
+
.coerce = NULL,
|
49
|
+
.destroy = NULL,
|
50
|
+
.to_json = int_to_text,
|
51
|
+
};
|
52
|
+
|
53
|
+
// I64 type, add on type.
|
54
|
+
static Text
|
55
|
+
i64_to_text(Text text, gqlValue value, int indent, int depth) {
|
56
|
+
char num[32];
|
57
|
+
int cnt;
|
58
|
+
|
59
|
+
cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i64);
|
60
|
+
|
61
|
+
return text_append(text, num, cnt);
|
62
|
+
}
|
63
|
+
|
64
|
+
struct _gqlType gql_i64_type = {
|
65
|
+
.name = "I64",
|
66
|
+
.desc = "64 bit integer scalar.",
|
67
|
+
.kind = GQL_SCALAR,
|
68
|
+
.locked = true,
|
69
|
+
.core = true,
|
70
|
+
.coerce = NULL,
|
71
|
+
.destroy = NULL,
|
72
|
+
.to_json = i64_to_text,
|
73
|
+
};
|
74
|
+
|
75
|
+
// String type
|
76
|
+
static void
|
77
|
+
string_destroy(gqlValue value) {
|
78
|
+
free((char*)value->str);
|
79
|
+
}
|
80
|
+
|
81
|
+
static Text string_to_text(Text text, gqlValue value, int indent, int depth);
|
82
|
+
|
83
|
+
struct _gqlType gql_string_type = {
|
84
|
+
.name = "String",
|
85
|
+
.desc = "String scalar.",
|
86
|
+
.kind = GQL_SCALAR,
|
87
|
+
.locked = true,
|
88
|
+
.core = true,
|
89
|
+
.coerce = NULL,
|
90
|
+
.destroy = string_destroy,
|
91
|
+
.to_json = string_to_text,
|
92
|
+
};
|
93
|
+
|
94
|
+
// Alternative to String but with no destroy needed.
|
95
|
+
struct _gqlType gql_str16_type = { // unregistered
|
96
|
+
.name = "str16",
|
97
|
+
.desc = NULL,
|
98
|
+
.kind = GQL_SCALAR,
|
99
|
+
.locked = true,
|
100
|
+
.core = true,
|
101
|
+
.coerce = NULL,
|
102
|
+
.destroy = NULL,
|
103
|
+
.to_json = string_to_text,
|
104
|
+
};
|
105
|
+
|
106
|
+
static Text
|
107
|
+
string_to_text(Text text, gqlValue value, int indent, int depth) {
|
108
|
+
if (&gql_str16_type == value->type) {
|
109
|
+
text = text_append(text, "\"", 1);
|
110
|
+
text = text_append(text, value->str16, -1);
|
111
|
+
text = text_append(text, "\"", 1);
|
112
|
+
} else if (NULL == value->str) {
|
113
|
+
text = text_append(text, "null", 4);
|
114
|
+
} else {
|
115
|
+
text = text_append(text, "\"", 1);
|
116
|
+
text = text_append(text, value->str, -1);
|
117
|
+
text = text_append(text, "\"", 1);
|
118
|
+
}
|
119
|
+
return text;
|
120
|
+
}
|
121
|
+
|
122
|
+
// Bool type
|
123
|
+
static Text
|
124
|
+
bool_to_text(Text text, gqlValue value, int indent, int depth) {
|
125
|
+
if (value->b) {
|
126
|
+
text = text_append(text, "true", 4);
|
127
|
+
} else {
|
128
|
+
text = text_append(text, "false", 5);
|
129
|
+
}
|
130
|
+
return text;
|
131
|
+
}
|
132
|
+
|
133
|
+
struct _gqlType gql_bool_type = {
|
134
|
+
.name = "Boolean",
|
135
|
+
.desc = "Boolean scalar.",
|
136
|
+
.kind = GQL_SCALAR,
|
137
|
+
.locked = true,
|
138
|
+
.core = true,
|
139
|
+
.coerce = NULL,
|
140
|
+
.destroy = NULL,
|
141
|
+
.to_json = bool_to_text,
|
142
|
+
};
|
143
|
+
|
144
|
+
// Float type
|
145
|
+
static Text
|
146
|
+
float_to_text(Text text, gqlValue value, int indent, int depth) {
|
147
|
+
char num[32];
|
148
|
+
int cnt;
|
149
|
+
|
150
|
+
cnt = snprintf(num, sizeof(num), "%g", value->f);
|
151
|
+
|
152
|
+
return text_append(text, num, cnt);
|
153
|
+
}
|
154
|
+
|
155
|
+
struct _gqlType gql_float_type = {
|
156
|
+
.name = "Float",
|
157
|
+
.desc = "Float scalar.",
|
158
|
+
.kind = GQL_SCALAR,
|
159
|
+
.locked = true,
|
160
|
+
.core = true,
|
161
|
+
.coerce = NULL,
|
162
|
+
.destroy = NULL,
|
163
|
+
.to_json = float_to_text,
|
164
|
+
};
|
165
|
+
|
166
|
+
// Time type
|
167
|
+
static const char*
|
168
|
+
read_num(const char *s, int len, int *vp) {
|
169
|
+
uint32_t v = 0;
|
170
|
+
|
171
|
+
for (; 0 < len; len--, s++) {
|
172
|
+
if ('0' <= *s && *s <= '9') {
|
173
|
+
v = v * 10 + *s - '0';
|
174
|
+
} else {
|
175
|
+
return NULL;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
*vp = (int)v;
|
179
|
+
|
180
|
+
return s;
|
181
|
+
}
|
182
|
+
|
183
|
+
static const char*
|
184
|
+
read_zone(const char *s, int *vp) {
|
185
|
+
int hr;
|
186
|
+
int min;
|
187
|
+
|
188
|
+
if (NULL == (s = read_num(s, 2, &hr))) {
|
189
|
+
return NULL;
|
190
|
+
}
|
191
|
+
if (':' != *s) {
|
192
|
+
return NULL;
|
193
|
+
}
|
194
|
+
s++;
|
195
|
+
if (NULL == (s = read_num(s, 2, &min))) {
|
196
|
+
return NULL;
|
197
|
+
}
|
198
|
+
*vp = hr * 60 + min;
|
199
|
+
|
200
|
+
return s;
|
201
|
+
}
|
202
|
+
|
203
|
+
static int64_t
|
204
|
+
time_parse(Err err, const char *str, int len) {
|
205
|
+
const char *s = str;
|
206
|
+
const char *end;
|
207
|
+
struct tm tm;
|
208
|
+
bool neg = false;
|
209
|
+
uint64_t nsecs = 0;
|
210
|
+
int i = 9;
|
211
|
+
int64_t secs;
|
212
|
+
|
213
|
+
if (0 > len) {
|
214
|
+
len = (int)strlen(str);
|
215
|
+
}
|
216
|
+
if (len < 10 || 36 < len) {
|
217
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
218
|
+
return 0;
|
219
|
+
}
|
220
|
+
end = str + len;
|
221
|
+
memset(&tm, 0, sizeof(tm));
|
222
|
+
if ('-' == *s) {
|
223
|
+
s++;
|
224
|
+
neg = true;
|
225
|
+
}
|
226
|
+
if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
|
227
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
228
|
+
return 0;
|
229
|
+
}
|
230
|
+
if (neg) {
|
231
|
+
tm.tm_year = -tm.tm_year;
|
232
|
+
neg = false;
|
233
|
+
}
|
234
|
+
tm.tm_year -= 1900;
|
235
|
+
if ('-' != *s) {
|
236
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
237
|
+
return 0;
|
238
|
+
}
|
239
|
+
s++;
|
240
|
+
|
241
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
|
242
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
243
|
+
return 0;
|
244
|
+
}
|
245
|
+
tm.tm_mon--;
|
246
|
+
if ('-' != *s) {
|
247
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
248
|
+
return 0;
|
249
|
+
}
|
250
|
+
s++;
|
251
|
+
|
252
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
|
253
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
254
|
+
return 0;
|
255
|
+
}
|
256
|
+
|
257
|
+
// If that's the end then pass back the date as a unix time.
|
258
|
+
if (end == s) {
|
259
|
+
return (int64_t)timegm(&tm) * 1000000000LL;
|
260
|
+
}
|
261
|
+
switch (*s++) {
|
262
|
+
case 'Z':
|
263
|
+
if (s == end) {
|
264
|
+
return (int64_t)timegm(&tm) * 1000000000LL;
|
265
|
+
}
|
266
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
267
|
+
return 0;
|
268
|
+
case '-':
|
269
|
+
neg = true;
|
270
|
+
// fall through
|
271
|
+
case '+': {
|
272
|
+
int v = 0;
|
273
|
+
|
274
|
+
if (NULL == (s = read_zone(s, &v))) {
|
275
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
276
|
+
return 0;
|
277
|
+
}
|
278
|
+
if (neg) {
|
279
|
+
v = -v;
|
280
|
+
}
|
281
|
+
if (s == end) {
|
282
|
+
return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL;
|
283
|
+
}
|
284
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
285
|
+
return 0;
|
286
|
+
}
|
287
|
+
case 'T':
|
288
|
+
break;
|
289
|
+
default:
|
290
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
291
|
+
return 0;
|
292
|
+
}
|
293
|
+
// T encountered, need space for time and zone
|
294
|
+
if (end - s < 9) {
|
295
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
296
|
+
return 0;
|
297
|
+
}
|
298
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
|
299
|
+
return 0;
|
300
|
+
}
|
301
|
+
if (':' != *s) {
|
302
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
303
|
+
return 0;
|
304
|
+
}
|
305
|
+
s++;
|
306
|
+
|
307
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
|
308
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
309
|
+
return 0;
|
310
|
+
}
|
311
|
+
if (':' != *s) {
|
312
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
313
|
+
return 0;
|
314
|
+
}
|
315
|
+
s++;
|
316
|
+
|
317
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
|
318
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
319
|
+
return 0;
|
320
|
+
}
|
321
|
+
switch (*s++) {
|
322
|
+
case 'Z':
|
323
|
+
if (s == end) {
|
324
|
+
return (int64_t)timegm(&tm) * 1000000000LL;
|
325
|
+
}
|
326
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
327
|
+
return 0;
|
328
|
+
case '-':
|
329
|
+
neg = true;
|
330
|
+
// fall through
|
331
|
+
case '+': {
|
332
|
+
int v = 0;
|
333
|
+
|
334
|
+
if (end - s < 5) {
|
335
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
336
|
+
return 0;
|
337
|
+
}
|
338
|
+
if (NULL == (s = read_zone(s, &v))) {
|
339
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
340
|
+
return 0;
|
341
|
+
}
|
342
|
+
if (neg) {
|
343
|
+
v = -v;
|
344
|
+
}
|
345
|
+
if (s == end) {
|
346
|
+
return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL;
|
347
|
+
}
|
348
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
349
|
+
return 0;
|
350
|
+
}
|
351
|
+
case '.':
|
352
|
+
break;
|
353
|
+
default:
|
354
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
355
|
+
return 0;
|
356
|
+
}
|
357
|
+
for (; 0 < i; i--, s++) {
|
358
|
+
if (end <= s) {
|
359
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
360
|
+
return 0;
|
361
|
+
}
|
362
|
+
if ('0' <= *s && *s <= '9') {
|
363
|
+
nsecs = nsecs * 10 + *s - '0';
|
364
|
+
} else {
|
365
|
+
break;
|
366
|
+
}
|
367
|
+
}
|
368
|
+
for (; 0 < i; i--) {
|
369
|
+
nsecs *= 10;
|
370
|
+
}
|
371
|
+
switch (*s++) {
|
372
|
+
case 'Z':
|
373
|
+
if (s == end) {
|
374
|
+
break;
|
375
|
+
}
|
376
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
377
|
+
return 0;
|
378
|
+
case '-':
|
379
|
+
neg = true;
|
380
|
+
// fall through
|
381
|
+
case '+': {
|
382
|
+
int v = 0;
|
383
|
+
|
384
|
+
if (end - s < 5) {
|
385
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
386
|
+
return 0;
|
387
|
+
}
|
388
|
+
if (NULL == (s = read_zone(s, &v))) {
|
389
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
390
|
+
return 0;
|
391
|
+
}
|
392
|
+
if (neg) {
|
393
|
+
v = -v;
|
394
|
+
}
|
395
|
+
if (s == end) {
|
396
|
+
return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL + nsecs;
|
397
|
+
}
|
398
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
399
|
+
return 0;
|
400
|
+
}
|
401
|
+
default:
|
402
|
+
if (s != end) {
|
403
|
+
err_set(err, ERR_PARSE, "Invalid time format.");
|
404
|
+
return 0;
|
405
|
+
}
|
406
|
+
}
|
407
|
+
if (0 <= (secs = (int64_t)timegm(&tm) * 1000000000LL)) {
|
408
|
+
return secs + nsecs;
|
409
|
+
}
|
410
|
+
return secs - nsecs;
|
411
|
+
}
|
412
|
+
|
413
|
+
static Text
|
414
|
+
time_to_text(Text text, gqlValue value, int indent, int depth) {
|
415
|
+
char str[64];
|
416
|
+
int cnt;
|
417
|
+
struct tm tm;
|
418
|
+
int64_t tt = value->time;
|
419
|
+
time_t t = (time_t)(tt / 1000000000LL);
|
420
|
+
long nsecs = tt - (int64_t)t * 1000000000LL;
|
421
|
+
|
422
|
+
if (0 > nsecs) {
|
423
|
+
nsecs = -nsecs;
|
424
|
+
}
|
425
|
+
gmtime_r(&t, &tm);
|
426
|
+
cnt = sprintf(str, "\"%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ\"",
|
427
|
+
1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
|
428
|
+
tm.tm_hour, tm.tm_min, tm.tm_sec, (long)nsecs);
|
429
|
+
|
430
|
+
return text_append(text, str, cnt);
|
431
|
+
}
|
432
|
+
|
433
|
+
struct _gqlType gql_time_type = {
|
434
|
+
.name = "Time",
|
435
|
+
.desc = "Time zulu scalar.",
|
436
|
+
.kind = GQL_SCALAR,
|
437
|
+
.locked = true,
|
438
|
+
.core = true,
|
439
|
+
.coerce = NULL,
|
440
|
+
.destroy = NULL,
|
441
|
+
.to_json = time_to_text,
|
442
|
+
};
|
443
|
+
|
444
|
+
// Uuid type
|
445
|
+
static int
|
446
|
+
hexVal(int c) {
|
447
|
+
int h = -1;
|
448
|
+
|
449
|
+
if ('0' <= c && c <= '9') {
|
450
|
+
h = c - '0';
|
451
|
+
} else if ('a' <= c && c <= 'f') {
|
452
|
+
h = c - 'a' + 10;
|
453
|
+
} else if ('A' <= c && c <= 'F') {
|
454
|
+
h = c - 'A' + 10;
|
455
|
+
}
|
456
|
+
return h;
|
457
|
+
}
|
458
|
+
|
459
|
+
// 123e4567-e89b-12d3-a456-426655440000
|
460
|
+
static int
|
461
|
+
parse_uuid(Err err, const char *str, int len, uint64_t *hip, uint64_t *lop) {
|
462
|
+
uint64_t hi = 0;
|
463
|
+
uint64_t lo = 0;
|
464
|
+
int i;
|
465
|
+
int n;
|
466
|
+
|
467
|
+
if (0 >= len) {
|
468
|
+
len = (int)strlen(str);
|
469
|
+
}
|
470
|
+
if (36 != len || '-' != str[8] || '-' != str[13] || '-' != str[18] || '-' != str[23]) {
|
471
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
472
|
+
}
|
473
|
+
for (i = 0; i < 8; i++, str++) {
|
474
|
+
if (0 > (n = hexVal(*str))) {
|
475
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
476
|
+
}
|
477
|
+
hi = (hi << 4) + n;
|
478
|
+
}
|
479
|
+
str++;
|
480
|
+
for (i = 0; i < 4; i++, str++) {
|
481
|
+
if (0 > (n = hexVal(*str))) {
|
482
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
483
|
+
}
|
484
|
+
hi = (hi << 4) + n;
|
485
|
+
}
|
486
|
+
str++;
|
487
|
+
for (i = 0; i < 4; i++, str++) {
|
488
|
+
if (0 > (n = hexVal(*str))) {
|
489
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
490
|
+
}
|
491
|
+
hi = (hi << 4) + n;
|
492
|
+
}
|
493
|
+
str++;
|
494
|
+
for (i = 0; i < 4; i++, str++) {
|
495
|
+
if (0 > (n = hexVal(*str))) {
|
496
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
497
|
+
}
|
498
|
+
lo = (lo << 4) + n;
|
499
|
+
}
|
500
|
+
str++;
|
501
|
+
for (i = 0; i < 12; i++, str++) {
|
502
|
+
if (0 > (n = hexVal(*str))) {
|
503
|
+
return err_set(err, ERR_PARSE, "not UUID format");
|
504
|
+
}
|
505
|
+
lo = (lo << 4) + n;
|
506
|
+
}
|
507
|
+
*hip = hi;
|
508
|
+
*lop = lo;
|
509
|
+
|
510
|
+
return ERR_OK;
|
511
|
+
}
|
512
|
+
|
513
|
+
static Text
|
514
|
+
uuid_to_text(Text text, gqlValue value, int indent, int depth) {
|
515
|
+
char str[64];
|
516
|
+
int cnt = sprintf(str, "\"%08lx-%04lx-%04lx-%04lx-%012lx\"",
|
517
|
+
(unsigned long)(value->uuid.hi >> 32),
|
518
|
+
(unsigned long)((value->uuid.hi >> 16) & 0x000000000000FFFFUL),
|
519
|
+
(unsigned long)(value->uuid.hi & 0x000000000000FFFFUL),
|
520
|
+
(unsigned long)(value->uuid.lo >> 48),
|
521
|
+
(unsigned long)(value->uuid.lo & 0x0000FFFFFFFFFFFFUL));
|
522
|
+
|
523
|
+
return text_append(text, str, cnt);
|
524
|
+
}
|
525
|
+
|
526
|
+
struct _gqlType gql_uuid_type = {
|
527
|
+
.name = "Uuid",
|
528
|
+
.desc = "UUID scalar.",
|
529
|
+
.kind = GQL_SCALAR,
|
530
|
+
.locked = true,
|
531
|
+
.core = true,
|
532
|
+
.coerce = NULL,
|
533
|
+
.destroy = NULL,
|
534
|
+
.to_json = uuid_to_text,
|
535
|
+
};
|
536
|
+
|
537
|
+
// Url type
|
538
|
+
static void
|
539
|
+
url_destroy(gqlValue value) {
|
540
|
+
free((char*)value->url);
|
541
|
+
}
|
542
|
+
|
543
|
+
static Text
|
544
|
+
url_to_text(Text text, gqlValue value, int indent, int depth) {
|
545
|
+
if (NULL == value->url) {
|
546
|
+
return text_append(text, "null", 4);
|
547
|
+
}
|
548
|
+
text = text_append(text, "\"", 1);
|
549
|
+
text = text_append(text, value->url, -1);
|
550
|
+
text = text_append(text, "\"", 1);
|
551
|
+
|
552
|
+
return text;
|
553
|
+
}
|
554
|
+
|
555
|
+
struct _gqlType gql_url_type = {
|
556
|
+
.name = "Url",
|
557
|
+
.desc = "URL scalar.",
|
558
|
+
.kind = GQL_SCALAR,
|
559
|
+
.locked = true,
|
560
|
+
.core = true,
|
561
|
+
.coerce = NULL,
|
562
|
+
.destroy = url_destroy,
|
563
|
+
.to_json = url_to_text,
|
564
|
+
};
|
565
|
+
|
566
|
+
// List, not visible but used for list values.
|
567
|
+
static void
|
568
|
+
list_destroy(gqlValue value) {
|
569
|
+
gqlLink link;
|
570
|
+
|
571
|
+
while (NULL != (link = value->members)) {
|
572
|
+
value->members = link->next;
|
573
|
+
gql_value_destroy(link->value);
|
574
|
+
DEBUG_ALLOC(mem_graphql_link, link);
|
575
|
+
free(link);
|
576
|
+
}
|
577
|
+
}
|
578
|
+
|
579
|
+
static Text
|
580
|
+
list_to_json(Text text, gqlValue value, int indent, int depth) {
|
581
|
+
int i = indent * depth;
|
582
|
+
int i2 = i + indent;
|
583
|
+
int d2 = depth + 1;
|
584
|
+
gqlLink link;
|
585
|
+
|
586
|
+
if (0 < indent) {
|
587
|
+
i++; // for \n
|
588
|
+
i2++;
|
589
|
+
}
|
590
|
+
if ((int)sizeof(spaces) <= i) {
|
591
|
+
i2 = sizeof(spaces) - 1;
|
592
|
+
i = i2 - indent;
|
593
|
+
}
|
594
|
+
text = text_append(text, "[", 1);
|
595
|
+
for (link = value->members; NULL != link; link = link->next) {
|
596
|
+
text = text_append(text, spaces, i2);
|
597
|
+
text = link->value->type->to_json(text, link->value, indent, d2);
|
598
|
+
if (NULL != link->next) {
|
599
|
+
text = text_append(text, ",", 1);
|
600
|
+
}
|
601
|
+
}
|
602
|
+
if (0 < indent) {
|
603
|
+
text = text_append(text, spaces, i);
|
604
|
+
}
|
605
|
+
text = text_append(text, "]", 1);
|
606
|
+
|
607
|
+
return text;
|
608
|
+
}
|
609
|
+
|
610
|
+
struct _gqlType list_type = { // unregistered
|
611
|
+
.name = "__List",
|
612
|
+
.desc = NULL,
|
613
|
+
.kind = GQL_SCALAR,
|
614
|
+
.locked = true,
|
615
|
+
.core = true,
|
616
|
+
.coerce = NULL,
|
617
|
+
.destroy = list_destroy,
|
618
|
+
.to_json = list_to_json,
|
619
|
+
};
|
620
|
+
|
621
|
+
// Object, not visible but used for object values.
|
622
|
+
static void
|
623
|
+
object_destroy(gqlValue value) {
|
624
|
+
gqlLink link;
|
625
|
+
|
626
|
+
while (NULL != (link = value->members)) {
|
627
|
+
value->members = link->next;
|
628
|
+
gql_value_destroy(link->value);
|
629
|
+
free(link->key);
|
630
|
+
DEBUG_ALLOC(mem_graphql_link, link);
|
631
|
+
free(link);
|
632
|
+
}
|
633
|
+
}
|
634
|
+
|
635
|
+
static Text
|
636
|
+
object_to_json(Text text, gqlValue value, int indent, int depth) {
|
637
|
+
int i = indent * depth;
|
638
|
+
int i2 = i + indent;
|
639
|
+
int d2 = depth + 1;
|
640
|
+
gqlLink link;
|
641
|
+
|
642
|
+
if (0 < indent) {
|
643
|
+
i++; // for \n
|
644
|
+
i2++;
|
645
|
+
}
|
646
|
+
if ((int)sizeof(spaces) <= i) {
|
647
|
+
i2 = sizeof(spaces) - 1;
|
648
|
+
i = i2 - indent;
|
649
|
+
}
|
650
|
+
text = text_append(text, "{", 1);
|
651
|
+
for (link = value->members; NULL != link; link = link->next) {
|
652
|
+
text = text_append(text, spaces, i2);
|
653
|
+
text = text_append(text, "\"", 1);
|
654
|
+
text = text_append(text, link->key, -1);
|
655
|
+
if (0 < indent) {
|
656
|
+
text = text_append(text, "\": ", 3);
|
657
|
+
} else {
|
658
|
+
text = text_append(text, "\":", 2);
|
659
|
+
}
|
660
|
+
text = link->value->type->to_json(text, link->value, indent, d2);
|
661
|
+
if (NULL != link->next) {
|
662
|
+
text = text_append(text, ",", 1);
|
663
|
+
}
|
664
|
+
}
|
665
|
+
if (0 < indent) {
|
666
|
+
text = text_append(text, spaces, i);
|
667
|
+
}
|
668
|
+
text = text_append(text, "}", 1);
|
669
|
+
|
670
|
+
return text;
|
671
|
+
}
|
672
|
+
|
673
|
+
struct _gqlType object_type = { // unregistered
|
674
|
+
.name = "__Object",
|
675
|
+
.desc = NULL,
|
676
|
+
.kind = GQL_SCALAR,
|
677
|
+
.locked = true,
|
678
|
+
.core = true,
|
679
|
+
.coerce = NULL,
|
680
|
+
.destroy = object_destroy,
|
681
|
+
.to_json = object_to_json,
|
682
|
+
};
|
683
|
+
|
684
|
+
////////////////////////////////////////////////////////////////////////////////
|
685
|
+
void
|
686
|
+
gql_value_destroy(gqlValue value) {
|
687
|
+
if (NULL != value->type->destroy) {
|
688
|
+
value->type->destroy(value);
|
689
|
+
}
|
690
|
+
DEBUG_ALLOC(mem_graphql_value, value);
|
691
|
+
free(value);
|
692
|
+
}
|
693
|
+
|
694
|
+
int
|
695
|
+
gql_value_init(Err err) {
|
696
|
+
if (ERR_OK != gql_type_set(err, &gql_int_type) ||
|
697
|
+
ERR_OK != gql_type_set(err, &gql_i64_type) ||
|
698
|
+
ERR_OK != gql_type_set(err, &gql_bool_type) ||
|
699
|
+
ERR_OK != gql_type_set(err, &gql_float_type) ||
|
700
|
+
ERR_OK != gql_type_set(err, &gql_time_type) ||
|
701
|
+
ERR_OK != gql_type_set(err, &gql_uuid_type) ||
|
702
|
+
ERR_OK != gql_type_set(err, &gql_url_type) ||
|
703
|
+
ERR_OK != gql_type_set(err, &gql_string_type)) {
|
704
|
+
return err->code;
|
705
|
+
}
|
706
|
+
return ERR_OK;
|
707
|
+
}
|
708
|
+
|
709
|
+
/// set functions /////////////////////////////////////////////////////////////
|
710
|
+
void
|
711
|
+
gql_int_set(gqlValue value, int32_t i) {
|
712
|
+
value->type = &gql_int_type;
|
713
|
+
value->i = i;
|
714
|
+
}
|
715
|
+
|
716
|
+
void
|
717
|
+
gql_i64_set(gqlValue value, int64_t i) {
|
718
|
+
value->type = &gql_i64_type;
|
719
|
+
value->i64 = i;
|
720
|
+
}
|
721
|
+
|
722
|
+
void
|
723
|
+
gql_string_set(gqlValue value, const char *str, int len) {
|
724
|
+
value->type = &gql_string_type;
|
725
|
+
if (NULL == str) {
|
726
|
+
value->str = NULL;
|
727
|
+
} else {
|
728
|
+
if (0 >= len) {
|
729
|
+
len = (int)strlen(str);
|
730
|
+
}
|
731
|
+
if (len < (int)sizeof(value->str16)) {
|
732
|
+
value->type = &gql_str16_type;
|
733
|
+
strncpy(value->str16, str, len);
|
734
|
+
} else {
|
735
|
+
value->str = strndup(str, len);
|
736
|
+
}
|
737
|
+
}
|
738
|
+
}
|
739
|
+
|
740
|
+
int
|
741
|
+
gql_url_set(Err err, gqlValue value, const char *url, int len) {
|
742
|
+
value->type = &gql_url_type;
|
743
|
+
if (NULL == url) {
|
744
|
+
value->url = NULL;
|
745
|
+
} else {
|
746
|
+
if (0 >= len) {
|
747
|
+
len = (int)strlen(url);
|
748
|
+
}
|
749
|
+
value->url = strndup(url, len);
|
750
|
+
}
|
751
|
+
return ERR_OK;
|
752
|
+
}
|
753
|
+
|
754
|
+
void
|
755
|
+
gql_bool_set(gqlValue value, bool b) {
|
756
|
+
value->b = b;
|
757
|
+
}
|
758
|
+
|
759
|
+
void
|
760
|
+
gql_float_set(gqlValue value, double f) {
|
761
|
+
value->f = f;
|
762
|
+
}
|
763
|
+
|
764
|
+
void
|
765
|
+
gql_time_set(gqlValue value, int64_t t) {
|
766
|
+
value->time = t;
|
767
|
+
}
|
768
|
+
|
769
|
+
int
|
770
|
+
gql_time_str_set(Err err, gqlValue value, const char *str, int len) {
|
771
|
+
if (0 >= len) {
|
772
|
+
len = (int)strlen(str);
|
773
|
+
}
|
774
|
+
value->time = time_parse(err, str, len);
|
775
|
+
|
776
|
+
return err->code;
|
777
|
+
}
|
778
|
+
|
779
|
+
void
|
780
|
+
gql_uuid_set(gqlValue value, uint64_t hi, uint64_t lo) {
|
781
|
+
value->uuid.hi = hi;
|
782
|
+
value->uuid.lo = lo;
|
783
|
+
}
|
784
|
+
|
785
|
+
int
|
786
|
+
gql_uuid_str_set(Err err, gqlValue value, const char *str, int len) {
|
787
|
+
uint64_t hi = 0;
|
788
|
+
uint64_t lo = 0;
|
789
|
+
|
790
|
+
if (ERR_OK != parse_uuid(err, str, len, &hi, &lo)) {
|
791
|
+
return err->code;
|
792
|
+
}
|
793
|
+
value->uuid.hi = hi;
|
794
|
+
value->uuid.lo = lo;
|
795
|
+
|
796
|
+
return ERR_OK;
|
797
|
+
}
|
798
|
+
|
799
|
+
extern void gql_null_set(gqlValue value);
|
800
|
+
|
801
|
+
gqlLink
|
802
|
+
link_create(Err err, gqlValue item) {
|
803
|
+
gqlLink link = (gqlLink)malloc(sizeof(struct _gqlLink));
|
804
|
+
|
805
|
+
if (NULL == link) {
|
806
|
+
err_set(err, ERR_MEMORY, "Failed to allocation memory for a list link.");
|
807
|
+
} else {
|
808
|
+
DEBUG_ALLOC(mem_graphql_link, link);
|
809
|
+
link->next = NULL;
|
810
|
+
link->key = NULL;
|
811
|
+
link->value = item;
|
812
|
+
}
|
813
|
+
return link;
|
814
|
+
}
|
815
|
+
|
816
|
+
int
|
817
|
+
gql_list_append(Err err, gqlValue list, gqlValue item) {
|
818
|
+
gqlLink link = link_create(err, item);
|
819
|
+
|
820
|
+
if (NULL != link) {
|
821
|
+
if (NULL == list->members) {
|
822
|
+
list->members = link;
|
823
|
+
} else {
|
824
|
+
gqlLink last = list->members;
|
825
|
+
|
826
|
+
for (; NULL != last->next; last = last->next) {
|
827
|
+
}
|
828
|
+
last->next = link;
|
829
|
+
}
|
830
|
+
}
|
831
|
+
return ERR_OK;
|
832
|
+
}
|
833
|
+
|
834
|
+
int
|
835
|
+
gql_list_prepend(Err err, gqlValue list, gqlValue item) {
|
836
|
+
gqlLink link = link_create(err, item);
|
837
|
+
|
838
|
+
if (NULL != link) {
|
839
|
+
link->next = list->members;
|
840
|
+
list->members = link;
|
841
|
+
}
|
842
|
+
return ERR_OK;
|
843
|
+
}
|
844
|
+
|
845
|
+
int
|
846
|
+
gql_object_set(Err err, gqlValue obj, const char *key, gqlValue item) {
|
847
|
+
gqlLink link = link_create(err, item);
|
848
|
+
|
849
|
+
if (NULL != link) {
|
850
|
+
link->key = strdup(key);
|
851
|
+
//link->next = obj->members;
|
852
|
+
if (NULL == obj->members) {
|
853
|
+
obj->members = link;
|
854
|
+
} else {
|
855
|
+
gqlLink last = obj->members;
|
856
|
+
|
857
|
+
for (; NULL != last->next; last = last->next) {
|
858
|
+
}
|
859
|
+
last->next = link;
|
860
|
+
}
|
861
|
+
}
|
862
|
+
return ERR_OK;
|
863
|
+
}
|
864
|
+
|
865
|
+
/// create functions //////////////////////////////////////////////////////////
|
866
|
+
|
867
|
+
static gqlValue
|
868
|
+
value_create(gqlType type) {
|
869
|
+
gqlValue v = (gqlValue)malloc(sizeof(struct _gqlValue));
|
870
|
+
|
871
|
+
if (NULL != v) {
|
872
|
+
DEBUG_ALLOC(mem_graphql_value, v);
|
873
|
+
memset(v, 0, sizeof(struct _gqlValue));
|
874
|
+
v->type = type;
|
875
|
+
}
|
876
|
+
return v;
|
877
|
+
}
|
878
|
+
|
879
|
+
gqlValue
|
880
|
+
gql_int_create(Err err, int32_t i) {
|
881
|
+
gqlValue v = value_create(&gql_int_type);
|
882
|
+
|
883
|
+
if (NULL != v) {
|
884
|
+
v->i = i;
|
885
|
+
}
|
886
|
+
return v;
|
887
|
+
}
|
888
|
+
|
889
|
+
gqlValue
|
890
|
+
gql_i64_create(Err err, int64_t i) {
|
891
|
+
gqlValue v = value_create(&gql_i64_type);
|
892
|
+
|
893
|
+
if (NULL != v) {
|
894
|
+
v->i64 = i;
|
895
|
+
}
|
896
|
+
return v;
|
897
|
+
}
|
898
|
+
|
899
|
+
gqlValue
|
900
|
+
gql_string_create(Err err, const char *str, int len) {
|
901
|
+
gqlValue v;
|
902
|
+
|
903
|
+
if (0 >= len) {
|
904
|
+
len = (int)strlen(str);
|
905
|
+
}
|
906
|
+
if ((int)sizeof(v->str16) <= len) {
|
907
|
+
if (NULL != (v = value_create(&gql_string_type))) {
|
908
|
+
v->str = strndup(str, len);
|
909
|
+
}
|
910
|
+
} else {
|
911
|
+
if (NULL != (v = value_create(&gql_str16_type))) {
|
912
|
+
strncpy(v->str16, str, len);
|
913
|
+
v->str16[len] = '\0';
|
914
|
+
}
|
915
|
+
}
|
916
|
+
return v;
|
917
|
+
}
|
918
|
+
|
919
|
+
gqlValue
|
920
|
+
gql_url_create(Err err, const char *url, int len) {
|
921
|
+
gqlValue v = value_create(&gql_url_type);
|
922
|
+
|
923
|
+
if (0 >= len) {
|
924
|
+
len = (int)strlen(url);
|
925
|
+
}
|
926
|
+
if (NULL != v) {
|
927
|
+
v->str = strndup(url, len);
|
928
|
+
}
|
929
|
+
return v;
|
930
|
+
}
|
931
|
+
|
932
|
+
gqlValue
|
933
|
+
gql_bool_create(Err err, bool b) {
|
934
|
+
gqlValue v = value_create(&gql_bool_type);
|
935
|
+
|
936
|
+
if (NULL != v) {
|
937
|
+
v->b = b;
|
938
|
+
}
|
939
|
+
return v;
|
940
|
+
}
|
941
|
+
|
942
|
+
gqlValue
|
943
|
+
gql_float_create(Err err, double f) {
|
944
|
+
gqlValue v = value_create(&gql_float_type);
|
945
|
+
|
946
|
+
if (NULL != v) {
|
947
|
+
v->f = f;
|
948
|
+
}
|
949
|
+
return v;
|
950
|
+
}
|
951
|
+
|
952
|
+
gqlValue
|
953
|
+
gql_time_create(Err err, int64_t t) {
|
954
|
+
gqlValue v = value_create(&gql_time_type);
|
955
|
+
|
956
|
+
if (NULL != v) {
|
957
|
+
v->time = t;
|
958
|
+
}
|
959
|
+
return v;
|
960
|
+
}
|
961
|
+
|
962
|
+
gqlValue
|
963
|
+
gql_time_str_create(Err err, const char *str, int len) {
|
964
|
+
gqlValue v = value_create(&gql_time_type);
|
965
|
+
|
966
|
+
if (NULL != v) {
|
967
|
+
if (0 >= len) {
|
968
|
+
len = (int)strlen(str);
|
969
|
+
}
|
970
|
+
v->time = time_parse(err, str, len);
|
971
|
+
}
|
972
|
+
return v;
|
973
|
+
}
|
974
|
+
|
975
|
+
gqlValue
|
976
|
+
gql_uuid_create(Err err, uint64_t hi, uint64_t lo) {
|
977
|
+
gqlValue v = value_create(&gql_uuid_type);
|
978
|
+
|
979
|
+
if (NULL != v) {
|
980
|
+
v->uuid.hi = hi;
|
981
|
+
v->uuid.lo = lo;
|
982
|
+
}
|
983
|
+
return v;
|
984
|
+
}
|
985
|
+
|
986
|
+
// 123e4567-e89b-12d3-a456-426655440000
|
987
|
+
gqlValue
|
988
|
+
gql_uuid_str_create(Err err, const char *str, int len) {
|
989
|
+
uint64_t hi = 0;
|
990
|
+
uint64_t lo = 0;
|
991
|
+
gqlValue v;
|
992
|
+
|
993
|
+
if (ERR_OK != parse_uuid(err, str, len, &hi, &lo)) {
|
994
|
+
return NULL;
|
995
|
+
}
|
996
|
+
if (NULL != (v = value_create(&gql_uuid_type))) {
|
997
|
+
v->uuid.hi = hi;
|
998
|
+
v->uuid.lo = lo;
|
999
|
+
}
|
1000
|
+
return v;
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
gqlValue
|
1004
|
+
gql_null_create(Err err) {
|
1005
|
+
gqlValue v = value_create(&gql_null_type);
|
1006
|
+
|
1007
|
+
return v;
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
gqlValue
|
1011
|
+
gql_list_create(Err err, gqlType itemType) {
|
1012
|
+
gqlValue v = value_create(&list_type);
|
1013
|
+
|
1014
|
+
if (NULL != v) {
|
1015
|
+
v->members = NULL;
|
1016
|
+
v->member_type = itemType;
|
1017
|
+
}
|
1018
|
+
return v;
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
gqlValue
|
1022
|
+
gql_object_create(Err err) {
|
1023
|
+
gqlValue v = value_create(&object_type);
|
1024
|
+
|
1025
|
+
if (NULL != v) {
|
1026
|
+
v->members = NULL;
|
1027
|
+
v->member_type = NULL;
|
1028
|
+
}
|
1029
|
+
return v;
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
Text
|
1033
|
+
gql_value_json(Text text, gqlValue value, int indent, int depth) {
|
1034
|
+
return value->type->to_json(text, value, indent, depth);
|
1035
|
+
}
|