Skip to content

Instantly share code, notes, and snippets.

@lidio601
Created May 13, 2015 09:35
Show Gist options
  • Save lidio601/b7d181359e4812bc538c to your computer and use it in GitHub Desktop.
Save lidio601/b7d181359e4812bc538c to your computer and use it in GitHub Desktop.
Simple JSON parser in C, parse a JSON-like string and look for the first key-value pair by using jsonparse(jsonstring, key); Run this with gcc test.c jsonparser.c; [ $? -ne 0 ] | ./a.out
/*
Copyright (c) 2015 Fabio Cigliano
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.
*/
/* jsonparser */
/* JSON key-value parser in C. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
// for the replace function
#include <stddef.h>
#include "jsonparser.h"
// http://sourceforge.net/projects/cjson/
static void *(*cJSON_malloc)(size_t sz) = malloc;
// http://sourceforge.net/projects/cjson/
static char* cJSON_strdup(const char* str)
{
size_t len;
char* copy;
len = strlen(str) + 1;
if (!(copy = (char*)cJSON_malloc(len))) return 0;
memcpy(copy,str,len);
return copy;
}
// http://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way
char * trim(char * s, char trimchar) {
int l = strlen(s);
while(s[l-1] == trimchar) --l;
while(isspace(s[l - 1])) --l;
while(s[l-1] == trimchar) --l;
while(*s && s[0]==trimchar) ++s, --l;
while(*s && isspace(*s)) ++s, --l;
while(*s && s[0]==trimchar) ++s, --l;
return strndup(s, l);
}
// http://creativeandcritical.net/str-replace-c
char *repl_str(const char *str, const char *old, const char *new) {
/* Adjust each of the below values to suit your needs. */
/* Increment positions cache size initially by this number. */
size_t cache_sz_inc = 16;
/* Thereafter, each time capacity needs to be increased,
* multiply the increment by this factor. */
const size_t cache_sz_inc_factor = 3;
/* But never increment capacity by more than this number. */
const size_t cache_sz_inc_max = 1048576;
char *pret, *ret = NULL;
const char *pstr2, *pstr = str;
size_t i, count = 0;
ptrdiff_t *pos_cache = NULL;
size_t cache_sz = 0;
size_t cpylen, orglen, retlen, newlen, oldlen = strlen(old);
/* Find all matches and cache their positions. */
while ((pstr2 = strstr(pstr, old)) != NULL) {
count++;
/* Increase the cache size when necessary. */
if (cache_sz < count) {
cache_sz += cache_sz_inc;
pos_cache = realloc(pos_cache, sizeof(*pos_cache) * cache_sz);
if (pos_cache == NULL) {
goto end_repl_str;
}
cache_sz_inc *= cache_sz_inc_factor;
if (cache_sz_inc > cache_sz_inc_max) {
cache_sz_inc = cache_sz_inc_max;
}
}
pos_cache[count-1] = pstr2 - str;
pstr = pstr2 + oldlen;
}
orglen = pstr - str + strlen(pstr);
/* Allocate memory for the post-replacement string. */
if (count > 0) {
newlen = strlen(new);
retlen = orglen + (newlen - oldlen) * count;
} else retlen = orglen;
ret = malloc(retlen + 1);
if (ret == NULL) {
goto end_repl_str;
}
if (count == 0) {
/* If no matches, then just duplicate the string. */
strcpy(ret, str);
} else {
/* Otherwise, duplicate the string whilst performing
* the replacements using the position cache. */
pret = ret;
memcpy(pret, str, pos_cache[0]);
pret += pos_cache[0];
for (i = 0; i < count; i++) {
memcpy(pret, new, newlen);
pret += newlen;
pstr = str + pos_cache[i] + oldlen;
cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - oldlen;
memcpy(pret, pstr, cpylen);
pret += cpylen;
}
ret[retlen] = '\0';
}
end_repl_str:
/* Free the cache and return the post-replacement string,
* which will be NULL in the event of an error. */
free(pos_cache);
return ret;
}
extern char* jsonparse(char* jsonstring, char* key) {
char input[strlen(jsonstring)];
strcpy(input, jsonstring);
char key2[strlen(key)+10];
sprintf(key2, "\"%s\":", key);
// printf("newkey: <%s>\n", key2);
// look for the key: value pair
// http://stackoverflow.com/questions/10844629/string-find-in-c
char* ris = strstr(input, key2);
// http://www.tutorialspoint.com/c_standard_library/c_function_strstr.htm
if(!ris) return ris;
// remove the "key": string
ris += strlen(key2);
// split to the ;
ris = strtok(ris,",");
// split to the }
ris = strtok(ris,"}");
// trim trailing \"
ris = trim(ris, '\"');
// replace the string \\\" with \"
ris = repl_str(ris, "\\\"", "\"");
// return
return cJSON_strdup(ris);
}
/*
Copyright (c) 2015 Fabio Cigliano
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 jsonparser__h
#define jsonparser__h
#ifdef __cplusplus
extern "C"
{
#endif
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern char* jsonparse(char* jsonstring, char* key);
#ifdef __cplusplus
}
#endif
#endif
/*
Copyright (c) 2015 Fabio Cigliano
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.
*/
// http://stackoverflow.com/questions/18815399/compiling-multiple-files-in-c
#include <stdio.h>
#include <stdlib.h>
#include "jsonparser.h"
/* Parse text to JSON, then render back to text, and print! */
void doit(char *jsonstring, char* key) {
char *out;
out = jsonparse(jsonstring, key);
if (!out) {
printf("Error while reading json key [%s]\n", key);
} else {
printf("input json: %s\n", jsonstring);
printf("key <%s> = <%s>\n", key, out);
printf("-------------------\n");
// free(out);
}
}
/*
run this with
# clear; gcc test.c jsonparser.c; [ $? -ne 0 ] | ./a.out
*/
int main (int argc, const char * argv[]) {
/* a bunch of json: */
char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}";
char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http:/*www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }";
char text5[]="[\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.7668,\n \"Longitude\": -122.3959,\n \"Address\": \"\",\n \"City\": \"SAN FRANCISCO\",\n \"State\": \"CA\",\n \"Zip\": \"94107\",\n \"Country\": \"US\"\n },\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.371991,\n \"Longitude\": -122.026020,\n \"Address\": \"\",\n \"City\": \"SUNNYVALE\",\n \"State\": \"CA\",\n \"Zip\": \"94085\",\n \"Country\": \"US\"\n }\n ]";
/* Process each json textblock by parsing, then rebuilding: */
doit(text1, "name");
doit(text4, "Title");
doit(text5, "Latitude");
doit(text5, "NOT-FOUND");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment