sassc 0.0.10 → 0.0.11

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.
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
  }