mirror of https://github.com/xfarrow/dircomp.git
code readability, importing JSON library
This commit is contained in:
parent
d872d3ba96
commit
0159a89394
|
@ -0,0 +1,119 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json - Parse and generate JSON (JavaScript Object Notation)
|
||||||
|
*
|
||||||
|
* This is a library for encoding and decoding JSON that strives to be
|
||||||
|
* easy to learn, use, and incorporate into an application.
|
||||||
|
*
|
||||||
|
* JSON (JavaScript Object Notation) facilitates passing data among different
|
||||||
|
* programming languages, particularly JavaScript. It looks like this:
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* {
|
||||||
|
* "id": 1,
|
||||||
|
* "firstname": "John",
|
||||||
|
* "lastname": "Smith",
|
||||||
|
* "email": "john@example.com",
|
||||||
|
* "likes_pizza": false
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* "id": 2,
|
||||||
|
* "firstname": "Linda",
|
||||||
|
* "lastname": "Jones",
|
||||||
|
* "email": null,
|
||||||
|
* "likes_pizza": true
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* #include <ccan/json/json.h>
|
||||||
|
* #include <math.h>
|
||||||
|
* #include <stdio.h>
|
||||||
|
* #include <stdlib.h>
|
||||||
|
*
|
||||||
|
* static int find_number(JsonNode *object, const char *name, double *out)
|
||||||
|
* {
|
||||||
|
* JsonNode *node = json_find_member(object, name);
|
||||||
|
* if (node && node->tag == JSON_NUMBER) {
|
||||||
|
* *out = node->number_;
|
||||||
|
* return 1;
|
||||||
|
* }
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* static void solve_pythagorean(JsonNode *triple)
|
||||||
|
* {
|
||||||
|
* double a = 0, b = 0, c = 0;
|
||||||
|
* int a_given, b_given, c_given;
|
||||||
|
*
|
||||||
|
* if (triple->tag != JSON_OBJECT) {
|
||||||
|
* fprintf(stderr, "Error: Expected a JSON object.\n");
|
||||||
|
* exit(EXIT_FAILURE);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* a_given = find_number(triple, "a", &a);
|
||||||
|
* b_given = find_number(triple, "b", &b);
|
||||||
|
* c_given = find_number(triple, "c", &c);
|
||||||
|
*
|
||||||
|
* if (a_given + b_given + c_given != 2) {
|
||||||
|
* fprintf(stderr, "Error: I need two sides to compute the length of the third.\n");
|
||||||
|
* exit(EXIT_FAILURE);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* if (a_given && b_given) {
|
||||||
|
* c = sqrt(a*a + b*b);
|
||||||
|
* json_append_member(triple, "c", json_mknumber(c));
|
||||||
|
* } else if (a_given && c_given) {
|
||||||
|
* b = sqrt(c*c - a*a);
|
||||||
|
* json_append_member(triple, "b", json_mknumber(b));
|
||||||
|
* } else if (b_given && c_given) {
|
||||||
|
* a = sqrt(c*c - b*b);
|
||||||
|
* json_append_member(triple, "a", json_mknumber(a));
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* int main(void)
|
||||||
|
* {
|
||||||
|
* JsonNode *triples = json_mkarray();
|
||||||
|
*
|
||||||
|
* json_append_element(triples, json_decode("{\"a\": 3, \"b\": 4}"));
|
||||||
|
* json_append_element(triples, json_decode("{\"a\": 5, \"c\": 13}"));
|
||||||
|
* json_append_element(triples, json_decode("{\"b\": 24, \"c\": 25}"));
|
||||||
|
*
|
||||||
|
* JsonNode *triple;
|
||||||
|
* json_foreach(triple, triples)
|
||||||
|
* solve_pythagorean(triple);
|
||||||
|
*
|
||||||
|
* char *tmp = json_stringify(triples, "\t");
|
||||||
|
* puts(tmp);
|
||||||
|
* free(tmp);
|
||||||
|
*
|
||||||
|
* json_delete(triples);
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Author: Joey Adams
|
||||||
|
* Version: 0.1
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* Expect exactly one argument */
|
||||||
|
if (argc != 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "depends") == 0) {
|
||||||
|
/* Nothing */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "libs") == 0) {
|
||||||
|
printf("m\n"); /* Needed for sqrt() used in example code above. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCAN_JSON_H
|
||||||
|
#define CCAN_JSON_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
JSON_NULL,
|
||||||
|
JSON_BOOL,
|
||||||
|
JSON_STRING,
|
||||||
|
JSON_NUMBER,
|
||||||
|
JSON_ARRAY,
|
||||||
|
JSON_OBJECT,
|
||||||
|
} JsonTag;
|
||||||
|
|
||||||
|
typedef struct JsonNode JsonNode;
|
||||||
|
|
||||||
|
struct JsonNode
|
||||||
|
{
|
||||||
|
/* only if parent is an object or array (NULL otherwise) */
|
||||||
|
JsonNode *parent;
|
||||||
|
JsonNode *prev, *next;
|
||||||
|
|
||||||
|
/* only if parent is an object (NULL otherwise) */
|
||||||
|
char *key; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
JsonTag tag;
|
||||||
|
union {
|
||||||
|
/* JSON_BOOL */
|
||||||
|
bool bool_;
|
||||||
|
|
||||||
|
/* JSON_STRING */
|
||||||
|
char *string_; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
/* JSON_NUMBER */
|
||||||
|
double number_;
|
||||||
|
|
||||||
|
/* JSON_ARRAY */
|
||||||
|
/* JSON_OBJECT */
|
||||||
|
struct {
|
||||||
|
JsonNode *head, *tail;
|
||||||
|
} children;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*** Encoding, decoding, and validation ***/
|
||||||
|
|
||||||
|
JsonNode *json_decode (const char *json);
|
||||||
|
char *json_encode (const JsonNode *node);
|
||||||
|
char *json_encode_string (const char *str);
|
||||||
|
char *json_stringify (const JsonNode *node, const char *space);
|
||||||
|
void json_delete (JsonNode *node);
|
||||||
|
|
||||||
|
bool json_validate (const char *json);
|
||||||
|
|
||||||
|
/*** Lookup and traversal ***/
|
||||||
|
|
||||||
|
JsonNode *json_find_element (JsonNode *array, int index);
|
||||||
|
JsonNode *json_find_member (JsonNode *object, const char *key);
|
||||||
|
|
||||||
|
JsonNode *json_first_child (const JsonNode *node);
|
||||||
|
|
||||||
|
#define json_foreach(i, object_or_array) \
|
||||||
|
for ((i) = json_first_child(object_or_array); \
|
||||||
|
(i) != NULL; \
|
||||||
|
(i) = (i)->next)
|
||||||
|
|
||||||
|
/*** Construction and manipulation ***/
|
||||||
|
|
||||||
|
JsonNode *json_mknull(void);
|
||||||
|
JsonNode *json_mkbool(bool b);
|
||||||
|
JsonNode *json_mkstring(const char *s);
|
||||||
|
JsonNode *json_mknumber(double n);
|
||||||
|
JsonNode *json_mkarray(void);
|
||||||
|
JsonNode *json_mkobject(void);
|
||||||
|
|
||||||
|
void json_append_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_prepend_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_append_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
|
||||||
|
void json_remove_from_parent(JsonNode *node);
|
||||||
|
|
||||||
|
/*** Debugging ***/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for structure and encoding problems in a JsonNode or its descendents.
|
||||||
|
*
|
||||||
|
* If a problem is detected, return false, writing a description of the problem
|
||||||
|
* to errmsg (unless errmsg is NULL).
|
||||||
|
*/
|
||||||
|
bool json_check(const JsonNode *node, char errmsg[256]);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <ccan/json/json.c>
|
||||||
|
#include <ccan/tap/tap.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static char *chomp(char *s)
|
||||||
|
{
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
if (s == NULL || *s == 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
e = strchr(s, 0);
|
||||||
|
if (e[-1] == '\n')
|
||||||
|
*--e = 0;
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
/* Build a list of numbers with various appends and prepends, verify them by testing against their encoded value, do pointer consistency checks each time, do element lookups, and remove items as well. */
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define should_be(var, expected) should_be_(var, #var, expected)
|
||||||
|
|
||||||
|
static void should_be_(const JsonNode *node, const char *name, const char *expected)
|
||||||
|
{
|
||||||
|
char errmsg[256];
|
||||||
|
char *encoded;
|
||||||
|
|
||||||
|
if (!json_check(node, errmsg)) {
|
||||||
|
fail("Invariants check failed: %s", errmsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded = json_encode(node);
|
||||||
|
|
||||||
|
if (strcmp(encoded, expected) == 0)
|
||||||
|
pass("%s is %s", name, expected);
|
||||||
|
else
|
||||||
|
fail("%s should be %s, but is actually %s", name, expected, encoded);
|
||||||
|
|
||||||
|
free(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_string(void)
|
||||||
|
{
|
||||||
|
JsonNode *str;
|
||||||
|
|
||||||
|
str = json_mkstring("Hello\tworld!\n\001");
|
||||||
|
should_be(str, "\"Hello\\tworld!\\n\\u0001\"");
|
||||||
|
json_delete(str);
|
||||||
|
|
||||||
|
str = json_mkstring("\"\\\b\f\n\r\t");
|
||||||
|
should_be(str, "\"\\\"\\\\\\b\\f\\n\\r\\t\"");
|
||||||
|
json_delete(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_number(void)
|
||||||
|
{
|
||||||
|
JsonNode *num;
|
||||||
|
|
||||||
|
num = json_mknumber(5678901234.0);
|
||||||
|
should_be(num, "5678901234");
|
||||||
|
json_delete(num);
|
||||||
|
|
||||||
|
num = json_mknumber(-5678901234.0);
|
||||||
|
should_be(num, "-5678901234");
|
||||||
|
json_delete(num);
|
||||||
|
|
||||||
|
num = json_mknumber(0.0 / 0.0);
|
||||||
|
should_be(num, "null");
|
||||||
|
json_delete(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_array(void)
|
||||||
|
{
|
||||||
|
JsonNode *array;
|
||||||
|
JsonNode *children[5 + 1];
|
||||||
|
|
||||||
|
array = json_mkarray();
|
||||||
|
should_be(array, "[]");
|
||||||
|
|
||||||
|
children[1] = json_mknumber(1);
|
||||||
|
children[2] = json_mknumber(2);
|
||||||
|
children[3] = json_mknumber(3);
|
||||||
|
children[4] = json_mknumber(4);
|
||||||
|
children[5] = json_mknumber(5);
|
||||||
|
|
||||||
|
json_append_element(array, children[3]);
|
||||||
|
should_be(array, "[3]");
|
||||||
|
|
||||||
|
json_remove_from_parent(children[3]);
|
||||||
|
should_be(array, "[]");
|
||||||
|
|
||||||
|
json_prepend_element(array, children[3]);
|
||||||
|
should_be(array, "[3]");
|
||||||
|
|
||||||
|
json_prepend_element(array, children[2]);
|
||||||
|
should_be(array, "[2,3]");
|
||||||
|
|
||||||
|
json_append_element(array, children[4]);
|
||||||
|
should_be(array, "[2,3,4]");
|
||||||
|
|
||||||
|
json_delete(children[3]);
|
||||||
|
should_be(array, "[2,4]");
|
||||||
|
|
||||||
|
json_prepend_element(array, children[1]);
|
||||||
|
should_be(array, "[1,2,4]");
|
||||||
|
|
||||||
|
json_delete(children[1]);
|
||||||
|
should_be(array, "[2,4]");
|
||||||
|
|
||||||
|
json_delete(children[4]);
|
||||||
|
should_be(array, "[2]");
|
||||||
|
|
||||||
|
ok1(json_find_element(array, 0) == children[2]);
|
||||||
|
ok1(json_find_element(array, -1) == NULL);
|
||||||
|
ok1(json_find_element(array, 1) == NULL);
|
||||||
|
|
||||||
|
json_append_element(array, children[5]);
|
||||||
|
should_be(array, "[2,5]");
|
||||||
|
|
||||||
|
ok1(json_find_element(array, 0) == children[2]);
|
||||||
|
ok1(json_find_element(array, 1) == children[5]);
|
||||||
|
ok1(json_find_element(array, -1) == NULL);
|
||||||
|
ok1(json_find_element(array, 2) == NULL);
|
||||||
|
|
||||||
|
json_delete(children[2]);
|
||||||
|
json_delete(children[5]);
|
||||||
|
should_be(array, "[]");
|
||||||
|
|
||||||
|
ok1(json_find_element(array, -1) == NULL);
|
||||||
|
ok1(json_find_element(array, 0) == NULL);
|
||||||
|
ok1(json_find_element(array, 1) == NULL);
|
||||||
|
|
||||||
|
json_delete(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_object(void)
|
||||||
|
{
|
||||||
|
JsonNode *object;
|
||||||
|
JsonNode *children[5 + 1];
|
||||||
|
|
||||||
|
object = json_mkobject();
|
||||||
|
should_be(object, "{}");
|
||||||
|
|
||||||
|
children[1] = json_mknumber(1);
|
||||||
|
children[2] = json_mknumber(2);
|
||||||
|
children[3] = json_mknumber(3);
|
||||||
|
|
||||||
|
ok1(json_find_member(object, "one") == NULL);
|
||||||
|
ok1(json_find_member(object, "two") == NULL);
|
||||||
|
ok1(json_find_member(object, "three") == NULL);
|
||||||
|
|
||||||
|
json_append_member(object, "one", children[1]);
|
||||||
|
should_be(object, "{\"one\":1}");
|
||||||
|
|
||||||
|
ok1(json_find_member(object, "one") == children[1]);
|
||||||
|
ok1(json_find_member(object, "two") == NULL);
|
||||||
|
ok1(json_find_member(object, "three") == NULL);
|
||||||
|
|
||||||
|
json_prepend_member(object, "two", children[2]);
|
||||||
|
should_be(object, "{\"two\":2,\"one\":1}");
|
||||||
|
|
||||||
|
ok1(json_find_member(object, "one") == children[1]);
|
||||||
|
ok1(json_find_member(object, "two") == children[2]);
|
||||||
|
ok1(json_find_member(object, "three") == NULL);
|
||||||
|
|
||||||
|
json_append_member(object, "three", children[3]);
|
||||||
|
should_be(object, "{\"two\":2,\"one\":1,\"three\":3}");
|
||||||
|
|
||||||
|
ok1(json_find_member(object, "one") == children[1]);
|
||||||
|
ok1(json_find_member(object, "two") == children[2]);
|
||||||
|
ok1(json_find_member(object, "three") == children[3]);
|
||||||
|
|
||||||
|
json_delete(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
JsonNode *node;
|
||||||
|
|
||||||
|
(void) chomp;
|
||||||
|
|
||||||
|
plan_tests(49);
|
||||||
|
|
||||||
|
ok1(json_find_element(NULL, 0) == NULL);
|
||||||
|
ok1(json_find_member(NULL, "") == NULL);
|
||||||
|
ok1(json_first_child(NULL) == NULL);
|
||||||
|
|
||||||
|
node = json_mknull();
|
||||||
|
should_be(node, "null");
|
||||||
|
json_delete(node);
|
||||||
|
|
||||||
|
node = json_mkbool(false);
|
||||||
|
should_be(node, "false");
|
||||||
|
json_delete(node);
|
||||||
|
|
||||||
|
node = json_mkbool(true);
|
||||||
|
should_be(node, "true");
|
||||||
|
json_delete(node);
|
||||||
|
|
||||||
|
test_string();
|
||||||
|
test_number();
|
||||||
|
test_array();
|
||||||
|
test_object();
|
||||||
|
|
||||||
|
return exit_status();
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const char *strings_file = "test/test-strings";
|
||||||
|
const char *strings_reencoded_file = "test/test-strings-reencoded";
|
||||||
|
FILE *f, *f2;
|
||||||
|
char buffer[1024], buffer2[1024];
|
||||||
|
|
||||||
|
plan_tests(90);
|
||||||
|
|
||||||
|
f = fopen(strings_file, "rb");
|
||||||
|
if (f == NULL) {
|
||||||
|
diag("Could not open %s: %s", strings_file, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
f2 = fopen(strings_reencoded_file, "rb");
|
||||||
|
if (f2 == NULL) {
|
||||||
|
diag("Could not open %s: %s", strings_reencoded_file, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buffer, sizeof(buffer), f)) {
|
||||||
|
const char *s = chomp(buffer);
|
||||||
|
bool valid;
|
||||||
|
JsonNode *node;
|
||||||
|
|
||||||
|
if (expect_literal(&s, "valid ")) {
|
||||||
|
valid = true;
|
||||||
|
} else if (expect_literal(&s, "invalid ")) {
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
fail("Invalid line in test-strings: %s", buffer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = json_decode(s);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
char *reencoded;
|
||||||
|
char errmsg[256];
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
fail("%s is valid, but json_decode returned NULL", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json_check(node, errmsg)) {
|
||||||
|
fail("Corrupt tree produced by json_decode: %s", errmsg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reencoded = json_encode(node);
|
||||||
|
|
||||||
|
if (!fgets(buffer2, sizeof(buffer2), f2)) {
|
||||||
|
fail("test-strings-reencoded is missing this line: %s", reencoded);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chomp(buffer2);
|
||||||
|
|
||||||
|
ok(strcmp(reencoded, buffer2) == 0, "re-encode %s -> %s", s, reencoded);
|
||||||
|
|
||||||
|
free(reencoded);
|
||||||
|
json_delete(node);
|
||||||
|
} else if (node != NULL) {
|
||||||
|
fail("%s is invalid, but json_decode returned non-NULL", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(f) || fclose(f) != 0 || ferror(f2) || fclose(f2) != 0) {
|
||||||
|
diag("I/O error reading test data.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit_status();
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
static char buf1[256], buf2[256];
|
||||||
|
|
||||||
|
/* Used for pass and fail messages */
|
||||||
|
static char *quote_string(const char *str, char buf[256])
|
||||||
|
{
|
||||||
|
char *out = buf;
|
||||||
|
|
||||||
|
*out++ = '"';
|
||||||
|
for (; *str != 0; str++) {
|
||||||
|
if (out - buf > 256 - 5) {
|
||||||
|
/* String is too long. End it with `...' */
|
||||||
|
out = buf + 256 - 5;
|
||||||
|
*out++ = '.';
|
||||||
|
*out++ = '.';
|
||||||
|
*out++ = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (*str) {
|
||||||
|
case '\t':
|
||||||
|
*out++ = '\\';
|
||||||
|
*out++ = 't';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*out++ = '\\';
|
||||||
|
*out++ = 'n';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
*out++ = '\\';
|
||||||
|
*out++ = '"';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
*out++ = '\\';
|
||||||
|
*out++ = '\\';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*out++ = *str;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out++ = '"';
|
||||||
|
|
||||||
|
*out = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stringify(const char *input, const char *expected)
|
||||||
|
{
|
||||||
|
JsonNode *node = NULL;
|
||||||
|
char *enc = NULL;
|
||||||
|
char *strn = NULL;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
node = json_decode(input);
|
||||||
|
if (node == NULL) {
|
||||||
|
fail("Failed to decode %s", input);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc = json_encode(node);
|
||||||
|
if (strcmp(enc, input) != 0) {
|
||||||
|
fail("%s re-encodes to %s. Either encode/decode is broken, or the input string needs to be normalized", input, enc);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
strn = json_stringify(node, NULL);
|
||||||
|
if (strcmp(strn, enc) != 0) {
|
||||||
|
fail("json_stringify with NULL space produced a different string than json_encode");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = json_stringify(node, "\t");
|
||||||
|
if (strcmp(str, expected) != 0) {
|
||||||
|
fail("Expected %s, but json_stringify produced %s",
|
||||||
|
quote_string(expected, buf1), quote_string(str, buf2));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("stringify %s", input);
|
||||||
|
|
||||||
|
end:
|
||||||
|
json_delete(node);
|
||||||
|
free(enc);
|
||||||
|
free(strn);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
(void) chomp;
|
||||||
|
|
||||||
|
plan_tests(9);
|
||||||
|
|
||||||
|
test_stringify("[]", "[]");
|
||||||
|
test_stringify("[1]", "[\n\t1\n]");
|
||||||
|
test_stringify("[1,2,3]", "[\n\t1,\n\t2,\n\t3\n]");
|
||||||
|
test_stringify("[[]]", "[\n\t[]\n]");
|
||||||
|
test_stringify("[[1,2],[3,4]]", "[\n\t[\n\t\t1,\n\t\t2\n\t],\n\t[\n\t\t3,\n\t\t4\n\t]\n]");
|
||||||
|
|
||||||
|
test_stringify("{}", "{}");
|
||||||
|
test_stringify("{\"one\":1}", "{\n\t\"one\": 1\n}");
|
||||||
|
test_stringify("{\"one\":1,\"t*\":[2,3,10]}", "{\n\t\"one\": 1,\n\t\"t*\": [\n\t\t2,\n\t\t3,\n\t\t10\n\t]\n}");
|
||||||
|
test_stringify("{\"a\":{\"1\":1,\"2\":2},\"b\":{\"3\":[null,false,true,\"\\f\"]}}",
|
||||||
|
"{\n\t\"a\": {\n\t\t\"1\": 1,\n\t\t\"2\": 2\n\t},\n\t\"b\": {\n\t\t\"3\": [\n\t\t\tnull,\n\t\t\tfalse,\n\t\t\ttrue,\n\t\t\t\"\\f\"\n\t\t]\n\t}\n}");
|
||||||
|
|
||||||
|
return exit_status();
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const char *strings_file = "test/test-strings";
|
||||||
|
FILE *f;
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
plan_tests(224);
|
||||||
|
|
||||||
|
f = fopen(strings_file, "rb");
|
||||||
|
if (f == NULL) {
|
||||||
|
diag("Could not open %s: %s", strings_file, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buffer, sizeof(buffer), f)) {
|
||||||
|
const char *s = chomp(buffer);
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
if (expect_literal(&s, "valid ")) {
|
||||||
|
valid = true;
|
||||||
|
} else if (expect_literal(&s, "invalid ")) {
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
fail("Invalid line in test-strings: %s", buffer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(s, "\"1\\u2\"") == 0)
|
||||||
|
puts("here");
|
||||||
|
|
||||||
|
if (json_validate(s) == valid) {
|
||||||
|
pass("%s %s", valid ? "valid" : "invalid", s);
|
||||||
|
} else {
|
||||||
|
fail("%s is %s, but json_validate returned %s",
|
||||||
|
s,
|
||||||
|
valid ? "valid" : "invalid",
|
||||||
|
valid ? "false" : "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(f) || fclose(f) != 0) {
|
||||||
|
diag("I/O error reading test strings.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit_status();
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
invalid
|
||||||
|
invalid
|
||||||
|
invalid "
|
||||||
|
invalid [,]
|
||||||
|
invalid [)
|
||||||
|
invalid []]
|
||||||
|
invalid [}
|
||||||
|
invalid {,}
|
||||||
|
invalid {]
|
||||||
|
invalid ["1":2]
|
||||||
|
invalid [1,2,]
|
||||||
|
invalid [1:2}
|
||||||
|
invalid {"1":2,}
|
||||||
|
invalid {1:2}
|
||||||
|
invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], [7 ]}]}
|
||||||
|
invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], [7]}]}
|
||||||
|
invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]
|
||||||
|
invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]]
|
||||||
|
invalid {"1":2, "3":4
|
||||||
|
invalid "1\u2"
|
||||||
|
invalid [,2]
|
||||||
|
invalid "3
|
||||||
|
invalid "3" "4"
|
||||||
|
invalid [3[4]
|
||||||
|
invalid [3[4]]
|
||||||
|
invalid [3, [4, [5], 6] 7, 8 9]
|
||||||
|
invalid [3, [4, [5], 6] 7, 8, 9]
|
||||||
|
invalid [3, [4, [5], 6], 7, 8 9]
|
||||||
|
invalid {"hello":true, "bye":false, null}
|
||||||
|
invalid {"hello":true, "bye":false, null:null}
|
||||||
|
invalid "hi
|
||||||
|
invalid "hi"""
|
||||||
|
invalid {"hi": "bye"]
|
||||||
|
invalid "\uD800\uD800"
|
||||||
|
invalid "\uD800\uDBFF"
|
||||||
|
invalid "\UD834\UDD1E"
|
||||||
|
invalid "\uDB00"
|
||||||
|
invalid "\uDB00\uDBFF"
|
||||||
|
valid "\uFFFE"
|
||||||
|
valid "\uFFFF"
|
||||||
|
invalid .
|
||||||
|
valid ""
|
||||||
|
valid []
|
||||||
|
valid {}
|
||||||
|
invalid +.
|
||||||
|
valid 0.5
|
||||||
|
invalid 0.e1
|
||||||
|
valid {"1":{}}
|
||||||
|
valid {"1":2}
|
||||||
|
valid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"]}]}
|
||||||
|
valid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]}
|
||||||
|
valid 1234
|
||||||
|
valid -1234
|
||||||
|
valid {"1":2, "3":4}
|
||||||
|
invalid +1234
|
||||||
|
invalid ++1234
|
||||||
|
valid 123.456e142
|
||||||
|
valid 123.456e-142
|
||||||
|
valid 123.456e+142
|
||||||
|
invalid 123.e-142
|
||||||
|
valid "1\u2000"
|
||||||
|
valid "1\u20001"
|
||||||
|
valid 2
|
||||||
|
invalid .246e-142
|
||||||
|
invalid .2e-142
|
||||||
|
valid 3
|
||||||
|
invalid .3
|
||||||
|
valid "3"
|
||||||
|
valid [3]
|
||||||
|
invalid +3.
|
||||||
|
valid 3.2e+1
|
||||||
|
valid [3, [4]]
|
||||||
|
valid [3, [4, [5]]]
|
||||||
|
valid [3, [4, [5], 6]]
|
||||||
|
valid [3, [4, [5], 6], 7]
|
||||||
|
valid [3, [4, [5], 6], 7, 8]
|
||||||
|
valid [3, [4, [5], 6], 7, 8, 9]
|
||||||
|
invalid +3.5
|
||||||
|
invalid .3e
|
||||||
|
invalid .3e1
|
||||||
|
invalid .3e-1
|
||||||
|
invalid .3e+1
|
||||||
|
invalid 3.e1
|
||||||
|
invalid 3.e+1
|
||||||
|
valid 3e+1
|
||||||
|
invalid .5
|
||||||
|
invalid +.5
|
||||||
|
invalid .5e+1
|
||||||
|
valid [ 7]
|
||||||
|
valid [7 ]
|
||||||
|
valid [7]
|
||||||
|
invalid .e-14234
|
||||||
|
valid "hello"
|
||||||
|
valid ["hello"]
|
||||||
|
valid ["hello", "bye"]
|
||||||
|
valid ["hello", "bye\n"]
|
||||||
|
valid ["hello", "bye\n\r\t"]
|
||||||
|
valid ["hello", "bye\n\r\t\b"]
|
||||||
|
valid ["hello", "bye\n\r\t\b",true]
|
||||||
|
valid ["hello", "bye\n\r\t\b",true , false]
|
||||||
|
valid ["hello", "bye\n\r\t\b",true , false, null]
|
||||||
|
invalid ["hello", "bye\n\r\t\v"]
|
||||||
|
valid {"hello":true}
|
||||||
|
valid {"hello":true, "bye":false}
|
||||||
|
valid {"hello":true, "bye":false, "foo":["one","two","three"]}
|
||||||
|
valid "hi"
|
||||||
|
valid ["hi"]
|
||||||
|
valid ["hi", "bye"]
|
||||||
|
valid {"hi": "bye"}
|
||||||
|
valid ["hi", "bye", 3]
|
||||||
|
valid ["hi", "bye[", 3]
|
||||||
|
valid "\u0007"
|
||||||
|
valid "\u0008"
|
||||||
|
valid "\u0009"
|
||||||
|
valid "\u0010"
|
||||||
|
valid "\u0020"
|
||||||
|
valid "\u10000"
|
||||||
|
valid "\u1234"
|
||||||
|
valid "\u99999"
|
||||||
|
valid "\ud800\udc00"
|
||||||
|
valid "\uD800\uDC00"
|
||||||
|
valid "\uD834\uDD1E"
|
||||||
|
valid "\uDBFF\uDFFF"
|
||||||
|
valid "\uFFFD"
|
||||||
|
valid "\uFFFF"
|
||||||
|
invalid hello
|
||||||
|
valid [32, 1]
|
||||||
|
invalid [32,
|
||||||
|
valid "\uD800\uDC00"
|
||||||
|
valid "\n"
|
||||||
|
valid "hello"
|
||||||
|
valid "hello\u0009world"
|
||||||
|
valid "hello"
|
||||||
|
valid "hello\n"
|
||||||
|
valid "hello"
|
||||||
|
valid 3
|
||||||
|
invalid 3.
|
||||||
|
invalid .3
|
||||||
|
valid 0.3
|
||||||
|
invalid 0.3e
|
||||||
|
invalid 0.3e+
|
||||||
|
valid 0.3e+5
|
||||||
|
valid 0.3e-5
|
||||||
|
valid 0.3e5
|
||||||
|
valid "hello"
|
||||||
|
invalid +3
|
||||||
|
valid -3
|
||||||
|
invalid -3.
|
||||||
|
valid -3.1
|
||||||
|
invalid .5
|
||||||
|
invalid 5.
|
||||||
|
invalid 5.e1
|
||||||
|
valid 0.5
|
||||||
|
invalid .3e1
|
||||||
|
invalid .3e+1
|
||||||
|
invalid .3e-1
|
||||||
|
invalid .3e-1 .5
|
||||||
|
invalid .3e-1.5
|
||||||
|
invalid .3e+1.5
|
||||||
|
invalid .3e+.
|
||||||
|
invalid .3e+.5
|
||||||
|
invalid .3e+1.5
|
||||||
|
invalid 9.3e+1.5
|
||||||
|
invalid 9.e+1.5
|
||||||
|
invalid 9.e+
|
||||||
|
invalid 9.e+1
|
||||||
|
valid "\""
|
||||||
|
valid "\"3.5"
|
||||||
|
valid "\"."
|
||||||
|
invalid "\".".
|
||||||
|
valid "\"....."
|
||||||
|
invalid "\"\"\"\"""
|
||||||
|
invalid ["\"\"\"\"", .5]
|
||||||
|
invalid [.5]
|
||||||
|
valid ["\"\"\"\"", 0.5]
|
||||||
|
invalid ["\"\"\"\"", .5]
|
||||||
|
invalid ["\"\"\"\"",.5]
|
||||||
|
invalid ["\"",.5]
|
||||||
|
invalid ["\".5",.5]
|
||||||
|
invalid ["\".5",".5\"".5]
|
||||||
|
invalid ["\".5",".5\"", .5]
|
||||||
|
invalid ["\".5",".5\"",.5]
|
||||||
|
valid ["\".5",".5\"",0.5]
|
||||||
|
invalid {"key":/*comment*/"value"}
|
||||||
|
invalid {"key":/*comment"value"}
|
||||||
|
invalid {"key":"value"}/*
|
||||||
|
invalid {"key":"value"}/**/
|
||||||
|
invalid {"key":"value"}/***/
|
||||||
|
invalid {"key":"value"}/**//
|
||||||
|
invalid {"key":"value"}/**///
|
||||||
|
invalid {"key":"value"}/**///----
|
||||||
|
invalid {"key":"value"}#
|
||||||
|
invalid {"key":"value"}#{
|
||||||
|
invalid {"key":"value"}#{}
|
||||||
|
invalid {"key":"value"}#,
|
||||||
|
invalid {"key":"value"/**/, "k2":"v2"}
|
||||||
|
valid "\u0027"
|
||||||
|
invalid "hello\'"
|
||||||
|
invalid 'hello\''
|
||||||
|
invalid 'hello'
|
||||||
|
invalid 'hell\'o'
|
||||||
|
invalid '\'hello'
|
||||||
|
invalid '\'hello\''
|
||||||
|
invalid \'hello\'
|
||||||
|
invalid 'hello\'
|
||||||
|
invalid ['hello\']
|
||||||
|
invalid ['hello\'']
|
||||||
|
invalid ['hello"']
|
||||||
|
invalid ['hello\"']
|
||||||
|
invalid ['hello"o']
|
||||||
|
invalid ['"']
|
||||||
|
invalid '"'
|
||||||
|
invalid '"hello"'
|
||||||
|
invalid '"hello'
|
||||||
|
invalid '"hi"'
|
||||||
|
valid [ 1 , 2 , 3 ]
|
||||||
|
invalid nil
|
||||||
|
invalid fals
|
||||||
|
invalid falsify
|
||||||
|
invalid falsetto
|
||||||
|
invalid truism
|
||||||
|
invalid {"key"
|
||||||
|
invalid {"key","key2":value}
|
||||||
|
invalid "\u0000"
|
|
@ -0,0 +1,90 @@
|
||||||
|
""
|
||||||
|
""
|
||||||
|
""
|
||||||
|
[]
|
||||||
|
{}
|
||||||
|
0.5
|
||||||
|
{"1":{}}
|
||||||
|
{"1":2}
|
||||||
|
{"1":2,"2.5":[3,4,{},{"5":["6"]}]}
|
||||||
|
{"1":2,"2.5":[3,4,{},{"5":["6"],"7":[8]}]}
|
||||||
|
1234
|
||||||
|
-1234
|
||||||
|
{"1":2,"3":4}
|
||||||
|
1.23456e+144
|
||||||
|
1.23456e-140
|
||||||
|
1.23456e+144
|
||||||
|
"1 "
|
||||||
|
"1 1"
|
||||||
|
2
|
||||||
|
3
|
||||||
|
"3"
|
||||||
|
[3]
|
||||||
|
32
|
||||||
|
[3,[4]]
|
||||||
|
[3,[4,[5]]]
|
||||||
|
[3,[4,[5],6]]
|
||||||
|
[3,[4,[5],6],7]
|
||||||
|
[3,[4,[5],6],7,8]
|
||||||
|
[3,[4,[5],6],7,8,9]
|
||||||
|
30
|
||||||
|
[7]
|
||||||
|
[7]
|
||||||
|
[7]
|
||||||
|
"hello"
|
||||||
|
["hello"]
|
||||||
|
["hello","bye"]
|
||||||
|
["hello","bye\n"]
|
||||||
|
["hello","bye\n\r\t"]
|
||||||
|
["hello","bye\n\r\t\b"]
|
||||||
|
["hello","bye\n\r\t\b",true]
|
||||||
|
["hello","bye\n\r\t\b",true,false]
|
||||||
|
["hello","bye\n\r\t\b",true,false,null]
|
||||||
|
{"hello":true}
|
||||||
|
{"hello":true,"bye":false}
|
||||||
|
{"hello":true,"bye":false,"foo":["one","two","three"]}
|
||||||
|
"hi"
|
||||||
|
["hi"]
|
||||||
|
["hi","bye"]
|
||||||
|
{"hi":"bye"}
|
||||||
|
["hi","bye",3]
|
||||||
|
["hi","bye[",3]
|
||||||
|
"\u0007"
|
||||||
|
"\b"
|
||||||
|
"\t"
|
||||||
|
"\u0010"
|
||||||
|
" "
|
||||||
|
"က0"
|
||||||
|
"ሴ"
|
||||||
|
"香9"
|
||||||
|
"𐀀"
|
||||||
|
"𐀀"
|
||||||
|
"𝄞"
|
||||||
|
""
|
||||||
|
"<22>"
|
||||||
|
""
|
||||||
|
[32,1]
|
||||||
|
"𐀀"
|
||||||
|
"\n"
|
||||||
|
"hello"
|
||||||
|
"hello\tworld"
|
||||||
|
"hello"
|
||||||
|
"hello\n"
|
||||||
|
"hello"
|
||||||
|
3
|
||||||
|
0.3
|
||||||
|
30000
|
||||||
|
3e-06
|
||||||
|
30000
|
||||||
|
"hello"
|
||||||
|
-3
|
||||||
|
-3.1
|
||||||
|
0.5
|
||||||
|
"\""
|
||||||
|
"\"3.5"
|
||||||
|
"\"."
|
||||||
|
"\"....."
|
||||||
|
["\"\"\"\"",0.5]
|
||||||
|
["\".5",".5\"",0.5]
|
||||||
|
"'"
|
||||||
|
[1,2,3]
|
17
dircomp.c
17
dircomp.c
|
@ -24,15 +24,19 @@ struct arguments{
|
||||||
|
|
||||||
struct arguments get_arguments(int, char**);
|
struct arguments get_arguments(int, char**);
|
||||||
void print_help(void);
|
void print_help(void);
|
||||||
void print_files_in_directory(char*, struct arguments);
|
void print_files_in_directory(struct arguments);
|
||||||
|
|
||||||
int main(int argc, char* argv[]){
|
int main(int argc, char* argv[]){
|
||||||
struct arguments arguments = get_arguments(argc, argv);
|
struct arguments arguments = get_arguments(argc, argv);
|
||||||
|
|
||||||
if(arguments.h == true)
|
if(arguments.h == true){
|
||||||
|
print_help();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
print_files_in_directory("/home/user", arguments);
|
arguments.directory1 = "/home/user";
|
||||||
|
arguments.directory2 = "/home/user";
|
||||||
|
print_files_in_directory(arguments);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +60,6 @@ struct arguments get_arguments(int argc, char** argv){
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
provided_arguments.h = true;
|
provided_arguments.h = true;
|
||||||
print_help();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,11 +79,11 @@ void print_help(void){
|
||||||
* References:
|
* References:
|
||||||
* https://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html
|
* https://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html
|
||||||
*/
|
*/
|
||||||
void print_files_in_directory(char* directory, struct arguments arguments){
|
void print_files_in_directory(struct arguments arguments){ // testing only
|
||||||
printf("\nAnalyzing directory %s\n", directory);
|
printf("\nAnalyzing directory %s\n", arguments.directory1);
|
||||||
DIR *d;
|
DIR *d;
|
||||||
struct dirent *dir;
|
struct dirent *dir;
|
||||||
d = opendir(directory);
|
d = opendir(arguments.directory1);
|
||||||
if (d) {
|
if (d) {
|
||||||
while ((dir = readdir(d)) != NULL) {
|
while ((dir = readdir(d)) != NULL) {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue