Browse Source

changed readme

Sergey Lyubka 11 years ago
parent
commit
bafab852b0
1 changed files with 171 additions and 1 deletions
  1. 171 1
      README.md

+ 171 - 1
README.md

@@ -1,4 +1,174 @@
 JSON parser and generator for C/C++
 ===========================================
 
-Documentation is at [http://cesanta.com](http://cesanta.com/docs.shtml?Frozen.md)
+# Features
+
+   * Portable to any environment
+   * Simple API: 2 functions for parsing and 4 for generation
+   * Very small footprint
+   * No dependencies
+   * Makes no memory allocations
+   * Code is strict ISO C and strict ISO C++ at the same time
+   * Supports superset of JSON: allows non-quoted identifiers as object keys
+   * Complete 100% test coverage
+
+# How to use it
+
+   1. Copy `frozen.c` and `frozen.h` to your project
+   2. Add `frozen.c` to the list of source files
+   3. Parsing with Frozen is done in two steps: first, split JSON string
+      into tokens by `parse_json()`. Second, search for certain
+      parameters in parsed string by `find_json_token()`. Below is an example,
+      error handling is omitted for clarity:
+
+
+        #include <stdio.h>
+        #include "frozen.h"
+
+        int main(void) {
+          static const char *json = " { foo: 1, bar: 2 } ";
+          struct json_token arr[10], *tok;
+
+          // Tokenize json string, fill in tokens array
+          parse_json(json, strlen(json), arr, sizeof(arr) / sizeof(arr[0]));
+
+          // Search for parameter "bar" and print it's value
+          tok = find_json_token(arr, "bar");
+          printf("Value of bar is: [%.*s]\n", tok->len, tok->ptr);
+
+          return 0;
+        }
+
+# API documentation
+
+    int parse_json(const char *json_string, int json_string_length,
+                   struct json_token *tokens_array, int size_of_tokens_array);
+
+Tokenizes `json_string` of length `json_string_length`.
+If `tokens_array` is not `NULL`, then
+all `parse_json` will store tokens in the `tokens_array`. Token with type
+`JSON_TYPE_EOF` marks the end of parsed tokens. JSON token is defined as:
+
+    struct json_token {
+      const char *ptr;    // Points to the beginning of the token
+      int len;            // Token length
+      int num_desc;       // For arrays and object, total number of descendants
+      int type;           // Type of the token, possible values below
+
+    #define JSON_TYPE_EOF     0   // Not a real token, but end-of-tokens marker
+    #define JSON_TYPE_STRING  1
+    #define JSON_TYPE_NUMBER  2
+    #define JSON_TYPE_OBJECT  3
+    #define JSON_TYPE_TRUE    4
+    #define JSON_TYPE_FALSE   5
+    #define JSON_TYPE_NULL    6
+    #define JSON_TYPE_ARRAY   7
+    };
+
+If `tokens_array` is `NULL`, then `parse_json` just checks the validity of
+the JSON string, and points where parsing stops. If `tokens_array` is not
+`NULL`, it must be pre-allocated by the caller. Note that `struct json_token`
+just points to the data inside `json_string`, it does not own the data. Thus
+the token's lifetime is identical to the lifetime of `json_string`, until
+`json_string` is freed or mutated.  
+Return: On success, an offset inside `json_string` is returned
+where parsing has finished. On failure, a negative number is
+returned, one of:
+
+    #define JSON_STRING_INVALID           -1
+    #define JSON_STRING_INCOMPLETE        -2
+    #define JSON_TOKEN_ARRAY_TOO_SMALL    -3
+
+Below is an illustration on how JSON string gets tokenized:
+
+       JSON string:      {  "key_1" : "value_1",  "key_2": [ 12345, null  ]   }
+
+       JSON_TYPE_OBJECT  |<-------------------------------------------------->|
+       JSON_TYPE_STRING      |<->|
+       JSON_TYPE_STRING                |<--->|
+       JSON_TYPE_STRING                            |<->|
+       JSON_TYPE_ARRAY                                     |<------------>|
+       JSON_TYPE_NUMBER                                      |<->|
+       JSON_TYPE_NULL                                               |<>|
+       JSON_TYPE_EOF
+
+<!-- -->
+
+    const struct json_token *find_json_token(const struct json_token *toks,
+                                             const char *path);
+
+This is a convenience function to fetch specific values from the parsed
+string. `toks` must be a valid array, successfully populated by `parse_json()`.
+A `path` is a string, an accessor to the desired element of the JSON object,
+as if it was written in Javascript. For example, if parsed JSON string is  
+`"{ foo : { bar: [1, 2, 3] } }"`, then path `"foo.bar[0]"` would return a token
+that points to number `"1"`.  
+Return: pointer to the found token, or NULL on failure.
+
+
+    int json_emit_int(char *buf, int buf_len, long int value);
+    int json_emit_double(char *buf, int buf_len, double value);
+    int json_emit_quoted_str(char *buf, int buf_len, const char *str);
+    int json_emit_raw_str(char *buf, int buf_len, const char *str);
+
+These functions are used to generate JSON string. All of them accept
+a destination buffer and a value to output, and return number of bytes printed.
+Returned value can be bigger then destination buffer size, this is an
+indication of overflow. If there is no overflow, a buffer is guaranteed to
+be nul-terminated. Numbers are printed by `json_emit_double()` and
+`json_emit_int()` functions, strings are printed by `json_emit_quoted_str()`
+function. Values for `null`, `true`, `false`, and characters
+`{`, `}`, `[`, `]`, `,`, `:` are printed by
+`json_emit_raw_str()` function.
+
+## Example: accessing configuration parameters
+
+    #include "frozen.h"
+
+    static const char *config_str = " { ports: [ 80, 443 ] } ";
+    struct json_token tokens[10];
+    int tokens_size = sizeof(tokens) / sizeof(tokens[0]);
+
+    // Parse config string and make sure tokenization is correct
+    ASSERT(parse_json(config_str, strlen(config_str), tokens, tokens_size) > 0);
+
+    ASSERT(tokens[0].type == JSON_TYPE_OBJECT);   // Tokens are populated
+    ASSERT(tokens[1].type == JSON_TYPE_STRING);   // in order of their
+    ASSERT(tokens[2].type == JSON_TYPE_ARRAY);    // appearance in the
+    ASSERT(tokens[3].type == JSON_TYPE_NUMBER);   // JSON string
+    ASSERT(tokens[4].type == JSON_TYPE_NUMBER);
+    ASSERT(tokens[5].type == JSON_TYPE_EOF);      // Last token is always EOF
+
+    // Fetch port values
+    ASSERT(find_json_token(tokens, "ports") == &tokens[2]);
+    ASSERT(find_json_token(tokens, "ports[0]") == &tokens[3]);
+    ASSERT(find_json_token(tokens, "ports[1]") == &tokens[4]);
+    ASSERT(find_json_token(tokens, "ports[3]") == NULL);  // Outside boundaries
+    ASSERT(find_json_token(tokens, "foo.bar") == NULL);   // Nonexistent
+
+## Example: generating JSON string `{"foo":[-123,true]}`
+
+    char buf[1000], *p = buf;
+
+    p += json_emit_raw_str(p, &buf[sizeof(buf)] - p, "{");
+    p += json_emit_quoted_str(p, &buf[sizeof(buf)] - p, "foo");
+    p += json_emit_raw_str(p, &buf[sizeof(buf)] - p, ":[");
+    p += json_emit_int(p, &buf[sizeof(buf)] - p, -123);
+    p += json_emit_raw_str(p, &buf[sizeof(buf)] - p, ",true]}");
+
+    ASSERT(strcmp(buf, "{\"foo\":[-123,true]}") == 0);
+    ASSERT(p < &buf[sizeof(buf)]);
+
+# License
+
+Frozen is released under
+[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
+Businesses have an option to get non-restrictive, royalty-free commercial
+license and professional support from
+[Cesanta Software](http://cesanta.com).
+
+[Super Light DNS Resolver](https://github.com/cesanta/sldr),
+[Super Light Regexp Library](https://github.com/cesanta/slre),
+[Mongoose web server](https://github.com/cesanta/mongoose)
+are other projects by Cesanta Software, developed with the same philosophy
+of functionality and simplicity.