Last active
January 4, 2016 17:38
-
-
Save jclulow/8654829 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| CFILES = run.c nvjson.c | |
| HDRS = nvjson.h | |
| run: $(CFILES) $(HDRS) | |
| gcc -o $@ $(CFILES) -lnvpair | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/ctype.h> | |
| #include <strings.h> | |
| #include <errno.h> | |
| #include <libnvpair.h> | |
| #include "nvjson.h" | |
| typedef enum json_type { | |
| JSON_TYPE_NOTHING, | |
| JSON_TYPE_STRING = 1, | |
| JSON_TYPE_INTEGER, | |
| JSON_TYPE_DOUBLE, | |
| JSON_TYPE_BOOLEAN, | |
| JSON_TYPE_NULL, | |
| JSON_TYPE_OBJECT, | |
| JSON_TYPE_ARRAY | |
| } json_type_t; | |
| typedef enum parse_state { | |
| PARSE_ERROR = -1, | |
| PARSE_DONE = 0, | |
| PARSE_REST, | |
| PARSE_OBJECT, | |
| PARSE_KEY_STRING, | |
| PARSE_COLON, | |
| PARSE_STRING, | |
| PARSE_OBJECT_COMMA, | |
| PARSE_ARRAY, | |
| PARSE_BAREWORD, | |
| PARSE_NUMBER, | |
| PARSE_ARRAY_VALUE, | |
| PARSE_ARRAY_COMMA, | |
| } parse_state_t; | |
| #define JSON_MARKER ".__json_" | |
| #define JSON_MARKER_ARRAY JSON_MARKER "array" | |
| typedef struct parse_frame { | |
| parse_state_t pf_ps; | |
| nvlist_t *pf_nvl; | |
| char *pf_key; | |
| void *pf_value; | |
| json_type_t pf_value_type; | |
| int pf_array_index; | |
| struct parse_frame *pf_next; | |
| } parse_frame_t; | |
| typedef struct state { | |
| char *s_in; | |
| off_t s_pos; | |
| size_t s_len; | |
| parse_frame_t *s_top; | |
| nvlist_parse_json_flags_t s_flags; | |
| } state_t; | |
| typedef void (*parse_handler_t)(state_t *); | |
| static void | |
| movestate(state_t *s, parse_state_t ps) | |
| { | |
| #ifdef DEBUG | |
| fprintf(stderr, "move state %d -> %d\n", s->s_top->pf_ps, ps); | |
| #endif | |
| s->s_top->pf_ps = ps; | |
| } | |
| static void | |
| pushstate(state_t *s, parse_state_t ps, parse_state_t retps) | |
| { | |
| parse_frame_t *n = calloc(1, sizeof (*n)); | |
| #ifdef DEBUG | |
| fprintf(stderr, "push state %d -> %d (ret %d)\n", s->s_top->pf_ps, ps, | |
| retps); | |
| #endif | |
| /* | |
| * Store the state we'll return to when popping this | |
| * frame: | |
| */ | |
| s->s_top->pf_ps = retps; | |
| /* | |
| * Store the initial state for the new frame, and | |
| * put it on top of the stack: | |
| */ | |
| n->pf_ps = ps; | |
| n->pf_value_type = JSON_TYPE_NOTHING; | |
| n->pf_next = s->s_top; | |
| s->s_top = n; | |
| } | |
| static void | |
| posterror(state_t *s, char *error) | |
| { | |
| /* | |
| * XXX do something better here. | |
| */ | |
| if (s->s_flags & NVJSON_ERRORS_TO_STDERR) | |
| fprintf(stderr, "error (pos %lld): %s\n", s->s_pos, error); | |
| movestate(s, PARSE_ERROR); | |
| } | |
| static char | |
| popchar(state_t *s) | |
| { | |
| if (s->s_pos > s->s_len) { | |
| return (0); | |
| } | |
| return (s->s_in[s->s_pos++]); | |
| } | |
| static char | |
| peekchar(state_t *s) | |
| { | |
| if (s->s_pos > s->s_len) { | |
| return (0); | |
| } | |
| return (s->s_in[s->s_pos]); | |
| } | |
| static void | |
| discard_whitespace(state_t *s) | |
| { | |
| while (ISSPACE(peekchar(s))) | |
| popchar(s); | |
| } | |
| static char *escape_pairs[] = { | |
| "\"\"", "\\\\", "//", "b\b", "f\f", "n\n", "r\r", "t\t", NULL | |
| }; | |
| static char | |
| collect_string_escape(state_t *s) | |
| { | |
| int i; | |
| char c = popchar(s); | |
| if (c == '\0') { | |
| fprintf(stderr, "ERROR: eof mid-escape\n"); | |
| return ('\0'); | |
| } else if (c == 'u') { | |
| int res; | |
| int ndigs = 0; | |
| char digs[5]; | |
| /* | |
| * Deal with 4-digit unicode escape. | |
| */ | |
| while (ndigs < 4) { | |
| if ((digs[ndigs++] = popchar(s)) == '\0') { | |
| fprintf(stderr, "ERROR: eof mid-escape\n"); | |
| return ('\0'); | |
| } | |
| } | |
| digs[4] = '\0'; | |
| res = atoi(digs); | |
| if (res > 127) { | |
| fprintf(stderr, "ERROR: unicode escape above 0x7f\n"); | |
| return ('\0'); | |
| } | |
| return (res); | |
| } | |
| for (i = 0; escape_pairs[i] != NULL; i++) { | |
| char *ep = escape_pairs[i]; | |
| if (ep[0] == c) | |
| return (ep[1]); | |
| } | |
| fprintf(stderr, "ERROR: unrecognised escape char %c\n", c); | |
| return ('\0'); | |
| } | |
| static char * | |
| collect_string(state_t *s) | |
| { | |
| /* XXX make this not static: */ | |
| char buf[1000]; | |
| char *pos = buf; | |
| for (;;) { | |
| char c = popchar(s); | |
| if (c == '\0') { | |
| /* | |
| * Unexpected EOF | |
| */ | |
| fprintf(stderr, "ERROR: unexpected EOF mid-string\n"); | |
| return (NULL); | |
| } else if (c == '\\') { | |
| char esc; | |
| /* | |
| * Escape Character. | |
| * | |
| * XXX better error handling here. | |
| */ | |
| if ((esc = collect_string_escape(s)) == '\0') | |
| return (NULL); | |
| *pos++ = esc; | |
| } else if (c == '"') { | |
| /* | |
| * Legal End of String. | |
| */ | |
| break; | |
| } else { | |
| *pos++ = c; | |
| } | |
| } | |
| *pos = '\0'; | |
| return (strdup(buf)); | |
| } | |
| static char * | |
| collect_bareword(state_t *s) | |
| { | |
| /* XXX make this not static: */ | |
| char out[100]; | |
| char *pos = out; | |
| char c; | |
| for (;;) { | |
| c = peekchar(s); | |
| if (ISLOWER(c)) { | |
| *pos++ = popchar(s); | |
| } else { | |
| /* | |
| * We're done... | |
| */ | |
| *pos = '\0'; | |
| break; | |
| } | |
| } | |
| return (strdup(out)); | |
| } | |
| static void | |
| hdlr_bareword(state_t *s) | |
| { | |
| char *str = collect_bareword(s); | |
| if (strcmp(str, "true") == 0) { | |
| s->s_top->pf_value_type = JSON_TYPE_BOOLEAN; | |
| s->s_top->pf_value = (void *) B_TRUE; | |
| } else if (strcmp(str, "false") == 0) { | |
| s->s_top->pf_value_type = JSON_TYPE_BOOLEAN; | |
| s->s_top->pf_value = (void *) B_FALSE; | |
| } else if (strcmp(str, "null") == 0) { | |
| s->s_top->pf_value_type = JSON_TYPE_NULL; | |
| } else { | |
| free(str); | |
| return (posterror(s, "expected 'true', 'false' or 'null'")); | |
| } | |
| free(str); | |
| return (movestate(s, PARSE_DONE)); | |
| } | |
| static int | |
| collect_number(state_t *s, boolean_t *isint, int32_t *result, | |
| double *fresult __UNUSED) | |
| { | |
| /* XXX make not static */ | |
| char out[100]; | |
| char *pos = out; | |
| boolean_t neg = B_FALSE; | |
| char c; | |
| if (peekchar(s) == '-') { | |
| neg = B_TRUE; | |
| popchar(s); | |
| } | |
| /* | |
| * Read the 'int' portion: | |
| */ | |
| #if 0 | |
| if ((c = peekchar(s)) == '0' || !ISDIGIT(c)) { | |
| #endif | |
| if (!ISDIGIT(c = peekchar(s))) { | |
| fprintf(stderr, "expected a digit (0-9)\n"); | |
| return (-1); | |
| } | |
| for (;;) { | |
| if (!ISDIGIT(peekchar(s))) | |
| break; | |
| *pos++ = popchar(s); | |
| } | |
| if (peekchar(s) == '.' || peekchar(s) == 'e' || peekchar(s) == 'E') { | |
| fprintf(stderr, "do not yet support FRACs or EXPs\n"); | |
| return (-1); | |
| } | |
| *isint = B_TRUE; | |
| *pos = '\0'; | |
| *result = neg == B_TRUE ? -atoi(out) : atoi(out); | |
| return (0); | |
| } | |
| static void | |
| hdlr_number(state_t *s) | |
| { | |
| boolean_t isint; | |
| int32_t result; | |
| double fresult; | |
| if (collect_number(s, &isint, &result, &fresult) != 0) { | |
| return (posterror(s, "malformed number")); | |
| } | |
| if (isint == B_TRUE) { | |
| s->s_top->pf_value = (void *) result; | |
| s->s_top->pf_value_type = JSON_TYPE_INTEGER; | |
| } else { | |
| s->s_top->pf_value = malloc(sizeof (fresult)); | |
| bcopy(&fresult, s->s_top->pf_value, sizeof (fresult)); | |
| s->s_top->pf_value_type = JSON_TYPE_DOUBLE; | |
| } | |
| return (movestate(s, PARSE_DONE)); | |
| } | |
| static void | |
| hdlr_rest(state_t *s) | |
| { | |
| char c; | |
| discard_whitespace(s); | |
| c = popchar(s); | |
| switch (c) { | |
| case '{': | |
| return (movestate(s, PARSE_OBJECT)); | |
| case '[': | |
| return (movestate(s, PARSE_ARRAY)); | |
| default: | |
| return (posterror(s, "eof before object or array")); | |
| } | |
| } | |
| static int | |
| add_empty_child(state_t *s) | |
| { | |
| /* | |
| * Here, we create an empty nvlist to represent this object | |
| * or array: | |
| */ | |
| nvlist_t *empty; | |
| if (nvlist_alloc(&empty, NV_UNIQUE_NAME, 0) != 0) | |
| return (-1); | |
| if (s->s_top->pf_next != NULL) { | |
| /* | |
| * If we're a child of the frame above, we store ourselves in | |
| * that frame's nvlist: | |
| */ | |
| nvlist_t *nvl = s->s_top->pf_next->pf_nvl; | |
| char *key = s->s_top->pf_next->pf_key; | |
| if (nvlist_add_nvlist(nvl, key, empty) != 0) { | |
| nvlist_free(empty); | |
| return (-1); | |
| } | |
| nvlist_free(empty); | |
| if (nvlist_lookup_nvlist(nvl, key, &empty) != 0) { | |
| return (-1); | |
| } | |
| } | |
| s->s_top->pf_nvl = empty; | |
| return (0); | |
| } | |
| static int | |
| decorate_array(state_t *s) | |
| { | |
| /* | |
| * When we are done creating an array, we store a 'length' | |
| * property on it, as well as an internal-use marker value. | |
| */ | |
| if (nvlist_add_boolean(s->s_top->pf_nvl, JSON_MARKER_ARRAY) != 0 || | |
| nvlist_add_uint32(s->s_top->pf_nvl, "length", | |
| s->s_top->pf_array_index)) | |
| return (-1); | |
| return (0); | |
| } | |
| static void | |
| hdlr_array(state_t *s) | |
| { | |
| char c; | |
| s->s_top->pf_value_type = JSON_TYPE_ARRAY; | |
| if (add_empty_child(s) == -1) | |
| return (posterror(s, "nvlist error")); | |
| discard_whitespace(s); | |
| c = peekchar(s); | |
| switch (c) { | |
| case ']': | |
| popchar(s); | |
| decorate_array(s); | |
| return (movestate(s, PARSE_DONE)); | |
| default: | |
| return (movestate(s, PARSE_ARRAY_VALUE)); | |
| } | |
| } | |
| static void | |
| hdlr_array_comma(state_t *s) | |
| { | |
| discard_whitespace(s); | |
| switch (popchar(s)) { | |
| case ']': | |
| decorate_array(s); | |
| return (movestate(s, PARSE_DONE)); | |
| case ',': | |
| return (movestate(s, PARSE_ARRAY_VALUE)); | |
| default: | |
| return (posterror(s, "expected ',' or ']'")); | |
| } | |
| } | |
| static void | |
| hdlr_array_value(state_t *s) | |
| { | |
| char c; | |
| discard_whitespace(s); | |
| /* | |
| * Generate keyname from the next array index: | |
| */ | |
| if (s->s_top->pf_key != NULL) { | |
| fprintf(stderr, "pf_key not null! was %s\n", s->s_top->pf_key); | |
| abort(); | |
| } | |
| s->s_top->pf_key = malloc(11); /* 10 digits in uint32_t */ | |
| if (s->s_top->pf_key == NULL) | |
| return (posterror(s, "could not allocate memory")); | |
| (void) snprintf(s->s_top->pf_key, 11, "%d", s->s_top->pf_array_index++); | |
| /* | |
| * Select which type handler we need for the next value: | |
| */ | |
| switch (c = peekchar(s)) { | |
| case '"': | |
| popchar(s); | |
| return (pushstate(s, PARSE_STRING, PARSE_ARRAY_COMMA)); | |
| case '{': | |
| popchar(s); | |
| return (pushstate(s, PARSE_OBJECT, PARSE_ARRAY_COMMA)); | |
| case '[': | |
| popchar(s); | |
| return (pushstate(s, PARSE_ARRAY, PARSE_ARRAY_COMMA)); | |
| default: | |
| if (ISLOWER(c)) | |
| return (pushstate(s, PARSE_BAREWORD, | |
| PARSE_ARRAY_COMMA)); | |
| else if (c == '-' || ISDIGIT(c)) | |
| return (pushstate(s, PARSE_NUMBER, PARSE_ARRAY_COMMA)); | |
| else | |
| return (posterror(s, "unexpected character at start " | |
| "of value")); | |
| } | |
| } | |
| static void | |
| hdlr_object(state_t *s) | |
| { | |
| char c; | |
| s->s_top->pf_value_type = JSON_TYPE_OBJECT; | |
| if (add_empty_child(s) == -1) | |
| return (posterror(s, "nvlist error")); | |
| discard_whitespace(s); | |
| c = popchar(s); | |
| switch (c) { | |
| case '}': | |
| return (movestate(s, PARSE_DONE)); | |
| case '"': | |
| return (movestate(s, PARSE_KEY_STRING)); | |
| default: | |
| return (posterror(s, "expected key or '}'")); | |
| } | |
| } | |
| static void | |
| hdlr_key_string(state_t *s) | |
| { | |
| char *str = collect_string(s); | |
| if (str == NULL) | |
| return (posterror(s, "could not collect key string")); | |
| /* | |
| * Record the name of the next | |
| */ | |
| s->s_top->pf_key = str; | |
| return (movestate(s, PARSE_COLON)); | |
| } | |
| static void | |
| hdlr_colon(state_t *s) | |
| { | |
| char c; | |
| discard_whitespace(s); | |
| if ((c = popchar(s)) != ':') | |
| return (posterror(s, "expected ':'")); | |
| discard_whitespace(s); | |
| /* | |
| * Select which type handler we need for the value after the colon: | |
| */ | |
| switch (c = peekchar(s)) { | |
| case '"': | |
| popchar(s); | |
| return (pushstate(s, PARSE_STRING, PARSE_OBJECT_COMMA)); | |
| case '{': | |
| popchar(s); | |
| return (pushstate(s, PARSE_OBJECT, PARSE_OBJECT_COMMA)); | |
| case '[': | |
| popchar(s); | |
| return (pushstate(s, PARSE_ARRAY, PARSE_OBJECT_COMMA)); | |
| default: | |
| if (ISLOWER(c)) | |
| return (pushstate(s, PARSE_BAREWORD, | |
| PARSE_OBJECT_COMMA)); | |
| else if (c == '-' || ISDIGIT(c)) | |
| return (pushstate(s, PARSE_NUMBER, PARSE_OBJECT_COMMA)); | |
| else | |
| return (posterror(s, "unexpected character at start " | |
| "of value")); | |
| } | |
| } | |
| static void | |
| hdlr_object_comma(state_t *s) | |
| { | |
| char c; | |
| discard_whitespace(s); | |
| switch (c = popchar(s)) { | |
| case '}': | |
| return (movestate(s, PARSE_DONE)); | |
| case ',': | |
| discard_whitespace(s); | |
| if ((c = popchar(s)) != '"') | |
| return (posterror(s, "expected '\"'")); | |
| return (movestate(s, PARSE_KEY_STRING)); | |
| default: | |
| return (posterror(s, "expected ',' or '}'")); | |
| } | |
| } | |
| static void | |
| hdlr_string(state_t *s) | |
| { | |
| s->s_top->pf_value = collect_string(s); | |
| if (s == NULL) | |
| return (posterror(s, "could not collect string")); | |
| s->s_top->pf_value_type = JSON_TYPE_STRING; | |
| return (movestate(s, PARSE_DONE)); | |
| } | |
| static int | |
| store_value(state_t *s) | |
| { | |
| nvlist_t *targ = s->s_top->pf_next->pf_nvl; | |
| char *key = s->s_top->pf_next->pf_key; | |
| json_type_t type = s->s_top->pf_value_type; | |
| int ret = 0; | |
| switch (type) { | |
| case JSON_TYPE_STRING: | |
| ret = nvlist_add_string(targ, key, s->s_top->pf_value); | |
| free(s->s_top->pf_value); | |
| goto out; | |
| case JSON_TYPE_BOOLEAN: | |
| ret = nvlist_add_boolean_value(targ, key, | |
| (boolean_t)s->s_top->pf_value); | |
| goto out; | |
| case JSON_TYPE_NULL: | |
| ret = nvlist_add_boolean(targ, key); | |
| goto out; | |
| case JSON_TYPE_INTEGER: | |
| ret = nvlist_add_int32(targ, key, (int32_t)s->s_top->pf_value); | |
| goto out; | |
| case JSON_TYPE_ARRAY: | |
| /* FALLTHRU */ | |
| case JSON_TYPE_OBJECT: | |
| /* | |
| * Objects and arrays are already 'stored' in their target | |
| * nvlist on creation. See: hdlr_object, hdlr_array. | |
| */ | |
| goto out; | |
| default: | |
| fprintf(stderr, "ERROR: could not store unknown type %d\n", | |
| type); | |
| abort(); | |
| } | |
| out: | |
| s->s_top->pf_value = NULL; | |
| free(s->s_top->pf_next->pf_key); | |
| s->s_top->pf_next->pf_key = NULL; | |
| return (ret); | |
| } | |
| static parse_frame_t * | |
| parse_frame_free(parse_frame_t *pf, boolean_t free_nvl) | |
| { | |
| parse_frame_t *next = pf->pf_next; | |
| if (pf->pf_key != NULL) | |
| free(pf->pf_key); | |
| if (pf->pf_value != NULL) | |
| abort(); | |
| if (free_nvl && pf->pf_nvl != NULL) | |
| nvlist_free(pf->pf_nvl); | |
| free(pf); | |
| return (next); | |
| } | |
| static parse_handler_t hdlrs[] = { | |
| NULL, /* PARSE_DONE */ | |
| hdlr_rest, /* PARSE_REST */ | |
| hdlr_object, /* PARSE_OBJECT */ | |
| hdlr_key_string, /* PARSE_KEY_STRING */ | |
| hdlr_colon, /* PARSE_COLON */ | |
| hdlr_string, /* PARSE_STRING */ | |
| hdlr_object_comma, /* PARSE_OBJECT_COMMA */ | |
| hdlr_array, /* PARSE_ARRAY */ | |
| hdlr_bareword, /* PARSE_BAREWORD */ | |
| hdlr_number, /* PARSE_NUMBER */ | |
| hdlr_array_value, /* PARSE_ARRAY_VALUE */ | |
| hdlr_array_comma, /* PARSE_ARRAY_COMMA */ | |
| }; | |
| #define NUM_PARSE_HANDLERS (int)(sizeof (hdlrs) / sizeof (hdlrs[0])) | |
| int | |
| nvlist_parse_json(char *buf, size_t buflen, nvlist_t **nvlp, | |
| nvlist_parse_json_flags_t flag) | |
| { | |
| int ret = 0; | |
| state_t s; | |
| /* | |
| * Check for valid flags: | |
| */ | |
| if ((flag & (NVJSON_FORCE_INTEGER | NVJSON_FORCE_DOUBLE)) == | |
| (NVJSON_FORCE_INTEGER | NVJSON_FORCE_DOUBLE)) { | |
| ret = EINVAL; | |
| goto out; | |
| } | |
| /* | |
| * Initialise parsing state structure: | |
| */ | |
| bzero(&s, sizeof (s)); | |
| s.s_in = buf; | |
| s.s_pos = 0; | |
| s.s_len = buflen; | |
| s.s_flags = flag; | |
| /* | |
| * Allocate top-most stack frame: | |
| */ | |
| s.s_top = calloc(1, sizeof (*s.s_top)); | |
| if (s.s_top == NULL) { | |
| ret = errno; | |
| goto out; | |
| } | |
| s.s_top->pf_ps = PARSE_REST; | |
| for (;;) { | |
| if (s.s_top->pf_ps < 0) { | |
| /* | |
| * The parser reported an error. | |
| */ | |
| #if 0 | |
| fprintf(stderr, "parse error\n"); | |
| #endif | |
| ret = EFAULT; | |
| goto out; | |
| } else if (s.s_top->pf_ps == PARSE_DONE) { | |
| if (s.s_top->pf_next == NULL) { | |
| /* | |
| * Last frame, so we're really | |
| * done. | |
| */ | |
| *nvlp = s.s_top->pf_nvl; | |
| goto out; | |
| } else { | |
| /* | |
| * Otherwise, pop a frame and continue | |
| * in previous state. | |
| */ | |
| #if 0 | |
| parse_frame_t *t = s.s_top->pf_next; | |
| #endif | |
| /* | |
| * Copy out the value we created in the | |
| * old frame: | |
| */ | |
| if ((ret = store_value(&s)) != 0) | |
| goto out; | |
| #if 0 | |
| fprintf(stderr, "pop state %d -> %d\n", | |
| s.s_top->pf_ps, t->pf_ps); | |
| #endif | |
| /* | |
| * Free old frame: | |
| */ | |
| s.s_top = parse_frame_free(s.s_top, B_FALSE); | |
| } | |
| } | |
| /* | |
| * Dispatch to parser handler routine for this state: | |
| */ | |
| if (s.s_top->pf_ps >= NUM_PARSE_HANDLERS || | |
| hdlrs[s.s_top->pf_ps] == NULL) { | |
| fprintf(stderr, "no handler for state %d\n", | |
| s.s_top->pf_ps); | |
| abort(); | |
| } | |
| hdlrs[s.s_top->pf_ps](&s); | |
| } | |
| out: | |
| while (s.s_top != NULL) | |
| s.s_top = parse_frame_free(s.s_top, ret == 0 ? B_FALSE : | |
| B_TRUE); | |
| return (ret); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <libnvpair.h> | |
| #ifndef _NVJSON_H_ | |
| #define _NVJSON_H_ | |
| typedef enum nvlist_parse_json_flags { | |
| NVJSON_FORCE_INTEGER = 0x01, | |
| NVJSON_FORCE_DOUBLE = 0x02, | |
| NVJSON_ERRORS_TO_STDERR = 0x04 | |
| } nvlist_parse_json_flags_t; | |
| extern int nvlist_parse_json(char *, size_t, nvlist_t **, | |
| nvlist_parse_json_flags_t); | |
| #define __UNUSED __attribute__((unused)) | |
| #endif /* _NVJSON_H_ */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <sys/mman.h> | |
| #include <fcntl.h> | |
| #include <libnvpair.h> | |
| #include <err.h> | |
| int | |
| main(int argc, char **argv) | |
| { | |
| int fd; | |
| struct stat st; | |
| const char *buf; | |
| nvlist_t *nvl; | |
| if (argc < 2) { | |
| errx(1, "usage: %s <input.json>", argv[0]); | |
| } | |
| if ((fd = open(argv[1], O_RDONLY)) == -1) { | |
| err(1, "could not open file"); | |
| } | |
| if (fstat(fd, &st) == -1) { | |
| err(2, "could not fstat file"); | |
| } | |
| if ((buf = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, | |
| fd, 0)) == MAP_FAILED) { | |
| err(3, "mmap failed"); | |
| } | |
| if (nvlist_parse_json(buf, st.st_size, &nvl, 0) == -1) { | |
| err(4, "parse failed"); | |
| } | |
| printf("dump list:\n\n"); | |
| dump_nvlist(nvl, 8); | |
| printf("\n\n"); | |
| (void) close(fd); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment