parent
2928f7ec0e
commit
4b5c5ed66a
@ -1,141 +0,0 @@
|
||||
/* This demo is not needed to be C89-compatible, so for now GCC extensions are
|
||||
* used */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "jsmn.h"
|
||||
|
||||
static void jsmn_dump_obj(jsmntok_t *obj, const char *js) {
|
||||
size_t len;
|
||||
char *s;
|
||||
|
||||
if (obj->end < 0 || obj->start < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = obj->end - obj->start;
|
||||
|
||||
printf("[%3d,%3d - %2d] (%c) ", obj->start, obj->end, obj->size,
|
||||
({
|
||||
char c;
|
||||
switch (obj->type) {
|
||||
case JSMN_PRIMITIVE: c = '.'; break;
|
||||
case JSMN_STRING: c = 's'; break;
|
||||
case JSMN_ARRAY: c = 'A'; break;
|
||||
case JSMN_OBJECT: c = 'O'; break;
|
||||
default: c = '?';
|
||||
}; c;
|
||||
}));
|
||||
|
||||
s = strndup((const char *) &js[obj->start], len);
|
||||
char *p;
|
||||
for (p = s; *p; p++) {
|
||||
printf("%c", *p == '\n' ? ' ' : *p);
|
||||
}
|
||||
printf("\n");
|
||||
free(s);
|
||||
}
|
||||
|
||||
void usage(void) {
|
||||
fprintf(stderr, "Usage: ./demo <file.js>\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
int r;
|
||||
int c;
|
||||
|
||||
FILE *f;
|
||||
int filesize = 0;
|
||||
|
||||
jsmn_parser parser;
|
||||
char *js = NULL;
|
||||
jsmntok_t *tokens;
|
||||
int block_size = 1024;
|
||||
int num_tokens = 100;
|
||||
|
||||
while ((c = getopt(argc, argv, "ht:b:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 't':
|
||||
num_tokens = atoi(optarg);
|
||||
if (errno || num_tokens < 0) {
|
||||
fprintf(stderr, "Invalid token number: %s!\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
block_size = atoi(optarg);
|
||||
if (errno || block_size < 0) {
|
||||
fprintf(stderr, "Invalid block size: %s!\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strcmp(argv[optind], "-") == 0) {
|
||||
f = stdin;
|
||||
} else {
|
||||
f = fopen(argv[optind], "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Failed to open file `%s`\n", argv[1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
tokens = malloc(num_tokens * sizeof(jsmntok_t));
|
||||
if (tokens == NULL) {
|
||||
fprintf(stderr, "Cannot allocate anough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
jsmn_init_parser(&parser, js, tokens, num_tokens);
|
||||
|
||||
char *buf = malloc(block_size);
|
||||
while (1) {
|
||||
r = fread(buf, 1, block_size, f);
|
||||
if (r <= 0) {
|
||||
break;
|
||||
}
|
||||
js = (char *) realloc(js, filesize + r + 1);
|
||||
if (js == NULL) {
|
||||
fprintf(stderr, "Cannot allocate anough memory\n");
|
||||
fclose(f);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
parser.js = js;
|
||||
|
||||
memcpy(js + filesize, buf, r);
|
||||
filesize += r;
|
||||
js[filesize] = '\0';
|
||||
|
||||
r = jsmn_parse(&parser);
|
||||
if (r < 0) {
|
||||
printf("error %d at pos %d: %s\n", r, parser.pos, &js[parser.pos]);
|
||||
}
|
||||
|
||||
for (i = 0; i<num_tokens; i++) {
|
||||
jsmn_dump_obj(&parser.tokens[i], js);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
free(buf);
|
||||
free(tokens);
|
||||
free(js);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jsmn.c"
|
||||
|
||||
static int test_passed = 0;
|
||||
static int test_failed = 0;
|
||||
|
||||
/* Terminate current test with error */
|
||||
#define fail() return __LINE__
|
||||
|
||||
/* Successfull end of the test case */
|
||||
#define done() return 0
|
||||
|
||||
/* Check single condition */
|
||||
#define check(cond) do { if (!(cond)) fail(); } while (0)
|
||||
|
||||
/* Test runner */
|
||||
static void test(int (*func)(void), const char *name) {
|
||||
int r = func();
|
||||
if (r == 0) {
|
||||
test_passed++;
|
||||
} else {
|
||||
test_failed++;
|
||||
printf("FAILED: %s (at line %d)\n", name, r);
|
||||
}
|
||||
}
|
||||
|
||||
#define TOKEN_EQ(t, tok_start, tok_end, tok_type) \
|
||||
((t).start == tok_start \
|
||||
&& (t).end == tok_end \
|
||||
&& (t).type == (tok_type))
|
||||
|
||||
#define TOKEN_PRINT(t) \
|
||||
printf("start: %d, end: %d, type: %d\n", (t).start, (t).end, (t).type)
|
||||
|
||||
|
||||
|
||||
int test_primitive() {
|
||||
int r;
|
||||
jsmn_parser p;
|
||||
jsmntok_t tokens[10];
|
||||
|
||||
jsmn_init_parser(&p, "{\"a\": 0}", tokens, 10);
|
||||
|
||||
r = jsmn_parse(&p);
|
||||
check(r == JSMN_SUCCESS);
|
||||
check(TOKEN_EQ(tokens[0], 0, 8, JSMN_OBJECT));
|
||||
check(TOKEN_EQ(tokens[1], 2, 3, JSMN_STRING));
|
||||
check(TOKEN_EQ(tokens[2], 6, 7, JSMN_PRIMITIVE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test(test_primitive, "test primitive values");
|
||||
return 0;
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Test script is organized like this:
|
||||
# o two variables (PASSED and FAILED) hold the total
|
||||
# number of passed/faled tests
|
||||
# o expect() function performs a single test. First
|
||||
# argument of the function is the variable name and
|
||||
# the second is an expected value. PASSED/FAILED
|
||||
# values are updated automatically
|
||||
#
|
||||
# Most tests look like:
|
||||
# |
|
||||
# | expect "varName" "expectedValue" << JSON_END
|
||||
# | ..json data here...
|
||||
# | JSON_END
|
||||
# |
|
||||
#
|
||||
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
|
||||
function expect() {
|
||||
ret=$(./demo -t 10 -b 256 - | grep -A 1 "$1" | tail -n 1 | cut -c 20-)
|
||||
if [ "x$ret" = "x$2" ]; then
|
||||
PASSED=$(($PASSED+1))
|
||||
else
|
||||
echo "Failed: $1 != $2"
|
||||
FAILED=$(($FAILED+1))
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# TEST SET: Basic types (simple values)
|
||||
#
|
||||
expect 'boolVar' 'true' << JSON_END
|
||||
"boolVar" : true
|
||||
JSON_END
|
||||
|
||||
expect 'boolVar' 'false'<< JSON_END
|
||||
"boolVar" : false
|
||||
JSON_END
|
||||
|
||||
expect 'intVar' '12345' << JSON_END
|
||||
"intVar" : 12345
|
||||
JSON_END
|
||||
|
||||
expect 'floatVar' '12.345' << JSON_END
|
||||
"floatVar" : 12.345
|
||||
JSON_END
|
||||
|
||||
expect 'nullVar' 'null' << JSON_END
|
||||
"nullVar" : null
|
||||
JSON_END
|
||||
|
||||
expect 'strVar' 'hello' << JSON_END
|
||||
"strVar" : "hello"
|
||||
JSON_END
|
||||
|
||||
#
|
||||
# TEST SET: Simple types (boundary values)
|
||||
#
|
||||
|
||||
expect 'intVar' '0' << JSON_END
|
||||
"intVar" : 0
|
||||
JSON_END
|
||||
|
||||
expect 'intVar' '-0' << JSON_END
|
||||
"intVar" : -0
|
||||
JSON_END
|
||||
|
||||
expect 'floarVar' '-0.0' << JSON_END
|
||||
"floarVar" : -0.0
|
||||
JSON_END
|
||||
|
||||
expect 'strVar' '\n\r\b\t \u1234' << JSON_END
|
||||
"strVar" : "\n\r\b\t \u1234"
|
||||
JSON_END
|
||||
|
||||
expect 'strVar' '' << JSON_END
|
||||
"strVar" : ""
|
||||
JSON_END
|
||||
|
||||
#
|
||||
# TEST SET: Array types
|
||||
#
|
||||
expect 'arr' '[1,2,3,4,5]' << JSON_END
|
||||
"arr" : [1,2,3,4,5]
|
||||
JSON_END
|
||||
|
||||
expect 'arr' '[1, 2.3, "4", null, true]' << JSON_END
|
||||
"arr" : [1, 2.3, "4", null, true]
|
||||
JSON_END
|
||||
|
||||
expect 'arr' '[]' << JSON_END
|
||||
"arr" : []
|
||||
JSON_END
|
||||
|
||||
#
|
||||
# TEST SET: Object types
|
||||
#
|
||||
expect 'obj' '{"a":"b"}' << JSON_END
|
||||
"obj":{"a":"b"}
|
||||
JSON_END
|
||||
|
||||
expect 'objField' 'value' << JSON_END
|
||||
{
|
||||
"foo" : "bar",
|
||||
"objField" : "value"
|
||||
}
|
||||
JSON_END
|
||||
|
||||
expect 'foo' 'bar' << JSON_END
|
||||
{
|
||||
"foo" : "bar"
|
||||
"a" : [
|
||||
{
|
||||
"x" : "y",
|
||||
"z" : "zz"
|
||||
},
|
||||
3,
|
||||
false,
|
||||
true,
|
||||
"end"
|
||||
],
|
||||
}
|
||||
JSON_END
|
||||
|
||||
echo
|
||||
echo "Passed: $PASSED"
|
||||
echo "Failed: $FAILED"
|
||||
echo
|
||||
|
Loading…
Reference in new issue