prometheus-client-mmap 0.7.0.beta32 → 0.7.0.beta33

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 668eeb5bd066bb7495b10016c900f346c5826ffb
4
- data.tar.gz: 9598055345b26e3d67bcaa251353740b456ca061
3
+ metadata.gz: 6a7956684dd9781b3ca54566d1822574a9efaba7
4
+ data.tar.gz: b1673743af7ef8d4cbe1f1fa40d2da9560ed4f98
5
5
  SHA512:
6
- metadata.gz: 9c925441a2a99af473762ba79e83cff1ef109b1e3445726b75b1fe72fc66ceb1072cae5efd89a3eca93b95a43cfba7db8147da53bd938d5a9b734addab2bdd13
7
- data.tar.gz: 0adac7c568db0af448674d293dc95b3b44ac20c3ade3ebc5b477e82a0ef5522cff96696dab1f060c1a9122d3f67ab8c685ab40bbbfcf6fecbf02ab7724db19e9
6
+ metadata.gz: 20ca0cf0603f45196a403348f8db23f5fb2b1d64fa0855c966e3448908eec3254b492670d219faa4f1040ab3f5c674a00eb34621729a38c34378641257c02e1f
7
+ data.tar.gz: c35c741b2a573826d3ac3096c14cf8e92a475f894bab7097404340161f37010e8703866424253ab2cb06871658105a9a7ba53136350ef07ce23c8e54f849d1b4
@@ -3,7 +3,5 @@ $CFLAGS << ' -std=c11 -Wall -Wextra -Werror'
3
3
 
4
4
  CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
5
5
 
6
- extension_name = 'fast_mmaped_file'
7
-
8
- dir_config(extension_name)
9
- create_makefile(extension_name)
6
+ dir_config('fast_mmaped_file')
7
+ create_makefile('fast_mmaped_file')
@@ -7,15 +7,6 @@
7
7
 
8
8
  #include "mmap.h"
9
9
 
10
- #ifdef UNUSED
11
- #elif defined(__GNUC__)
12
- #define UNUSED(x) UNUSED_ ## x __attribute__((unused))
13
- #elif defined(__LCLINT__)
14
- #define UNUSED(x) /*@unused@*/ x
15
- #else
16
- #define UNUSED(x) x
17
- #endif
18
-
19
10
  VALUE MMAPED_FILE = Qnil;
20
11
 
21
12
  #define START_POSITION 8
@@ -146,106 +137,8 @@ VALUE method_get_double(VALUE self, VALUE index) {
146
137
  return DBL2NUM(tmp);
147
138
  }
148
139
 
149
- #include <jsmn.h>
150
-
151
- #define min(a,b) \
152
- ({ __typeof__ (a) _a = (a); \
153
- __typeof__ (b) _b = (b); \
154
- _a < _b ? _a : _b; })
155
-
156
- VALUE token_to_s(char* json, jsmntok_t *t){
157
- int len = t->end - t->start;
158
- if (len == 0) {
159
- return rb_str_new_literal("");
160
- } else {
161
- return rb_str_new(json + t->start, t->end - t->start);
162
- }
163
- }
164
-
165
- VALUE fast_json_parse(char* json, size_t json_size){
166
- jsmn_parser parser;
167
- jsmn_init(&parser);
168
-
169
- jsmntok_t t[128];
170
- int r = jsmn_parse(&parser, json, json_size, t, sizeof(t)/sizeof(t[0]));
171
-
172
- if (r < 3) {
173
- return Qnil;
174
- }
175
-
176
- VALUE labels = rb_hash_new();
177
- int label_cnt = (r-5)/2;
178
- //TODO: (r - 4) % 2 == 0
179
-
180
- for(int i = 0; i < label_cnt; i++){
181
- int key = 4 + i;
182
- int val = 5 + label_cnt + i;
183
- //TODO: add type checks
184
-
185
- if (strncmp("null", json + t[val].start, min(4, t[val].end - t[val].start)) == 0) {
186
- rb_hash_aset(labels, token_to_s(json, &t[key]), Qnil);
187
- } else {
188
- rb_hash_aset(labels, token_to_s(json, &t[key]), token_to_s(json, &t[val]));
189
- }
190
- }
191
-
192
- return rb_ary_new_from_args(3, token_to_s(json, &t[1]), token_to_s(json, &t[2]), labels);
193
- }
194
-
195
-
196
- VALUE method_fast_json_parse(VALUE UNUSED(self), VALUE source){
197
- Check_Type(source, T_STRING);
198
-
199
- return fast_json_parse(StringValuePtr(source), RSTRING_LEN(source));
200
- }
201
-
202
- VALUE method_fast_entries(VALUE UNUSED(self), VALUE _data){
203
- Check_Type(_data, T_STRING);
204
-
205
- char *data = StringValuePtr(_data);
206
- uint64_t data_len = RSTRING_LEN(_data);
207
-
208
- uint32_t used;
209
- memcpy(&used, data, sizeof(uint32_t));
210
-
211
- uint32_t pos = START_POSITION;
212
-
213
- while (pos < used && (pos + 2*sizeof(uint32_t)) < data_len) {
214
- uint32_t encoded_len, first_bytes;
215
- memcpy(&encoded_len, data + pos, sizeof(uint32_t));
216
- pos += sizeof(uint32_t);
217
-
218
- memcpy(&first_bytes, data + pos, sizeof(uint32_t));
219
- if (encoded_len == 0 || first_bytes == 0){
220
- pos += 8;
221
- continue; // do not parse empty data
222
- }
223
-
224
- uint32_t value_offset = encoded_len + padding_length(encoded_len);
225
- VALUE metric_name_labels = fast_json_parse(data + pos, encoded_len);
226
-
227
- double value;
228
- pos += value_offset;
229
- memcpy(&value, data + pos, sizeof(double));
230
-
231
- rb_yield_values(4, rb_ary_entry(metric_name_labels, 0),
232
- rb_ary_entry(metric_name_labels, 1),
233
- rb_ary_entry(metric_name_labels, 2),
234
- DBL2NUM(value)
235
- );
236
-
237
- pos += sizeof(double);
238
- }
239
-
240
- return Qnil;
241
- }
242
-
243
140
  void Init_fast_mmaped_file() {
244
-
245
141
  MMAPED_FILE = rb_define_module("FastMmapedFile");
246
- rb_define_singleton_method(MMAPED_FILE, "fast_json_parse", method_fast_json_parse, 1);
247
- rb_define_singleton_method(MMAPED_FILE, "fast_entries", method_fast_entries, 1);
248
-
249
142
  rb_define_method(MMAPED_FILE, "get_double", method_get_double, 1);
250
143
  rb_define_method(MMAPED_FILE, "add_entry", method_add_entry, 3);
251
144
  }
Binary file
@@ -1,5 +1,4 @@
1
1
  require 'prometheus/client/helper/json_parser'
2
- require 'fast_mmaped_file'
3
2
 
4
3
  module Prometheus
5
4
  module Client
@@ -78,20 +77,21 @@ module Prometheus
78
77
  end
79
78
 
80
79
  def to_metrics(metrics = {}, ignore_errors = false)
81
- FastMmapedFile.fast_entries(data) do |metric_name, name, labels, value|
80
+ parsed_entries(ignore_errors).each do |key, value|
82
81
  begin
82
+ metric_name, name, labelnames, labelvalues = JsonParser.load(key)
83
83
  metric = metrics.fetch(metric_name,
84
84
  metric_name: metric_name,
85
85
  help: 'Multiprocess metric',
86
86
  type: type,
87
- samples: {}
87
+ samples: []
88
88
  )
89
89
  if type == :gauge
90
90
  metric[:multiprocess_mode] = multiprocess_mode
91
- merge_samples(name, labels, value, metric[:samples])
91
+ metric[:samples] += [[name, labelnames.zip(labelvalues) + [['pid', pid]], value]]
92
92
  else
93
- merge_samples(name, labels, value, metric[:samples])
94
93
  # The duplicates and labels are fixed in the next for.
94
+ metric[:samples] += [[name, labelnames.zip(labelvalues), value]]
95
95
  end
96
96
  metrics[metric_name] = metric
97
97
  rescue JSON::ParserError => e
@@ -103,54 +103,6 @@ module Prometheus
103
103
  metrics
104
104
  end
105
105
 
106
-
107
- def min(a, b)
108
- if a < b
109
- a
110
- else
111
- b
112
- end
113
- end
114
-
115
- def max(a, b)
116
- if a > b
117
- a
118
- else
119
- b
120
- end
121
- end
122
-
123
- def merge_samples(name, labels, value, samples)
124
- samples ||= {}
125
- case type
126
- when :gauge
127
- case multiprocess_mode
128
- when 'min'
129
- key = labels.merge!(__key_name: name)
130
- s = samples.fetch(key, value)
131
- samples[key] = min(s, value)
132
- when 'max'
133
- key = labels.merge!(__key_name: name)
134
- s = samples.fetch(key, value)
135
- samples[key] = max(s, value)
136
- when 'livesum'
137
- key = labels.merge!(__key_name: name)
138
- s = samples.fetch(key, 0.0)
139
- samples[key] = s + value
140
- else # all/liveall
141
- key = labels.merge!(pid: pid, __key_name: name)
142
- samples[key] = value
143
- end
144
- else
145
- key = labels.merge!(__key_name: name)
146
- # Counter, Histogram and Summary.
147
- s = samples.fetch(key, 0.0)
148
- samples[key] = s + value
149
- end
150
-
151
- samples
152
- end
153
-
154
106
  private
155
107
 
156
108
  def bin_to_hex(s)
@@ -3,54 +3,37 @@ module Prometheus
3
3
  module Helper
4
4
  module MetricsProcessing
5
5
  def self.merge_metrics(metrics)
6
- metrics
7
- end
8
-
9
- def self.min(a, b)
10
- if a < b
11
- a
12
- else
13
- b
14
- end
15
- end
16
-
17
- def self.max(a, b)
18
- if a > b
19
- a
20
- else
21
- b
6
+ metrics.each_value do |metric|
7
+ metric[:samples] = merge_samples(metric[:samples], metric[:type], metric[:multiprocess_mode]).map do |(name, labels), value|
8
+ [name, labels.to_h, value]
9
+ end
22
10
  end
23
11
  end
24
12
 
25
13
  def self.merge_samples(raw_samples, metric_type, multiprocess_mode)
26
14
  samples = {}
27
15
  raw_samples.each do |name, labels, value|
28
- key = { name: name, labels: labels }
29
- # without_pid = labels.delete(:pid)
16
+ without_pid = labels.reject { |l| l[0] == 'pid' }
30
17
 
31
18
  case metric_type
32
19
  when :gauge
33
20
  case multiprocess_mode
34
21
  when 'min'
35
- labels.delete(:pid)
36
- s = samples.fetch(key, value)
37
- samples[key] = min(s, value)
22
+ s = samples.fetch([name, without_pid], value)
23
+ samples[[name, without_pid]] = [s, value].min
38
24
  when 'max'
39
- labels.delete(:pid)
40
- s = samples.fetch(key, value)
41
- samples[key] = max(s, value)
25
+ s = samples.fetch([name, without_pid], value)
26
+ samples[[name, without_pid]] = [s, value].max
42
27
  when 'livesum'
43
- labels.delete(:pid)
44
- s = samples.fetch(key, 0.0)
45
- samples[key] = s + value
28
+ s = samples.fetch([name, without_pid], 0.0)
29
+ samples[[name, without_pid]] = s + value
46
30
  else # all/liveall
47
- samples[key] = value
31
+ samples[[name, labels]] = value
48
32
  end
49
33
  else
50
- labels.delete(:pid)
51
34
  # Counter, Histogram and Summary.
52
- s = samples.fetch(key, 0.0)
53
- samples[key] = s + value
35
+ s = samples.fetch([name, without_pid], 0.0)
36
+ samples[[name, without_pid]] = s + value
54
37
  end
55
38
  end
56
39
 
@@ -19,9 +19,8 @@ module Prometheus
19
19
  metrics.each do |name, metric|
20
20
  lines << format(HELP_LINE, name, escape(metric[:help]))
21
21
  lines << format(TYPE_LINE, name, metric[:type])
22
- metric[:samples].each do |labels, value|
23
- key = labels.delete(:__key_name)
24
- lines << metric(key, format_labels(labels), value)
22
+ metric[:samples].each do |metric_name, labels, value|
23
+ lines << metric(metric_name, format_labels(labels), value)
25
24
  end
26
25
  end
27
26
 
@@ -33,7 +32,7 @@ module Prometheus
33
32
  format(METRIC_LINE, name, labels, value)
34
33
  end
35
34
 
36
- def self.format_labels(set) #TODO: rename set
35
+ def self.format_labels(set)
37
36
  return if set.empty?
38
37
 
39
38
  strings = set.each_with_object([]) do |(key, value), memo|
@@ -1,7 +1,7 @@
1
1
  require 'prometheus/client/helper/entry_parser'
2
2
  require 'prometheus/client/helper/file_locker'
3
- require 'mmap'
4
3
  require 'fast_mmaped_file'
4
+ require 'mmap'
5
5
 
6
6
  module Prometheus
7
7
  module Client
@@ -5,7 +5,7 @@ module Prometheus
5
5
  module Helper
6
6
  class PlainFile
7
7
  include EntryParser
8
- attr_reader :filepath, :data
8
+ attr_reader :filepath
9
9
 
10
10
  def initialize(filepath)
11
11
  @filepath = filepath
@@ -19,8 +19,6 @@ module Prometheus
19
19
  @file_prefix += '_' + multiprocess_mode.to_s
20
20
  end
21
21
 
22
- self.class.reset_on_pid_change
23
- # initialize_file
24
22
  @pid = -1
25
23
 
26
24
  @mutex = Mutex.new
@@ -65,6 +63,7 @@ module Prometheus
65
63
  def initialize_file
66
64
  VALUE_LOCK.synchronize do
67
65
  return if @file && !pid_changed?
66
+ self.class.reset_on_pid_change
68
67
 
69
68
  @pid = Process.pid
70
69
  unless @@files.has_key?(@file_prefix)
@@ -90,16 +89,17 @@ module Prometheus
90
89
  end
91
90
 
92
91
  def self.reset_on_pid_change
93
- VALUE_LOCK.synchronize do
94
- if pid_changed?
95
- @@pid = Process.pid
96
- @@files = {}
97
- end
92
+ if pid_changed?
93
+ @@pid = Process.pid
94
+ @@files = {}
98
95
  end
99
96
  end
100
97
 
101
98
  def self.reinitialize_on_pid_change
102
- reset_on_pid_change
99
+ VALUE_LOCK.synchronize do
100
+ reset_on_pid_change
101
+ end
102
+
103
103
  ObjectSpace.each_object(MmapedValue, &:reinitialize)
104
104
  end
105
105
 
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.7.0.beta32'.freeze
3
+ VERSION = '0.7.0.beta33'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client-mmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.beta32
4
+ version: 0.7.0.beta33
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
@@ -59,6 +59,20 @@ dependencies:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 1.0.4
62
+ - !ruby/object:Gem::Dependency
63
+ name: ruby-prof
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.16.2
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.16.2
62
76
  description:
63
77
  email:
64
78
  - ts@soundcloud.com
@@ -71,8 +85,6 @@ files:
71
85
  - README.md
72
86
  - ext/fast_mmaped_file/extconf.rb
73
87
  - ext/fast_mmaped_file/fast_mmaped_file.c
74
- - ext/fast_mmaped_file/jsmn.c
75
- - ext/fast_mmaped_file/jsmn.h
76
88
  - ext/fast_mmaped_file/mmap.h
77
89
  - lib/fast_mmaped_file.bundle
78
90
  - lib/prometheus.rb
@@ -1,313 +0,0 @@
1
- #include "jsmn.h"
2
-
3
- /**
4
- * Allocates a fresh unused token from the token pull.
5
- */
6
- static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
7
- jsmntok_t *tokens, size_t num_tokens) {
8
- jsmntok_t *tok;
9
- if (parser->toknext >= num_tokens) {
10
- return NULL;
11
- }
12
- tok = &tokens[parser->toknext++];
13
- tok->start = tok->end = -1;
14
- tok->size = 0;
15
- #ifdef JSMN_PARENT_LINKS
16
- tok->parent = -1;
17
- #endif
18
- return tok;
19
- }
20
-
21
- /**
22
- * Fills token type and boundaries.
23
- */
24
- static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
25
- int start, int end) {
26
- token->type = type;
27
- token->start = start;
28
- token->end = end;
29
- token->size = 0;
30
- }
31
-
32
- /**
33
- * Fills next available token with JSON primitive.
34
- */
35
- static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
36
- size_t len, jsmntok_t *tokens, size_t num_tokens) {
37
- jsmntok_t *token;
38
- int start;
39
-
40
- start = parser->pos;
41
-
42
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
43
- switch (js[parser->pos]) {
44
- #ifndef JSMN_STRICT
45
- /* In strict mode primitive must be followed by "," or "}" or "]" */
46
- case ':':
47
- #endif
48
- case '\t' : case '\r' : case '\n' : case ' ' :
49
- case ',' : case ']' : case '}' :
50
- goto found;
51
- }
52
- if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
53
- parser->pos = start;
54
- return JSMN_ERROR_INVAL;
55
- }
56
- }
57
- #ifdef JSMN_STRICT
58
- /* In strict mode primitive must be followed by a comma/object/array */
59
- parser->pos = start;
60
- return JSMN_ERROR_PART;
61
- #endif
62
-
63
- found:
64
- if (tokens == NULL) {
65
- parser->pos--;
66
- return 0;
67
- }
68
- token = jsmn_alloc_token(parser, tokens, num_tokens);
69
- if (token == NULL) {
70
- parser->pos = start;
71
- return JSMN_ERROR_NOMEM;
72
- }
73
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
74
- #ifdef JSMN_PARENT_LINKS
75
- token->parent = parser->toksuper;
76
- #endif
77
- parser->pos--;
78
- return 0;
79
- }
80
-
81
- /**
82
- * Fills next token with JSON string.
83
- */
84
- static int jsmn_parse_string(jsmn_parser *parser, const char *js,
85
- size_t len, jsmntok_t *tokens, size_t num_tokens) {
86
- jsmntok_t *token;
87
-
88
- int start = parser->pos;
89
-
90
- parser->pos++;
91
-
92
- /* Skip starting quote */
93
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
94
- char c = js[parser->pos];
95
-
96
- /* Quote: end of string */
97
- if (c == '\"') {
98
- if (tokens == NULL) {
99
- return 0;
100
- }
101
- token = jsmn_alloc_token(parser, tokens, num_tokens);
102
- if (token == NULL) {
103
- parser->pos = start;
104
- return JSMN_ERROR_NOMEM;
105
- }
106
- jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
107
- #ifdef JSMN_PARENT_LINKS
108
- token->parent = parser->toksuper;
109
- #endif
110
- return 0;
111
- }
112
-
113
- /* Backslash: Quoted symbol expected */
114
- if (c == '\\' && parser->pos + 1 < len) {
115
- int i;
116
- parser->pos++;
117
- switch (js[parser->pos]) {
118
- /* Allowed escaped symbols */
119
- case '\"': case '/' : case '\\' : case 'b' :
120
- case 'f' : case 'r' : case 'n' : case 't' :
121
- break;
122
- /* Allows escaped symbol \uXXXX */
123
- case 'u':
124
- parser->pos++;
125
- for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
126
- /* If it isn't a hex character we have an error */
127
- if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
128
- (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
129
- (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
130
- parser->pos = start;
131
- return JSMN_ERROR_INVAL;
132
- }
133
- parser->pos++;
134
- }
135
- parser->pos--;
136
- break;
137
- /* Unexpected symbol */
138
- default:
139
- parser->pos = start;
140
- return JSMN_ERROR_INVAL;
141
- }
142
- }
143
- }
144
- parser->pos = start;
145
- return JSMN_ERROR_PART;
146
- }
147
-
148
- /**
149
- * Parse JSON string and fill tokens.
150
- */
151
- int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
152
- jsmntok_t *tokens, unsigned int num_tokens) {
153
- int r;
154
- int i;
155
- jsmntok_t *token;
156
- int count = parser->toknext;
157
-
158
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
159
- char c;
160
- jsmntype_t type;
161
-
162
- c = js[parser->pos];
163
- switch (c) {
164
- case '{': case '[':
165
- count++;
166
- if (tokens == NULL) {
167
- break;
168
- }
169
- token = jsmn_alloc_token(parser, tokens, num_tokens);
170
- if (token == NULL)
171
- return JSMN_ERROR_NOMEM;
172
- if (parser->toksuper != -1) {
173
- tokens[parser->toksuper].size++;
174
- #ifdef JSMN_PARENT_LINKS
175
- token->parent = parser->toksuper;
176
- #endif
177
- }
178
- token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
179
- token->start = parser->pos;
180
- parser->toksuper = parser->toknext - 1;
181
- break;
182
- case '}': case ']':
183
- if (tokens == NULL)
184
- break;
185
- type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
186
- #ifdef JSMN_PARENT_LINKS
187
- if (parser->toknext < 1) {
188
- return JSMN_ERROR_INVAL;
189
- }
190
- token = &tokens[parser->toknext - 1];
191
- for (;;) {
192
- if (token->start != -1 && token->end == -1) {
193
- if (token->type != type) {
194
- return JSMN_ERROR_INVAL;
195
- }
196
- token->end = parser->pos + 1;
197
- parser->toksuper = token->parent;
198
- break;
199
- }
200
- if (token->parent == -1) {
201
- if(token->type != type || parser->toksuper == -1) {
202
- return JSMN_ERROR_INVAL;
203
- }
204
- break;
205
- }
206
- token = &tokens[token->parent];
207
- }
208
- #else
209
- for (i = parser->toknext - 1; i >= 0; i--) {
210
- token = &tokens[i];
211
- if (token->start != -1 && token->end == -1) {
212
- if (token->type != type) {
213
- return JSMN_ERROR_INVAL;
214
- }
215
- parser->toksuper = -1;
216
- token->end = parser->pos + 1;
217
- break;
218
- }
219
- }
220
- /* Error if unmatched closing bracket */
221
- if (i == -1) return JSMN_ERROR_INVAL;
222
- for (; i >= 0; i--) {
223
- token = &tokens[i];
224
- if (token->start != -1 && token->end == -1) {
225
- parser->toksuper = i;
226
- break;
227
- }
228
- }
229
- #endif
230
- break;
231
- case '\"':
232
- r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
233
- if (r < 0) return r;
234
- count++;
235
- if (parser->toksuper != -1 && tokens != NULL)
236
- tokens[parser->toksuper].size++;
237
- break;
238
- case '\t' : case '\r' : case '\n' : case ' ':
239
- break;
240
- case ':':
241
- parser->toksuper = parser->toknext - 1;
242
- break;
243
- case ',':
244
- if (tokens != NULL && parser->toksuper != -1 &&
245
- tokens[parser->toksuper].type != JSMN_ARRAY &&
246
- tokens[parser->toksuper].type != JSMN_OBJECT) {
247
- #ifdef JSMN_PARENT_LINKS
248
- parser->toksuper = tokens[parser->toksuper].parent;
249
- #else
250
- for (i = parser->toknext - 1; i >= 0; i--) {
251
- if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
252
- if (tokens[i].start != -1 && tokens[i].end == -1) {
253
- parser->toksuper = i;
254
- break;
255
- }
256
- }
257
- }
258
- #endif
259
- }
260
- break;
261
- #ifdef JSMN_STRICT
262
- /* In strict mode primitives are: numbers and booleans */
263
- case '-': case '0': case '1' : case '2': case '3' : case '4':
264
- case '5': case '6': case '7' : case '8': case '9':
265
- case 't': case 'f': case 'n' :
266
- /* And they must not be keys of the object */
267
- if (tokens != NULL && parser->toksuper != -1) {
268
- jsmntok_t *t = &tokens[parser->toksuper];
269
- if (t->type == JSMN_OBJECT ||
270
- (t->type == JSMN_STRING && t->size != 0)) {
271
- return JSMN_ERROR_INVAL;
272
- }
273
- }
274
- #else
275
- /* In non-strict mode every unquoted value is a primitive */
276
- default:
277
- #endif
278
- r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
279
- if (r < 0) return r;
280
- count++;
281
- if (parser->toksuper != -1 && tokens != NULL)
282
- tokens[parser->toksuper].size++;
283
- break;
284
-
285
- #ifdef JSMN_STRICT
286
- /* Unexpected char in strict mode */
287
- default:
288
- return JSMN_ERROR_INVAL;
289
- #endif
290
- }
291
- }
292
-
293
- if (tokens != NULL) {
294
- for (i = parser->toknext - 1; i >= 0; i--) {
295
- /* Unmatched opened object or array */
296
- if (tokens[i].start != -1 && tokens[i].end == -1) {
297
- return JSMN_ERROR_PART;
298
- }
299
- }
300
- }
301
-
302
- return count;
303
- }
304
-
305
- /**
306
- * Creates a new parser based over a given buffer with an array of tokens
307
- * available.
308
- */
309
- void jsmn_init(jsmn_parser *parser) {
310
- parser->pos = 0;
311
- parser->toknext = 0;
312
- parser->toksuper = -1;
313
- }
@@ -1,76 +0,0 @@
1
- #ifndef __JSMN_H_
2
- #define __JSMN_H_
3
-
4
- #include <stddef.h>
5
-
6
- #ifdef __cplusplus
7
- extern "C" {
8
- #endif
9
-
10
- /**
11
- * JSON type identifier. Basic types are:
12
- * o Object
13
- * o Array
14
- * o String
15
- * o Other primitive: number, boolean (true/false) or null
16
- */
17
- typedef enum {
18
- JSMN_UNDEFINED = 0,
19
- JSMN_OBJECT = 1,
20
- JSMN_ARRAY = 2,
21
- JSMN_STRING = 3,
22
- JSMN_PRIMITIVE = 4
23
- } jsmntype_t;
24
-
25
- enum jsmnerr {
26
- /* Not enough tokens were provided */
27
- JSMN_ERROR_NOMEM = -1,
28
- /* Invalid character inside JSON string */
29
- JSMN_ERROR_INVAL = -2,
30
- /* The string is not a full JSON packet, more bytes expected */
31
- JSMN_ERROR_PART = -3
32
- };
33
-
34
- /**
35
- * JSON token description.
36
- * type type (object, array, string etc.)
37
- * start start position in JSON data string
38
- * end end position in JSON data string
39
- */
40
- typedef struct {
41
- jsmntype_t type;
42
- int start;
43
- int end;
44
- int size;
45
- #ifdef JSMN_PARENT_LINKS
46
- int parent;
47
- #endif
48
- } jsmntok_t;
49
-
50
- /**
51
- * JSON parser. Contains an array of token blocks available. Also stores
52
- * the string being parsed now and current position in that string
53
- */
54
- typedef struct {
55
- unsigned int pos; /* offset in the JSON string */
56
- unsigned int toknext; /* next token to allocate */
57
- int toksuper; /* superior token node, e.g parent object or array */
58
- } jsmn_parser;
59
-
60
- /**
61
- * Create JSON parser over an array of tokens
62
- */
63
- void jsmn_init(jsmn_parser *parser);
64
-
65
- /**
66
- * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
67
- * a single JSON object.
68
- */
69
- int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
70
- jsmntok_t *tokens, unsigned int num_tokens);
71
-
72
- #ifdef __cplusplus
73
- }
74
- #endif
75
-
76
- #endif /* __JSMN_H_ */