sassc 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/libsass/.gitignore +6 -0
  4. data/ext/libsass/.travis.yml +5 -1
  5. data/ext/libsass/Makefile +12 -3
  6. data/ext/libsass/Makefile.am +16 -28
  7. data/ext/libsass/Readme.md +1 -0
  8. data/ext/libsass/appveyor.yml +1 -2
  9. data/ext/libsass/ast.cpp +9 -0
  10. data/ext/libsass/ast.hpp +152 -55
  11. data/ext/libsass/ast_factory.hpp +2 -0
  12. data/ext/libsass/ast_fwd_decl.hpp +1 -0
  13. data/ext/libsass/backtrace.hpp +2 -2
  14. data/ext/libsass/bind.cpp +15 -13
  15. data/ext/libsass/configure.ac +17 -5
  16. data/ext/libsass/constants.cpp +22 -2
  17. data/ext/libsass/constants.hpp +21 -2
  18. data/ext/libsass/context.cpp +79 -57
  19. data/ext/libsass/context.hpp +23 -9
  20. data/ext/libsass/contextualize.cpp +2 -28
  21. data/ext/libsass/contextualize.hpp +6 -10
  22. data/ext/libsass/contextualize_eval.cpp +93 -0
  23. data/ext/libsass/contextualize_eval.hpp +44 -0
  24. data/ext/libsass/contrib/plugin.cpp +57 -0
  25. data/ext/libsass/cssize.cpp +3 -1
  26. data/ext/libsass/debugger.hpp +242 -83
  27. data/ext/libsass/emitter.cpp +1 -1
  28. data/ext/libsass/emitter.hpp +1 -1
  29. data/ext/libsass/environment.hpp +109 -25
  30. data/ext/libsass/error_handling.cpp +3 -3
  31. data/ext/libsass/error_handling.hpp +0 -1
  32. data/ext/libsass/eval.cpp +145 -61
  33. data/ext/libsass/eval.hpp +9 -1
  34. data/ext/libsass/expand.cpp +134 -60
  35. data/ext/libsass/expand.hpp +5 -2
  36. data/ext/libsass/extend.cpp +7 -5
  37. data/ext/libsass/file.cpp +176 -123
  38. data/ext/libsass/file.hpp +44 -7
  39. data/ext/libsass/functions.cpp +36 -17
  40. data/ext/libsass/functions.hpp +2 -2
  41. data/ext/libsass/inspect.cpp +23 -14
  42. data/ext/libsass/inspect.hpp +1 -0
  43. data/ext/libsass/json.cpp +132 -135
  44. data/ext/libsass/lexer.cpp +133 -0
  45. data/ext/libsass/lexer.hpp +239 -0
  46. data/ext/libsass/listize.cpp +83 -0
  47. data/ext/libsass/listize.hpp +41 -0
  48. data/ext/libsass/operation.hpp +2 -0
  49. data/ext/libsass/output.cpp +5 -6
  50. data/ext/libsass/parser.cpp +426 -388
  51. data/ext/libsass/parser.hpp +97 -109
  52. data/ext/libsass/plugins.cpp +15 -2
  53. data/ext/libsass/plugins.hpp +6 -4
  54. data/ext/libsass/position.cpp +52 -17
  55. data/ext/libsass/position.hpp +19 -17
  56. data/ext/libsass/prelexer.cpp +202 -235
  57. data/ext/libsass/prelexer.hpp +73 -333
  58. data/ext/libsass/sass.cpp +21 -11
  59. data/ext/libsass/sass.h +6 -6
  60. data/ext/libsass/sass_context.cpp +167 -81
  61. data/ext/libsass/sass_context.h +26 -6
  62. data/ext/libsass/sass_functions.cpp +49 -40
  63. data/ext/libsass/sass_functions.h +55 -43
  64. data/ext/libsass/sass_interface.cpp +9 -8
  65. data/ext/libsass/sass_interface.h +3 -3
  66. data/ext/libsass/sass_version.h +8 -0
  67. data/ext/libsass/sass_version.h.in +8 -0
  68. data/ext/libsass/script/ci-build-libsass +3 -3
  69. data/ext/libsass/script/ci-report-coverage +2 -1
  70. data/ext/libsass/source_map.cpp +2 -2
  71. data/ext/libsass/util.cpp +60 -11
  72. data/ext/libsass/util.hpp +6 -1
  73. data/ext/libsass/win/libsass.filters +12 -0
  74. data/ext/libsass/win/libsass.vcxproj +10 -0
  75. data/lib/sassc.rb +3 -1
  76. data/lib/sassc/cache_stores/base.rb +2 -0
  77. data/lib/sassc/dependency.rb +3 -1
  78. data/lib/sassc/engine.rb +31 -16
  79. data/lib/sassc/error.rb +3 -2
  80. data/lib/sassc/functions_handler.rb +54 -0
  81. data/lib/sassc/import_handler.rb +41 -0
  82. data/lib/sassc/importer.rb +4 -31
  83. data/lib/sassc/native.rb +1 -1
  84. data/lib/sassc/native/native_context_api.rb +3 -2
  85. data/lib/sassc/script.rb +0 -51
  86. data/lib/sassc/version.rb +1 -1
  87. data/sassc.gemspec +1 -0
  88. data/test/custom_importer_test.rb +72 -69
  89. data/test/engine_test.rb +53 -54
  90. data/test/functions_test.rb +40 -39
  91. data/test/native_test.rb +145 -149
  92. data/test/output_style_test.rb +98 -0
  93. data/test/test_helper.rb +21 -7
  94. metadata +28 -2
@@ -2,21 +2,58 @@
2
2
  #define SASS_FILE_H
3
3
 
4
4
  #include <string>
5
+ #include <vector>
5
6
 
6
7
  namespace Sass {
7
8
  using namespace std;
8
9
  class Context;
9
10
  namespace File {
11
+
12
+ // return the current directory
13
+ // always with forward slashes
10
14
  string get_cwd();
11
- string base_name(string);
12
- string dir_name(string);
13
- string join_paths(string, string);
15
+
16
+ // test if path exists and is a file
17
+ bool file_exists(const string& file);
18
+
19
+ // return if given path is absolute
20
+ // works with *nix and windows paths
14
21
  bool is_absolute_path(const string& path);
22
+
23
+ // return only the directory part of path
24
+ string dir_name(const string& path);
25
+
26
+ // return only the filename part of path
27
+ string base_name(const string&);
28
+
29
+ // do a locigal clean up of the path
30
+ // no physical check on the filesystem
15
31
  string make_canonical_path (string path);
16
- string make_absolute_path(const string& path, const string& cwd);
17
- string resolve_relative_path(const string& uri, const string& base, const string& cwd);
18
- char* resolve_and_load(string path, string& real_path);
19
- char* read_file(string path);
32
+
33
+ // join two path segments cleanly together
34
+ // but only if right side is not absolute yet
35
+ string join_paths(string root, string name);
36
+
37
+ // create an absolute path by resolving relative paths with cwd
38
+ string make_absolute_path(const string& path, const string& cwd = ".");
39
+
40
+ // create a path that is relative to the given base directory
41
+ // path and base will first be resolved against cwd to make them absolute
42
+ string resolve_relative_path(const string& path, const string& base, const string& cwd = ".");
43
+
44
+ // try to find/resolve the filename
45
+ string resolve_file(const string& file);
46
+
47
+ // helper function to resolve a filename
48
+ string find_file(const string& file, const vector<string> paths);
49
+ // inc paths can be directly passed from C code
50
+ string find_file(const string& file, const char** paths);
51
+
52
+ // try to load the given filename
53
+ // returned memory must be freed
54
+ // will auto convert .sass files
55
+ char* read_file(const string& file);
56
+
20
57
  }
21
58
  }
22
59
 
@@ -35,7 +35,7 @@ namespace Sass {
35
35
  using std::stringstream;
36
36
  using std::endl;
37
37
 
38
- Definition* make_native_function(Signature sig, Native_Function f, Context& ctx)
38
+ Definition* make_native_function(Signature sig, Native_Function func, Context& ctx)
39
39
  {
40
40
  Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[built-in function]"));
41
41
  sig_parser.lex<Prelexer::identifier>();
@@ -45,12 +45,14 @@ namespace Sass {
45
45
  sig,
46
46
  name,
47
47
  params,
48
- f,
48
+ func,
49
+ &ctx,
49
50
  false);
50
51
  }
51
52
 
52
- Definition* make_c_function(Signature sig, Sass_C_Function f, void* cookie, Context& ctx)
53
+ Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx)
53
54
  {
55
+ const char* sig = sass_function_get_signature(c_func);
54
56
  Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[c function]"));
55
57
  // allow to overload generic callback plus @warn, @error and @debug with custom functions
56
58
  sig_parser.lex < alternatives < identifier, exactly <'*'>,
@@ -64,8 +66,8 @@ namespace Sass {
64
66
  sig,
65
67
  name,
66
68
  params,
67
- f,
68
- cookie,
69
+ c_func,
70
+ &ctx,
69
71
  false, true);
70
72
  }
71
73
 
@@ -145,7 +147,11 @@ namespace Sass {
145
147
  static mt19937 rand(static_cast<unsigned int>(GetSeed()));
146
148
 
147
149
  // features
148
- static set<string> features;
150
+ static set<string> features {
151
+ "global-variable-shadowing",
152
+ "at-error",
153
+ "units-level-3"
154
+ };
149
155
 
150
156
  ////////////////
151
157
  // RGB FUNCTIONS
@@ -940,7 +946,7 @@ namespace Sass {
940
946
  error(msg, pstate, backtrace);
941
947
  }
942
948
  catch (...) { throw; }
943
- return new (ctx.mem) String_Constant(pstate, newstr);
949
+ return new (ctx.mem) String_Quoted(pstate, newstr);
944
950
  }
945
951
 
946
952
  Signature to_upper_case_sig = "to-upper-case($string)";
@@ -1065,16 +1071,16 @@ namespace Sass {
1065
1071
  BUILT_IN(random)
1066
1072
  {
1067
1073
  Number* l = dynamic_cast<Number*>(env["$limit"]);
1068
- if (l && trunc(l->value()) != l->value()) error("argument $limit of `" + string(sig) + "` must be an integer", pstate);
1069
1074
  if (l) {
1075
+ if (trunc(l->value()) != l->value() || l->value() == 0) error("argument $limit of `" + string(sig) + "` must be a positive integer", pstate);
1070
1076
  uniform_real_distribution<> distributor(1, l->value() + 1);
1071
1077
  uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
1072
1078
  return new (ctx.mem) Number(pstate, (double)distributed);
1073
1079
  }
1074
1080
  else {
1075
1081
  uniform_real_distribution<> distributor(0, 1);
1076
- uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
1077
- return new (ctx.mem) Number(pstate, trunc(distributed));
1082
+ double distributed = static_cast<double>(distributor(rand));
1083
+ return new (ctx.mem) Number(pstate, distributed);
1078
1084
  }
1079
1085
  }
1080
1086
 
@@ -1408,7 +1414,7 @@ namespace Sass {
1408
1414
  {
1409
1415
  string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1410
1416
 
1411
- if(d_env.global_frame_has("$"+s)) {
1417
+ if(d_env.has_global("$"+s)) {
1412
1418
  return new (ctx.mem) Boolean(pstate, true);
1413
1419
  }
1414
1420
  else {
@@ -1421,7 +1427,7 @@ namespace Sass {
1421
1427
  {
1422
1428
  string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1423
1429
 
1424
- if(d_env.global_frame_has(s+"[f]")) {
1430
+ if(d_env.has_global(s+"[f]")) {
1425
1431
  return new (ctx.mem) Boolean(pstate, true);
1426
1432
  }
1427
1433
  else {
@@ -1434,7 +1440,7 @@ namespace Sass {
1434
1440
  {
1435
1441
  string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1436
1442
 
1437
- if(d_env.global_frame_has(s+"[m]")) {
1443
+ if(d_env.has_global(s+"[m]")) {
1438
1444
  return new (ctx.mem) Boolean(pstate, true);
1439
1445
  }
1440
1446
  else {
@@ -1463,11 +1469,22 @@ namespace Sass {
1463
1469
 
1464
1470
  Arguments* args = new (ctx.mem) Arguments(pstate);
1465
1471
  for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1466
- Argument* arg = new (ctx.mem) Argument(pstate, arglist->value_at_index(i));
1467
- *args << arg;
1472
+ Expression* expr = arglist->value_at_index(i);
1473
+ if (arglist->is_arglist()) {
1474
+ Argument* arg = static_cast<Argument*>(expr);
1475
+ *args << new (ctx.mem) Argument(pstate,
1476
+ expr,
1477
+ "",
1478
+ arg->is_rest_argument(),
1479
+ arg->is_keyword_argument());
1480
+ } else {
1481
+ *args << new (ctx.mem) Argument(pstate, expr);
1482
+ }
1468
1483
  }
1469
1484
  Function_Call* func = new (ctx.mem) Function_Call(pstate, name, args);
1470
- Eval eval(ctx, &d_env, backtrace);
1485
+ Contextualize contextualize(ctx, &d_env, backtrace);
1486
+ Listize listize(ctx);
1487
+ Eval eval(ctx, &contextualize, &listize, &d_env, backtrace);
1471
1488
  return func->perform(&eval);
1472
1489
 
1473
1490
  }
@@ -1485,7 +1502,9 @@ namespace Sass {
1485
1502
  // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); }
1486
1503
  BUILT_IN(sass_if)
1487
1504
  {
1488
- Eval eval(ctx, &d_env, backtrace);
1505
+ Contextualize contextualize(ctx, &d_env, backtrace);
1506
+ Listize listize(ctx);
1507
+ Eval eval(ctx, &contextualize, &listize, &d_env, backtrace);
1489
1508
  bool is_true = !ARG("$condition", Expression)->perform(&eval)->is_false();
1490
1509
  if (is_true) {
1491
1510
  return ARG("$if-true", Expression)->perform(&eval);
@@ -20,8 +20,8 @@ namespace Sass {
20
20
  typedef const char* Signature;
21
21
  typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
22
22
 
23
- Definition* make_native_function(Signature, Native_Function, Context&);
24
- Definition* make_c_function(Signature sig, Sass_C_Function f, void* cookie, Context& ctx);
23
+ Definition* make_native_function(Signature, Native_Function, Context& ctx);
24
+ Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx);
25
25
 
26
26
  namespace Functions {
27
27
 
@@ -44,9 +44,8 @@ namespace Sass {
44
44
 
45
45
  void Inspect::operator()(Keyframe_Rule* rule)
46
46
  {
47
- append_indentation();
48
- if (rule->rules()) rule->rules()->perform(this);
49
- rule->block()->perform(this);
47
+ if (rule->selector()) rule->selector()->perform(this);
48
+ if (rule->block()) rule->block()->perform(this);
50
49
  }
51
50
 
52
51
  void Inspect::operator()(Propset* propset)
@@ -59,14 +58,10 @@ namespace Sass {
59
58
  void Inspect::operator()(Bubble* bubble)
60
59
  {
61
60
  append_indentation();
62
- append_token("Bubble", bubble);
63
- append_optional_space();
64
- append_string("(");
65
- append_optional_space();
61
+ append_token("::BUBBLE", bubble);
62
+ append_scope_opener();
66
63
  bubble->node()->perform(this);
67
- append_optional_space();
68
- append_string(")");
69
- append_optional_space();
64
+ append_scope_closer();
70
65
  }
71
66
 
72
67
  void Inspect::operator()(Media_Block* media_block)
@@ -104,9 +99,9 @@ namespace Sass {
104
99
  append_token(at_rule->keyword(), at_rule);
105
100
  if (at_rule->selector()) {
106
101
  append_mandatory_space();
107
- in_at_rule = true;
102
+ in_wrapped = true;
108
103
  at_rule->selector()->perform(this);
109
- in_at_rule = false;
104
+ in_wrapped = false;
110
105
  }
111
106
  if (at_rule->block()) {
112
107
  at_rule->block()->perform(this);
@@ -141,7 +136,7 @@ namespace Sass {
141
136
  append_token(assn->variable(), assn);
142
137
  append_colon_separator();
143
138
  assn->value()->perform(this);
144
- if (assn->is_guarded()) {
139
+ if (assn->is_default()) {
145
140
  append_optional_space();
146
141
  append_string("!default");
147
142
  }
@@ -665,6 +660,17 @@ namespace Sass {
665
660
  append_token("null", n);
666
661
  }
667
662
 
663
+ void Inspect::operator()(Parent_Selector* p)
664
+ {
665
+ if (p->selector()) {
666
+ p->selector()->perform(this);
667
+ append_delimiter();
668
+ }
669
+ else {
670
+ append_string("&");
671
+ }
672
+ }
673
+
668
674
  // parameters and arguments
669
675
  void Inspect::operator()(Parameter* p)
670
676
  {
@@ -781,9 +787,12 @@ namespace Sass {
781
787
 
782
788
  void Inspect::operator()(Wrapped_Selector* s)
783
789
  {
790
+ bool was = in_wrapped;
791
+ in_wrapped = true;
784
792
  append_token(s->name(), s);
785
793
  s->selector()->perform(this);
786
794
  append_string(")");
795
+ in_wrapped = was;
787
796
  }
788
797
 
789
798
  void Inspect::operator()(Compound_Selector* s)
@@ -838,7 +847,7 @@ namespace Sass {
838
847
  {
839
848
  if (g->empty()) return;
840
849
  for (size_t i = 0, L = g->length(); i < L; ++i) {
841
- if (!in_at_rule && i == 0) append_indentation();
850
+ if (!in_wrapped && i == 0) append_indentation();
842
851
  (*g)[i]->perform(this);
843
852
  if (i < L - 1) {
844
853
  append_comma_separator();
@@ -71,6 +71,7 @@ namespace Sass {
71
71
  virtual void operator()(Media_Query_Expression*);
72
72
  virtual void operator()(At_Root_Expression*);
73
73
  virtual void operator()(Null*);
74
+ virtual void operator()(Parent_Selector* p);
74
75
  // parameters and arguments
75
76
  virtual void operator()(Parameter*);
76
77
  virtual void operator()(Parameters*);
@@ -102,11 +102,11 @@ static void sb_grow(SB *sb, int need)
102
102
  {
103
103
  size_t length = sb->cur - sb->start;
104
104
  size_t alloc = sb->end - sb->start;
105
-
105
+
106
106
  do {
107
107
  alloc *= 2;
108
108
  } while (alloc < length + need);
109
-
109
+
110
110
  sb->start = (char*) realloc(sb->start, alloc + 1);
111
111
  if (sb->start == NULL)
112
112
  out_of_memory();
@@ -150,13 +150,10 @@ static void sb_free(SB *sb)
150
150
  * These are taken from the ccan/charset module and customized a bit.
151
151
  * Putting them here means the compiler can (choose to) inline them,
152
152
  * and it keeps ccan/json from having a dependency.
153
- */
154
-
155
- /*
156
- * Type for Unicode codepoints.
153
+ *
154
+ * We use uint32_t Type for Unicode codepoints.
157
155
  * We need our own because wchar_t might be 16 bits.
158
156
  */
159
- typedef uint32_t uchar_t;
160
157
 
161
158
  /*
162
159
  * Validate a single UTF-8 character starting at @s.
@@ -181,7 +178,7 @@ typedef uint32_t uchar_t;
181
178
  static int utf8_validate_cz(const char *s)
182
179
  {
183
180
  unsigned char c = *s++;
184
-
181
+
185
182
  if (c <= 0x7F) { /* 00..7F */
186
183
  return 1;
187
184
  } else if (c <= 0xC1) { /* 80..C1 */
@@ -191,33 +188,33 @@ static int utf8_validate_cz(const char *s)
191
188
  /* Make sure subsequent byte is in the range 0x80..0xBF. */
192
189
  if (((unsigned char)*s++ & 0xC0) != 0x80)
193
190
  return 0;
194
-
191
+
195
192
  return 2;
196
193
  } else if (c <= 0xEF) { /* E0..EF */
197
194
  /* Disallow overlong 3-byte sequence. */
198
195
  if (c == 0xE0 && (unsigned char)*s < 0xA0)
199
196
  return 0;
200
-
197
+
201
198
  /* Disallow U+D800..U+DFFF. */
202
199
  if (c == 0xED && (unsigned char)*s > 0x9F)
203
200
  return 0;
204
-
201
+
205
202
  /* Make sure subsequent bytes are in the range 0x80..0xBF. */
206
203
  if (((unsigned char)*s++ & 0xC0) != 0x80)
207
204
  return 0;
208
205
  if (((unsigned char)*s++ & 0xC0) != 0x80)
209
206
  return 0;
210
-
207
+
211
208
  return 3;
212
209
  } else if (c <= 0xF4) { /* F0..F4 */
213
210
  /* Disallow overlong 4-byte sequence. */
214
211
  if (c == 0xF0 && (unsigned char)*s < 0x90)
215
212
  return 0;
216
-
213
+
217
214
  /* Disallow codepoints beyond U+10FFFF. */
218
215
  if (c == 0xF4 && (unsigned char)*s > 0x8F)
219
216
  return 0;
220
-
217
+
221
218
  /* Make sure subsequent bytes are in the range 0x80..0xBF. */
222
219
  if (((unsigned char)*s++ & 0xC0) != 0x80)
223
220
  return 0;
@@ -225,7 +222,7 @@ static int utf8_validate_cz(const char *s)
225
222
  return 0;
226
223
  if (((unsigned char)*s++ & 0xC0) != 0x80)
227
224
  return 0;
228
-
225
+
229
226
  return 4;
230
227
  } else { /* F5..FF */
231
228
  return 0;
@@ -236,13 +233,13 @@ static int utf8_validate_cz(const char *s)
236
233
  static bool utf8_validate(const char *s)
237
234
  {
238
235
  int len;
239
-
236
+
240
237
  for (; *s != 0; s += len) {
241
238
  len = utf8_validate_cz(s);
242
239
  if (len == 0)
243
240
  return false;
244
241
  }
245
-
242
+
246
243
  return true;
247
244
  }
248
245
 
@@ -253,10 +250,10 @@ static bool utf8_validate(const char *s)
253
250
  * This function assumes input is valid UTF-8,
254
251
  * and that there are enough characters in front of @s.
255
252
  */
256
- static int utf8_read_char(const char *s, uchar_t *out)
253
+ static int utf8_read_char(const char *s, uint32_t *out)
257
254
  {
258
255
  const unsigned char *c = (const unsigned char*) s;
259
-
256
+
260
257
  assert(utf8_validate_cz(s));
261
258
 
262
259
  if (c[0] <= 0x7F) {
@@ -265,21 +262,21 @@ static int utf8_read_char(const char *s, uchar_t *out)
265
262
  return 1;
266
263
  } else if (c[0] <= 0xDF) {
267
264
  /* C2..DF (unless input is invalid) */
268
- *out = ((uchar_t)c[0] & 0x1F) << 6 |
269
- ((uchar_t)c[1] & 0x3F);
265
+ *out = ((uint32_t)c[0] & 0x1F) << 6 |
266
+ ((uint32_t)c[1] & 0x3F);
270
267
  return 2;
271
268
  } else if (c[0] <= 0xEF) {
272
269
  /* E0..EF */
273
- *out = ((uchar_t)c[0] & 0xF) << 12 |
274
- ((uchar_t)c[1] & 0x3F) << 6 |
275
- ((uchar_t)c[2] & 0x3F);
270
+ *out = ((uint32_t)c[0] & 0xF) << 12 |
271
+ ((uint32_t)c[1] & 0x3F) << 6 |
272
+ ((uint32_t)c[2] & 0x3F);
276
273
  return 3;
277
274
  } else {
278
275
  /* F0..F4 (unless input is invalid) */
279
- *out = ((uchar_t)c[0] & 0x7) << 18 |
280
- ((uchar_t)c[1] & 0x3F) << 12 |
281
- ((uchar_t)c[2] & 0x3F) << 6 |
282
- ((uchar_t)c[3] & 0x3F);
276
+ *out = ((uint32_t)c[0] & 0x7) << 18 |
277
+ ((uint32_t)c[1] & 0x3F) << 12 |
278
+ ((uint32_t)c[2] & 0x3F) << 6 |
279
+ ((uint32_t)c[3] & 0x3F);
283
280
  return 4;
284
281
  }
285
282
  }
@@ -292,10 +289,10 @@ static int utf8_read_char(const char *s, uchar_t *out)
292
289
  *
293
290
  * This function will write up to 4 bytes to @out.
294
291
  */
295
- static int utf8_write_char(uchar_t unicode, char *out)
292
+ static int utf8_write_char(uint32_t unicode, char *out)
296
293
  {
297
294
  unsigned char *o = (unsigned char*) out;
298
-
295
+
299
296
  assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
300
297
 
301
298
  if (unicode <= 0x7F) {
@@ -329,10 +326,10 @@ static int utf8_write_char(uchar_t unicode, char *out)
329
326
  * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF.
330
327
  * If they aren't, this function returns false.
331
328
  */
332
- static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uchar_t *unicode)
329
+ static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uint32_t *unicode)
333
330
  {
334
331
  if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
335
- *unicode = 0x10000 + ((((uchar_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
332
+ *unicode = 0x10000 + ((((uint32_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
336
333
  return true;
337
334
  } else {
338
335
  return false;
@@ -344,12 +341,12 @@ static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uchar_t *unicode)
344
341
  *
345
342
  * @unicode must be U+10000..U+10FFFF.
346
343
  */
347
- static void to_surrogate_pair(uchar_t unicode, uint16_t *uc, uint16_t *lc)
344
+ static void to_surrogate_pair(uint32_t unicode, uint16_t *uc, uint16_t *lc)
348
345
  {
349
- uchar_t n;
350
-
346
+ uint32_t n;
347
+
351
348
  assert(unicode >= 0x10000 && unicode <= 0x10FFFF);
352
-
349
+
353
350
  n = unicode - 0x10000;
354
351
  *uc = ((n >> 10) & 0x3FF) | 0xD800;
355
352
  *lc = (n & 0x3FF) | 0xDC00;
@@ -392,17 +389,17 @@ JsonNode *json_decode(const char *json)
392
389
  {
393
390
  const char *s = json;
394
391
  JsonNode *ret;
395
-
392
+
396
393
  skip_space(&s);
397
394
  if (!parse_value(&s, &ret))
398
395
  return NULL;
399
-
396
+
400
397
  skip_space(&s);
401
398
  if (*s != 0) {
402
399
  json_delete(ret);
403
400
  return NULL;
404
401
  }
405
-
402
+
406
403
  return ret;
407
404
  }
408
405
 
@@ -415,9 +412,9 @@ char *json_encode_string(const char *str)
415
412
  {
416
413
  SB sb;
417
414
  sb_init(&sb);
418
-
415
+
419
416
  emit_string(&sb, str);
420
-
417
+
421
418
  return sb_finish(&sb);
422
419
  }
423
420
 
@@ -425,12 +422,12 @@ char *json_stringify(const JsonNode *node, const char *space)
425
422
  {
426
423
  SB sb;
427
424
  sb_init(&sb);
428
-
425
+
429
426
  if (space != NULL)
430
427
  emit_value_indented(&sb, node, space, 0);
431
428
  else
432
429
  emit_value(&sb, node);
433
-
430
+
434
431
  return sb_finish(&sb);
435
432
  }
436
433
 
@@ -438,7 +435,7 @@ void json_delete(JsonNode *node)
438
435
  {
439
436
  if (node != NULL) {
440
437
  json_remove_from_parent(node);
441
-
438
+
442
439
  switch (node->tag) {
443
440
  case JSON_STRING:
444
441
  free(node->string_);
@@ -455,7 +452,7 @@ void json_delete(JsonNode *node)
455
452
  }
456
453
  default:;
457
454
  }
458
-
455
+
459
456
  free(node);
460
457
  }
461
458
  }
@@ -463,15 +460,15 @@ void json_delete(JsonNode *node)
463
460
  bool json_validate(const char *json)
464
461
  {
465
462
  const char *s = json;
466
-
463
+
467
464
  skip_space(&s);
468
465
  if (!parse_value(&s, NULL))
469
466
  return false;
470
-
467
+
471
468
  skip_space(&s);
472
469
  if (*s != 0)
473
470
  return false;
474
-
471
+
475
472
  return true;
476
473
  }
477
474
 
@@ -479,30 +476,30 @@ JsonNode *json_find_element(JsonNode *array, int index)
479
476
  {
480
477
  JsonNode *element;
481
478
  int i = 0;
482
-
479
+
483
480
  if (array == NULL || array->tag != JSON_ARRAY)
484
481
  return NULL;
485
-
482
+
486
483
  json_foreach(element, array) {
487
484
  if (i == index)
488
485
  return element;
489
486
  i++;
490
487
  }
491
-
488
+
492
489
  return NULL;
493
490
  }
494
491
 
495
492
  JsonNode *json_find_member(JsonNode *object, const char *name)
496
493
  {
497
494
  JsonNode *member;
498
-
495
+
499
496
  if (object == NULL || object->tag != JSON_OBJECT)
500
497
  return NULL;
501
-
498
+
502
499
  json_foreach(member, object)
503
500
  if (strcmp(member->key, name) == 0)
504
501
  return member;
505
-
502
+
506
503
  return NULL;
507
504
  }
508
505
 
@@ -568,7 +565,7 @@ static void append_node(JsonNode *parent, JsonNode *child)
568
565
  child->parent = parent;
569
566
  child->prev = parent->children.tail;
570
567
  child->next = NULL;
571
-
568
+
572
569
  if (parent->children.tail != NULL)
573
570
  parent->children.tail->next = child;
574
571
  else
@@ -581,7 +578,7 @@ static void prepend_node(JsonNode *parent, JsonNode *child)
581
578
  child->parent = parent;
582
579
  child->prev = NULL;
583
580
  child->next = parent->children.head;
584
-
581
+
585
582
  if (parent->children.head != NULL)
586
583
  parent->children.head->prev = child;
587
584
  else
@@ -599,7 +596,7 @@ void json_append_element(JsonNode *array, JsonNode *element)
599
596
  {
600
597
  assert(array->tag == JSON_ARRAY);
601
598
  assert(element->parent == NULL);
602
-
599
+
603
600
  append_node(array, element);
604
601
  }
605
602
 
@@ -607,7 +604,7 @@ void json_prepend_element(JsonNode *array, JsonNode *element)
607
604
  {
608
605
  assert(array->tag == JSON_ARRAY);
609
606
  assert(element->parent == NULL);
610
-
607
+
611
608
  prepend_node(array, element);
612
609
  }
613
610
 
@@ -615,7 +612,7 @@ void json_append_member(JsonNode *object, const char *key, JsonNode *value)
615
612
  {
616
613
  assert(object->tag == JSON_OBJECT);
617
614
  assert(value->parent == NULL);
618
-
615
+
619
616
  append_member(object, json_strdup(key), value);
620
617
  }
621
618
 
@@ -623,7 +620,7 @@ void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
623
620
  {
624
621
  assert(object->tag == JSON_OBJECT);
625
622
  assert(value->parent == NULL);
626
-
623
+
627
624
  value->key = json_strdup(key);
628
625
  prepend_node(object, value);
629
626
  }
@@ -631,7 +628,7 @@ void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
631
628
  void json_remove_from_parent(JsonNode *node)
632
629
  {
633
630
  JsonNode *parent = node->parent;
634
-
631
+
635
632
  if (parent != NULL) {
636
633
  if (node->prev != NULL)
637
634
  node->prev->next = node->next;
@@ -641,9 +638,9 @@ void json_remove_from_parent(JsonNode *node)
641
638
  node->next->prev = node->prev;
642
639
  else
643
640
  parent->children.tail = node->prev;
644
-
641
+
645
642
  free(node->key);
646
-
643
+
647
644
  node->parent = NULL;
648
645
  node->prev = node->next = NULL;
649
646
  node->key = NULL;
@@ -653,7 +650,7 @@ void json_remove_from_parent(JsonNode *node)
653
650
  static bool parse_value(const char **sp, JsonNode **out)
654
651
  {
655
652
  const char *s = *sp;
656
-
653
+
657
654
  switch (*s) {
658
655
  case 'n':
659
656
  if (expect_literal(&s, "null")) {
@@ -663,7 +660,7 @@ static bool parse_value(const char **sp, JsonNode **out)
663
660
  return true;
664
661
  }
665
662
  return false;
666
-
663
+
667
664
  case 'f':
668
665
  if (expect_literal(&s, "false")) {
669
666
  if (out)
@@ -672,7 +669,7 @@ static bool parse_value(const char **sp, JsonNode **out)
672
669
  return true;
673
670
  }
674
671
  return false;
675
-
672
+
676
673
  case 't':
677
674
  if (expect_literal(&s, "true")) {
678
675
  if (out)
@@ -681,7 +678,7 @@ static bool parse_value(const char **sp, JsonNode **out)
681
678
  return true;
682
679
  }
683
680
  return false;
684
-
681
+
685
682
  case '"': {
686
683
  char *str;
687
684
  if (parse_string(&s, out ? &str : NULL)) {
@@ -692,21 +689,21 @@ static bool parse_value(const char **sp, JsonNode **out)
692
689
  }
693
690
  return false;
694
691
  }
695
-
692
+
696
693
  case '[':
697
694
  if (parse_array(&s, out)) {
698
695
  *sp = s;
699
696
  return true;
700
697
  }
701
698
  return false;
702
-
699
+
703
700
  case '{':
704
701
  if (parse_object(&s, out)) {
705
702
  *sp = s;
706
703
  return true;
707
704
  }
708
705
  return false;
709
-
706
+
710
707
  default: {
711
708
  double num;
712
709
  if (parse_number(&s, out ? &num : NULL)) {
@@ -725,34 +722,34 @@ static bool parse_array(const char **sp, JsonNode **out)
725
722
  const char *s = *sp;
726
723
  JsonNode *ret = out ? json_mkarray() : NULL;
727
724
  JsonNode *element;
728
-
725
+
729
726
  if (*s++ != '[')
730
727
  goto failure;
731
728
  skip_space(&s);
732
-
729
+
733
730
  if (*s == ']') {
734
731
  s++;
735
732
  goto success;
736
733
  }
737
-
734
+
738
735
  for (;;) {
739
736
  if (!parse_value(&s, out ? &element : NULL))
740
737
  goto failure;
741
738
  skip_space(&s);
742
-
739
+
743
740
  if (out)
744
741
  json_append_element(ret, element);
745
-
742
+
746
743
  if (*s == ']') {
747
744
  s++;
748
745
  goto success;
749
746
  }
750
-
747
+
751
748
  if (*s++ != ',')
752
749
  goto failure;
753
750
  skip_space(&s);
754
751
  }
755
-
752
+
756
753
  success:
757
754
  *sp = s;
758
755
  if (out)
@@ -770,42 +767,42 @@ static bool parse_object(const char **sp, JsonNode **out)
770
767
  JsonNode *ret = out ? json_mkobject() : NULL;
771
768
  char *key;
772
769
  JsonNode *value;
773
-
770
+
774
771
  if (*s++ != '{')
775
772
  goto failure;
776
773
  skip_space(&s);
777
-
774
+
778
775
  if (*s == '}') {
779
776
  s++;
780
777
  goto success;
781
778
  }
782
-
779
+
783
780
  for (;;) {
784
781
  if (!parse_string(&s, out ? &key : NULL))
785
782
  goto failure;
786
783
  skip_space(&s);
787
-
784
+
788
785
  if (*s++ != ':')
789
786
  goto failure_free_key;
790
787
  skip_space(&s);
791
-
788
+
792
789
  if (!parse_value(&s, out ? &value : NULL))
793
790
  goto failure_free_key;
794
791
  skip_space(&s);
795
-
792
+
796
793
  if (out)
797
794
  append_member(ret, key, value);
798
-
795
+
799
796
  if (*s == '}') {
800
797
  s++;
801
798
  goto success;
802
799
  }
803
-
800
+
804
801
  if (*s++ != ',')
805
802
  goto failure;
806
803
  skip_space(&s);
807
804
  }
808
-
805
+
809
806
  success:
810
807
  *sp = s;
811
808
  if (out)
@@ -827,10 +824,10 @@ bool parse_string(const char **sp, char **out)
827
824
  char throwaway_buffer[4];
828
825
  /* enough space for a UTF-8 character */
829
826
  char *b;
830
-
827
+
831
828
  if (*s++ != '"')
832
829
  return false;
833
-
830
+
834
831
  if (out) {
835
832
  sb_init(&sb);
836
833
  sb_need(&sb, 4);
@@ -838,10 +835,10 @@ bool parse_string(const char **sp, char **out)
838
835
  } else {
839
836
  b = throwaway_buffer;
840
837
  }
841
-
838
+
842
839
  while (*s != '"') {
843
840
  unsigned char c = *s++;
844
-
841
+
845
842
  /* Parse next character, and write it to b. */
846
843
  if (c == '\\') {
847
844
  c = *s++;
@@ -869,11 +866,11 @@ bool parse_string(const char **sp, char **out)
869
866
  case 'u':
870
867
  {
871
868
  uint16_t uc, lc;
872
- uchar_t unicode;
873
-
869
+ uint32_t unicode;
870
+
874
871
  if (!parse_hex16(&s, &uc))
875
872
  goto failed;
876
-
873
+
877
874
  if (uc >= 0xD800 && uc <= 0xDFFF) {
878
875
  /* Handle UTF-16 surrogate pair. */
879
876
  if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc))
@@ -886,7 +883,7 @@ bool parse_string(const char **sp, char **out)
886
883
  } else {
887
884
  unicode = uc;
888
885
  }
889
-
886
+
890
887
  b += utf8_write_char(unicode, b);
891
888
  break;
892
889
  }
@@ -900,16 +897,16 @@ bool parse_string(const char **sp, char **out)
900
897
  } else {
901
898
  /* Validate and echo a UTF-8 character. */
902
899
  int len;
903
-
900
+
904
901
  s--;
905
902
  len = utf8_validate_cz(s);
906
903
  if (len == 0)
907
904
  goto failed; /* Invalid UTF-8 character. */
908
-
905
+
909
906
  while (len--)
910
907
  *b++ = *s++;
911
908
  }
912
-
909
+
913
910
  /*
914
911
  * Update sb to know about the new bytes,
915
912
  * and set up b to write another character.
@@ -923,7 +920,7 @@ bool parse_string(const char **sp, char **out)
923
920
  }
924
921
  }
925
922
  s++;
926
-
923
+
927
924
  if (out)
928
925
  *out = sb_finish(&sb);
929
926
  *sp = s;
@@ -1058,7 +1055,7 @@ void emit_value_indented(SB *out, const JsonNode *node, const char *space, int i
1058
1055
  static void emit_array(SB *out, const JsonNode *array)
1059
1056
  {
1060
1057
  const JsonNode *element;
1061
-
1058
+
1062
1059
  sb_putc(out, '[');
1063
1060
  json_foreach(element, array) {
1064
1061
  emit_value(out, element);
@@ -1072,18 +1069,18 @@ static void emit_array_indented(SB *out, const JsonNode *array, const char *spac
1072
1069
  {
1073
1070
  const JsonNode *element = array->children.head;
1074
1071
  int i;
1075
-
1072
+
1076
1073
  if (element == NULL) {
1077
1074
  sb_puts(out, "[]");
1078
1075
  return;
1079
1076
  }
1080
-
1077
+
1081
1078
  sb_puts(out, "[\n");
1082
1079
  while (element != NULL) {
1083
1080
  for (i = 0; i < indent_level + 1; i++)
1084
1081
  sb_puts(out, space);
1085
1082
  emit_value_indented(out, element, space, indent_level + 1);
1086
-
1083
+
1087
1084
  element = element->next;
1088
1085
  sb_puts(out, element != NULL ? ",\n" : "\n");
1089
1086
  }
@@ -1095,7 +1092,7 @@ static void emit_array_indented(SB *out, const JsonNode *array, const char *spac
1095
1092
  static void emit_object(SB *out, const JsonNode *object)
1096
1093
  {
1097
1094
  const JsonNode *member;
1098
-
1095
+
1099
1096
  sb_putc(out, '{');
1100
1097
  json_foreach(member, object) {
1101
1098
  emit_string(out, member->key);
@@ -1111,12 +1108,12 @@ static void emit_object_indented(SB *out, const JsonNode *object, const char *sp
1111
1108
  {
1112
1109
  const JsonNode *member = object->children.head;
1113
1110
  int i;
1114
-
1111
+
1115
1112
  if (member == NULL) {
1116
1113
  sb_puts(out, "{}");
1117
1114
  return;
1118
1115
  }
1119
-
1116
+
1120
1117
  sb_puts(out, "{\n");
1121
1118
  while (member != NULL) {
1122
1119
  for (i = 0; i < indent_level + 1; i++)
@@ -1124,7 +1121,7 @@ static void emit_object_indented(SB *out, const JsonNode *object, const char *sp
1124
1121
  emit_string(out, member->key);
1125
1122
  sb_puts(out, ": ");
1126
1123
  emit_value_indented(out, member, space, indent_level + 1);
1127
-
1124
+
1128
1125
  member = member->next;
1129
1126
  sb_puts(out, member != NULL ? ",\n" : "\n");
1130
1127
  }
@@ -1138,20 +1135,20 @@ void emit_string(SB *out, const char *str)
1138
1135
  bool escape_unicode = false;
1139
1136
  const char *s = str;
1140
1137
  char *b;
1141
-
1138
+
1142
1139
  assert(utf8_validate(str));
1143
-
1140
+
1144
1141
  /*
1145
1142
  * 14 bytes is enough space to write up to two
1146
1143
  * \uXXXX escapes and two quotation marks.
1147
1144
  */
1148
1145
  sb_need(out, 14);
1149
1146
  b = out->cur;
1150
-
1147
+
1151
1148
  *b++ = '"';
1152
1149
  while (*s != 0) {
1153
1150
  unsigned char c = *s++;
1154
-
1151
+
1155
1152
  /* Encode the next character, and write it to b. */
1156
1153
  switch (c) {
1157
1154
  case '"':
@@ -1184,10 +1181,10 @@ void emit_string(SB *out, const char *str)
1184
1181
  break;
1185
1182
  default: {
1186
1183
  int len;
1187
-
1184
+
1188
1185
  s--;
1189
1186
  len = utf8_validate_cz(s);
1190
-
1187
+
1191
1188
  if (len == 0) {
1192
1189
  /*
1193
1190
  * Handle invalid UTF-8 character gracefully in production
@@ -1210,9 +1207,9 @@ void emit_string(SB *out, const char *str)
1210
1207
  } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) {
1211
1208
  /* Encode using \u.... */
1212
1209
  uint32_t unicode;
1213
-
1210
+
1214
1211
  s += utf8_read_char(s, &unicode);
1215
-
1212
+
1216
1213
  if (unicode <= 0xFFFF) {
1217
1214
  *b++ = '\\';
1218
1215
  *b++ = 'u';
@@ -1234,11 +1231,11 @@ void emit_string(SB *out, const char *str)
1234
1231
  while (len--)
1235
1232
  *b++ = *s++;
1236
1233
  }
1237
-
1234
+
1238
1235
  break;
1239
1236
  }
1240
1237
  }
1241
-
1238
+
1242
1239
  /*
1243
1240
  * Update *out to know about the new bytes,
1244
1241
  * and set up b to write another encoded character.
@@ -1248,7 +1245,7 @@ void emit_string(SB *out, const char *str)
1248
1245
  b = out->cur;
1249
1246
  }
1250
1247
  *b++ = '"';
1251
-
1248
+
1252
1249
  out->cur = b;
1253
1250
  }
1254
1251
 
@@ -1262,7 +1259,7 @@ static void emit_number(SB *out, double num)
1262
1259
  */
1263
1260
  char buf[64];
1264
1261
  sprintf(buf, "%.16g", num);
1265
-
1262
+
1266
1263
  if (number_is_valid(buf))
1267
1264
  sb_puts(out, buf);
1268
1265
  else
@@ -1282,11 +1279,11 @@ static bool number_is_valid(const char *num)
1282
1279
  static bool expect_literal(const char **sp, const char *str)
1283
1280
  {
1284
1281
  const char *s = *sp;
1285
-
1282
+
1286
1283
  while (*str != '\0')
1287
1284
  if (*s++ != *str++)
1288
1285
  return false;
1289
-
1286
+
1290
1287
  *sp = s;
1291
1288
  return true;
1292
1289
  }
@@ -1317,7 +1314,7 @@ static bool parse_hex16(const char **sp, uint16_t *out)
1317
1314
  ret <<= 4;
1318
1315
  ret += tmp;
1319
1316
  }
1320
-
1317
+
1321
1318
  if (out)
1322
1319
  *out = ret;
1323
1320
  *sp = s;
@@ -1331,12 +1328,12 @@ static bool parse_hex16(const char **sp, uint16_t *out)
1331
1328
  static int write_hex16(char *out, uint16_t val)
1332
1329
  {
1333
1330
  const char *hex = "0123456789ABCDEF";
1334
-
1331
+
1335
1332
  *out++ = hex[(val >> 12) & 0xF];
1336
1333
  *out++ = hex[(val >> 8) & 0xF];
1337
1334
  *out++ = hex[(val >> 4) & 0xF];
1338
1335
  *out++ = hex[ val & 0xF];
1339
-
1336
+
1340
1337
  return 4;
1341
1338
  }
1342
1339
 
@@ -1347,13 +1344,13 @@ bool json_check(const JsonNode *node, char errmsg[256])
1347
1344
  snprintf(errmsg, 256, __VA_ARGS__); \
1348
1345
  return false; \
1349
1346
  } while (0)
1350
-
1347
+
1351
1348
  if (node->key != NULL && !utf8_validate(node->key))
1352
1349
  problem("key contains invalid UTF-8");
1353
-
1350
+
1354
1351
  if (!tag_is_valid(node->tag))
1355
1352
  problem("tag is invalid (%u)", node->tag);
1356
-
1353
+
1357
1354
  if (node->tag == JSON_BOOL) {
1358
1355
  if (node->bool_ != false && node->bool_ != true)
1359
1356
  problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true);
@@ -1365,7 +1362,7 @@ bool json_check(const JsonNode *node, char errmsg[256])
1365
1362
  } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) {
1366
1363
  JsonNode *head = node->children.head;
1367
1364
  JsonNode *tail = node->children.tail;
1368
-
1365
+
1369
1366
  if (head == NULL || tail == NULL) {
1370
1367
  if (head != NULL)
1371
1368
  problem("tail is NULL, but head is not");
@@ -1374,10 +1371,10 @@ bool json_check(const JsonNode *node, char errmsg[256])
1374
1371
  } else {
1375
1372
  JsonNode *child;
1376
1373
  JsonNode *last = NULL;
1377
-
1374
+
1378
1375
  if (head->prev != NULL)
1379
1376
  problem("First child's prev pointer is not NULL");
1380
-
1377
+
1381
1378
  for (child = head; child != NULL; last = child, child = child->next) {
1382
1379
  if (child == node)
1383
1380
  problem("node is its own child");
@@ -1385,27 +1382,27 @@ bool json_check(const JsonNode *node, char errmsg[256])
1385
1382
  problem("child->next == child (cycle)");
1386
1383
  if (child->next == head)
1387
1384
  problem("child->next == head (cycle)");
1388
-
1385
+
1389
1386
  if (child->parent != node)
1390
1387
  problem("child does not point back to parent");
1391
1388
  if (child->next != NULL && child->next->prev != child)
1392
1389
  problem("child->next does not point back to child");
1393
-
1390
+
1394
1391
  if (node->tag == JSON_ARRAY && child->key != NULL)
1395
1392
  problem("Array element's key is not NULL");
1396
1393
  if (node->tag == JSON_OBJECT && child->key == NULL)
1397
1394
  problem("Object member's key is NULL");
1398
-
1395
+
1399
1396
  if (!json_check(child, errmsg))
1400
1397
  return false;
1401
1398
  }
1402
-
1399
+
1403
1400
  if (last != tail)
1404
1401
  problem("tail does not match pointer found by starting at head and following next links");
1405
1402
  }
1406
1403
  }
1407
-
1404
+
1408
1405
  return true;
1409
-
1406
+
1410
1407
  #undef problem
1411
1408
  }