JST: JSON tools  1.0.0
JSON tools dynamic library for reading, manipulating and writing JSON tree
JST_load.c
Go to the documentation of this file.
1 #include "JST_private.h"
2 #include "JST_list.h"
3 #include "JST_string.h"
4 
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 
12 #include "jstools.h"
13 
14 bool JST_DEBUG_SHOW_TOKENS = false;
15 
16 const JST_Array JST_Array_Zero = { .items = NULL, .count = 0U, .parent = NULL };
17 const JST_Object JST_Object_Zero = { .items = NULL, .count = 0U, .parent = NULL, .first = NULL };
18 const JST_Value JST_Value_Zero = { .object = JST_Object_Zero };
19 const JST_Element JST_Element_Zero = { .type = JST_NULL, .value = JST_Value_Zero };
20 const JST_ArrayItem JST_ArrayItem_Zero = { .parent = NULL, .element = JST_Element_Zero };
21 const JST_Pair JST_Pair_Zero = { .parent = NULL, .element = JST_Element_Zero, .name = NULL, .next = NULL };
22 const JST_SyntaxError JST_SyntaxError_Zero = { .line = 0U, .pos = 0U };
23 
24 typedef enum {
38 } TokenType;
39 
40 static const TokenType TokenType_Zero = TOKEN_NONE;
41 
42 typedef union {
43  int64_t i;
44  double d;
45  char * s;
46 } TokenValue;
47 
48 static const TokenValue TokenValue_Zero = { .s = NULL };
49 
50 typedef struct {
51  TokenType type;
52  TokenValue value;
53 } Token;
54 
55 static const Token Token_Zero = { .type = TokenType_Zero, .value = TokenValue_Zero };
56 
57 typedef struct {
58  FILE * stream;
59  char look_ahead;
60  char buffer[4096];
61  size_t limit;
62  size_t pos;
63  size_t line;
64  JST_Error error;
65 } Context;
66 
67 static const Context Context_Zero = {
68  .stream = NULL,
69  .look_ahead = '\0',
70  .buffer = "",
71  .limit = 0U,
72  .pos = 0U,
73  .line = 0U,
74  .error = JST_ERR_NONE
75 };
76 
77 static const char EndOfFile = 26;
78 
79 static bool get_next_char( Context * context, char * c ) {
80  if( context->look_ahead ) {
81  *c = context->look_ahead;
82  context->look_ahead = '\0';
83  return true;
84  }
85  if( context->pos >= context->limit ) {
86  context->limit = fread( context->buffer, 1, sizeof( context->buffer ), context->stream );
87  if(( context->limit == 0 )&& feof( context->stream )) {
88  *c = EndOfFile;
89  return true;
90  }
91  context->pos = 0;
92  }
93  *c = context->buffer[context->pos++];
94  return true;
95 }
96 
97 static bool remaining_chars_are_only_whitespaces( Context * context ) {
98  while( context->pos < context->limit ) {
99  char c = 0;
100  if( get_next_char( context, &c )&&( NULL == strchr( " \t\r\n", c ))) {
101  context->error = JST_ERR_UNEXPECTED_TOKEN;
102  return false;
103  }
104  }
105  return true;
106 }
107 
108 static bool check_separator( Context * context, JST_Error error ) {
109  char c = 0;
110  if( ! get_next_char( context, &c )) {
111  context->error = error;
112  return false;
113  }
114  if( ( c == ' ' )||( c == '\t' )
115  ||( c == '\r' )||( c == '\n' )
116  ||( c == ',' )||( c == ':' )
117  ||( c == '}' )||( c == ']' )
118  ||( c == '\0' )||( c == EndOfFile ))
119  {
120  context->look_ahead = c; // On remet ce qu'on a lu de trop
121  return true;
122  }
123  context->error = error;
124  return false;
125 }
126 
127 static bool is_separator_after_number( char c ) {
128  return( c == '\0' )
129  || ( c == ' ' )||( c == '\t' )
130  || ( c == '\r' )||( c == '\n' )
131  || ( c == ',' )||( c == '}' )||( c == ']' );
132 }
133 
134 static bool get_number( Context * context, char c, Token * token ) {
136  JST_String_append_char( &s, c );
137  while( get_next_char( context, &c )
138  &&( ! is_separator_after_number( c ))
139  &&( c != EndOfFile )
140  && JST_String_append_char( &s, c ));
141  context->look_ahead = c; // On remet ce qu'on a lu de trop
142  if(( s.length > 2 )&&( s.buffer[0] == '0' )&&( s.buffer[1] != '.' )) {
143  context->error = JST_ERR_NUMBER_EXPECTED;
144  JST_String_delete( &s );
145  return false;
146  }
147  s.buffer[s.length] = '\0';
148  char * err = NULL;
149  token->value.i = strtoll( s.buffer, &err, 10 );
150  if( is_separator_after_number( *err )) {
151  token->type = TOKEN_INTEGER;
152  if( JST_DEBUG_SHOW_TOKENS ) {
153  fprintf( stderr, "TOKEN_INTEGER: %ld\n", token->value.i );
154  }
155  JST_String_delete( &s );
156  return true;
157  }
158  token->value.d = strtod( s.buffer, &err );
159  if( is_separator_after_number( *err )) {
160  token->type = TOKEN_DOUBLE;
161  if( JST_DEBUG_SHOW_TOKENS ) {
162  fprintf( stderr, "TOKEN_DOUBLE: %G\n", token->value.d );
163  }
164  JST_String_delete( &s );
165  return true;
166  }
167  context->error = JST_ERR_NUMBER_EXPECTED;
168  JST_String_delete( &s );
169  return false;
170 }
171 
172 static bool get_string( Context * context, Token * token ) {
173  token->type = TOKEN_STRING;
175  char c = '"', p;
176  do {
177  p = c;
178  if(( ! get_next_char( context, &c ))||( ! JST_String_append_char( &s, c ))) {
179  context->error = JST_ERR_ERRNO;
180  JST_String_delete( &s );
181  return false;
182  }
183  if( strchr( "\b\f\n\r\t", c )) {
185  JST_String_delete( &s );
186  return false;
187  }
188  if( p == '\\' ) {
189  if( NULL == strchr( "\"\\/bfnrtu", c )) {
190  context->error = JST_ERR_STRING_BAD_ESCAPE_SEQUENCE;
191  JST_String_delete( &s );
192  return false;
193  }
194  else if( c == 'u' ) {
195  for( int i = 0; i < 4; ++i ) {
196  if( ! get_next_char( context, &c )) {
197  JST_String_delete( &s );
198  return false;
199  }
200  if( ! isxdigit( c )) {
201  context->error = JST_ERR_STRING_BAD_ESCAPE_SEQUENCE;
202  JST_String_delete( &s );
203  return false;
204  }
205  if( ! JST_String_append_char( &s, c )) {
206  context->error = JST_ERR_ERRNO;
207  JST_String_delete( &s );
208  return false;
209  }
210  }
211  }
212  if( ( ! get_next_char( context, &c ) )
213  ||( ! JST_String_append_char( &s, c )))
214  {
215  context->error = JST_ERR_ERRNO;
216  JST_String_delete( &s );
217  return false;
218  }
219  }
220  } while( c != '"' );
221  if( c == '"' ) {
222  if( s.buffer ) {
223  s.buffer[s.length-1] = '\0';
224  token->value.s = strdup( s.buffer );
225  JST_String_delete( &s );
226  if( JST_DEBUG_SHOW_TOKENS ) {
227  fprintf( stderr, "TOKEN_STRING: '%s'\n", token->value.s );
228  }
229  return true;
230  }
231  context->error = JST_ERR_ERRNO;
232  JST_String_delete( &s );
233  return false;
234  }
235  context->error = JST_ERR_STRING_NOT_ENDED;
236  JST_String_delete( &s );
237  return false;
238 }
239 
240 static bool get_true( Context * context, Token * token ) {
241  char c = 't';
242  if( get_next_char( context, &c )&&( c == 'r' )
243  && get_next_char( context, &c )&&( c == 'u' )
244  && get_next_char( context, &c )&&( c == 'e' ))
245  {
246  token->type = TOKEN_TRUE;
247  if( JST_DEBUG_SHOW_TOKENS ) {
248  fprintf( stderr, "TOKEN_TRUE\n" );
249  }
250  return check_separator( context, JST_ERR_SEPARATOR_EXPECTED_AFTER_TRUE );
251  }
252  context->error = JST_ERR_TRUE_EXPECTED;
253  return false;
254 }
255 
256 static bool get_false( Context * context, Token * token ) {
257  char c = 'f';
258  if( get_next_char( context, &c )&&( c == 'a' )
259  && get_next_char( context, &c )&&( c == 'l' )
260  && get_next_char( context, &c )&&( c == 's' )
261  && get_next_char( context, &c )&&( c == 'e' ))
262  {
263  token->type = TOKEN_FALSE;
264  if( JST_DEBUG_SHOW_TOKENS ) {
265  fprintf( stderr, "TOKEN_FALSE\n" );
266  }
267  return check_separator( context, JST_ERR_SEPARATOR_EXPECTED_AFTER_FALSE );
268  }
269  context->error = JST_ERR_FALSE_EXPECTED;
270  return false;
271 }
272 
273 static bool get_null( Context * context, Token * token ) {
274  char c = 'n';
275  if( get_next_char( context, &c )&&( c == 'u' )
276  && get_next_char( context, &c )&&( c == 'l' )
277  && get_next_char( context, &c )&&( c == 'l' ))
278  {
279  token->type = TOKEN_NULL;
280  if( JST_DEBUG_SHOW_TOKENS ) {
281  fprintf( stderr, "TOKEN_NULL\n" );
282  }
283  return check_separator( context, JST_ERR_SEPARATOR_EXPECTED_AFTER_NULL );
284  }
285  context->error = JST_ERR_NULL_EXPECTED;
286  return false;
287 }
288 
289 static bool get_next_token( Context * context, Token * token ) {
290  token->type = TOKEN_NONE;
291  char c = ' ';
292  while(( c == ' ' )||( c == '\t' )||( c == '\r' )||( c == '\n' )) {
293  if(( c == '\r' )||( c == '\n' )) {
294  context->line++;
295  }
296  if( ! get_next_char( context, &c )) {
297  return false;
298  }
299  }
300  switch( c ) {
301  case '{':
302  if( JST_DEBUG_SHOW_TOKENS ) {
303  fprintf( stderr, "TOKEN_OPEN_OBJECT\n" );
304  }
305  token->type = TOKEN_OPEN_OBJECT;
306  break;
307  case ':':
308  if( JST_DEBUG_SHOW_TOKENS ) {
309  fprintf( stderr, "TOKEN_COLON\n" );
310  }
311  token->type = TOKEN_COLON;
312  break;
313  case ',':
314  if( JST_DEBUG_SHOW_TOKENS ) {
315  fprintf( stderr, "TOKEN_COMMA\n" );
316  }
317  token->type = TOKEN_COMMA;
318  break;
319  case '}':
320  if( JST_DEBUG_SHOW_TOKENS ) {
321  fprintf( stderr, "TOKEN_CLOSE_OBJECT\n" );
322  }
323  token->type = TOKEN_CLOSE_OBJECT;
324  break;
325  case '[':
326  if( JST_DEBUG_SHOW_TOKENS ) {
327  fprintf( stderr, "TOKEN_OPEN_ARRAY\n" );
328  }
329  token->type = TOKEN_OPEN_ARRAY;
330  break;
331  case ']':
332  if( JST_DEBUG_SHOW_TOKENS ) {
333  fprintf( stderr, "TOKEN_CLOSE_ARRAY\n" );
334  }
335  token->type = TOKEN_CLOSE_ARRAY;
336  break;
337  case '"': return get_string( context, token );
338  case 't': return get_true ( context, token );
339  case 'f': return get_false ( context, token );
340  case 'n': return get_null ( context, token );
341  case '-': case '0':case '1':case '2':case '3':
342  case '4': case '5':case '6':case '7':case '8':
343  case '9': return get_number( context, c, token );
344  default:
345  context->error = JST_ERR_UNEXPECTED_TOKEN;
346  return false;
347  }
348  return true;
349 }
350 
351 static bool add_object( Context * context, JST_Object * object, JST_Element * parent );
352 static bool add_array( Context * context, JST_Array * array, JST_Element * parent );
353 
354 static bool set_value( Context * context, JST_Element * node, JST_Element * parent, const Token * token ) {
355  switch( token->type ) {
356  case TOKEN_OPEN_OBJECT:
357  node->type = JST_OBJECT;
358  return add_object( context, &(node->value.object), parent );
359  case TOKEN_OPEN_ARRAY :
360  node->type = JST_ARRAY;
361  return add_array( context, &(node->value.array), parent );
362  case TOKEN_NULL :
363  node->type = JST_NULL;
364  break;
365  case TOKEN_TRUE:
366  node->type = JST_BOOLEAN;
367  node->value.boolean = true;
368  break;
369  case TOKEN_FALSE:
370  node->type = JST_BOOLEAN;
371  node->value.boolean = false;
372  break;
373  case TOKEN_INTEGER:
374  node->type = JST_INTEGER;
375  node->value.integer = token->value.i;
376  break;
377  case TOKEN_DOUBLE:
378  node->type = JST_DOUBLE;
379  node->value.dbl = token->value.d;
380  break;
381  case TOKEN_STRING:
382  node->type = JST_STRING;
383  node->value.string = token->value.s;
384  break;
385  default:
386  context->error = JST_ERR_UNEXPECTED_TOKEN;
387  return false;
388  }
389  return true;
390 }
391 
392 static JST_Pair * add_property( Context * context, char * property_name, JST_Object * parent ) {
393  JST_Pair * item = calloc( 1, sizeof( JST_Pair ));
394  if( ! item ) {
395  context->error = JST_ERR_ERRNO;
396  return NULL;
397  }
398  item->name = property_name;
399  item->parent = parent;
400  Token token;
401  if( get_next_token( context, &token )) {
402  if( token.type == TOKEN_COLON ) {
403  if( get_next_token( context, &token ) && set_value( context, &(item->element), (JST_Element *)item, &token )) {
404  return item;
405  }
406  }
407  else {
408  context->error = JST_ERR_COLON_EXPECTED;
409  }
410  }
411  free( property_name );
412  free( item );
413  return NULL;
414 }
415 
416 static JST_ArrayItem * add_item( Context * context, const Token * token, JST_Array * parent ) {
417  JST_ArrayItem * item = calloc( 1, sizeof( JST_ArrayItem ));
418  if( ! item ) {
419  context->error = JST_ERR_ERRNO;
420  return NULL;
421  }
422  item->parent = parent;
423  if( set_value( context, &(item->element), (JST_Element *)item, token )) {
424  return item;
425  }
426  free( item );
427  return NULL;
428 }
429 
430 static void set_pair( void * dest, unsigned index, void * src ) {
431  JST_Object * object = dest;
432  if( index == 0 ) {
433  object->first = src;
434  }
435  else {
436  JST_Pair * prev = object->items[index-1];
437  prev->next = src;
438  }
439  object->items[index] = src;
440 }
441 
442 static void set_item( void * dest, unsigned index, void * src ) {
443  ((JST_Array *)dest)->items[index] = src;
444 }
445 
446 static bool add_object( Context * context, JST_Object * object, JST_Element * parent ) {
447  object->parent = parent;
448  Token token = { .type = TOKEN_NONE, .value = { .s = NULL }};
449  JST_List * first = NULL;
450  JST_List * current = NULL;
451  bool item_expected = true;
452  while(( context->error == JST_ERR_NONE )&&( token.type != TOKEN_CLOSE_OBJECT )) {
453  if( get_next_token( context, &token )) {
454  if( item_expected ) {
455  if(( token.type == TOKEN_CLOSE_OBJECT )&&( object->count == 0 )) {
456  break;
457  }
458  if( token.type == TOKEN_STRING ) {
459  JST_Pair * pair = add_property( context, token.value.s, object );
460  if( pair ) {
461  JST_List_push_back( &first, &current, pair );
462  ++(object->count);
463  if( get_next_token( context, &token )) {
464  if(( token.type != TOKEN_COMMA )&&( token.type != TOKEN_CLOSE_OBJECT )) {
465  context->error = JST_ERR_UNEXPECTED_TOKEN;
466  }
467  else {
468  item_expected = token.type == TOKEN_COMMA;
469  }
470  }
471  else {
472  context->error = JST_ERR_UNEXPECTED_TOKEN;
473  }
474  }
475  }
476  else {
477  context->error = JST_ERR_UNEXPECTED_TOKEN;
478  }
479  }
480  else {
481  context->error = JST_ERR_UNEXPECTED_TOKEN;
482  }
483  }
484  }
485  object->items = calloc( object->count, sizeof( JST_Pair *));
486  JST_List_move_to( first, object, set_pair );
487  qsort( object->items, object->count, sizeof( JST_Pair *), JST_pairs_compare );
488  if( context->error == JST_ERR_NONE ) {
489  return true;
490  }
491  return false;
492 }
493 
494 static bool add_array( Context * context, JST_Array * array, JST_Element * parent ) {
495  array->parent = parent;
496  Token token = { .type = TOKEN_NONE, .value = { .s = NULL }};
497  JST_List * first = NULL;
498  JST_List * current = NULL;
499  bool item_expected = true;
500  while(( context->error == JST_ERR_NONE )&&( token.type != TOKEN_CLOSE_ARRAY )) {
501  if( get_next_token( context, &token )) {
502  if( item_expected ) {
503  if(( token.type == TOKEN_CLOSE_ARRAY )&&( array->count == 0 )) {
504  break;
505  }
506  JST_ArrayItem * item = add_item( context, &token, array );
507  if( item ) {
508  JST_List_push_back( &first, &current, item );
509  ++(array->count);
510  if( get_next_token( context, &token )) {
511  if(( token.type != TOKEN_COMMA )&&( token.type != TOKEN_CLOSE_ARRAY )) {
512  context->error = JST_ERR_UNEXPECTED_TOKEN;
513  }
514  else {
515  item_expected = token.type == TOKEN_COMMA;
516  }
517  }
518  else {
519  context->error = JST_ERR_UNEXPECTED_TOKEN;
520  }
521  }
522  }
523  else {
524  context->error = JST_ERR_UNEXPECTED_TOKEN;
525  }
526  }
527  }
528  array->items = calloc( array->count, sizeof( JST_ArrayItem *));
529  JST_List_move_to( first, array, set_item );
530  return context->error == JST_ERR_NONE;
531 }
532 
533 JST_Error JST_load_from_stream( FILE * stream, JST_Element * root, JST_SyntaxError * syntax_error ) {
534  if( syntax_error ) {
535  *syntax_error = JST_SyntaxError_Zero;
536  }
537  if(( stream == NULL )||( root == NULL )) {
538  return JST_ERR_NULL_ARGUMENT;
539  }
540  *root = JST_Element_Zero;
541  Context context = Context_Zero;
542  Token token = Token_Zero;
543  context.stream = stream;
544  bool ok = true
545  && get_next_token( &context, &token )
546  && set_value( &context, root, NULL, &token )
547  && remaining_chars_are_only_whitespaces( &context );
548  if( ! ok ) {
549  if( syntax_error ) {
550  syntax_error->line = (unsigned)( 1 + context.line );
551  size_t pos = (( context.pos < context.limit )||(context.limit == 0 )) ? context.pos : ( context.limit - 1 );
552  while(( pos > 0 )
553  && (( context.pos - pos ) < ( sizeof( syntax_error->context ) / 2 ))
554  && ( context.buffer[pos] != '\r' )
555  && ( context.buffer[pos] != '\n' ))
556  {
557  --pos;
558  }
559  if(( context.buffer[pos] == '\r' )||( context.buffer[pos] == '\n' )) {
560  ++pos;
561  }
562  strncpy( syntax_error->context, context.buffer + pos, sizeof( syntax_error->context ) - 1 );
563  syntax_error->context[sizeof( syntax_error->context )-1] = '\0';
564  syntax_error->pos = (unsigned)( context.pos - pos );
565  if( syntax_error->pos > 0 ) {
566  --(syntax_error->pos);
567  }
568  }
569  }
570  return context.error;
571 }
572 
573 JST_Error JST_load_from_file( const char * path, JST_Element * root, JST_SyntaxError * syntax_error ) {
574  if(( path == NULL )) {
575  return JST_ERR_NULL_ARGUMENT;
576  }
577  FILE * stream = fopen( path, "rt" );
578  if( stream == NULL ) {
579  return JST_ERR_ERRNO;
580  }
581  JST_Error error = JST_load_from_stream( stream, root, syntax_error );
582  int myerrno = errno;
583  fclose( stream );
584  errno = myerrno;
585  return error;
586 }
struct JST_Pair_ ** items
Array of JST_Pair, ordered by JST_Pair.name to ease search with bsearch()
Definition: jstools.h:25
char * name
This property&#39;s name.
Definition: jstools.h:96
&#39;false&#39; token was expected
Definition: jstools.h:120
token is not a colon
Definition: jstools.h:123
unsigned length
Definition: JST_string.h:6
only ", \, /, b, f, n, r, t, u may be escaped
Definition: jstools.h:114
int JST_pairs_compare(const void *left, const void *right)
const JST_Object JST_Object_Zero
Constant defined to initialize safely a variable of type JST_Object.
Definition: JST_load.c:17
A JSON Value may be an object, an array, a boolean, a number or a string.
Definition: jstools.h:40
void * item
Definition: JST_list.h:5
const JST_Element JST_Element_Zero
Constant defined to initialize safely a variable of type JST_Element.
Definition: JST_load.c:19
syntax error or &#39;null&#39;
Definition: jstools.h:118
&#39;true&#39; token was expected
Definition: jstools.h:119
token is not a number
Definition: jstools.h:122
char * buffer
Definition: JST_string.h:8
A object attribute item has a parent and is a named-typed-value pair.
Definition: jstools.h:93
A JSON array.
Definition: jstools.h:10
JST_Element element
Definition: jstools.h:85
An array item has a parent and a typed value.
Definition: jstools.h:83
TokenType
Definition: JST_load.c:24
JST_Error JST_load_from_file(const char *path, JST_Element *root, JST_SyntaxError *syntax_error)
Reads the input file, allocates the node of the corresponding tree, than frees the input buffer...
Definition: JST_load.c:573
char * string
Definition: jstools.h:46
const JST_Value JST_Value_Zero
Constant defined to initialize safely a variable of type JST_Value.
Definition: JST_load.c:18
ending quote has not been found
Definition: jstools.h:113
syntax error or &#39;false&#39;
Definition: jstools.h:117
A JSON object, a sorted set of named-value pairs.
Definition: jstools.h:24
JST_Object object
Definition: jstools.h:41
&#39;null&#39; token was expected
Definition: jstools.h:121
JST_Error JST_load_from_stream(FILE *stream, JST_Element *root, JST_SyntaxError *syntax_error)
Reads the input stream, allocates the node of the corresponding tree, than frees the input buffer...
Definition: JST_load.c:533
bool boolean
Definition: jstools.h:43
syntax error or &#39;true&#39;
Definition: jstools.h:116
JST_Error JST_List_push_back(JST_List **first, JST_List **current, void *data)
Definition: JST_list.c:7
const JST_ArrayItem JST_ArrayItem_Zero
Definition: JST_load.c:20
bool JST_DEBUG_SHOW_TOKENS
Definition: JST_load.c:14
JST_Value value
Definition: jstools.h:72
char context[80]
Characters around the error.
Definition: jstools.h:141
JST_Error
When things goes wrong, an error information is given.
Definition: jstools.h:108
struct JST_Pair_ * first
A linked list is mandatory to preserve the properties&#39;s order.
Definition: jstools.h:28
strerror() or perror() can be used to show the operating system layer error
Definition: jstools.h:112
An element is a typed value.
Definition: jstools.h:70
Information returned by JST_load() in case of error.
Definition: jstools.h:139
bool JST_String_append_char(JST_String *string, char c)
Definition: JST_string.c:8
JST_Array array
Definition: jstools.h:42
const JST_SyntaxError JST_SyntaxError_Zero
Constant defined to initialize safely a variable of type JST_SyntaxError.
Definition: JST_load.c:22
JST_Error JST_List_move_to(JST_List *from, void *dest, LST_assign_t assign)
For each item in list, call assign to transfert ownership of items and free the list, node by node.
Definition: JST_list.c:25
double dbl
Definition: jstools.h:45
JST_Object * parent
This property&#39;s owner.
Definition: jstools.h:94
JST_Error JST_String_delete(JST_String *string)
Definition: JST_string.c:45
struct JST_Pair_ * next
A linked list is mandatory to preserve the properties&#39;s order.
Definition: jstools.h:97
int64_t integer
Definition: jstools.h:44
JST_Array * parent
Definition: jstools.h:84
unsigned line
Last line&#39;s index (from 1)
Definition: jstools.h:140
Function misused.
Definition: jstools.h:110
struct JST_ArrayItem_ ** items
Array of JST_ArrayItem.
Definition: jstools.h:11
const JST_Pair JST_Pair_Zero
Constant defined to initialize safely a variable of type JST_Pair.
Definition: JST_load.c:21
unsigned count
Cardinality of the previous array.
Definition: jstools.h:12
JST_ValueType type
Definition: jstools.h:71
struct JST_Element_ * parent
of type JST_ArrayItem or JST_Pair, case selector is parent->type
Definition: jstools.h:13
const JST_Array JST_Array_Zero
Constant defined to initialize safely a variable of type JST_Array.
Definition: JST_load.c:16
JST_Element element
The value associated with the name.
Definition: jstools.h:95
unexpected token
Definition: jstools.h:124
const JST_String JST_String_Zero
Definition: JST_string.c:6
unsigned count
Cardinality of the previous array.
Definition: jstools.h:26
unsigned pos
Position of error in context.
Definition: jstools.h:142