ffi-nats-core 0.3.0 → 0.3.1
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.
- checksums.yaml +4 -4
- data/ffi-nats-core.gemspec +8 -0
- data/lib/ffi/nats/core/version.rb +1 -1
- data/vendor/cnats/CMakeLists.txt +137 -0
- data/vendor/cnats/adapters/libevent.h +220 -0
- data/vendor/cnats/adapters/libuv.h +472 -0
- data/vendor/cnats/examples/CMakeLists.txt +56 -0
- data/vendor/cnats/examples/asynctimeout.c +83 -0
- data/vendor/cnats/examples/examples.h +322 -0
- data/vendor/cnats/examples/libevent-pub.c +136 -0
- data/vendor/cnats/examples/libevent-sub.c +104 -0
- data/vendor/cnats/examples/libuv-pub.c +120 -0
- data/vendor/cnats/examples/libuv-sub.c +114 -0
- data/vendor/cnats/examples/publisher.c +62 -0
- data/vendor/cnats/examples/queuegroup.c +132 -0
- data/vendor/cnats/examples/replier.c +149 -0
- data/vendor/cnats/examples/requestor.c +75 -0
- data/vendor/cnats/examples/subscriber.c +133 -0
- data/vendor/cnats/src/CMakeLists.txt +31 -0
- data/vendor/cnats/src/asynccb.c +66 -0
- data/vendor/cnats/src/asynccb.h +42 -0
- data/vendor/cnats/src/buf.c +246 -0
- data/vendor/cnats/src/buf.h +116 -0
- data/vendor/cnats/src/comsock.c +474 -0
- data/vendor/cnats/src/comsock.h +81 -0
- data/vendor/cnats/src/conn.c +2725 -0
- data/vendor/cnats/src/conn.h +75 -0
- data/vendor/cnats/src/err.h +31 -0
- data/vendor/cnats/src/gc.h +27 -0
- data/vendor/cnats/src/hash.c +725 -0
- data/vendor/cnats/src/hash.h +141 -0
- data/vendor/cnats/src/include/n-unix.h +56 -0
- data/vendor/cnats/src/include/n-win.h +59 -0
- data/vendor/cnats/src/mem.h +20 -0
- data/vendor/cnats/src/msg.c +155 -0
- data/vendor/cnats/src/msg.h +43 -0
- data/vendor/cnats/src/nats.c +1734 -0
- data/vendor/cnats/src/nats.h +2024 -0
- data/vendor/cnats/src/natsp.h +518 -0
- data/vendor/cnats/src/natstime.c +79 -0
- data/vendor/cnats/src/natstime.h +27 -0
- data/vendor/cnats/src/nuid.c +265 -0
- data/vendor/cnats/src/nuid.h +21 -0
- data/vendor/cnats/src/opts.c +1030 -0
- data/vendor/cnats/src/opts.h +19 -0
- data/vendor/cnats/src/parser.c +869 -0
- data/vendor/cnats/src/parser.h +87 -0
- data/vendor/cnats/src/pub.c +293 -0
- data/vendor/cnats/src/srvpool.c +380 -0
- data/vendor/cnats/src/srvpool.h +71 -0
- data/vendor/cnats/src/stats.c +54 -0
- data/vendor/cnats/src/stats.h +21 -0
- data/vendor/cnats/src/status.c +60 -0
- data/vendor/cnats/src/status.h +95 -0
- data/vendor/cnats/src/sub.c +956 -0
- data/vendor/cnats/src/sub.h +34 -0
- data/vendor/cnats/src/timer.c +86 -0
- data/vendor/cnats/src/timer.h +57 -0
- data/vendor/cnats/src/unix/cond.c +103 -0
- data/vendor/cnats/src/unix/mutex.c +107 -0
- data/vendor/cnats/src/unix/sock.c +105 -0
- data/vendor/cnats/src/unix/thread.c +162 -0
- data/vendor/cnats/src/url.c +134 -0
- data/vendor/cnats/src/url.h +24 -0
- data/vendor/cnats/src/util.c +823 -0
- data/vendor/cnats/src/util.h +75 -0
- data/vendor/cnats/src/version.h +29 -0
- data/vendor/cnats/src/version.h.in +29 -0
- data/vendor/cnats/src/win/cond.c +86 -0
- data/vendor/cnats/src/win/mutex.c +54 -0
- data/vendor/cnats/src/win/sock.c +158 -0
- data/vendor/cnats/src/win/strings.c +108 -0
- data/vendor/cnats/src/win/thread.c +180 -0
- data/vendor/cnats/test/CMakeLists.txt +35 -0
- data/vendor/cnats/test/certs/ca.pem +38 -0
- data/vendor/cnats/test/certs/client-cert.pem +30 -0
- data/vendor/cnats/test/certs/client-key.pem +51 -0
- data/vendor/cnats/test/certs/server-cert.pem +31 -0
- data/vendor/cnats/test/certs/server-key.pem +51 -0
- data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
- data/vendor/cnats/test/dylib/nonats.c +13 -0
- data/vendor/cnats/test/list.txt +125 -0
- data/vendor/cnats/test/test.c +11655 -0
- data/vendor/cnats/test/tls.conf +15 -0
- data/vendor/cnats/test/tlsverify.conf +19 -0
- metadata +83 -1
@@ -0,0 +1,162 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "../natsp.h"
|
4
|
+
#include "../mem.h"
|
5
|
+
|
6
|
+
bool
|
7
|
+
nats_InitOnce(natsInitOnceType *control, natsInitOnceCb cb)
|
8
|
+
{
|
9
|
+
if (pthread_once(control, cb) != 0)
|
10
|
+
return false;
|
11
|
+
|
12
|
+
return true;
|
13
|
+
}
|
14
|
+
|
15
|
+
struct threadCtx
|
16
|
+
{
|
17
|
+
natsThreadCb entry;
|
18
|
+
void *arg;
|
19
|
+
};
|
20
|
+
|
21
|
+
static void*
|
22
|
+
_threadStart(void *arg)
|
23
|
+
{
|
24
|
+
struct threadCtx *c = (struct threadCtx*) arg;
|
25
|
+
|
26
|
+
c->entry(c->arg);
|
27
|
+
|
28
|
+
NATS_FREE(c);
|
29
|
+
|
30
|
+
return NULL;
|
31
|
+
}
|
32
|
+
|
33
|
+
natsStatus
|
34
|
+
natsThread_Create(natsThread **thread, natsThreadCb cb, void *arg)
|
35
|
+
{
|
36
|
+
struct threadCtx *ctx = NULL;
|
37
|
+
natsThread *t = NULL;
|
38
|
+
natsStatus s = NATS_OK;
|
39
|
+
int err;
|
40
|
+
|
41
|
+
ctx = (struct threadCtx*) NATS_CALLOC(1, sizeof(*ctx));
|
42
|
+
t = (natsThread*) NATS_CALLOC(1, sizeof(natsThread));
|
43
|
+
|
44
|
+
if ((ctx == NULL) || (t == NULL))
|
45
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
46
|
+
|
47
|
+
if (s == NATS_OK)
|
48
|
+
{
|
49
|
+
ctx->entry = cb;
|
50
|
+
ctx->arg = arg;
|
51
|
+
|
52
|
+
err = pthread_create(t, NULL, _threadStart, ctx);
|
53
|
+
if (err)
|
54
|
+
s = nats_setError(NATS_SYS_ERROR,
|
55
|
+
"pthread_create error: %d", errno);
|
56
|
+
}
|
57
|
+
|
58
|
+
if (s == NATS_OK)
|
59
|
+
{
|
60
|
+
*thread = t;
|
61
|
+
}
|
62
|
+
else
|
63
|
+
{
|
64
|
+
NATS_FREE(ctx);
|
65
|
+
NATS_FREE(t);
|
66
|
+
}
|
67
|
+
|
68
|
+
return s;
|
69
|
+
}
|
70
|
+
|
71
|
+
void
|
72
|
+
natsThread_Join(natsThread *t)
|
73
|
+
{
|
74
|
+
// I think that 'join' should automatically detect if the call is made
|
75
|
+
// from the current thread. This simplify the use. That is, you don't
|
76
|
+
// need to do:
|
77
|
+
// if (!natsThread_IsCurrent(t))
|
78
|
+
// natsThread_Join(t)
|
79
|
+
|
80
|
+
if (!natsThread_IsCurrent(t))
|
81
|
+
{
|
82
|
+
if (pthread_join(*t, NULL) != 0)
|
83
|
+
abort();
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
pthread_detach(*t);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
void
|
92
|
+
natsThread_Detach(natsThread *t)
|
93
|
+
{
|
94
|
+
if (pthread_detach(*t) !=0)
|
95
|
+
abort();
|
96
|
+
}
|
97
|
+
|
98
|
+
bool
|
99
|
+
natsThread_IsCurrent(natsThread *t)
|
100
|
+
{
|
101
|
+
if (pthread_equal(pthread_self(), *t) == 0)
|
102
|
+
return false;
|
103
|
+
|
104
|
+
return true;
|
105
|
+
}
|
106
|
+
|
107
|
+
void
|
108
|
+
natsThread_Yield(void)
|
109
|
+
{
|
110
|
+
sched_yield();
|
111
|
+
}
|
112
|
+
|
113
|
+
void
|
114
|
+
natsThread_Destroy(natsThread *t)
|
115
|
+
{
|
116
|
+
if (t == NULL)
|
117
|
+
return;
|
118
|
+
|
119
|
+
NATS_FREE(t);
|
120
|
+
}
|
121
|
+
|
122
|
+
natsStatus
|
123
|
+
natsThreadLocal_CreateKey(natsThreadLocal *tl, void (*destructor)(void*))
|
124
|
+
{
|
125
|
+
int ret;
|
126
|
+
|
127
|
+
if ((ret = pthread_key_create(tl, destructor)) != 0)
|
128
|
+
{
|
129
|
+
return nats_setError(NATS_SYS_ERROR,
|
130
|
+
"pthread_key_create error: %d", ret);
|
131
|
+
}
|
132
|
+
|
133
|
+
return NATS_OK;
|
134
|
+
}
|
135
|
+
|
136
|
+
void*
|
137
|
+
natsThreadLocal_Get(natsThreadLocal tl)
|
138
|
+
{
|
139
|
+
return pthread_getspecific(tl);
|
140
|
+
}
|
141
|
+
|
142
|
+
natsStatus
|
143
|
+
natsThreadLocal_SetEx(natsThreadLocal tl, const void *value, bool setErr)
|
144
|
+
{
|
145
|
+
int ret;
|
146
|
+
|
147
|
+
if ((ret = pthread_setspecific(tl, value)) != 0)
|
148
|
+
{
|
149
|
+
return nats_setError(NATS_SYS_ERROR,
|
150
|
+
"pthread_setspecific: %d",
|
151
|
+
ret);
|
152
|
+
}
|
153
|
+
|
154
|
+
return NATS_OK;
|
155
|
+
}
|
156
|
+
|
157
|
+
void
|
158
|
+
natsThreadLocal_DestroyKey(natsThreadLocal tl)
|
159
|
+
{
|
160
|
+
pthread_key_delete(tl);
|
161
|
+
}
|
162
|
+
|
@@ -0,0 +1,134 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
#include "mem.h"
|
8
|
+
|
9
|
+
void
|
10
|
+
natsUrl_Destroy(natsUrl *url)
|
11
|
+
{
|
12
|
+
if (url == NULL)
|
13
|
+
return;
|
14
|
+
|
15
|
+
NATS_FREE(url->fullUrl);
|
16
|
+
NATS_FREE(url->host);
|
17
|
+
NATS_FREE(url->username);
|
18
|
+
NATS_FREE(url->password);
|
19
|
+
NATS_FREE(url);
|
20
|
+
}
|
21
|
+
|
22
|
+
static natsStatus
|
23
|
+
_parseHostAndPort(natsUrl *url, char *host, bool uInfo)
|
24
|
+
{
|
25
|
+
natsStatus s = NATS_OK;
|
26
|
+
char *sport = NULL;
|
27
|
+
|
28
|
+
sport = strrchr(host, ':');
|
29
|
+
if (sport != NULL)
|
30
|
+
{
|
31
|
+
if (sport[1] != '\0')
|
32
|
+
url->port = atoi(sport + 1);
|
33
|
+
|
34
|
+
*sport = '\0';
|
35
|
+
}
|
36
|
+
|
37
|
+
if (uInfo)
|
38
|
+
{
|
39
|
+
url->host = NATS_STRDUP(host + 1);
|
40
|
+
*host = '\0';
|
41
|
+
|
42
|
+
if (url->host == NULL)
|
43
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
44
|
+
}
|
45
|
+
else
|
46
|
+
{
|
47
|
+
url->host = NATS_STRDUP(host);
|
48
|
+
if (url->host == NULL)
|
49
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
50
|
+
}
|
51
|
+
|
52
|
+
return s;
|
53
|
+
}
|
54
|
+
|
55
|
+
natsStatus
|
56
|
+
natsUrl_Create(natsUrl **newUrl, const char *urlStr)
|
57
|
+
{
|
58
|
+
natsStatus s = NATS_OK;
|
59
|
+
bool uInfo = false;
|
60
|
+
char *copy = NULL;
|
61
|
+
char *ptr = NULL;
|
62
|
+
char *host = NULL;
|
63
|
+
char *pwd = NULL;
|
64
|
+
natsUrl *url = NULL;
|
65
|
+
|
66
|
+
if ((urlStr == NULL) || (strlen(urlStr) == 0))
|
67
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
68
|
+
|
69
|
+
url = (natsUrl*) NATS_CALLOC(1, sizeof(natsUrl));
|
70
|
+
if (url == NULL)
|
71
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
72
|
+
|
73
|
+
url->fullUrl = NATS_STRDUP(urlStr);
|
74
|
+
if (url->fullUrl == NULL)
|
75
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
76
|
+
|
77
|
+
if (s == NATS_OK)
|
78
|
+
{
|
79
|
+
copy = NATS_STRDUP(urlStr);
|
80
|
+
if (copy == NULL)
|
81
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
82
|
+
}
|
83
|
+
|
84
|
+
// This is based on the results of the Go parsing.
|
85
|
+
// If '//' is not present, there is no error, but
|
86
|
+
// no host, user, password is returned.
|
87
|
+
if ((s == NATS_OK)
|
88
|
+
&& ((ptr = strstr(copy, "//")) != NULL)
|
89
|
+
&& (*(ptr += 2) != '\0'))
|
90
|
+
{
|
91
|
+
// If '@' is present, everything after is the host
|
92
|
+
// everything before is username/password combo.
|
93
|
+
|
94
|
+
host = strrchr(ptr, '@');
|
95
|
+
if (host != NULL)
|
96
|
+
uInfo = true;
|
97
|
+
else
|
98
|
+
host = ptr;
|
99
|
+
|
100
|
+
if ((host != NULL) && (host[1] != '\0'))
|
101
|
+
{
|
102
|
+
s = _parseHostAndPort(url, host, uInfo);
|
103
|
+
}
|
104
|
+
|
105
|
+
if ((s == NATS_OK) && uInfo)
|
106
|
+
{
|
107
|
+
pwd = strchr(ptr, ':');
|
108
|
+
if ((pwd != NULL) && (pwd[1] != '\0'))
|
109
|
+
{
|
110
|
+
url->password = NATS_STRDUP(pwd + 1);
|
111
|
+
*pwd = '\0';
|
112
|
+
|
113
|
+
if (url->password == NULL)
|
114
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
115
|
+
}
|
116
|
+
|
117
|
+
if ((s == NATS_OK) && (strlen(ptr) > 0))
|
118
|
+
{
|
119
|
+
url->username = NATS_STRDUP(ptr);
|
120
|
+
if (url->username == NULL)
|
121
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
NATS_FREE(copy);
|
127
|
+
|
128
|
+
if (s == NATS_OK)
|
129
|
+
*newUrl = url;
|
130
|
+
else
|
131
|
+
natsUrl_Destroy(url);
|
132
|
+
|
133
|
+
return NATS_UPDATE_ERR_STACK(s);
|
134
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef URL_H_
|
4
|
+
#define URL_H_
|
5
|
+
|
6
|
+
#include "status.h"
|
7
|
+
|
8
|
+
typedef struct __natsUrl
|
9
|
+
{
|
10
|
+
char *fullUrl;
|
11
|
+
char *host;
|
12
|
+
int port;
|
13
|
+
char *username;
|
14
|
+
char *password;
|
15
|
+
|
16
|
+
} natsUrl;
|
17
|
+
|
18
|
+
natsStatus
|
19
|
+
natsUrl_Create(natsUrl **newUrl, const char *urlStr);
|
20
|
+
|
21
|
+
void
|
22
|
+
natsUrl_Destroy(natsUrl *url);
|
23
|
+
|
24
|
+
#endif /* SRC_URL_H_ */
|
@@ -0,0 +1,823 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdarg.h>
|
7
|
+
#include <string.h>
|
8
|
+
|
9
|
+
#include "util.h"
|
10
|
+
#include "mem.h"
|
11
|
+
|
12
|
+
#define ASCII_0 (48)
|
13
|
+
#define ASCII_9 (57)
|
14
|
+
|
15
|
+
// parseInt64 expects decimal positive numbers. We
|
16
|
+
// return -1 to signal error
|
17
|
+
int64_t
|
18
|
+
nats_ParseInt64(const char *d, int dLen)
|
19
|
+
{
|
20
|
+
int i;
|
21
|
+
char dec;
|
22
|
+
int64_t n = 0;
|
23
|
+
|
24
|
+
if (dLen == 0)
|
25
|
+
return -1;
|
26
|
+
|
27
|
+
for (i=0; i<dLen; i++)
|
28
|
+
{
|
29
|
+
dec = d[i];
|
30
|
+
if ((dec < ASCII_0) || (dec > ASCII_9))
|
31
|
+
return -1;
|
32
|
+
|
33
|
+
n = (n * 10) + ((int64_t)dec - ASCII_0);
|
34
|
+
}
|
35
|
+
|
36
|
+
return n;
|
37
|
+
}
|
38
|
+
|
39
|
+
natsStatus
|
40
|
+
nats_ParseControl(natsControl *control, const char *line)
|
41
|
+
{
|
42
|
+
natsStatus s = NATS_OK;
|
43
|
+
char *tok = NULL;
|
44
|
+
int len = 0;
|
45
|
+
|
46
|
+
if ((line == NULL) || (line[0] == '\0'))
|
47
|
+
return nats_setDefaultError(NATS_PROTOCOL_ERROR);
|
48
|
+
|
49
|
+
tok = strchr(line, (int) ' ');
|
50
|
+
if (tok == NULL)
|
51
|
+
{
|
52
|
+
control->op = NATS_STRDUP(line);
|
53
|
+
if (control->op == NULL)
|
54
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
55
|
+
|
56
|
+
return NATS_OK;
|
57
|
+
}
|
58
|
+
|
59
|
+
len = (int) (tok - line);
|
60
|
+
control->op = NATS_MALLOC(len + 1);
|
61
|
+
if (control->op == NULL)
|
62
|
+
{
|
63
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
64
|
+
}
|
65
|
+
else
|
66
|
+
{
|
67
|
+
memcpy(control->op, line, len);
|
68
|
+
control->op[len] = '\0';
|
69
|
+
}
|
70
|
+
|
71
|
+
if (s == NATS_OK)
|
72
|
+
{
|
73
|
+
// Discard all spaces and the like in between the next token
|
74
|
+
while ((tok[0] != '\0')
|
75
|
+
&& ((tok[0] == ' ')
|
76
|
+
|| (tok[0] == '\r')
|
77
|
+
|| (tok[0] == '\n')
|
78
|
+
|| (tok[0] == '\t')))
|
79
|
+
{
|
80
|
+
tok++;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
// If there is a token...
|
85
|
+
if (tok[0] != '\0')
|
86
|
+
{
|
87
|
+
char *tmp;
|
88
|
+
|
89
|
+
len = (int) strlen(tok);
|
90
|
+
tmp = &(tok[len - 1]);
|
91
|
+
|
92
|
+
// Remove trailing spaces and the like.
|
93
|
+
while ((tmp[0] != '\0')
|
94
|
+
&& ((tmp[0] == ' ')
|
95
|
+
|| (tmp[0] == '\r')
|
96
|
+
|| (tmp[0] == '\n')
|
97
|
+
|| (tmp[0] == '\t')))
|
98
|
+
{
|
99
|
+
tmp--;
|
100
|
+
len--;
|
101
|
+
}
|
102
|
+
|
103
|
+
// We are sure that len is > 0 because of the first while() loop.
|
104
|
+
|
105
|
+
control->args = NATS_MALLOC(len + 1);
|
106
|
+
if (control->args == NULL)
|
107
|
+
{
|
108
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
109
|
+
}
|
110
|
+
else
|
111
|
+
{
|
112
|
+
memcpy(control->args, tok, len);
|
113
|
+
control->args[len] = '\0';
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
if (s != NATS_OK)
|
118
|
+
{
|
119
|
+
NATS_FREE(control->op);
|
120
|
+
control->op = NULL;
|
121
|
+
|
122
|
+
NATS_FREE(control->args);
|
123
|
+
control->args = NULL;
|
124
|
+
}
|
125
|
+
|
126
|
+
return NATS_UPDATE_ERR_STACK(s);
|
127
|
+
}
|
128
|
+
|
129
|
+
natsStatus
|
130
|
+
nats_CreateStringFromBuffer(char **newStr, natsBuffer *buf)
|
131
|
+
{
|
132
|
+
char *str = NULL;
|
133
|
+
int len = 0;
|
134
|
+
|
135
|
+
if ((buf == NULL) || ((len = natsBuf_Len(buf)) == 0))
|
136
|
+
return NATS_OK;
|
137
|
+
|
138
|
+
str = NATS_MALLOC(len + 1);
|
139
|
+
if (str == NULL)
|
140
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
141
|
+
|
142
|
+
memcpy(str, natsBuf_Data(buf), len);
|
143
|
+
str[len] = '\0';
|
144
|
+
|
145
|
+
*newStr = str;
|
146
|
+
|
147
|
+
return NATS_OK;
|
148
|
+
}
|
149
|
+
|
150
|
+
void
|
151
|
+
nats_Sleep(int64_t millisec)
|
152
|
+
{
|
153
|
+
#ifdef _WIN32
|
154
|
+
Sleep((DWORD) millisec);
|
155
|
+
#else
|
156
|
+
usleep(millisec * 1000);
|
157
|
+
#endif
|
158
|
+
}
|
159
|
+
|
160
|
+
const char*
|
161
|
+
nats_GetBoolStr(bool value)
|
162
|
+
{
|
163
|
+
if (value)
|
164
|
+
return "true";
|
165
|
+
|
166
|
+
return "false";
|
167
|
+
}
|
168
|
+
|
169
|
+
void
|
170
|
+
nats_NormalizeErr(char *error)
|
171
|
+
{
|
172
|
+
int start = 0;
|
173
|
+
int end = 0;
|
174
|
+
int len = (int) strlen(error);
|
175
|
+
int i;
|
176
|
+
|
177
|
+
if (strncmp(error, _ERR_OP_, _ERR_OP_LEN_) == 0)
|
178
|
+
start = _ERR_OP_LEN_;
|
179
|
+
|
180
|
+
for (i=start; i<len; i++)
|
181
|
+
{
|
182
|
+
if ((error[i] != ' ') && (error[i] != '\''))
|
183
|
+
break;
|
184
|
+
}
|
185
|
+
|
186
|
+
start = i;
|
187
|
+
if (start == len)
|
188
|
+
{
|
189
|
+
error[0] = '\0';
|
190
|
+
return;
|
191
|
+
}
|
192
|
+
|
193
|
+
for (end=len-1; end>0; end--)
|
194
|
+
if ((error[end] != ' ') && (error[end] != '\''))
|
195
|
+
break;
|
196
|
+
|
197
|
+
if (end <= start)
|
198
|
+
{
|
199
|
+
error[0] = '\0';
|
200
|
+
return;
|
201
|
+
}
|
202
|
+
|
203
|
+
len = end - start + 1;
|
204
|
+
memmove(error, error + start, len);
|
205
|
+
error[len] = '\0';
|
206
|
+
}
|
207
|
+
|
208
|
+
static natsStatus
|
209
|
+
_jsonCreateField(nats_JSONField **newField, char *fieldName)
|
210
|
+
{
|
211
|
+
nats_JSONField *field = NULL;
|
212
|
+
|
213
|
+
field = (nats_JSONField*) NATS_CALLOC(1, sizeof(nats_JSONField));
|
214
|
+
if (field == NULL)
|
215
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
216
|
+
|
217
|
+
field->name = fieldName;
|
218
|
+
field->typ = TYPE_NOT_SET;
|
219
|
+
|
220
|
+
*newField = field;
|
221
|
+
|
222
|
+
return NATS_OK;
|
223
|
+
}
|
224
|
+
|
225
|
+
static void
|
226
|
+
_jsonFreeField(nats_JSONField *field)
|
227
|
+
{
|
228
|
+
if (field->typ == TYPE_ARRAY)
|
229
|
+
{
|
230
|
+
NATS_FREE(field->value.varr->values);
|
231
|
+
NATS_FREE(field->value.varr);
|
232
|
+
}
|
233
|
+
NATS_FREE(field);
|
234
|
+
}
|
235
|
+
|
236
|
+
static char*
|
237
|
+
_jsonTrimSpace(char *ptr)
|
238
|
+
{
|
239
|
+
while ((*ptr != '\0')
|
240
|
+
&& ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')))
|
241
|
+
{
|
242
|
+
ptr += 1;
|
243
|
+
}
|
244
|
+
return ptr;
|
245
|
+
}
|
246
|
+
|
247
|
+
static natsStatus
|
248
|
+
_jsonGetStr(char **ptr, char **value)
|
249
|
+
{
|
250
|
+
char *p = *ptr;
|
251
|
+
|
252
|
+
do
|
253
|
+
{
|
254
|
+
while ((*p != '\0') && (*p != '"'))
|
255
|
+
p += 1;
|
256
|
+
}
|
257
|
+
while ((*p != '\0') && (*p == '"') && (*(p - 1) == '\\') && (p += 1));
|
258
|
+
|
259
|
+
if (*p != '\0')
|
260
|
+
{
|
261
|
+
*value = *ptr;
|
262
|
+
*p = '\0';
|
263
|
+
*ptr = (char*) (p + 1);
|
264
|
+
return NATS_OK;
|
265
|
+
}
|
266
|
+
return nats_setError(NATS_INVALID_ARG, "%s",
|
267
|
+
"error parsing string: unexpected end of JSON input");
|
268
|
+
}
|
269
|
+
|
270
|
+
static natsStatus
|
271
|
+
_jsonGetNum(char **ptr, long double *val)
|
272
|
+
{
|
273
|
+
char *tail = NULL;
|
274
|
+
long double lval = 0;
|
275
|
+
|
276
|
+
errno = 0;
|
277
|
+
|
278
|
+
lval = strtold(*ptr, &tail);
|
279
|
+
if (errno != 0)
|
280
|
+
return nats_setError(NATS_INVALID_ARG,
|
281
|
+
"error parsing numeric: %d", errno);
|
282
|
+
|
283
|
+
*ptr = tail;
|
284
|
+
*val = lval;
|
285
|
+
return NATS_OK;
|
286
|
+
}
|
287
|
+
|
288
|
+
static natsStatus
|
289
|
+
_jsonGetBool(char **ptr, bool *val)
|
290
|
+
{
|
291
|
+
if (strncmp(*ptr, "true", 4) == 0)
|
292
|
+
{
|
293
|
+
*val = true;
|
294
|
+
*ptr += 4;
|
295
|
+
return NATS_OK;
|
296
|
+
}
|
297
|
+
else if (strncmp(*ptr, "false", 5) == 0)
|
298
|
+
{
|
299
|
+
*val = false;
|
300
|
+
*ptr += 5;
|
301
|
+
return NATS_OK;
|
302
|
+
}
|
303
|
+
return nats_setError(NATS_INVALID_ARG,
|
304
|
+
"error parsing boolean, got: '%s'", *ptr);
|
305
|
+
}
|
306
|
+
|
307
|
+
static natsStatus
|
308
|
+
_jsonGetArray(char **ptr, nats_JSONArray **newArray)
|
309
|
+
{
|
310
|
+
natsStatus s = NATS_OK;
|
311
|
+
char *p = *ptr;
|
312
|
+
char *val = NULL;
|
313
|
+
bool end = false;
|
314
|
+
nats_JSONArray array;
|
315
|
+
|
316
|
+
// Initialize our stack variable
|
317
|
+
memset(&array, 0, sizeof(nats_JSONArray));
|
318
|
+
|
319
|
+
// We support only string array for now
|
320
|
+
array.typ = TYPE_STR;
|
321
|
+
array.eltSize = sizeof(char*);
|
322
|
+
array.size = 0;
|
323
|
+
array.cap = 4;
|
324
|
+
array.values = NATS_CALLOC(array.cap, array.eltSize);
|
325
|
+
|
326
|
+
while ((s == NATS_OK) && (*p != '\0'))
|
327
|
+
{
|
328
|
+
p = _jsonTrimSpace(p);
|
329
|
+
|
330
|
+
// We support only array of strings for now
|
331
|
+
if (*p != '"')
|
332
|
+
{
|
333
|
+
s = nats_setError(NATS_NOT_PERMITTED,
|
334
|
+
"only string arrays supported, got '%s'", p);
|
335
|
+
break;
|
336
|
+
}
|
337
|
+
|
338
|
+
p += 1;
|
339
|
+
|
340
|
+
s = _jsonGetStr(&p, &val);
|
341
|
+
if (s != NATS_OK)
|
342
|
+
break;
|
343
|
+
|
344
|
+
if (array.size + 1 > array.cap)
|
345
|
+
{
|
346
|
+
char **newValues = NULL;
|
347
|
+
int newCap = 2 * array.cap;
|
348
|
+
|
349
|
+
newValues = (char**) NATS_REALLOC(array.values, newCap * sizeof(char*));
|
350
|
+
if (newValues == NULL)
|
351
|
+
{
|
352
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
353
|
+
break;
|
354
|
+
}
|
355
|
+
array.values = (void**) newValues;
|
356
|
+
array.cap = newCap;
|
357
|
+
}
|
358
|
+
((char**)array.values)[array.size++] = val;
|
359
|
+
|
360
|
+
p = _jsonTrimSpace(p);
|
361
|
+
if (*p == '\0')
|
362
|
+
break;
|
363
|
+
|
364
|
+
if (*p == ']')
|
365
|
+
{
|
366
|
+
end = true;
|
367
|
+
break;
|
368
|
+
}
|
369
|
+
else if (*p == ',')
|
370
|
+
{
|
371
|
+
p += 1;
|
372
|
+
}
|
373
|
+
else
|
374
|
+
{
|
375
|
+
s = nats_setError(NATS_ERR, "expected ',' got '%s'", p);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
if ((s == NATS_OK) && !end)
|
379
|
+
{
|
380
|
+
s = nats_setError(NATS_ERR,
|
381
|
+
"unexpected end of array: '%s'",
|
382
|
+
(*p != '\0' ? p : "NULL"));
|
383
|
+
}
|
384
|
+
if (s == NATS_OK)
|
385
|
+
{
|
386
|
+
*newArray = NATS_MALLOC(sizeof(nats_JSONArray));
|
387
|
+
if (*newArray == NULL)
|
388
|
+
{
|
389
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
390
|
+
}
|
391
|
+
else
|
392
|
+
{
|
393
|
+
memcpy(*newArray, &array, sizeof(nats_JSONArray));
|
394
|
+
*ptr = (char*) (p + 1);
|
395
|
+
}
|
396
|
+
}
|
397
|
+
if (s != NATS_OK)
|
398
|
+
{
|
399
|
+
int i;
|
400
|
+
for (i=0; i<array.size; i++)
|
401
|
+
{
|
402
|
+
p = ((char**)array.values)[i];
|
403
|
+
*(p + strlen(p)) = '"';
|
404
|
+
}
|
405
|
+
NATS_FREE(array.values);
|
406
|
+
}
|
407
|
+
|
408
|
+
return NATS_UPDATE_ERR_STACK(s);
|
409
|
+
}
|
410
|
+
|
411
|
+
static char*
|
412
|
+
_jsonSkipUnknownType(char *ptr)
|
413
|
+
{
|
414
|
+
char *p = ptr;
|
415
|
+
int skip = 0;
|
416
|
+
bool quoteOpen = false;
|
417
|
+
|
418
|
+
while (*p != '\0')
|
419
|
+
{
|
420
|
+
if (((*p == ',') || (*p == '}')) && (skip == 0))
|
421
|
+
break;
|
422
|
+
else if ((*p == '{') || (*p == '['))
|
423
|
+
skip++;
|
424
|
+
else if ((*p == '}') || (*p == ']'))
|
425
|
+
skip--;
|
426
|
+
else if ((*p == '"') && (*(p-1) != '\\'))
|
427
|
+
{
|
428
|
+
if (quoteOpen)
|
429
|
+
{
|
430
|
+
quoteOpen = false;
|
431
|
+
skip--;
|
432
|
+
}
|
433
|
+
else
|
434
|
+
{
|
435
|
+
quoteOpen = true;
|
436
|
+
skip++;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
p += 1;
|
440
|
+
}
|
441
|
+
return p;
|
442
|
+
}
|
443
|
+
|
444
|
+
#define JSON_STATE_START (0)
|
445
|
+
#define JSON_STATE_NO_FIELD_YET (1)
|
446
|
+
#define JSON_STATE_FIELD (2)
|
447
|
+
#define JSON_STATE_SEPARATOR (3)
|
448
|
+
#define JSON_STATE_VALUE (4)
|
449
|
+
#define JSON_STATE_NEXT_FIELD (5)
|
450
|
+
#define JSON_STATE_END (6)
|
451
|
+
|
452
|
+
natsStatus
|
453
|
+
nats_JSONParse(nats_JSON **newJSON, const char *jsonStr, int jsonLen)
|
454
|
+
{
|
455
|
+
natsStatus s = NATS_OK;
|
456
|
+
nats_JSON *json = NULL;
|
457
|
+
nats_JSONField *field = NULL;
|
458
|
+
nats_JSONField *oldField = NULL;
|
459
|
+
char *ptr;
|
460
|
+
char *fieldName = NULL;
|
461
|
+
int state;
|
462
|
+
bool gotEnd = false;
|
463
|
+
|
464
|
+
if (jsonLen < 0)
|
465
|
+
{
|
466
|
+
if (jsonStr == NULL)
|
467
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
468
|
+
|
469
|
+
jsonLen = (int) strlen(jsonStr);
|
470
|
+
}
|
471
|
+
|
472
|
+
json = NATS_CALLOC(1, sizeof(nats_JSON));
|
473
|
+
if (json == NULL)
|
474
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
475
|
+
|
476
|
+
s = natsStrHash_Create(&(json->fields), 4);
|
477
|
+
if (s == NATS_OK)
|
478
|
+
{
|
479
|
+
json->str = NATS_MALLOC(jsonLen + 1);
|
480
|
+
if (json->str == NULL)
|
481
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
482
|
+
|
483
|
+
if (s == NATS_OK)
|
484
|
+
{
|
485
|
+
memcpy(json->str, jsonStr, jsonLen);
|
486
|
+
json->str[jsonLen] = '\0';
|
487
|
+
}
|
488
|
+
}
|
489
|
+
if (s != NATS_OK)
|
490
|
+
{
|
491
|
+
nats_JSONDestroy(json);
|
492
|
+
return NATS_UPDATE_ERR_STACK(s);
|
493
|
+
}
|
494
|
+
|
495
|
+
ptr = json->str;
|
496
|
+
state = JSON_STATE_START;
|
497
|
+
|
498
|
+
while ((s == NATS_OK) && (*ptr != '\0'))
|
499
|
+
{
|
500
|
+
ptr = _jsonTrimSpace(ptr);
|
501
|
+
if (*ptr == '\0')
|
502
|
+
break;
|
503
|
+
switch (state)
|
504
|
+
{
|
505
|
+
case JSON_STATE_START:
|
506
|
+
{
|
507
|
+
// Should be the start of the JSON string
|
508
|
+
if (*ptr != '{')
|
509
|
+
{
|
510
|
+
s = nats_setError(NATS_ERR, "incorrect JSON string: '%s'", ptr);
|
511
|
+
break;
|
512
|
+
}
|
513
|
+
ptr += 1;
|
514
|
+
state = JSON_STATE_NO_FIELD_YET;
|
515
|
+
break;
|
516
|
+
}
|
517
|
+
case JSON_STATE_NO_FIELD_YET:
|
518
|
+
case JSON_STATE_FIELD:
|
519
|
+
{
|
520
|
+
// Check for end, which is valid only in state == JSON_STATE_NO_FIELD_YET
|
521
|
+
if (*ptr == '}')
|
522
|
+
{
|
523
|
+
if (state == JSON_STATE_NO_FIELD_YET)
|
524
|
+
{
|
525
|
+
ptr += 1;
|
526
|
+
state = JSON_STATE_END;
|
527
|
+
break;
|
528
|
+
}
|
529
|
+
s = nats_setError(NATS_ERR,
|
530
|
+
"expected beginning of field, got: '%s'",
|
531
|
+
ptr);
|
532
|
+
break;
|
533
|
+
}
|
534
|
+
// Check for
|
535
|
+
// Should be the first quote of a field name
|
536
|
+
if (*ptr != '"')
|
537
|
+
{
|
538
|
+
s = nats_setError(NATS_ERR, "missing quote: '%s'", ptr);
|
539
|
+
break;
|
540
|
+
}
|
541
|
+
ptr += 1;
|
542
|
+
s = _jsonGetStr(&ptr, &fieldName);
|
543
|
+
if (s != NATS_OK)
|
544
|
+
{
|
545
|
+
s = nats_setError(NATS_ERR, "invalid field name: '%s'", ptr);
|
546
|
+
break;
|
547
|
+
}
|
548
|
+
s = _jsonCreateField(&field, fieldName);
|
549
|
+
if (s != NATS_OK)
|
550
|
+
{
|
551
|
+
NATS_UPDATE_ERR_STACK(s);
|
552
|
+
break;
|
553
|
+
}
|
554
|
+
s = natsStrHash_Set(json->fields, fieldName, false, (void*) field, (void**)&oldField);
|
555
|
+
if (s != NATS_OK)
|
556
|
+
{
|
557
|
+
NATS_UPDATE_ERR_STACK(s);
|
558
|
+
break;
|
559
|
+
}
|
560
|
+
if (oldField != NULL)
|
561
|
+
{
|
562
|
+
NATS_FREE(oldField);
|
563
|
+
oldField = NULL;
|
564
|
+
}
|
565
|
+
state = JSON_STATE_SEPARATOR;
|
566
|
+
break;
|
567
|
+
}
|
568
|
+
case JSON_STATE_SEPARATOR:
|
569
|
+
{
|
570
|
+
// Should be the separation between field name and value.
|
571
|
+
if (*ptr != ':')
|
572
|
+
{
|
573
|
+
s = nats_setError(NATS_ERR, "missing value for field '%s': '%s'", fieldName, ptr);
|
574
|
+
break;
|
575
|
+
}
|
576
|
+
ptr += 1;
|
577
|
+
state = JSON_STATE_VALUE;
|
578
|
+
break;
|
579
|
+
}
|
580
|
+
case JSON_STATE_VALUE:
|
581
|
+
{
|
582
|
+
// Parsing value here. Determine the type based on first character.
|
583
|
+
if (*ptr == '"')
|
584
|
+
{
|
585
|
+
field->typ = TYPE_STR;
|
586
|
+
ptr += 1;
|
587
|
+
s = _jsonGetStr(&ptr, &field->value.vstr);
|
588
|
+
if (s != NATS_OK)
|
589
|
+
s = nats_setError(NATS_ERR,
|
590
|
+
"invalid string value for field '%s': '%s'",
|
591
|
+
fieldName, ptr);
|
592
|
+
}
|
593
|
+
else if ((*ptr == 't') || (*ptr == 'f'))
|
594
|
+
{
|
595
|
+
field->typ = TYPE_BOOL;
|
596
|
+
s = _jsonGetBool(&ptr, &field->value.vbool);
|
597
|
+
if (s != NATS_OK)
|
598
|
+
s = nats_setError(NATS_ERR,
|
599
|
+
"invalid boolean value for field '%s': '%s'",
|
600
|
+
fieldName, ptr);
|
601
|
+
}
|
602
|
+
else if (((*ptr >= 48) && (*ptr <= 57)) || (*ptr == '-'))
|
603
|
+
{
|
604
|
+
field->typ = TYPE_NUM;
|
605
|
+
s = _jsonGetNum(&ptr, &field->value.vdec);
|
606
|
+
if (s != NATS_OK)
|
607
|
+
s = nats_setError(NATS_ERR,
|
608
|
+
"invalid numeric value for field '%s': '%s'",
|
609
|
+
fieldName, ptr);
|
610
|
+
}
|
611
|
+
else if ((*ptr == '[') || (*ptr == '{'))
|
612
|
+
{
|
613
|
+
bool doSkip = true;
|
614
|
+
|
615
|
+
if (*ptr == '[')
|
616
|
+
{
|
617
|
+
ptr += 1;
|
618
|
+
s = _jsonGetArray(&ptr, &field->value.varr);
|
619
|
+
if (s == NATS_OK)
|
620
|
+
{
|
621
|
+
field->typ = TYPE_ARRAY;
|
622
|
+
doSkip = false;
|
623
|
+
}
|
624
|
+
else if (s == NATS_NOT_PERMITTED)
|
625
|
+
{
|
626
|
+
// This is an array but we don't support the
|
627
|
+
// type of elements, so skip.
|
628
|
+
s = NATS_OK;
|
629
|
+
// Clear error stack
|
630
|
+
nats_clearLastError();
|
631
|
+
// Need to go back to the '[' character.
|
632
|
+
ptr -= 1;
|
633
|
+
}
|
634
|
+
}
|
635
|
+
if ((s == NATS_OK) && doSkip)
|
636
|
+
{
|
637
|
+
// Don't support, skip until next field.
|
638
|
+
ptr = _jsonSkipUnknownType(ptr);
|
639
|
+
// Destroy the field that we have created
|
640
|
+
natsStrHash_Remove(json->fields, fieldName);
|
641
|
+
_jsonFreeField(field);
|
642
|
+
field = NULL;
|
643
|
+
}
|
644
|
+
}
|
645
|
+
else
|
646
|
+
{
|
647
|
+
s = nats_setError(NATS_ERR,
|
648
|
+
"looking for value, got: '%s'", ptr);
|
649
|
+
}
|
650
|
+
if (s == NATS_OK)
|
651
|
+
state = JSON_STATE_NEXT_FIELD;
|
652
|
+
break;
|
653
|
+
}
|
654
|
+
case JSON_STATE_NEXT_FIELD:
|
655
|
+
{
|
656
|
+
// We should have a ',' separator or be at the end of the string
|
657
|
+
if ((*ptr != ',') && (*ptr != '}'))
|
658
|
+
{
|
659
|
+
s = nats_setError(NATS_ERR, "missing separator: '%s' (%s)", ptr, jsonStr);
|
660
|
+
break;
|
661
|
+
}
|
662
|
+
if (*ptr == ',')
|
663
|
+
state = JSON_STATE_FIELD;
|
664
|
+
else
|
665
|
+
state = JSON_STATE_END;
|
666
|
+
ptr += 1;
|
667
|
+
break;
|
668
|
+
}
|
669
|
+
case JSON_STATE_END:
|
670
|
+
{
|
671
|
+
// If we are here it means that there was a character after the '}'
|
672
|
+
// so that's considered a failure.
|
673
|
+
s = nats_setError(NATS_ERR,
|
674
|
+
"invalid characters after end of JSON: '%s'",
|
675
|
+
ptr);
|
676
|
+
break;
|
677
|
+
}
|
678
|
+
}
|
679
|
+
}
|
680
|
+
if (s == NATS_OK)
|
681
|
+
{
|
682
|
+
if (state != JSON_STATE_END)
|
683
|
+
s = nats_setError(NATS_ERR, "%s", "JSON string not properly closed");
|
684
|
+
}
|
685
|
+
if (s == NATS_OK)
|
686
|
+
*newJSON = json;
|
687
|
+
else
|
688
|
+
nats_JSONDestroy(json);
|
689
|
+
|
690
|
+
return NATS_UPDATE_ERR_STACK(s);
|
691
|
+
}
|
692
|
+
|
693
|
+
natsStatus
|
694
|
+
nats_JSONGetValue(nats_JSON *json, const char *fieldName, int fieldType, void **addr)
|
695
|
+
{
|
696
|
+
nats_JSONField *field = NULL;
|
697
|
+
|
698
|
+
field = (nats_JSONField*) natsStrHash_Get(json->fields, (char*) fieldName);
|
699
|
+
// If unknown field, just ignore
|
700
|
+
if (field == NULL)
|
701
|
+
return NATS_OK;
|
702
|
+
|
703
|
+
// Check parsed type matches what is being asked.
|
704
|
+
if ((((fieldType == TYPE_INT) || (fieldType == TYPE_LONG)) && (field->typ != TYPE_NUM))
|
705
|
+
|| ((field->typ != TYPE_NUM) && (fieldType != field->typ)))
|
706
|
+
{
|
707
|
+
return nats_setError(NATS_INVALID_ARG,
|
708
|
+
"Asked for field '%s' as type %d, but got type %d when parsing",
|
709
|
+
field->name, fieldType, field->typ);
|
710
|
+
}
|
711
|
+
switch (fieldType)
|
712
|
+
{
|
713
|
+
case TYPE_STR:
|
714
|
+
{
|
715
|
+
if (field->value.vstr == NULL)
|
716
|
+
{
|
717
|
+
(*(char**)addr) = NULL;
|
718
|
+
}
|
719
|
+
else
|
720
|
+
{
|
721
|
+
char *tmp = NATS_STRDUP(field->value.vstr);
|
722
|
+
if (tmp == NULL)
|
723
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
724
|
+
(*(char**)addr) = tmp;
|
725
|
+
}
|
726
|
+
break;
|
727
|
+
}
|
728
|
+
case TYPE_BOOL: (*(bool*)addr) = field->value.vbool; break;
|
729
|
+
case TYPE_INT: (*(int*)addr) = (int)field->value.vdec; break;
|
730
|
+
case TYPE_LONG: (*(int64_t*)addr) = (int64_t) field->value.vdec; break;
|
731
|
+
case TYPE_DOUBLE: (*(long double*)addr) = field->value.vdec; break;
|
732
|
+
default:
|
733
|
+
{
|
734
|
+
return nats_setError(NATS_NOT_FOUND,
|
735
|
+
"Unknown field type for field '%s': %d",
|
736
|
+
field->name, fieldType);
|
737
|
+
}
|
738
|
+
}
|
739
|
+
return NATS_OK;
|
740
|
+
}
|
741
|
+
|
742
|
+
natsStatus
|
743
|
+
nats_JSONGetArrayValue(nats_JSON *json, const char *fieldName, int fieldType, void ***array, int *arraySize)
|
744
|
+
{
|
745
|
+
natsStatus s = NATS_OK;
|
746
|
+
nats_JSONField *field = NULL;
|
747
|
+
void **values = NULL;
|
748
|
+
|
749
|
+
field = (nats_JSONField*) natsStrHash_Get(json->fields, (char*) fieldName);
|
750
|
+
// If unknown field, just ignore
|
751
|
+
if (field == NULL)
|
752
|
+
return NATS_OK;
|
753
|
+
|
754
|
+
// Check parsed type matches what is being asked.
|
755
|
+
if (field->typ != TYPE_ARRAY)
|
756
|
+
return nats_setError(NATS_INVALID_ARG,
|
757
|
+
"Field '%s' is not an array, it has type: %d",
|
758
|
+
field->name, field->typ);
|
759
|
+
if (fieldType != field->value.varr->typ)
|
760
|
+
return nats_setError(NATS_INVALID_ARG,
|
761
|
+
"Asked for field '%s' as an array of type: %d, but it is an array of type: %d",
|
762
|
+
field->name, fieldType, field->typ);
|
763
|
+
|
764
|
+
values = NATS_CALLOC(field->value.varr->size, field->value.varr->eltSize);
|
765
|
+
if (values == NULL)
|
766
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
767
|
+
|
768
|
+
if (fieldType == TYPE_STR)
|
769
|
+
{
|
770
|
+
int i;
|
771
|
+
|
772
|
+
for (i=0; i<field->value.varr->size; i++)
|
773
|
+
{
|
774
|
+
values[i] = NATS_STRDUP((char*)(field->value.varr->values[i]));
|
775
|
+
if (values[i] == NULL)
|
776
|
+
{
|
777
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
778
|
+
break;
|
779
|
+
}
|
780
|
+
}
|
781
|
+
if (s != NATS_OK)
|
782
|
+
{
|
783
|
+
int j;
|
784
|
+
|
785
|
+
for (j=0; j<i; j++)
|
786
|
+
NATS_FREE(values[i]);
|
787
|
+
|
788
|
+
NATS_FREE(values);
|
789
|
+
}
|
790
|
+
}
|
791
|
+
else
|
792
|
+
{
|
793
|
+
s = nats_setError(NATS_INVALID_ARG, "%s",
|
794
|
+
"Only string arrays are supported");
|
795
|
+
}
|
796
|
+
if (s == NATS_OK)
|
797
|
+
{
|
798
|
+
*array = values;
|
799
|
+
*arraySize = field->value.varr->size;
|
800
|
+
}
|
801
|
+
|
802
|
+
return NATS_UPDATE_ERR_STACK(s);
|
803
|
+
}
|
804
|
+
|
805
|
+
void
|
806
|
+
nats_JSONDestroy(nats_JSON *json)
|
807
|
+
{
|
808
|
+
natsStrHashIter iter;
|
809
|
+
nats_JSONField *field;
|
810
|
+
|
811
|
+
if (json == NULL)
|
812
|
+
return;
|
813
|
+
|
814
|
+
natsStrHashIter_Init(&iter, json->fields);
|
815
|
+
while (natsStrHashIter_Next(&iter, NULL, (void**)&field))
|
816
|
+
{
|
817
|
+
natsStrHashIter_RemoveCurrent(&iter);
|
818
|
+
_jsonFreeField(field);
|
819
|
+
}
|
820
|
+
natsStrHash_Destroy(json->fields);
|
821
|
+
NATS_FREE(json->str);
|
822
|
+
NATS_FREE(json);
|
823
|
+
}
|