cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

json.c
Go to the documentation of this file.
1 /*
2  Copyright 2020 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <logging.h>
26 #include <json.h>
27 #include <json-priv.h>
28 #include <json-yaml.h>
29 
30 #include <alloc.h>
31 #include <sequence.h>
32 #include <string_lib.h>
33 #include <misc_lib.h>
34 #include <file_lib.h>
35 #include <printsize.h>
36 #ifdef WITH_PCRE
37 #include <regex.h>
38 #endif
39 #include <buffer.h>
40 
41 static const int SPACES_PER_INDENT = 2;
43 
44 static const char *const JSON_TRUE = "true";
45 static const char *const JSON_FALSE = "false";
46 static const char *const JSON_NULL = "null";
47 
49 {
51 
52  // We don't have a separate struct for the key-value pairs in a JSON
53  // Object. Instead, a JSON Object has a JsonElement Seq, where each element
54  // has a propertyName (the key). A JSON Object key-value pair is sometimes
55  // called a JSON Object property.
56  char *propertyName;
57 
58  union
59  {
60  struct JsonContainer
61  {
65  struct JsonPrimitive
66  {
68  const char *value;
70  };
71 };
72 
73 // *******************************************************************************************
74 // JsonElement Functions
75 // *******************************************************************************************
76 
78 {
79  switch (type)
80  {
82  return "string";
85  return "number";
87  return "boolean";
88  default:
89  UnexpectedError("Unknown JSON primitive type: %d", type);
90  return "(null)";
91  }
92 }
93 
95  JsonElement *const element, const char *const propertyName)
96 {
97  assert(element != NULL);
98 
99  if (element->propertyName != NULL)
100  {
101  free(element->propertyName);
102  element->propertyName = NULL;
103  }
104 
105  if (propertyName != NULL)
106  {
107  element->propertyName = xstrdup(propertyName);
108  }
109 }
110 
111 const char *JsonElementGetPropertyName(const JsonElement *const element)
112 {
113  assert(element != NULL);
114 
115  return element->propertyName;
116 }
117 
119  const JsonContainerType containerType,
120  const char *const propertyName,
121  const size_t initialCapacity)
122 {
123  JsonElement *element = xcalloc(1, sizeof(JsonElement));
124 
126 
127  JsonElementSetPropertyName(element, propertyName);
128 
129  element->container.type = containerType;
130  element->container.children = SeqNew(initialCapacity, JsonDestroy);
131 
132  return element;
133 }
134 
136  JsonPrimitiveType primitiveType, const char *value)
137 {
138  JsonElement *element = xcalloc(1, sizeof(JsonElement));
139 
141 
142  element->primitive.type = primitiveType;
143  element->primitive.value = value;
144 
145  return element;
146 }
147 
148 static JsonElement *JsonArrayCopy(const JsonElement *array)
149 {
150  assert(array != NULL);
151  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
152  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
153 
154  JsonElement *copy = JsonArrayCreate(JsonLength(array));
155 
156  JsonIterator iter = JsonIteratorInit(array);
157  const JsonElement *child;
158  while ((child = JsonIteratorNextValue(&iter)) != NULL)
159  {
160  JsonArrayAppendElement(copy, JsonCopy(child));
161  }
162 
163  return copy;
164 }
165 
166 static JsonElement *JsonObjectCopy(const JsonElement *const object)
167 {
168  assert(object != NULL);
169  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
170  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
171 
172  JsonElement *copy = JsonObjectCreate(JsonLength(object));
173 
174  JsonIterator iter = JsonIteratorInit(object);
175  const JsonElement *child;
176  while ((child = JsonIteratorNextValue(&iter)) != NULL)
177  {
179  copy, JsonIteratorCurrentKey(&iter), JsonCopy(child));
180  }
181 
182  return copy;
183 }
184 
185 
186 static JsonElement *JsonContainerCopy(const JsonElement *const container)
187 {
188  assert(container != NULL);
189  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
190 
191  const JsonContainerType type = container->container.type;
192  switch (type)
193  {
195  return JsonArrayCopy(container);
196 
198  return JsonObjectCopy(container);
199 
200  default:
201  UnexpectedError("Unknown JSON container type: %d", type);
202  return NULL;
203  }
204 }
205 
206 static JsonElement *JsonPrimitiveCopy(const JsonElement *const primitive)
207 {
208  assert(primitive != NULL);
209  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
210 
211  const JsonPrimitiveType type = primitive->primitive.type;
212 
213  switch (type)
214  {
216  return JsonBoolCreate(JsonPrimitiveGetAsBool(primitive));
217 
219  return JsonIntegerCreate(JsonPrimitiveGetAsInteger(primitive));
220 
222  return JsonNullCreate();
223 
225  return JsonRealCreate(JsonPrimitiveGetAsReal(primitive));
226 
228  return JsonStringCreate(JsonPrimitiveGetAsString(primitive));
229  }
230 
231  UnexpectedError("Unknown JSON primitive type: %d", type);
232  return NULL;
233 }
234 
235 JsonElement *JsonCopy(const JsonElement *const element)
236 {
237  assert(element != NULL);
238  switch (element->type)
239  {
241  return JsonContainerCopy(element);
243  return JsonPrimitiveCopy(element);
244  }
245 
246  UnexpectedError("Unknown JSON element type: %d", element->type);
247  return NULL;
248 }
249 
250 static int JsonArrayCompare(
251  const JsonElement *const a, const JsonElement *const b)
252 {
253  assert(a != NULL);
254  assert(b != NULL);
255  assert(a->type == JSON_ELEMENT_TYPE_CONTAINER);
256  assert(b->type == JSON_ELEMENT_TYPE_CONTAINER);
257  assert(a->container.type == JSON_CONTAINER_TYPE_ARRAY);
258  assert(b->container.type == JSON_CONTAINER_TYPE_ARRAY);
259 
260  int ret = JsonLength(a) - JsonLength(b);
261  if (ret != 0)
262  {
263  return ret;
264  }
265 
266  JsonIterator iter_a = JsonIteratorInit(a);
267  JsonIterator iter_b = JsonIteratorInit(a);
268 
269  for (size_t i = 0; i < JsonLength(a); i++)
270  {
271  const JsonElement *child_a = JsonIteratorNextValue(&iter_a);
272  const JsonElement *child_b = JsonIteratorNextValue(&iter_b);
273 
274  ret = JsonCompare(child_a, child_b);
275  if (ret != 0)
276  {
277  return ret;
278  }
279  }
280 
281  return ret;
282 }
283 
284 static int JsonObjectCompare(
285  const JsonElement *const a, const JsonElement *const b)
286 {
287  assert(a != NULL);
288  assert(b != NULL);
289  assert(a->type == JSON_ELEMENT_TYPE_CONTAINER);
290  assert(b->type == JSON_ELEMENT_TYPE_CONTAINER);
291  assert(a->container.type == JSON_CONTAINER_TYPE_OBJECT);
292  assert(b->container.type == JSON_CONTAINER_TYPE_OBJECT);
293 
294  int ret = JsonLength(a) - JsonLength(b);
295  if (ret != 0)
296  {
297  return ret;
298  }
299 
300  JsonIterator iter_a = JsonIteratorInit(a);
301  JsonIterator iter_b = JsonIteratorInit(a);
302 
303  for (size_t i = 0; i < JsonLength(a); i++)
304  {
305  const JsonElement *child_a = JsonIteratorNextValue(&iter_a);
306  const JsonElement *child_b = JsonIteratorNextValue(&iter_b);
307 
308  const char *const key_a = JsonIteratorCurrentKey(&iter_a);
309  const char *const key_b = JsonIteratorCurrentKey(&iter_b);
310 
311  ret = strcmp(key_a, key_b);
312  if (ret != 0)
313  {
314  return ret;
315  }
316 
317  ret = JsonCompare(child_a, child_b);
318  if (ret != 0)
319  {
320  return ret;
321  }
322  }
323 
324  return ret;
325 }
326 
327 
329  const JsonElement *const a, const JsonElement *const b)
330 {
331  assert(a != NULL);
332  assert(b != NULL);
333  assert(a->type == JSON_ELEMENT_TYPE_CONTAINER);
334  assert(b->type == JSON_ELEMENT_TYPE_CONTAINER);
335 
336  const JsonContainerType type_a = a->container.type;
337  const JsonContainerType type_b = b->container.type;
338 
339  if (type_a != type_b)
340  {
341  return type_a - type_b;
342  }
343 
344  switch (type_a)
345  {
347  return JsonArrayCompare(a, b);
348 
350  return JsonObjectCompare(a, b);
351 
352  default:
353  UnexpectedError("Unknown JSON container type: %d", type_a);
354  return -1;
355  }
356 }
357 
358 int JsonCompare(const JsonElement *const a, const JsonElement *const b)
359 {
360  assert(a != NULL);
361  assert(b != NULL);
362 
363  const JsonElementType type_a = a->type;
364  const JsonElementType type_b = b->type;
365 
366  if (type_a != type_b)
367  {
368  return type_a - type_b;
369  }
370 
371  switch (type_a)
372  {
374  return JsonContainerCompare(a, b);
375 
377  return strcmp(a->primitive.value, b->primitive.value);
378 
379  default:
380  UnexpectedError("Unknown JSON element type: %d", type_a);
381  return -1;
382  }
383 }
384 
385 
386 void JsonDestroy(JsonElement *const element)
387 {
388  if (element != NULL)
389  {
390  switch (element->type)
391  {
393  assert(element->container.children);
394  SeqDestroy(element->container.children);
395  element->container.children = NULL;
396  break;
397 
399  assert(element->primitive.value);
400 
401  if (element->primitive.type != JSON_PRIMITIVE_TYPE_NULL
402  && element->primitive.type != JSON_PRIMITIVE_TYPE_BOOL)
403  {
404  free((void *) element->primitive.value);
405  }
406  element->primitive.value = NULL;
407  break;
408 
409  default:
410  UnexpectedError("Unknown JSON element type: %d", element->type);
411  }
412 
413  if (element->propertyName != NULL)
414  {
415  free(element->propertyName);
416  }
417 
418  free(element);
419  }
420 }
421 
422 void JsonDestroyMaybe(JsonElement *const element, const bool allocated)
423 {
424  if (allocated)
425  {
426  JsonDestroy(element);
427  }
428 }
429 
431  const JsonElement *const a, const JsonElement *const b)
432 {
433  assert(JsonGetElementType(a) == JsonGetElementType(b));
437 
439  for (size_t i = 0; i < JsonLength(a); i++)
440  {
441  JsonArrayAppendElement(result, JsonCopy(JsonAt(a, i)));
442  }
443 
444  for (size_t i = 0; i < JsonLength(b); i++)
445  {
446  JsonArrayAppendElement(result, JsonCopy(JsonAt(b, i)));
447  }
448 
449  return result;
450 }
451 
453  const JsonElement *const a, const JsonElement *const b)
454 {
455  assert(JsonGetElementType(a) == JsonGetElementType(b));
459 
460  JsonElement *result = JsonObjectCopy(a);
461  for (size_t i = 0; i < JsonLength(b); i++)
462  {
463  char *key = StringFromLong(i);
464  JsonObjectAppendElement(result, key, JsonCopy(JsonAt(b, i)));
465  free(key);
466  }
467 
468  return result;
469 }
470 
472  const JsonElement *const a, const JsonElement *const b)
473 {
474  assert(JsonGetElementType(a) == JsonGetElementType(b));
478 
479  JsonElement *result = JsonObjectCopy(a);
480  JsonIterator iter = JsonIteratorInit(b);
481  const char *key;
482  while ((key = JsonIteratorNextKey(&iter)))
483  {
485  result, key, JsonCopy(JsonIteratorCurrentValue(&iter)));
486  }
487 
488  return result;
489 }
490 
491 JsonElement *JsonMerge(const JsonElement *const a, const JsonElement *const b)
492 {
493  assert(JsonGetElementType(a) == JsonGetElementType(b));
495 
496  switch (JsonGetContainerType(a))
497  {
499  switch (JsonGetContainerType(b))
500  {
502  return JsonObjectMergeArray(b, a);
504  return JsonArrayMergeArray(a, b);
505  }
507  "Unknown JSON container type: %d", JsonGetContainerType(b));
508  break;
509 
511  switch (JsonGetContainerType(b))
512  {
514  return JsonObjectMergeObject(a, b);
516  return JsonObjectMergeArray(a, b);
517  }
519  "Unknown JSON container type: %d", JsonGetContainerType(b));
520  break;
521 
522  default:
524  "Unknown JSON container type: %d", JsonGetContainerType(a));
525  }
526 
527  return NULL;
528 }
529 
530 
531 size_t JsonLength(const JsonElement *const element)
532 {
533  assert(element != NULL);
534 
535  switch (element->type)
536  {
538  return SeqLength(element->container.children);
539 
541  return strlen(element->primitive.value);
542 
543  default:
544  UnexpectedError("Unknown JSON element type: %d", element->type);
545  return (size_t) -1; // appease gcc
546  }
547 }
548 
550 {
551  assert(container != NULL);
552  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
553 
554  return (JsonIterator){container, 0};
555 }
556 
557 const char *JsonIteratorNextKey(JsonIterator *const iter)
558 {
559  assert(iter != NULL);
560  assert(iter->container != NULL);
561  assert(iter->container->type == JSON_ELEMENT_TYPE_CONTAINER);
562  assert(iter->container->container.type == JSON_CONTAINER_TYPE_OBJECT);
563 
564  const JsonElement *child = JsonIteratorNextValue(iter);
565  return child ? child->propertyName : NULL;
566 }
567 
569 {
570  assert(iter != NULL);
571  assert(iter->container != NULL);
572  assert(iter->container->type == JSON_ELEMENT_TYPE_CONTAINER);
573 
574  if (iter->index >= JsonLength(iter->container))
575  {
576  return NULL;
577  }
578 
579  Seq *const children = iter->container->container.children;
580  return SeqAt(children, iter->index++);
581 }
582 
584  JsonIterator *const iter, const JsonElementType type, const bool skip_null)
585 {
586  JsonElement *e = NULL;
587  while ((e = JsonIteratorNextValue(iter)))
588  {
589  if (skip_null && JsonGetType(e) == JSON_TYPE_NULL)
590  {
591  continue;
592  }
593 
594  if (e->type == type)
595  {
596  return e;
597  }
598  }
599 
600  return NULL;
601 }
602 
604 {
605  assert(iter != NULL);
606  assert(iter->container != NULL);
607  assert(iter->container->type == JSON_ELEMENT_TYPE_CONTAINER);
608 
609  if (iter->index == 0 || iter->index > JsonLength(iter->container))
610  {
611  return NULL;
612  }
613 
614  Seq *const children = iter->container->container.children;
615  return SeqAt(children, iter->index - 1);
616 }
617 
618 const char *JsonIteratorCurrentKey(const JsonIterator *const iter)
619 {
620  assert(iter != NULL);
621  assert(iter->container != NULL);
622  assert(iter->container->type == JSON_ELEMENT_TYPE_CONTAINER);
623  assert(iter->container->container.type == JSON_CONTAINER_TYPE_OBJECT);
624 
625  const JsonElement *child = JsonIteratorCurrentValue(iter);
626 
627  return child ? child->propertyName : NULL;
628 }
629 
631 {
632  assert(iter != NULL);
633 
634  const JsonElement *child = JsonIteratorCurrentValue(iter);
635  return child->type;
636 }
637 
639  const JsonIterator *const iter)
640 {
641  assert(iter != NULL);
642 
643  const JsonElement *child = JsonIteratorCurrentValue(iter);
644  assert(child->type == JSON_ELEMENT_TYPE_CONTAINER);
645 
646  return child->container.type;
647 }
648 
650  const JsonIterator *const iter)
651 {
652  assert(iter != NULL);
653 
654  const JsonElement *child = JsonIteratorCurrentValue(iter);
655  assert(child->type == JSON_ELEMENT_TYPE_PRIMITIVE);
656 
657  return child->primitive.type;
658 }
659 
660 bool JsonIteratorHasMore(const JsonIterator *const iter)
661 {
662  assert(iter != NULL);
663 
664  return iter->index < JsonLength(iter->container);
665 }
666 
668 {
669  assert(element != NULL);
670 
671  return element->type;
672 }
673 
675 {
677  {
678  return (JsonType) JsonGetContainerType(element);
679  }
680 
682  return (JsonType) JsonGetPrimitiveType(element);
683 }
684 
686 {
687  assert(container != NULL);
688  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
689 
690  return container->container.type;
691 }
692 
694 {
695  assert(primitive != NULL);
696  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
697 
698  return primitive->primitive.type;
699 }
700 
701 const char *JsonPrimitiveGetAsString(const JsonElement *const primitive)
702 {
703  assert(primitive != NULL);
704  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
705 
706  return primitive->primitive.value;
707 }
708 
709 char *JsonPrimitiveToString(const JsonElement *const primitive)
710 {
712  {
713  return NULL;
714  }
715 
716  switch (JsonGetPrimitiveType(primitive))
717  {
719  return xstrdup(JsonPrimitiveGetAsBool(primitive) ? "true" : "false");
720  break;
721 
723  return StringFromLong(JsonPrimitiveGetAsInteger(primitive));
724  break;
725 
727  return StringFromDouble(JsonPrimitiveGetAsReal(primitive));
728  break;
729 
731  return xstrdup(JsonPrimitiveGetAsString(primitive));
732  break;
733 
734  case JSON_PRIMITIVE_TYPE_NULL: // redundant
735  break;
736  }
737 
738  return NULL;
739 }
740 
741 bool JsonPrimitiveGetAsBool(const JsonElement *const primitive)
742 {
743  assert(primitive != NULL);
744  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
745  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_BOOL);
746 
747  return StringEqual(JSON_TRUE, primitive->primitive.value);
748 }
749 
750 long JsonPrimitiveGetAsInteger(const JsonElement *const primitive)
751 {
752  assert(primitive != NULL);
753  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
754  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_INTEGER);
755 
756  return StringToLongExitOnError(primitive->primitive.value);
757 }
758 
759 
760 int JsonPrimitiveGetAsInt64(const JsonElement *primitive, int64_t *value_out)
761 {
762  assert(primitive != NULL);
763  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
764  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_INTEGER);
765 
766  return StringToInt64(primitive->primitive.value, value_out);
767 }
768 
769 int64_t JsonPrimitiveGetAsInt64DefaultOnError(const JsonElement *primitive, int64_t default_return)
770 {
771  assert(primitive != NULL);
772  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
773  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_INTEGER);
774 
775  return StringToInt64DefaultOnError(primitive->primitive.value, default_return);
776 }
777 
779 {
780  assert(primitive != NULL);
781  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
782  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_INTEGER);
783 
784  return StringToInt64ExitOnError(primitive->primitive.value);
785 }
786 
787 double JsonPrimitiveGetAsReal(const JsonElement *const primitive)
788 {
789  assert(primitive != NULL);
790  assert(primitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
791  assert(primitive->primitive.type == JSON_PRIMITIVE_TYPE_REAL);
792 
793  return StringToDouble(primitive->primitive.value);
794 }
795 
796 const char *JsonGetPropertyAsString(const JsonElement *const element)
797 {
798  assert(element != NULL);
799 
800  return element->propertyName;
801 }
802 
803 void JsonSort(
804  const JsonElement *const container,
805  JsonComparator *const Compare,
806  void *const user_data)
807 {
808  assert(container != NULL);
809  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
810 
811  Seq *const children = container->container.children;
812  SeqSort(children, (SeqItemComparator) Compare, user_data);
813 }
814 
815 JsonElement *JsonAt(const JsonElement *container, const size_t index)
816 {
817  assert(container != NULL);
818  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
819  assert(index < JsonLength(container));
820 
821  return SeqAt(container->container.children, index);
822 }
823 
825  JsonElement *const element, const size_t num_indices, char **const indices)
826 {
827  if (num_indices == 0)
828  {
829  return element;
830  }
831  else
832  {
834  {
835  return NULL;
836  }
837 
838  const char *index = indices[0];
839 
840  switch (JsonGetContainerType(element))
841  {
843  {
844  JsonElement *child = JsonObjectGet(element, index);
845  if (child != NULL)
846  {
847  return JsonSelect(child, num_indices - 1, indices + 1);
848  }
849  }
850  return NULL;
851 
853  if (StringIsNumeric(index))
854  {
855  size_t i = StringToLongExitOnError(index);
856  if (i < JsonLength(element))
857  {
858  JsonElement *child = JsonArrayGet(element, i);
859  if (child != NULL)
860  {
861  return JsonSelect(child, num_indices - 1, indices + 1);
862  }
863  }
864  }
865  break;
866 
867  default:
869  "Unknown JSON container type: %d",
870  JsonGetContainerType(element));
871  }
872  return NULL;
873  }
874 }
875 
876 // *******************************************************************************************
877 // JsonObject Functions
878 // *******************************************************************************************
879 
880 JsonElement *JsonObjectCreate(const size_t initialCapacity)
881 {
883  JSON_CONTAINER_TYPE_OBJECT, NULL, initialCapacity);
884 }
885 
887  const char *const unescaped_string, Writer *const writer)
888 {
889  assert(unescaped_string != NULL);
890 
891  for (const char *c = unescaped_string; *c != '\0'; c++)
892  {
893  switch (*c)
894  {
895  case '\"':
896  case '\\':
897  WriterWriteChar(writer, '\\');
898  WriterWriteChar(writer, *c);
899  break;
900  case '\b':
901  WriterWriteChar(writer, '\\');
902  WriterWriteChar(writer, 'b');
903  break;
904  case '\f':
905  WriterWriteChar(writer, '\\');
906  WriterWriteChar(writer, 'f');
907  break;
908  case '\n':
909  WriterWriteChar(writer, '\\');
910  WriterWriteChar(writer, 'n');
911  break;
912  case '\r':
913  WriterWriteChar(writer, '\\');
914  WriterWriteChar(writer, 'r');
915  break;
916  case '\t':
917  WriterWriteChar(writer, '\\');
918  WriterWriteChar(writer, 't');
919  break;
920  default:
921  WriterWriteChar(writer, *c);
922  }
923  }
924 }
925 
926 char *JsonEncodeString(const char *const unescaped_string)
927 {
928  Writer *writer = StringWriter();
929 
930  JsonEncodeStringWriter(unescaped_string, writer);
931 
932  return StringWriterClose(writer);
933 }
934 
936  const char *const escaped_string, Writer *const w)
937 {
938  assert(escaped_string != NULL);
939 
940  for (const char *c = escaped_string; *c != '\0'; c++)
941  {
942  if (*c == '\\')
943  {
944  switch (c[1])
945  {
946  case '\"':
947  case '\\':
948  WriterWriteChar(w, c[1]);
949  c++;
950  break;
951  case 'b':
952  WriterWriteChar(w, '\b');
953  c++;
954  break;
955  case 'f':
956  WriterWriteChar(w, '\f');
957  c++;
958  break;
959  case 'n':
960  WriterWriteChar(w, '\n');
961  c++;
962  break;
963  case 'r':
964  WriterWriteChar(w, '\r');
965  c++;
966  break;
967  case 't':
968  WriterWriteChar(w, '\t');
969  c++;
970  break;
971  default:
972  WriterWriteChar(w, *c);
973  break;
974  }
975  }
976  else
977  {
978  WriterWriteChar(w, *c);
979  }
980  }
981 }
982 
983 char *JsonDecodeString(const char *const escaped_string)
984 {
985  Writer *writer = StringWriter();
986 
987  JsonDecodeStringWriter(escaped_string, writer);
988 
989  return StringWriterClose(writer);
990 }
991 
992 void Json5EscapeDataWriter(const Slice unescaped_data, Writer *const writer)
993 {
994  // See: https://spec.json5.org/#strings
995 
996  const char *const data = unescaped_data.data;
997  assert(data != NULL);
998 
999  const size_t size = unescaped_data.size;
1000 
1001  for (size_t index = 0; index < size; index++)
1002  {
1003  const char byte = data[index];
1004  switch (byte)
1005  {
1006  case '\0':
1007  WriterWrite(writer, "\\0");
1008  break;
1009  case '\"':
1010  case '\\':
1011  WriterWriteChar(writer, '\\');
1012  WriterWriteChar(writer, byte);
1013  break;
1014  case '\b':
1015  WriterWrite(writer, "\\b");
1016  break;
1017  case '\f':
1018  WriterWrite(writer, "\\f");
1019  break;
1020  case '\n':
1021  WriterWrite(writer, "\\n");
1022  break;
1023  case '\r':
1024  WriterWrite(writer, "\\r");
1025  break;
1026  case '\t':
1027  WriterWrite(writer, "\\t");
1028  break;
1029  default:
1030  {
1031  if (CharIsPrintableAscii(byte))
1032  {
1033  WriterWriteChar(writer, byte);
1034  }
1035  else
1036  {
1037  // unsigned char behaves better when implicitly cast to int:
1038  WriterWriteF(writer, "\\x%2.2X", (unsigned char) byte);
1039  }
1040  break;
1041  }
1042  }
1043  }
1044 }
1045 
1046 char *Json5EscapeData(Slice unescaped_data)
1047 {
1048  Writer *writer = StringWriter();
1049 
1050  Json5EscapeDataWriter(unescaped_data, writer);
1051 
1052  return StringWriterClose(writer);
1053 }
1054 
1056  JsonElement *const object, const char *const key, const char *const value)
1057 {
1058  JsonElement *child = JsonStringCreate(value);
1059  JsonObjectAppendElement(object, key, child);
1060 }
1061 
1063  JsonElement *const object, const char *const key, const int value)
1064 {
1065  JsonElement *child = JsonIntegerCreate(value);
1066  JsonObjectAppendElement(object, key, child);
1067 }
1068 
1070  JsonElement *const object, const char *const key, const _Bool value)
1071 {
1072  JsonElement *child = JsonBoolCreate(value);
1073  JsonObjectAppendElement(object, key, child);
1074 }
1075 
1077  JsonElement *const object, const char *const key, const double value)
1078 {
1079  JsonElement *child = JsonRealCreate(value);
1080  JsonObjectAppendElement(object, key, child);
1081 }
1082 
1083 void JsonObjectAppendNull(JsonElement *const object, const char *const key)
1084 {
1085  JsonElement *child = JsonNullCreate();
1086  JsonObjectAppendElement(object, key, child);
1087 }
1088 
1090  JsonElement *const object, const char *const key, JsonElement *const array)
1091 {
1092  assert(array != NULL);
1093  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1094  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1095 
1096  JsonObjectAppendElement(object, key, array);
1097 }
1098 
1100  JsonElement *const object,
1101  const char *const key,
1102  JsonElement *const childObject)
1103 {
1104  assert(childObject != NULL);
1105  assert(childObject->type == JSON_ELEMENT_TYPE_CONTAINER);
1106  assert(childObject->container.type == JSON_CONTAINER_TYPE_OBJECT);
1107 
1108  JsonObjectAppendElement(object, key, childObject);
1109 }
1110 
1112  JsonElement *const object,
1113  const char *const key,
1114  JsonElement *const element)
1115 {
1116  assert(object != NULL);
1117  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1118  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1119  assert(key != NULL);
1120  assert(element != NULL);
1121 
1122  JsonObjectRemoveKey(object, key);
1123 
1124  JsonElementSetPropertyName(element, key);
1125  SeqAppend(object->container.children, element);
1126 }
1127 
1129  const void *const propertyName,
1130  const void *const jsonElement,
1131  ARG_UNUSED void *const user_data)
1132 {
1133  assert(propertyName != NULL);
1134 
1135  const JsonElement *element = jsonElement;
1136 
1137  assert(element->propertyName != NULL);
1138 
1139  if (strcmp(propertyName, element->propertyName) == 0)
1140  {
1141  return 0;
1142  }
1143  return -1;
1144 }
1145 
1147  const void *const a, const void *const b, ARG_UNUSED void *const user_data)
1148 {
1149  assert(b != NULL);
1150  const char *const key_a = a;
1151  const JsonElement *const json_b = b;
1152  return StringSafeCompare(key_a, json_b->propertyName);
1153 }
1154 
1156  JsonElement *const parent, const char *const key)
1157 {
1158  assert(parent != NULL);
1159  assert(parent->type == JSON_ELEMENT_TYPE_CONTAINER);
1160  assert(parent->container.type == JSON_CONTAINER_TYPE_OBJECT);
1161  assert(key != NULL);
1162 
1163  Seq *const children = parent->container.children;
1164  return SeqIndexOf(children, key, CompareKeyToPropertyName);
1165 }
1166 
1167 bool JsonObjectRemoveKey(JsonElement *const object, const char *const key)
1168 {
1169  assert(object != NULL);
1170  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1171  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1172  assert(key != NULL);
1173 
1174  const ssize_t index = JsonElementIndexInParentObject(object, key);
1175  if (index != -1)
1176  {
1177  SeqRemove(object->container.children, index);
1178  return true;
1179  }
1180  return false;
1181 }
1182 
1184  JsonElement *const object, const char *const key)
1185 {
1186  assert(object != NULL);
1187  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1188  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1189  assert(key != NULL);
1190 
1191  JsonElement *detached = NULL;
1192 
1193  ssize_t index = JsonElementIndexInParentObject(object, key);
1194  if (index != -1)
1195  {
1196  Seq *const children = object->container.children;
1197  detached = SeqLookup(children, key, JsonElementHasProperty);
1198  SeqSoftRemove(children, index);
1199  }
1200 
1201  return detached;
1202 }
1203 
1205  const JsonElement *const object, const char *const key)
1206 {
1207  assert(object != NULL);
1208  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1209  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1210  assert(key != NULL);
1211 
1212  JsonElement *childPrimitive =
1213  SeqLookup(object->container.children, key, JsonElementHasProperty);
1214 
1215  if (childPrimitive != NULL)
1216  {
1217  assert(childPrimitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
1218  return childPrimitive->primitive.value;
1219  }
1220 
1221  return NULL;
1222 }
1223 
1225  JsonElement *const object, const char *const key)
1226 {
1227  assert(object != NULL);
1228  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1229  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1230  assert(key != NULL);
1231 
1232  JsonElement *childPrimitive =
1233  SeqLookup(object->container.children, key, JsonElementHasProperty);
1234 
1235  if (childPrimitive != NULL)
1236  {
1237  assert(childPrimitive->type == JSON_ELEMENT_TYPE_CONTAINER);
1238  assert(childPrimitive->container.type == JSON_CONTAINER_TYPE_OBJECT);
1239  return childPrimitive;
1240  }
1241 
1242  return NULL;
1243 }
1244 
1246  JsonElement *const object, const char *const key)
1247 {
1248  assert(object != NULL);
1249  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1250  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1251  assert(key != NULL);
1252 
1253  JsonElement *childPrimitive =
1254  SeqLookup(object->container.children, key, JsonElementHasProperty);
1255 
1256  if (childPrimitive != NULL)
1257  {
1258  assert(childPrimitive->type == JSON_ELEMENT_TYPE_CONTAINER);
1259  assert(childPrimitive->container.type == JSON_CONTAINER_TYPE_ARRAY);
1260  return childPrimitive;
1261  }
1262 
1263  return NULL;
1264 }
1265 
1267  const JsonElement *const object, const char *const key)
1268 {
1269  assert(object != NULL);
1270  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1271  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1272  assert(key != NULL);
1273 
1274  return SeqLookup(object->container.children, key, JsonElementHasProperty);
1275 }
1276 
1277 // *******************************************************************************************
1278 // JsonArray Functions
1279 // *******************************************************************************************
1280 
1281 JsonElement *JsonArrayCreate(const size_t initialCapacity)
1282 {
1284  JSON_CONTAINER_TYPE_ARRAY, NULL, initialCapacity);
1285 }
1286 
1287 void JsonArrayAppendString(JsonElement *const array, const char *const value)
1288 {
1289  JsonElement *child = JsonStringCreate(value);
1290  JsonArrayAppendElement(array, child);
1291 }
1292 
1293 void JsonArrayAppendBool(JsonElement *const array, const bool value)
1294 {
1295  JsonElement *child = JsonBoolCreate(value);
1296  JsonArrayAppendElement(array, child);
1297 }
1298 
1299 void JsonArrayAppendInteger(JsonElement *const array, const int value)
1300 {
1301  JsonElement *child = JsonIntegerCreate(value);
1302  JsonArrayAppendElement(array, child);
1303 }
1304 
1305 void JsonArrayAppendReal(JsonElement *const array, const double value)
1306 {
1307  JsonElement *child = JsonRealCreate(value);
1308  JsonArrayAppendElement(array, child);
1309 }
1310 
1312 {
1313  JsonElement *child = JsonNullCreate();
1314  JsonArrayAppendElement(array, child);
1315 }
1316 
1318  JsonElement *const array, JsonElement *const childArray)
1319 {
1320  assert(childArray != NULL);
1321  assert(childArray->type == JSON_ELEMENT_TYPE_CONTAINER);
1322  assert(childArray->container.type == JSON_CONTAINER_TYPE_ARRAY);
1323 
1324  JsonArrayAppendElement(array, childArray);
1325 }
1326 
1327 void JsonArrayAppendObject(JsonElement *const array, JsonElement *const object)
1328 {
1329  assert(object != NULL);
1330  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1331  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1332 
1333  JsonArrayAppendElement(array, object);
1334 }
1335 
1337  JsonElement *const array, JsonElement *const element)
1338 {
1339  assert(array != NULL);
1340  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1341  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1342  assert(element != NULL);
1343 
1344  SeqAppend(array->container.children, element);
1345 }
1346 
1348  JsonElement *const array, const size_t start, const size_t end)
1349 {
1350  assert(array != NULL);
1351  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1352  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1353  assert(end < SeqLength(array->container.children));
1354  assert(start <= end);
1355 
1356  SeqRemoveRange(array->container.children, start, end);
1357 }
1358 
1359 const char *JsonArrayGetAsString(JsonElement *const array, const size_t index)
1360 {
1361  assert(array != NULL);
1362  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1363  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1364  assert(index < SeqLength(array->container.children));
1365 
1366  JsonElement *childPrimitive = SeqAt(array->container.children, index);
1367 
1368  if (childPrimitive != NULL)
1369  {
1370  assert(childPrimitive->type == JSON_ELEMENT_TYPE_PRIMITIVE);
1371  assert(childPrimitive->primitive.type == JSON_PRIMITIVE_TYPE_STRING);
1372  return childPrimitive->primitive.value;
1373  }
1374 
1375  return NULL;
1376 }
1377 
1378 JsonElement *JsonArrayGetAsObject(JsonElement *const array, const size_t index)
1379 {
1380  assert(array != NULL);
1381  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1382  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1383  assert(index < SeqLength(array->container.children));
1384 
1385  JsonElement *child = SeqAt(array->container.children, index);
1386 
1387  if (child != NULL)
1388  {
1389  assert(child->type == JSON_ELEMENT_TYPE_CONTAINER);
1390  assert(child->container.type == JSON_CONTAINER_TYPE_OBJECT);
1391  return child;
1392  }
1393 
1394  return NULL;
1395 }
1396 
1397 JsonElement *JsonArrayGet(const JsonElement *const array, const size_t index)
1398 {
1399  assert(array != NULL);
1400  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1401  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1402 
1403  return JsonAt(array, index);
1404 }
1405 
1407 {
1408  assert(array != NULL);
1409  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1410  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1411 
1412 
1413  for (size_t i = 0; i < JsonLength(array); i++)
1414  {
1415  JsonElement *child = JsonArrayGet(array, i);
1416 
1417  if (child->type != JSON_ELEMENT_TYPE_PRIMITIVE)
1418  {
1419  return false;
1420  }
1421  }
1422 
1423  return true;
1424 }
1425 
1427 {
1428  assert(array != NULL);
1429  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1430  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1431 
1432  SeqReverse(array->container.children);
1433 }
1434 
1435 // *******************************************************************************************
1436 // Primitive Functions
1437 // *******************************************************************************************
1438 
1439 JsonElement *JsonStringCreate(const char *const value)
1440 {
1441  assert(value != NULL);
1442 
1445 }
1446 
1448 {
1449  char *buffer;
1450  xasprintf(&buffer, "%d", value);
1451 
1453 }
1454 
1456 {
1457  if (isnan(value) || !isfinite(value))
1458  {
1459  value = 0.0;
1460  }
1461 
1462  char *buffer = xcalloc(32, sizeof(char));
1463  snprintf(buffer, 32, "%.4f", value);
1464 
1466 }
1467 
1468 JsonElement *JsonBoolCreate(const bool value)
1469 {
1470  const char *const as_string = value ? JSON_TRUE : JSON_FALSE;
1472 }
1473 
1475 {
1477 }
1478 
1479 // *******************************************************************************************
1480 // Printing
1481 // *******************************************************************************************
1482 
1483 static void JsonContainerWrite(
1484  Writer *writer, const JsonElement *containerElement, size_t indent_level);
1485 static void JsonContainerWriteCompact(
1486  Writer *writer, const JsonElement *containerElement);
1487 
1488 static bool IsWhitespace(const char ch)
1489 {
1490  return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
1491 }
1492 
1493 static bool IsSeparator(const char ch)
1494 {
1495  return IsWhitespace(ch) || ch == ',' || ch == ']' || ch == '}';
1496 }
1497 
1498 static bool IsDigit(const char ch)
1499 {
1500  // [1,9]
1501  return (ch >= 49 && ch <= 57);
1502 }
1503 
1504 static void PrintIndent(Writer *const writer, const int num)
1505 {
1506  int i = 0;
1507 
1508  for (i = 0; i < num * SPACES_PER_INDENT; i++)
1509  {
1510  WriterWriteChar(writer, ' ');
1511  }
1512 }
1513 
1515  Writer *const writer,
1516  const JsonElement *const primitiveElement,
1517  const size_t indent_level)
1518 {
1519  assert(primitiveElement != NULL);
1520  assert(primitiveElement->type == JSON_ELEMENT_TYPE_PRIMITIVE);
1521 
1522  const char *const value = primitiveElement->primitive.value;
1523 
1524  if (primitiveElement->primitive.type == JSON_PRIMITIVE_TYPE_STRING)
1525  {
1526  PrintIndent(writer, indent_level);
1527  {
1528  char *encoded = JsonEncodeString(value);
1529  WriterWriteF(writer, "\"%s\"", encoded);
1530  free(encoded);
1531  }
1532  }
1533  else
1534  {
1535  PrintIndent(writer, indent_level);
1536  WriterWrite(writer, value);
1537  }
1538 }
1539 
1540 static void JsonArrayWrite(
1541  Writer *const writer,
1542  const JsonElement *const array,
1543  const size_t indent_level)
1544 {
1545  assert(array != NULL);
1546  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1547  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1548  assert(array->container.children != NULL);
1549 
1550  if (JsonLength(array) == 0)
1551  {
1552  WriterWrite(writer, "[]");
1553  return;
1554  }
1555 
1556  WriterWrite(writer, "[\n");
1557 
1558  Seq *const children = array->container.children;
1559  const size_t length = SeqLength(children);
1560  for (size_t i = 0; i < length; i++)
1561  {
1562  JsonElement *const child = SeqAt(children, i);
1563 
1564  switch (child->type)
1565  {
1567  JsonPrimitiveWrite(writer, child, indent_level + 1);
1568  break;
1569 
1571  PrintIndent(writer, indent_level + 1);
1572  JsonContainerWrite(writer, child, indent_level + 1);
1573  break;
1574 
1575  default:
1576  UnexpectedError("Unknown JSON element type: %d", child->type);
1577  }
1578 
1579  if (i < length - 1)
1580  {
1581  WriterWrite(writer, ",\n");
1582  }
1583  else
1584  {
1585  WriterWrite(writer, "\n");
1586  }
1587  }
1588 
1589  PrintIndent(writer, indent_level);
1590  WriterWriteChar(writer, ']');
1591 }
1592 
1594  const void *const e1,
1595  const void *const e2,
1596  ARG_UNUSED void *const user_data)
1597 {
1598  assert(e1 != NULL);
1599  assert(e2 != NULL);
1600 
1601  return strcmp(
1602  ((JsonElement *) e1)->propertyName,
1603  ((JsonElement *) e2)->propertyName);
1604 }
1605 
1606 #ifndef NDEBUG // gcc would complain about unused function
1607 
1608 static bool all_children_have_keys(const JsonElement *const object)
1609 {
1610  assert(object != NULL);
1611  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1612 
1613  Seq *const children = object->container.children;
1614  const size_t length = SeqLength(children);
1615  for (size_t i = 0; i < length; i++)
1616  {
1617  const JsonElement *const child = SeqAt(children, i);
1618  if (child->propertyName == NULL)
1619  {
1620  return false;
1621  }
1622  }
1623  return true;
1624 }
1625 
1626 #endif
1627 
1629  Writer *const writer,
1630  const JsonElement *const object,
1631  const size_t indent_level)
1632 {
1633  assert(object != NULL);
1634  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1635  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1636  assert(object->container.children != NULL);
1637 
1638  WriterWrite(writer, "{\n");
1639 
1640  assert(all_children_have_keys(object));
1641 
1642  // sort the children Seq so the output is canonical (keys are sorted)
1643  // we've already asserted that the children have a valid propertyName
1645 
1646  Seq *const children = object->container.children;
1647  const size_t length = SeqLength(children);
1648  for (size_t i = 0; i < length; i++)
1649  {
1650  JsonElement *child = SeqAt(children, i);
1651 
1652  PrintIndent(writer, indent_level + 1);
1653 
1654  assert(child->propertyName != NULL);
1655  WriterWriteF(writer, "\"%s\": ", child->propertyName);
1656 
1657  switch (child->type)
1658  {
1660  JsonPrimitiveWrite(writer, child, 0);
1661  break;
1662 
1664  JsonContainerWrite(writer, child, indent_level + 1);
1665  break;
1666 
1667  default:
1668  UnexpectedError("Unknown JSON element type: %d", child->type);
1669  }
1670 
1671  if (i < length - 1)
1672  {
1673  WriterWriteChar(writer, ',');
1674  }
1675  WriterWrite(writer, "\n");
1676  }
1677 
1678  PrintIndent(writer, indent_level);
1679  WriterWriteChar(writer, '}');
1680 }
1681 
1683  Writer *const writer,
1684  const JsonElement *const container,
1685  const size_t indent_level)
1686 {
1687  assert(container != NULL);
1688  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
1689 
1690  switch (container->container.type)
1691  {
1693  JsonObjectWrite(writer, container, indent_level);
1694  break;
1695 
1697  JsonArrayWrite(writer, container, indent_level);
1698  }
1699 }
1700 
1702  Writer *const writer,
1703  const JsonElement *const element,
1704  const size_t indent_level)
1705 {
1706  assert(writer != NULL);
1707  assert(element != NULL);
1708 
1709  switch (element->type)
1710  {
1712  JsonContainerWrite(writer, element, indent_level);
1713  break;
1714 
1716  JsonPrimitiveWrite(writer, element, indent_level);
1717  break;
1718 
1719  default:
1720  UnexpectedError("Unknown JSON element type: %d", element->type);
1721  }
1722 }
1723 
1725  Writer *const writer, const JsonElement *const array)
1726 {
1727  assert(array != NULL);
1728  assert(array->type == JSON_ELEMENT_TYPE_CONTAINER);
1729  assert(array->container.type == JSON_CONTAINER_TYPE_ARRAY);
1730  assert(array->container.children != NULL);
1731 
1732  if (JsonLength(array) == 0)
1733  {
1734  WriterWrite(writer, "[]");
1735  return;
1736  }
1737 
1738  WriterWrite(writer, "[");
1739  Seq *const children = array->container.children;
1740  const size_t length = SeqLength(children);
1741  for (size_t i = 0; i < length; i++)
1742  {
1743  JsonElement *const child = SeqAt(children, i);
1744  assert(child != NULL);
1745 
1746  switch (child->type)
1747  {
1749  JsonPrimitiveWrite(writer, child, 0);
1750  break;
1751 
1753  JsonContainerWriteCompact(writer, child);
1754  break;
1755 
1756  default:
1757  UnexpectedError("Unknown JSON element type: %d", child->type);
1758  }
1759 
1760  if (i < length - 1)
1761  {
1762  WriterWrite(writer, ",");
1763  }
1764  }
1765 
1766  WriterWriteChar(writer, ']');
1767 }
1768 
1770  Writer *const writer, const JsonElement *const object)
1771 {
1772  assert(object != NULL);
1773  assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
1774  assert(object->container.type == JSON_CONTAINER_TYPE_OBJECT);
1775 
1776  WriterWrite(writer, "{");
1777 
1778  assert(all_children_have_keys(object));
1779 
1780  // sort the children Seq so the output is canonical (keys are sorted)
1781  // we've already asserted that the children have a valid propertyName
1783 
1784  Seq *const children = object->container.children;
1785  const size_t length = SeqLength(children);
1786  for (size_t i = 0; i < length; i++)
1787  {
1788  JsonElement *child = SeqAt(children, i);
1789 
1790  WriterWriteF(writer, "\"%s\":", child->propertyName);
1791 
1792  switch (child->type)
1793  {
1795  JsonPrimitiveWrite(writer, child, 0);
1796  break;
1797 
1799  JsonContainerWriteCompact(writer, child);
1800  break;
1801 
1802  default:
1803  UnexpectedError("Unknown JSON element type: %d", child->type);
1804  }
1805 
1806  if (i < length - 1)
1807  {
1808  WriterWriteChar(writer, ',');
1809  }
1810  }
1811 
1812  WriterWriteChar(writer, '}');
1813 }
1814 
1816  Writer *const writer, const JsonElement *const container)
1817 {
1818  assert(container != NULL);
1819  assert(container->type == JSON_ELEMENT_TYPE_CONTAINER);
1820 
1821  switch (container->container.type)
1822  {
1824  JsonObjectWriteCompact(writer, container);
1825  break;
1826 
1828  JsonArrayWriteCompact(writer, container);
1829  }
1830 }
1831 
1832 void JsonWriteCompact(Writer *const w, const JsonElement *const element)
1833 {
1834  assert(w != NULL);
1835  assert(element != NULL);
1836 
1837  switch (element->type)
1838  {
1840  JsonContainerWriteCompact(w, element);
1841  break;
1842 
1844  JsonPrimitiveWrite(w, element, 0);
1845  break;
1846 
1847  default:
1848  UnexpectedError("Unknown JSON element type: %d", element->type);
1849  }
1850 }
1851 
1852 // *******************************************************************************************
1853 // Parsing
1854 // *******************************************************************************************
1855 
1857  void *lookup_context,
1858  JsonLookup *lookup_function,
1859  const char **data,
1860  JsonElement **json_out);
1861 
1862 static JsonElement *JsonParseAsBoolean(const char **const data)
1863 {
1864  assert(data != NULL);
1865 
1866  if (StringStartsWith(*data, "true"))
1867  {
1868  char next = *(*data + 4);
1869  if (IsSeparator(next) || next == '\0')
1870  {
1871  *data += 3;
1872  return JsonBoolCreate(true);
1873  }
1874  }
1875  else if (StringStartsWith(*data, "false"))
1876  {
1877  char next = *(*data + 5);
1878  if (IsSeparator(next) || next == '\0')
1879  {
1880  *data += 4;
1881  return JsonBoolCreate(false);
1882  }
1883  }
1884 
1885  return NULL;
1886 }
1887 
1888 static JsonElement *JsonParseAsNull(const char **const data)
1889 {
1890  assert(data != NULL);
1891 
1892  if (StringStartsWith(*data, "null"))
1893  {
1894  char next = *(*data + 4);
1895  if (IsSeparator(next) || next == '\0')
1896  {
1897  *data += 3;
1898  return JsonNullCreate();
1899  }
1900  }
1901 
1902  return NULL;
1903 }
1904 
1905 const char *JsonParseErrorToString(const JsonParseError error)
1906 {
1907  assert(error < JSON_PARSE_ERROR_MAX);
1908 
1909  static const char *const parse_errors[JSON_PARSE_ERROR_MAX] = {
1910  [JSON_PARSE_OK] = "Success",
1911 
1913  "Unable to parse json data as string, did not start with doublequote",
1915  "Unable to parse json data as string, did not end with doublequote",
1916 
1918  "Unable to parse json data as number, - not at the start or not after exponent",
1920  "Unable to parse json data as number, + without preceding exponent",
1922  "Unable to parse json data as number, started with 0 before dot or exponent, duplicate 0 seen",
1924  "Unable to parse json data as number, dot not preceded by digit",
1926  "Unable to parse json data as number, two or more dots (decimal points)",
1928  "Unable to parse json data as number, duplicate exponent",
1930  "Unable to parse json data as number, exponent without preceding digit",
1932  "Unable to parse json data as number, dot or exponent must follow leading 0",
1934  "Unable to parse json data as number, invalid symbol",
1936  "Unable to parse json data as string, did not end with digit",
1937 
1939  "Unable to parse json data as array, did not start with '['",
1941  "Unable to parse json data as array, did not end with ']'",
1943  "Unable to parse json data as array, extraneous commas",
1944 
1946  "Unable to parse json data as object, unrecognized token beginning entry",
1948  "Unable to parse json data as object, did not start with '{'",
1950  "Unable to parse json data as string, did not end with '}'",
1952  "Unable to parse json data as object, ':' seen without having specified an l-value",
1954  "Unable to parse json data as object, ',' seen without having specified an r-value",
1956  "Unable to parse json data as object, array not allowed as l-value",
1958  "Unable to parse json data as object, object not allowed as l-value",
1960  "Unable to parse json data as object, tried to close object having opened an l-value",
1961 
1963  "Unwilling to parse json data starting with invalid character",
1965  "Unable to parse JSON without truncating",
1967  "CFEngine was not built with libyaml support",
1968  [JSON_PARSE_ERROR_LIBYAML_FAILURE] = "libyaml internal failure",
1969  [JSON_PARSE_ERROR_NO_SUCH_FILE] = "No such file or directory",
1970  [JSON_PARSE_ERROR_NO_DATA] = "No data"};
1971 
1972  return parse_errors[error];
1973 }
1974 
1976  const char **const data, char **const str_out)
1977 {
1978  assert(data != NULL);
1979  assert(*data != NULL);
1980  assert(str_out != NULL);
1981 
1982  /* NB: although JavaScript supports both single and double quotes
1983  * as string delimiters, JSON only supports double quotes. */
1984  if (**data != '"')
1985  {
1986  *str_out = NULL;
1988  }
1989 
1990  Writer *writer = StringWriter();
1991 
1992  for (*data = *data + 1; **data != '\0'; *data = *data + 1)
1993  {
1994  switch (**data)
1995  {
1996  case '"':
1997  *str_out = StringWriterClose(writer);
1998  return JSON_PARSE_OK;
1999 
2000  case '\\':
2001  *data = *data + 1;
2002  switch (**data)
2003  {
2004  case '\\':
2005  case '"':
2006  case '/':
2007  break;
2008 
2009  case 'b':
2010  WriterWriteChar(writer, '\b');
2011  continue;
2012  case 'f':
2013  WriterWriteChar(writer, '\f');
2014  continue;
2015  case 'n':
2016  WriterWriteChar(writer, '\n');
2017  continue;
2018  case 'r':
2019  WriterWriteChar(writer, '\r');
2020  continue;
2021  case 't':
2022  WriterWriteChar(writer, '\t');
2023  continue;
2024 
2025  default:
2026  /* Unrecognised escape sequence.
2027  *
2028  * For example, we fail to handle Unicode escapes -
2029  * \u{hex digits} - we have no way to represent the
2030  * character they denote. So keep them verbatim, for
2031  * want of any other way to handle them; but warn. */
2033  "Keeping verbatim unrecognised JSON escape '%.6s'",
2034  *data - 1); // Include the \ in the displayed escape
2035  WriterWriteChar(writer, '\\');
2036  break;
2037  }
2038  /* Deliberate fall-through */
2039  default:
2040  WriterWriteChar(writer, **data);
2041  break;
2042  }
2043  }
2044 
2045  WriterClose(writer);
2046  *str_out = NULL;
2048 }
2049 
2051  const char **const data, JsonElement **const json_out)
2052 {
2053  assert(data != NULL);
2054  assert(*data != NULL);
2055  assert(json_out != NULL);
2056 
2057  Writer *writer = StringWriter();
2058 
2059  bool zero_started = false;
2060  bool seen_dot = false;
2061  bool seen_exponent = false;
2062 
2063  char prev_char = 0;
2064 
2065  for (*data = *data; **data != '\0' && !IsSeparator(**data);
2066  prev_char = **data, *data = *data + 1)
2067  {
2068  switch (**data)
2069  {
2070  case '-':
2071  if (prev_char != 0 && prev_char != 'e' && prev_char != 'E')
2072  {
2073  *json_out = NULL;
2074  WriterClose(writer);
2076  }
2077  break;
2078 
2079  case '+':
2080  if (prev_char != 'e' && prev_char != 'E')
2081  {
2082  *json_out = NULL;
2083  WriterClose(writer);
2085  }
2086  break;
2087 
2088  case '0':
2089  if (zero_started && !seen_dot && !seen_exponent)
2090  {
2091  *json_out = NULL;
2092  WriterClose(writer);
2094  }
2095  if (prev_char == 0)
2096  {
2097  zero_started = true;
2098  }
2099  break;
2100 
2101  case '.':
2102  if (seen_dot)
2103  {
2104  *json_out = NULL;
2105  WriterClose(writer);
2107  }
2108  if (prev_char != '0' && !IsDigit(prev_char))
2109  {
2110  *json_out = NULL;
2111  WriterClose(writer);
2113  }
2114  seen_dot = true;
2115  break;
2116 
2117  case 'e':
2118  case 'E':
2119  if (seen_exponent)
2120  {
2121  *json_out = NULL;
2122  WriterClose(writer);
2124  }
2125  else if (!IsDigit(prev_char) && prev_char != '0')
2126  {
2127  *json_out = NULL;
2128  WriterClose(writer);
2130  }
2131  seen_exponent = true;
2132  break;
2133 
2134  default:
2135  if (zero_started && !seen_dot && !seen_exponent)
2136  {
2137  *json_out = NULL;
2138  WriterClose(writer);
2140  }
2141 
2142  if (!IsDigit(**data))
2143  {
2144  *json_out = NULL;
2145  WriterClose(writer);
2147  }
2148  break;
2149  }
2150 
2151  WriterWriteChar(writer, **data);
2152  }
2153 
2154  if (prev_char != '0' && !IsDigit(prev_char))
2155  {
2156  *json_out = NULL;
2157  WriterClose(writer);
2159  }
2160 
2161  // rewind 1 char so caller will see separator next
2162  *data = *data - 1;
2163 
2164  if (seen_dot)
2165  {
2166  *json_out = JsonElementCreatePrimitive(
2168  return JSON_PARSE_OK;
2169  }
2170  else
2171  {
2172  *json_out = JsonElementCreatePrimitive(
2174  return JSON_PARSE_OK;
2175  }
2176 }
2177 
2179  const char **const data, JsonElement **const json_out)
2180 {
2181  assert(json_out != NULL);
2182  assert(data != NULL);
2183  assert(*data != NULL);
2184 
2185  if (**data == '"')
2186  {
2187  char *value = NULL;
2188  const JsonParseError err = JsonParseAsString(data, &value);
2189  if (err != JSON_PARSE_OK)
2190  {
2191  return err;
2192  }
2193  *json_out = JsonElementCreatePrimitive(
2195  free(value);
2196  return JSON_PARSE_OK;
2197  }
2198  else
2199  {
2200  if (**data == '-' || **data == '0' || IsDigit(**data))
2201  {
2202  const JsonParseError err = JsonParseAsNumber(data, json_out);
2203  if (err != JSON_PARSE_OK)
2204  {
2205  return err;
2206  }
2207  return JSON_PARSE_OK;
2208  }
2209 
2210  JsonElement *const child_bool = JsonParseAsBoolean(data);
2211  if (child_bool != NULL)
2212  {
2213  *json_out = child_bool;
2214  return JSON_PARSE_OK;
2215  }
2216 
2217  JsonElement *const child_null = JsonParseAsNull(data);
2218  if (child_null != NULL)
2219  {
2220  *json_out = child_null;
2221  return JSON_PARSE_OK;
2222  }
2223 
2224  *json_out = NULL;
2226  }
2227 }
2228 
2230  void *const lookup_context,
2231  JsonLookup *const lookup_function,
2232  const char **const data,
2233  JsonElement **const json_out)
2234 {
2235  assert(json_out != NULL);
2236  assert(data != NULL);
2237  assert(*data != NULL);
2238 
2239  if (**data != '[')
2240  {
2241  *json_out = NULL;
2243  }
2244 
2246  char prev_char = '[';
2247 
2248  for (*data = *data + 1; **data != '\0'; *data = *data + 1)
2249  {
2250  if (IsWhitespace(**data))
2251  {
2252  continue;
2253  }
2254 
2255  switch (**data)
2256  {
2257  case '"':
2258  {
2259  char *value = NULL;
2260  JsonParseError err = JsonParseAsString(data, &value);
2261  if (err != JSON_PARSE_OK)
2262  {
2263  return err;
2264  }
2266  array,
2269  free(value);
2270  }
2271  break;
2272 
2273  case '[':
2274  {
2275  if (prev_char != '[' && prev_char != ',')
2276  {
2277  JsonDestroy(array);
2279  }
2280  JsonElement *child_array = NULL;
2282  lookup_context, lookup_function, data, &child_array);
2283  if (err != JSON_PARSE_OK)
2284  {
2285  JsonDestroy(array);
2286  return err;
2287  }
2288  assert(child_array);
2289 
2290  JsonArrayAppendArray(array, child_array);
2291  }
2292  break;
2293 
2294  case '{':
2295  {
2296  if (prev_char != '[' && prev_char != ',')
2297  {
2298  JsonDestroy(array);
2300  }
2301  JsonElement *child_object = NULL;
2303  lookup_context, lookup_function, data, &child_object);
2304  if (err != JSON_PARSE_OK)
2305  {
2306  JsonDestroy(array);
2307  return err;
2308  }
2309  assert(child_object);
2310 
2311  JsonArrayAppendObject(array, child_object);
2312  }
2313  break;
2314 
2315  case ',':
2316  if (prev_char == ',' || prev_char == '[')
2317  {
2318  JsonDestroy(array);
2320  }
2321  break;
2322 
2323  case ']':
2324  *json_out = array;
2325  return JSON_PARSE_OK;
2326 
2327  default:
2328  if (**data == '-' || **data == '0' || IsDigit(**data))
2329  {
2330  JsonElement *child = NULL;
2331  JsonParseError err = JsonParseAsNumber(data, &child);
2332  if (err != JSON_PARSE_OK)
2333  {
2334  JsonDestroy(array);
2335  return err;
2336  }
2337  assert(child);
2338 
2339  JsonArrayAppendElement(array, child);
2340  break;
2341  }
2342 
2343  JsonElement *child_bool = JsonParseAsBoolean(data);
2344  if (child_bool != NULL)
2345  {
2346  JsonArrayAppendElement(array, child_bool);
2347  break;
2348  }
2349 
2350  JsonElement *child_null = JsonParseAsNull(data);
2351  if (child_null != NULL)
2352  {
2353  JsonArrayAppendElement(array, child_null);
2354  break;
2355  }
2356 
2357  if (lookup_function != NULL)
2358  {
2359  JsonElement *child_ref =
2360  (*lookup_function)(lookup_context, data);
2361  if (child_ref != NULL)
2362  {
2363  JsonArrayAppendElement(array, child_ref);
2364  break;
2365  }
2366  }
2367 
2368  *json_out = NULL;
2369  JsonDestroy(array);
2371  }
2372 
2373  prev_char = **data;
2374  }
2375 
2376  *json_out = NULL;
2377  JsonDestroy(array);
2379 }
2380 
2381 static bool wc(char c)
2382 {
2383  // word character, \w in regex
2384  return (isalnum(c) || c == '_');
2385 }
2386 
2387 static const char *unquoted_key_with_colon(const char *data)
2388 {
2389  // Implements the regex: ^\w[-\w]*\s*:
2390  if (!wc(data[0]))
2391  {
2392  return NULL;
2393  }
2394  int i;
2395  for (i = 1; data[i] != '\0' && (data[i] == '-' || wc(data[i])); ++i)
2396  {
2397  // Skip past word characters (\w) and dashes
2398  }
2399  for (; data[i] != '\0' && IsWhitespace(data[i]); ++i)
2400  {
2401  // Skip past whitespace
2402  }
2403  if (data[i] != ':')
2404  {
2405  return NULL;
2406  }
2407  return data + i;
2408 }
2409 
2411  void *const lookup_context,
2412  JsonLookup *const lookup_function,
2413  const char **const data,
2414  JsonElement **const json_out)
2415 {
2416  assert(json_out != NULL);
2417  assert(data != NULL);
2418  assert(*data != NULL);
2419 
2420  if (**data != '{')
2421  {
2422  *json_out = NULL;
2424  }
2425 
2427  char *property_name = NULL;
2428  char prev_char = '{';
2429 
2430  for (*data = *data + 1; **data != '\0'; *data = *data + 1)
2431  {
2432  if (IsWhitespace(**data))
2433  {
2434  continue;
2435  }
2436 
2437  switch (**data)
2438  {
2439  case '"':
2440  if (property_name != NULL)
2441  {
2442  char *property_value = NULL;
2443  JsonParseError err = JsonParseAsString(data, &property_value);
2444  if (err != JSON_PARSE_OK)
2445  {
2446  free(property_name);
2447  JsonDestroy(object);
2448  return err;
2449  }
2450  assert(property_value);
2451 
2453  object,
2454  property_name,
2457  JsonDecodeString(property_value)));
2458  free(property_value);
2459  free(property_name);
2460  property_name = NULL;
2461  }
2462  else
2463  {
2464  property_name = NULL;
2465  JsonParseError err = JsonParseAsString(data, &property_name);
2466  if (err != JSON_PARSE_OK)
2467  {
2468  JsonDestroy(object);
2469  return err;
2470  }
2471  assert(property_name);
2472  }
2473  break;
2474 
2475  case ':':
2476  if (property_name == NULL || prev_char == ':' || prev_char == ',')
2477  {
2478  *json_out = NULL;
2479  free(property_name);
2480  JsonDestroy(object);
2482  }
2483  break;
2484 
2485  case ',':
2486  if (property_name != NULL || prev_char == ':' || prev_char == ',')
2487  {
2488  free(property_name);
2489  JsonDestroy(object);
2491  }
2492  break;
2493 
2494  case '[':
2495  if (property_name != NULL)
2496  {
2497  JsonElement *child_array = NULL;
2499  lookup_context, lookup_function, data, &child_array);
2500  if (err != JSON_PARSE_OK)
2501  {
2502  free(property_name);
2503  JsonDestroy(object);
2504  return err;
2505  }
2506 
2507  JsonObjectAppendArray(object, property_name, child_array);
2508  free(property_name);
2509  property_name = NULL;
2510  }
2511  else
2512  {
2513  free(property_name);
2514  JsonDestroy(object);
2516  }
2517  break;
2518 
2519  case '{':
2520  if (property_name != NULL)
2521  {
2522  JsonElement *child_object = NULL;
2524  lookup_context, lookup_function, data, &child_object);
2525  if (err != JSON_PARSE_OK)
2526  {
2527  free(property_name);
2528  JsonDestroy(object);
2529  return err;
2530  }
2531 
2532  JsonObjectAppendObject(object, property_name, child_object);
2533  free(property_name);
2534  property_name = NULL;
2535  }
2536  else
2537  {
2538  *json_out = NULL;
2539  free(property_name);
2540  JsonDestroy(object);
2542  }
2543  break;
2544 
2545  case '}':
2546  if (property_name != NULL)
2547  {
2548  *json_out = NULL;
2549  free(property_name);
2550  JsonDestroy(object);
2552  }
2553  free(property_name);
2554  *json_out = object;
2555  return JSON_PARSE_OK;
2556 
2557  default:
2558  {
2559  const char *colon = NULL;
2560  // Note the character class excludes ':'.
2561  // This will match the key from { foo : 2 } but not { -foo: 2 }
2562  if (property_name == NULL
2563  && (colon = unquoted_key_with_colon(*data)) != NULL)
2564  {
2565  // Step backwards until we are on the last whitespace.
2566 
2567  // Note that this is safe because the above function guarantees
2568  // we will find at least one non-whitespace character as we
2569  // go backwards.
2570  const char *ws = colon;
2571  while (IsWhitespace(*(ws - 1)))
2572  {
2573  ws -= 1;
2574  }
2575 
2576  property_name = xstrndup(*data, ws - *data);
2577  *data = colon;
2578 
2579  break;
2580  }
2581  else if (property_name != NULL)
2582  {
2583  if (**data == '-' || **data == '0' || IsDigit(**data))
2584  {
2585  JsonElement *child = NULL;
2586  JsonParseError err = JsonParseAsNumber(data, &child);
2587  if (err != JSON_PARSE_OK)
2588  {
2589  free(property_name);
2590  JsonDestroy(object);
2591  return err;
2592  }
2593  JsonObjectAppendElement(object, property_name, child);
2594  free(property_name);
2595  property_name = NULL;
2596  break;
2597  }
2598 
2599  JsonElement *child_bool = JsonParseAsBoolean(data);
2600  if (child_bool != NULL)
2601  {
2602  JsonObjectAppendElement(object, property_name, child_bool);
2603  free(property_name);
2604  property_name = NULL;
2605  break;
2606  }
2607 
2608  JsonElement *child_null = JsonParseAsNull(data);
2609  if (child_null != NULL)
2610  {
2611  JsonObjectAppendElement(object, property_name, child_null);
2612  free(property_name);
2613  property_name = NULL;
2614  break;
2615  }
2616 
2617  if (lookup_function != NULL)
2618  {
2619  JsonElement *child_ref =
2620  (*lookup_function)(lookup_context, data);
2621  if (child_ref != NULL)
2622  {
2624  object, property_name, child_ref);
2625  free(property_name);
2626  property_name = NULL;
2627  break;
2628  }
2629  }
2630  }
2631 
2632  *json_out = NULL;
2633  free(property_name);
2634  JsonDestroy(object);
2636  } // default
2637  } // switch
2638 
2639  prev_char = **data;
2640  }
2641 
2642  *json_out = NULL;
2643  free(property_name);
2644  JsonDestroy(object);
2646 }
2647 
2648 JsonParseError JsonParse(const char **const data, JsonElement **const json_out)
2649 {
2650  return JsonParseWithLookup(NULL, NULL, data, json_out);
2651 }
2652 
2654  void *const lookup_context,
2655  JsonLookup *const lookup_function,
2656  const char **const data,
2657  JsonElement **const json_out)
2658 {
2659  assert(data != NULL);
2660  assert(*data != NULL);
2661  if (data == NULL || *data == NULL)
2662  {
2663  return JSON_PARSE_ERROR_NO_DATA;
2664  }
2665 
2666  while (**data)
2667  {
2668  if (**data == '{')
2669  {
2670  return JsonParseAsObject(
2671  lookup_context, lookup_function, data, json_out);
2672  }
2673  else if (**data == '[')
2674  {
2675  return JsonParseAsArray(
2676  lookup_context, lookup_function, data, json_out);
2677  }
2678  else if (IsWhitespace(**data))
2679  {
2680  (*data)++;
2681  }
2682  else
2683  {
2684  return JsonParseAsPrimitive(data, json_out);
2685  }
2686  }
2687 
2688  return JSON_PARSE_ERROR_NO_DATA;
2689 }
2690 
2692  const char *const path,
2693  const size_t size_max,
2694  JsonElement **const json_out,
2695  const bool yaml_format)
2696 {
2697  assert(json_out != NULL);
2698 
2699  bool truncated = false;
2700  Writer *contents = FileRead(path, size_max, &truncated);
2701  if (contents == NULL)
2702  {
2704  }
2705  else if (truncated)
2706  {
2708  }
2709  assert(json_out);
2710  *json_out = NULL;
2711  const char *data = StringWriterData(contents);
2712  JsonParseError err;
2713 
2714  if (yaml_format)
2715  {
2716  err = JsonParseYamlString(&data, json_out);
2717  }
2718  else
2719  {
2720  err = JsonParse(&data, json_out);
2721  }
2722 
2723  WriterClose(contents);
2724  return err;
2725 }
2726 
2728  const char *const path,
2729  const size_t size_max,
2730  JsonElement **const json_out)
2731 {
2732  return JsonParseAnyFile(path, size_max, json_out, false);
2733 }
2734 
2735 /*******************************************************************/
2736 
2737 #ifdef WITH_PCRE
2738 #include <json-pcre.h>
2739 
2740 // returns NULL on any failure
2741 // takes either a pre-compiled pattern OR a regex (one of the two shouldn't be
2742 // NULL)
2744  pcre *const pattern, const char *const regex, const char *const data)
2745 {
2746  assert(regex != NULL || pattern != NULL);
2747  assert(data != NULL);
2748 
2749  Seq *s;
2750 
2751  if (pattern != NULL)
2752  {
2753  s = StringMatchCapturesWithPrecompiledRegex(pattern, data, true);
2754  }
2755  else
2756  {
2757  s = StringMatchCaptures(regex, data, true);
2758  }
2759 
2760  const size_t length = (s != NULL) ? SeqLength(s) : 0;
2761 
2762  if (length == 0)
2763  {
2764  SeqDestroy(s);
2765  return NULL;
2766  }
2767 
2768  JsonElement *json = JsonObjectCreate(length / 2);
2769 
2770  for (int i = 1; i < length; i += 2)
2771  {
2772  Buffer *key = SeqAt(s, i - 1);
2773  Buffer *value = SeqAt(s, i);
2774 
2775  JsonObjectAppendString(json, BufferData(key), BufferData(value));
2776  }
2777 
2778  SeqDestroy(s);
2779 
2780  JsonObjectRemoveKey(json, "0");
2781  return json;
2782 }
2783 
2784 #endif // WITH_PCRE
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
char * xstrndup(const char *str, size_t n)
Definition: alloc.c:61
const char * BufferData(const Buffer *buffer)
Provides a pointer to the internal data.
Definition: buffer.c:470
#define ARG_UNUSED
Definition: cf-net.c:47
void free(void *)
Writer * FileRead(const char *filename, size_t max_size, bool *truncated)
Definition: file_lib.c:63
#define NULL
Definition: getopt1.c:56
JsonElement * StringCaptureData(pcre *pattern, const char *regex, const char *data)
JsonParseError JsonParseYamlString(const char **data, JsonElement **json_out)
Parse a YAML string to create a JsonElement.
Definition: json-yaml.c:360
static int JsonArrayCompare(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:250
static int JsonContainerCompare(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:328
bool JsonPrimitiveGetAsBool(const JsonElement *const primitive)
Definition: json.c:741
int JsonCompare(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:358
JsonElement * JsonMerge(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:491
static const char *const JSON_NULL
Definition: json.c:46
void JsonWrite(Writer *const writer, const JsonElement *const element, const size_t indent_level)
Pretty-print a JsonElement recursively into a Writer. If it's a JsonObject, its children will be sort...
Definition: json.c:1701
const char * JsonElementGetPropertyName(const JsonElement *const element)
Definition: json.c:111
static JsonParseError JsonParseAsArray(void *const lookup_context, JsonLookup *const lookup_function, const char **const data, JsonElement **const json_out)
Definition: json.c:2229
JsonParseError JsonParseAsNumber(const char **const data, JsonElement **const json_out)
Definition: json.c:2050
static JsonParseError JsonParseAsString(const char **const data, char **const str_out)
Definition: json.c:1975
void JsonArrayAppendObject(JsonElement *const array, JsonElement *const object)
Append an object to an array.
Definition: json.c:1327
void Json5EscapeDataWriter(const Slice unescaped_data, Writer *const writer)
Definition: json.c:992
const char * JsonIteratorNextKey(JsonIterator *const iter)
Definition: json.c:557
JsonPrimitiveType JsonIteratorCurrentPrimitiveType(const JsonIterator *const iter)
Definition: json.c:649
JsonElement * JsonObjectCreate(const size_t initialCapacity)
Create a new JSON object.
Definition: json.c:880
void JsonDestroy(JsonElement *const element)
Destroy a JSON element.
Definition: json.c:386
static void JsonObjectWriteCompact(Writer *const writer, const JsonElement *const object)
Definition: json.c:1769
static void JsonContainerWriteCompact(Writer *writer, const JsonElement *containerElement)
Definition: json.c:1815
static void JsonEncodeStringWriter(const char *const unescaped_string, Writer *const writer)
Definition: json.c:886
JsonElement * JsonIteratorCurrentValue(const JsonIterator *const iter)
Definition: json.c:603
JsonElementType JsonGetElementType(const JsonElement *const element)
Definition: json.c:667
static int JsonElementHasProperty(const void *const propertyName, const void *const jsonElement, void *const user_data)
Definition: json.c:1128
void JsonObjectAppendInteger(JsonElement *const object, const char *const key, const int value)
Append an integer field to an object.
Definition: json.c:1062
bool JsonIteratorHasMore(const JsonIterator *const iter)
Definition: json.c:660
JsonIterator JsonIteratorInit(const JsonElement *const container)
Definition: json.c:549
char * JsonEncodeString(const char *const unescaped_string)
Definition: json.c:926
static void JsonElementSetPropertyName(JsonElement *const element, const char *const propertyName)
Definition: json.c:94
const char * JsonArrayGetAsString(JsonElement *const array, const size_t index)
Get a string value from an array.
Definition: json.c:1359
int JsonElementPropertyCompare(const void *const e1, const void *const e2, void *const user_data)
Definition: json.c:1593
JsonElement * JsonNullCreate()
Definition: json.c:1474
JsonElement * JsonCopy(const JsonElement *const element)
Definition: json.c:235
JsonElement * JsonArrayMergeArray(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:430
static JsonElement * JsonPrimitiveCopy(const JsonElement *const primitive)
Definition: json.c:206
void JsonArrayAppendReal(JsonElement *const array, const double value)
Append an real to an array.
Definition: json.c:1305
void JsonObjectAppendNull(JsonElement *const object, const char *const key)
Append null field to an object.
Definition: json.c:1083
JsonElement * JsonObjectMergeObject(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:471
static const char * unquoted_key_with_colon(const char *data)
Definition: json.c:2387
void JsonArrayAppendArray(JsonElement *const array, JsonElement *const childArray)
Append an array to an array.
Definition: json.c:1317
JsonElement * JsonObjectDetachKey(JsonElement *const object, const char *const key)
Detach json element ownership from parent object;.
Definition: json.c:1183
JsonElement * JsonObjectGet(const JsonElement *const object, const char *const key)
Definition: json.c:1266
void JsonObjectAppendBool(JsonElement *const object, const char *const key, const _Bool value)
Definition: json.c:1069
void JsonObjectAppendElement(JsonElement *const object, const char *const key, JsonElement *const element)
Append any JSON element to an object.
Definition: json.c:1111
JsonParseError JsonParseWithLookup(void *const lookup_context, JsonLookup *const lookup_function, const char **const data, JsonElement **const json_out)
Parse a string to create a JsonElement.
Definition: json.c:2653
JsonParseError JsonParseFile(const char *const path, const size_t size_max, JsonElement **const json_out)
Convenience function to parse JSON from a file.
Definition: json.c:2727
int64_t JsonPrimitiveGetAsInt64DefaultOnError(const JsonElement *primitive, int64_t default_return)
Definition: json.c:769
JsonElement * JsonBoolCreate(const bool value)
Definition: json.c:1468
JsonElement * JsonObjectMergeArray(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:452
JsonElement * JsonArrayGetAsObject(JsonElement *const array, const size_t index)
Get an object value from an array.
Definition: json.c:1378
JsonElement * JsonArrayCreate(const size_t initialCapacity)
Create a new JSON array.
Definition: json.c:1281
const char * JsonObjectGetAsString(const JsonElement *const object, const char *const key)
Get the value of a field in an object, as a string.
Definition: json.c:1204
void JsonArrayRemoveRange(JsonElement *const array, const size_t start, const size_t end)
Remove an inclusive range from a JSON array.
Definition: json.c:1347
static ssize_t JsonElementIndexInParentObject(JsonElement *const parent, const char *const key)
Definition: json.c:1155
static JsonElement * JsonParseAsNull(const char **const data)
Definition: json.c:1888
bool JsonArrayContainsOnlyPrimitives(JsonElement *const array)
Check if an array contains only primitives.
Definition: json.c:1406
void JsonObjectAppendReal(JsonElement *const object, const char *const key, const double value)
Append an real number field to an object.
Definition: json.c:1076
const char * JsonGetPropertyAsString(const JsonElement *const element)
Definition: json.c:796
void JsonArrayAppendNull(JsonElement *const array)
Append null to an array.
Definition: json.c:1311
JsonContainerType JsonGetContainerType(const JsonElement *const container)
Definition: json.c:685
const int DEFAULT_CONTAINER_CAPACITY
Definition: json.c:42
static JsonElement * JsonParseAsBoolean(const char **const data)
Definition: json.c:1862
JsonParseError JsonParseAnyFile(const char *const path, const size_t size_max, JsonElement **const json_out, const bool yaml_format)
Convenience function to parse JSON or YAML from a file.
Definition: json.c:2691
static JsonParseError JsonParseAsPrimitive(const char **const data, JsonElement **const json_out)
Definition: json.c:2178
void JsonArrayAppendString(JsonElement *const array, const char *const value)
Append a string to an array.
Definition: json.c:1287
static JsonElement * JsonElementCreateContainer(const JsonContainerType containerType, const char *const propertyName, const size_t initialCapacity)
Definition: json.c:118
static bool IsDigit(const char ch)
Definition: json.c:1498
static const char *const JSON_TRUE
Definition: json.c:44
static void JsonArrayWriteCompact(Writer *const writer, const JsonElement *const array)
Definition: json.c:1724
void JsonContainerReverse(JsonElement *const array)
Definition: json.c:1426
JsonElement * JsonIntegerCreate(const int value)
Definition: json.c:1447
JsonElementType JsonIteratorCurrentElementType(const JsonIterator *const iter)
Definition: json.c:630
JsonElement * JsonArrayGet(const JsonElement *const array, const size_t index)
Definition: json.c:1397
static JsonParseError JsonParseAsObject(void *lookup_context, JsonLookup *lookup_function, const char **data, JsonElement **json_out)
Definition: json.c:2410
static void JsonArrayWrite(Writer *const writer, const JsonElement *const array, const size_t indent_level)
Definition: json.c:1540
static JsonElement * JsonArrayCopy(const JsonElement *array)
Definition: json.c:148
JsonElement * JsonIteratorNextValue(JsonIterator *const iter)
Definition: json.c:568
JsonPrimitiveType JsonGetPrimitiveType(const JsonElement *const primitive)
Definition: json.c:693
JsonElement * JsonObjectGetAsArray(JsonElement *const object, const char *const key)
Get the value of a field in an object, as an array.
Definition: json.c:1245
JsonElement * JsonStringCreate(const char *const value)
Definition: json.c:1439
JsonType JsonGetType(const JsonElement *element)
Definition: json.c:674
void JsonObjectAppendString(JsonElement *const object, const char *const key, const char *const value)
Append a string field to an object.
Definition: json.c:1055
void JsonObjectAppendArray(JsonElement *const object, const char *const key, JsonElement *const array)
Append an array field to an object.
Definition: json.c:1089
static void JsonPrimitiveWrite(Writer *const writer, const JsonElement *const primitiveElement, const size_t indent_level)
Definition: json.c:1514
JsonElement * JsonAt(const JsonElement *container, const size_t index)
Definition: json.c:815
JsonElement * JsonIteratorNextValueByType(JsonIterator *const iter, const JsonElementType type, const bool skip_null)
Definition: json.c:583
static void PrintIndent(Writer *const writer, const int num)
Definition: json.c:1504
static bool all_children_have_keys(const JsonElement *const object)
Definition: json.c:1608
void JsonArrayAppendBool(JsonElement *const array, const bool value)
Definition: json.c:1293
void JsonWriteCompact(Writer *const w, const JsonElement *const element)
Definition: json.c:1832
char * Json5EscapeData(Slice unescaped_data)
Definition: json.c:1046
static JsonElement * JsonElementCreatePrimitive(JsonPrimitiveType primitiveType, const char *value)
Definition: json.c:135
char * JsonDecodeString(const char *const escaped_string)
Definition: json.c:983
JsonContainerType JsonIteratorCurrentContainerType(const JsonIterator *const iter)
Definition: json.c:638
void JsonObjectWrite(Writer *const writer, const JsonElement *const object, const size_t indent_level)
Definition: json.c:1628
const char * JsonPrimitiveTypeToString(const JsonPrimitiveType type)
Definition: json.c:77
void JsonArrayAppendInteger(JsonElement *const array, const int value)
Append an integer to an array.
Definition: json.c:1299
JsonParseError JsonParse(const char **const data, JsonElement **const json_out)
Parse a string to create a JsonElement.
Definition: json.c:2648
static int JsonObjectCompare(const JsonElement *const a, const JsonElement *const b)
Definition: json.c:284
static bool IsWhitespace(const char ch)
Definition: json.c:1488
int64_t JsonPrimitiveGetAsInt64ExitOnError(const JsonElement *primitive)
Definition: json.c:778
JsonElement * JsonRealCreate(double value)
Definition: json.c:1455
static void JsonDecodeStringWriter(const char *const escaped_string, Writer *const w)
Definition: json.c:935
double JsonPrimitiveGetAsReal(const JsonElement *const primitive)
Definition: json.c:787
void JsonDestroyMaybe(JsonElement *const element, const bool allocated)
Destroy a JSON element if needed.
Definition: json.c:422
char * JsonPrimitiveToString(const JsonElement *const primitive)
Definition: json.c:709
const char * JsonPrimitiveGetAsString(const JsonElement *const primitive)
Definition: json.c:701
bool JsonObjectRemoveKey(JsonElement *const object, const char *const key)
Remove key from the object.
Definition: json.c:1167
long JsonPrimitiveGetAsInteger(const JsonElement *const primitive)
Definition: json.c:750
static bool wc(char c)
Definition: json.c:2381
static bool IsSeparator(const char ch)
Definition: json.c:1493
size_t JsonLength(const JsonElement *const element)
Get the length of a JsonElement. This is the number of elements or fields in an array or object respe...
Definition: json.c:531
void JsonSort(const JsonElement *const container, JsonComparator *const Compare, void *const user_data)
Definition: json.c:803
static JsonElement * JsonContainerCopy(const JsonElement *const container)
Definition: json.c:186
JsonElement * JsonSelect(JsonElement *const element, const size_t num_indices, char **const indices)
Definition: json.c:824
int JsonPrimitiveGetAsInt64(const JsonElement *primitive, int64_t *value_out)
Definition: json.c:760
static int CompareKeyToPropertyName(const void *const a, const void *const b, void *const user_data)
Definition: json.c:1146
const char * JsonIteratorCurrentKey(const JsonIterator *const iter)
Definition: json.c:618
JsonElement * JsonObjectGetAsObject(JsonElement *const object, const char *const key)
Get the value of a field in an object, as an object.
Definition: json.c:1224
static const char *const JSON_FALSE
Definition: json.c:45
void JsonArrayAppendElement(JsonElement *const array, JsonElement *const element)
Append any JSON element to an array.
Definition: json.c:1336
static JsonElement * JsonObjectCopy(const JsonElement *const object)
Definition: json.c:166
static const int SPACES_PER_INDENT
Definition: json.c:41
static void JsonContainerWrite(Writer *writer, const JsonElement *containerElement, size_t indent_level)
Definition: json.c:1682
void JsonObjectAppendObject(JsonElement *const object, const char *const key, JsonElement *const childObject)
Append an object field to an object.
Definition: json.c:1099
const char * JsonParseErrorToString(const JsonParseError error)
Definition: json.c:1905
JsonElement * JsonLookup(void *ctx, const char **data)
Definition: json.h:466
JsonParseError
Definition: json.h:83
@ JSON_PARSE_ERROR_NUMBER_EXPONENT_DUPLICATE
Definition: json.h:94
@ JSON_PARSE_ERROR_NUMBER_BAD_SYMBOL
Definition: json.h:97
@ JSON_PARSE_ERROR_NUMBER_DIGIT_END
Definition: json.h:98
@ JSON_PARSE_ERROR_NUMBER_EXPONENT_FOLLOW_LEADING_ZERO
Definition: json.h:96
@ JSON_PARSE_ERROR_NO_LIBYAML
Definition: json.h:114
@ JSON_PARSE_ERROR_NO_DATA
Definition: json.h:117
@ JSON_PARSE_ERROR_TRUNCATED
Definition: json.h:118
@ JSON_PARSE_ERROR_STRING_NO_DOUBLEQUOTE_START
Definition: json.h:86
@ JSON_PARSE_ERROR_ARRAY_START
Definition: json.h:100
@ JSON_PARSE_ERROR_OBJECT_END
Definition: json.h:106
@ JSON_PARSE_ERROR_NUMBER_EXPONENT_NEGATIVE
Definition: json.h:89
@ JSON_PARSE_ERROR_STRING_NO_DOUBLEQUOTE_END
Definition: json.h:87
@ JSON_PARSE_ERROR_OBJECT_BAD_SYMBOL
Definition: json.h:104
@ JSON_PARSE_ERROR_NUMBER_EXPONENT_DIGIT
Definition: json.h:95
@ JSON_PARSE_ERROR_NUMBER_MULTIPLE_DOTS
Definition: json.h:93
@ JSON_PARSE_ERROR_OBJECT_OBJECT_LVAL
Definition: json.h:110
@ JSON_PARSE_ERROR_ARRAY_COMMA
Definition: json.h:102
@ JSON_PARSE_ERROR_INVALID_START
Definition: json.h:113
@ JSON_PARSE_ERROR_LIBYAML_FAILURE
Definition: json.h:115
@ JSON_PARSE_ERROR_NO_SUCH_FILE
Definition: json.h:116
@ JSON_PARSE_ERROR_NUMBER_NO_DIGIT
Definition: json.h:92
@ JSON_PARSE_ERROR_ARRAY_END
Definition: json.h:101
@ JSON_PARSE_ERROR_OBJECT_OPEN_LVAL
Definition: json.h:111
@ JSON_PARSE_ERROR_OBJECT_START
Definition: json.h:105
@ JSON_PARSE_ERROR_MAX
Definition: json.h:120
@ JSON_PARSE_OK
Definition: json.h:84
@ JSON_PARSE_ERROR_NUMBER_DUPLICATE_ZERO
Definition: json.h:91
@ JSON_PARSE_ERROR_NUMBER_EXPONENT_POSITIVE
Definition: json.h:90
@ JSON_PARSE_ERROR_OBJECT_COMMA
Definition: json.h:108
@ JSON_PARSE_ERROR_OBJECT_ARRAY_LVAL
Definition: json.h:109
@ JSON_PARSE_ERROR_OBJECT_COLON
Definition: json.h:107
JsonType
Definition: json.h:72
@ JSON_TYPE_NULL
Definition: json.h:79
JsonPrimitiveType
Definition: json.h:63
@ JSON_PRIMITIVE_TYPE_REAL
Definition: json.h:66
@ JSON_PRIMITIVE_TYPE_INTEGER
Definition: json.h:65
@ JSON_PRIMITIVE_TYPE_NULL
Definition: json.h:68
@ JSON_PRIMITIVE_TYPE_STRING
Definition: json.h:64
@ JSON_PRIMITIVE_TYPE_BOOL
Definition: json.h:67
int JsonComparator(const JsonElement *, const JsonElement *, void *user_data)
Definition: json.h:218
JsonElementType
JSON data-structure.
Definition: json.h:51
@ JSON_ELEMENT_TYPE_PRIMITIVE
Definition: json.h:53
@ JSON_ELEMENT_TYPE_CONTAINER
Definition: json.h:52
JsonContainerType
Definition: json.h:57
@ JSON_CONTAINER_TYPE_ARRAY
Definition: json.h:59
@ JSON_CONTAINER_TYPE_OBJECT
Definition: json.h:58
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
#define UnexpectedError(...)
Definition: misc_lib.h:38
Seq * StringMatchCapturesWithPrecompiledRegex(const pcre *pattern, const char *str, const bool return_names)
Definition: regex.c:144
Seq * StringMatchCaptures(const char *regex, const char *str, const bool return_names)
Definition: regex.c:232
void SeqRemove(Seq *seq, size_t index)
Remove a single item in the sequence.
Definition: sequence.c:156
void SeqSoftRemove(Seq *seq, size_t index)
Remove a single item handle from the sequence.
Definition: sequence.c:322
void SeqRemoveRange(Seq *seq, size_t start, size_t end)
Remove an inclusive range of items in the Sequence. A single item may be removed by specifying start ...
Definition: sequence.c:138
size_t SeqLength(const Seq *seq)
Length of the sequence.
Definition: sequence.c:354
Seq * SeqNew(size_t initialCapacity, void(ItemDestroy)(void *item))
Definition: sequence.c:31
ssize_t SeqIndexOf(Seq *seq, const void *key, SeqItemComparator Compare)
Linearly searches through the sequence and returns the index of the first matching object,...
Definition: sequence.c:189
void SeqReverse(Seq *seq)
Reverses the order of the sequence.
Definition: sequence.c:327
void * SeqLookup(Seq *seq, const void *key, SeqItemComparator Compare)
Linearly searches through the sequence and return the first item considered equal to the specified ke...
Definition: sequence.c:161
void SeqSort(Seq *seq, SeqItemComparator Compare, void *user_data)
Sort a Sequence according to the given item comparator function.
Definition: sequence.c:279
void SeqDestroy(Seq *seq)
Destroy an existing Sequence.
Definition: sequence.c:60
void SeqAppend(Seq *seq, void *item)
Append a new item to the Sequence.
Definition: sequence.c:104
static void * SeqAt(const Seq *seq, int i)
Definition: sequence.h:57
int(* SeqItemComparator)(const void *, const void *, void *user_data)
Function to compare two items in a Sequence.
Definition: sequence.h:100
char * StringFromDouble(double number)
Definition: string_lib.c:741
bool StringStartsWith(const char *str, const char *prefix)
Check if a string starts with the given prefix.
Definition: string_lib.c:1335
int64_t StringToInt64DefaultOnError(const char *str, int64_t default_return)
Converts a string to int64_t, with a default value in case of errors.
Definition: string_lib.c:685
int StringToInt64(const char *str, int64_t *value_out)
Converts a string of numerals in base 10 to 64-bit signed int.
Definition: string_lib.c:608
bool StringIsNumeric(const char *s)
Definition: string_lib.c:428
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
double StringToDouble(const char *str)
Definition: string_lib.c:729
char * StringFromLong(long number)
Definition: string_lib.c:720
int StringSafeCompare(const char *const a, const char *const b)
Definition: string_lib.c:226
int64_t StringToInt64ExitOnError(const char *str)
Convert a string to int64_t, exits if parsing fails.
Definition: string_lib.c:662
long StringToLongExitOnError(const char *str)
Converts a string of numerals in base 10 to a long integer, exits on error.
Definition: string_lib.c:584
static bool CharIsPrintableAscii(const char c)
Check if a char is "printable", replacement for isprint.
Definition: string_lib.h:103
Definition: buffer.h:50
struct JsonElement_::@3::JsonPrimitive primitive
JsonElementType type
Definition: json.c:50
struct JsonElement_::@3::JsonContainer container
const char * value
Definition: json.c:68
JsonPrimitiveType type
Definition: json.c:67
char * propertyName
Definition: json.c:56
Seq * children
Definition: json.c:63
JsonContainerType type
Definition: json.c:62
size_t index
Definition: json.h:128
const JsonElement * container
Definition: json.h:127
Sequence data-structure.
Definition: sequence.h:50
Definition: writer.c:45
Definition: json.h:140
void * data
Definition: json.h:145
size_t size
Definition: json.h:146
size_t WriterWrite(Writer *writer, const char *str)
Definition: writer.c:193
char * StringWriterClose(Writer *writer)
Definition: writer.c:262
const char * StringWriterData(const Writer *writer)
Definition: writer.c:229
size_t WriterWriteChar(Writer *writer, char c)
Definition: writer.c:200
void WriterClose(Writer *writer)
Definition: writer.c:242
size_t WriterWriteF(Writer *writer, const char *fmt,...)
Definition: writer.c:144
Writer * StringWriter(void)
Definition: writer.c:67