Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
JSONPath.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26
27#include "Array.h"
28#include "Boole.h"
29#include "Dictionary.h"
30#include "JSONPath.h"
31#include "Number.h"
32#include "Regexp.h"
33#include "String.h"
34
35#define _Class _JSONPath
36
37#pragma mark - JSONPath
38
39static Regexp *_re;
40
45static ident objectForKeyPath(const ident root, const char *path) {
46
47 assert(root);
48 assert(path);
49
50 assert(*path == '$');
51 const char *c = path;
52
53 ident obj = root;
54 while (obj) {
55
56 Range *matches;
57 if ($(_re, matchesCharacters, c, 0, &matches) == false) {
58 break;
59 }
60
61 const uint8_t *bytes = (uint8_t *) c + matches[1].location;
62 const size_t length = matches[1].length;
63
64 String *segment = $$(String, stringWithBytes, bytes, length, STRING_ENCODING_UTF8);
65 if (*segment->chars == '.') {
66
68 const Range range = { .location = 1, .length = segment->length - 1 };
69
70 String *key = $(segment, substring, range);
71
72 obj = $(dictionary, objectForKey, key);
73
74 release(key);
75
76 } else if (*segment->chars == '[') {
77
78 const Array *array = cast(Array, obj);
79 const unsigned long index = strtoul(segment->chars + 1, NULL, 10);
80 if (index < array->count) {
81 obj = $(array, objectAtIndex, index);
82 } else {
83 obj = NULL;
84 }
85 }
86 release(segment);
87
88 c += length;
89 }
90
91 return obj;
92}
93
94#pragma mark - Class lifecycle
95
99static void initialize(Class *clazz) {
100
101 ((JSONPathInterface *) clazz->interface)->objectForKeyPath = objectForKeyPath;
102
103 _re = re("(.[^.\\[]+|\\[[0-9]+\\])", 0);
104}
105
109static void destroy(Class *clazz) {
110
111 release(_re);
112}
113
119 static Class *clazz;
120 static Once once;
121
122 do_once(&once, {
123 clazz = _initialize(&(const ClassDef) {
124 .name = "JSONPath",
125 .superclass = _Object(),
126 .instanceSize = sizeof(JSONPath),
127 .interfaceOffset = offsetof(JSONPath, interface),
128 .interfaceSize = sizeof(JSONPathInterface),
130 .destroy = destroy,
131 });
132 });
133
134 return clazz;
135}
136
137#undef _Class
Immutable arrays.
A wrapper for placing boolean primitives into collections, etc.
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
#define obj
#define cast(type, obj)
Safely cast obj to type.
Definition: Class.h:165
Immutable key-value stores.
static void destroy(Class *clazz)
Definition: JSONPath.c:109
static Regexp * _re
Definition: JSONPath.c:39
static void initialize(Class *clazz)
Definition: JSONPath.c:99
A minimal JSONPath implementation.
A wrapper for placing numeric primitives into collections, etc.
Extended POSIX regular expressions.
Immutable UTF-8 strings.
@ STRING_ENCODING_UTF8
Definition: String.h:53
void * ident
The identity type, similar to Objective-C id.
Definition: Types.h:49
long Once
The Once type.
Definition: Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition: Once.h:43
Immutable arrays.
Definition: Array.h:56
ident objectAtIndex(const Array *self, int index)
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition: Class.h:41
The runtime representation of a Class.
Definition: Class.h:95
ident interface
The interface of the Class.
Definition: Class.h:105
Immutable key-value stores.
Definition: Dictionary.h:60
ident objectForKeyPath(const Dictionary *self, const char *path)
Definition: Dictionary.c:406
ident objectForKey(const Dictionary *self, const ident key)
Definition: Dictionary.c:382
A minimal JSONPath implementation.
Definition: JSONPath.h:42
Class * _JSONPath(void)
The JSONPath archetype.
Definition: JSONPath.c:118
MutableArray * array(void)
Returns a new MutableArray.
Definition: MutableArray.c:153
MutableDictionary * dictionary(void)
Returns a new MutableDictionary.
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
A location and length into contiguous collections.
Definition: Types.h:54
ssize_t location
The location.
Definition: Types.h:59
size_t length
The length.
Definition: Types.h:64
Extended POSIX regular expressions.
Definition: Regexp.h:43
_Bool matchesCharacters(const Regexp *self, const char *chars, int options, Range **matches)
Matches this regular expression against the given characters.
Definition: Regexp.c:134
OBJECTIVELY_EXPORT Regexp * re(const char *pattern, int options)
A convenience function for instantiating Regexps.
Definition: Regexp.c:219
Immutable UTF-8 strings.
Definition: String.h:69
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition: String.h:85
size_t length
The length of the String in bytes.
Definition: String.h:90
String * stringWithBytes(const uint8_t *bytes, size_t length, StringEncoding encoding)
Returns a new String by decoding length of bytes to UTF-8.
Definition: String.c:478
String * substring(const String *string, const Range range)
Creates a new String from a subset of this one.
Definition: String.c:539