2 Copyright (C) 2021 David Knapp (Cloudwalk)
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 // taken from json's wikipedia article
25 const char json_test_string[] =
28 "\t\"firstName\": \"John\",\n"
29 "\t\"lastName\": \"Smith\",\n"
30 "\t\"isAlive\": true,\n"
33 "\t\t\"streetAddress\": \"21 2nd Street\",\n"
34 "\t\t\"city\": \"New York\",\n"
35 "\t\t\"state\": \"NY\",\n"
36 "\t\t\"postalCode\": \"10021-3100\"\n"
38 "\t\"phoneNumbers\": [\n"
40 "\t\t\t\"type\": \"home\",\n"
41 "\t\t\t\"number\": \"212 555-1234\"\n"
44 "\t\t\t\"type\": \"office\",\n"
45 "\t\t\t\"number\": \"646 555-4567\"\n"
48 "\t\"children\": [],\n"
49 "\t\"spouse\": null\n"
53 static jmp_buf json_error;
55 typedef enum qjson_err_e
63 typedef enum qjson_type_e
65 JSON_TYPE_UNDEFINED = 0,
69 JSON_TYPE_PRIMITIVE = 4
72 typedef struct qjson_token_s
75 struct qjson_token_s *next; // if an array, next will be a NULL terminated array
76 char *string; // ASCII only for now
81 qjson_token_t *head, *cur;
87 static void Json_Parse_Object(struct qjson_state_s *state);
88 static void Json_Parse_Array(struct qjson_state_s *state);
90 // Tell the user that their json is broken, why it's broken, and where it's broken, so hopefully they fix it.
91 static void Json_Parse_Error(struct qjson_state_s *state, qjson_err_t error)
100 Con_Printf(CON_ERROR "Json Error: Unexpected token '%c', line %i, column %i\n", *state->pos, state->line, state->col);
103 Con_Printf(CON_ERROR "Json Error: Unexpected end-of-file\n");
109 longjmp(json_error, 1);
112 // Skips newlines, and handles different line endings.
113 static qbool Json_Parse_Newline(struct qjson_state_s *state)
115 if(*state->pos == '\n')
117 if(*state->pos == '\r')
119 if(*state->pos + 1 == '\n')
131 // Skips the current line. Only useful for comments.
132 static void Json_Parse_SkipLine(struct qjson_state_s *state)
134 while(!Json_Parse_Newline(state))
138 // Checks for C/C++-style comments and ignores them. This is not standard json.
139 static qbool Json_Parse_Comment(struct qjson_state_s *state)
141 if(*state->pos == '/')
143 if(*state->pos++ == '/')
144 Json_Parse_SkipLine(state);
145 else if(*state->pos == '*')
147 while(*state->pos++ != '*' && *state->pos + 1 != '/')
151 Json_Parse_Error(state, JSON_ERR_INVAL);
157 // Advance forward in the stream as many times as 'count', cleanly.
158 static void Json_Parse_Next(struct qjson_state_s *state, size_t count)
160 state->col = state->col + count;
161 state->pos = state->pos + count;
164 Json_Parse_Error(state, JSON_ERR_EOF);
167 // Skip all whitespace, as we normally know it.
168 static void Json_Parse_Whitespace(struct qjson_state_s *state)
170 while(*state->pos == ' ' || *state->pos == '\t')
171 Json_Parse_Next(state, 1);
174 // Skip all whitespace, as json defines it.
175 static void Json_Parse_Skip(struct qjson_state_s *state)
178 * Repeat this until we run out of whitespace, newlines, and comments.
179 * state->pos should be left on non-whitespace when this returns.
182 Json_Parse_Whitespace(state);
183 } while (Json_Parse_Comment(state) || Json_Parse_Newline(state));
186 // Skip to the next token that isn't whitespace. Hopefully a valid one.
187 static char Json_Parse_NextToken(struct qjson_state_s *state)
190 * This assumes state->pos is already on whitespace. Most of the time this
191 * doesn't happen automatically, but advancing the pointer here would break
192 * comment and newline handling when it does happen automatically.
194 Json_Parse_Skip(state);
198 // TODO: handle escape sequences
199 static void Json_Parse_String(struct qjson_state_s *state)
202 Json_Parse_Next(state, 1);
203 if(*state->pos == '\\')
204 Json_Parse_Next(state, 1);
205 } while(*state->pos != '"');
207 Json_Parse_Next(state, 1);
210 // Handles numbers. Json numbers can be either an integer or a double.
211 static qbool Json_Parse_Number(struct qjson_state_s *state)
214 const char *in = state->pos;
216 qbool is_float = false;
217 qbool is_exp = false;
219 for(i = 0, numsize = 0; isdigit(in[i]); i++, numsize++)
221 //out[numsize] = in[numsize];
225 if(is_float || is_exp)
226 Json_Parse_Error(state, JSON_ERR_INVAL);
232 if(in[i] == 'e' || in[i] == 'E')
235 Json_Parse_Error(state, JSON_ERR_INVAL);
236 if(in[i+1] == '+' || in[i+1] == '-')
243 // TODO: use strtod()
244 Json_Parse_Next(state, i);
249 static qbool Json_Parse_Keyword(struct qjson_state_s *state, const char *keyword)
251 size_t keyword_size = strlen(keyword);
252 if(!strncmp(keyword, state->pos, keyword_size))
254 Json_Parse_Next(state, keyword_size);
261 static void Json_Parse_Value(struct qjson_state_s *state)
263 Json_Parse_Next(state, 1);
265 switch(Json_Parse_NextToken(state))
268 Json_Parse_String(state);
271 Json_Parse_Object(state);
274 Json_Parse_Array(state);
277 Json_Parse_Number(state);
280 if(Json_Parse_Keyword(state, "true"))
282 if(Json_Parse_Keyword(state, "false"))
284 if(Json_Parse_Keyword(state, "null"))
286 if(isdigit(*state->pos))
287 Json_Parse_Number(state);
292 static void Json_Parse_Object(struct qjson_state_s *state)
295 * Json objects are basically a data map; key-value pairs.
296 * They end in a comma or a closing curly brace.
299 Json_Parse_Next(state, 1);
302 if(Json_Parse_NextToken(state) == '"')
303 Json_Parse_String(state);
308 if(Json_Parse_NextToken(state) == ':')
309 Json_Parse_Value(state);
312 } while (Json_Parse_NextToken(state) == ',');
314 if(Json_Parse_NextToken(state) == '}')
317 Json_Parse_Error(state, JSON_ERR_INVAL);
321 static void Json_Parse_Array(struct qjson_state_s *state)
324 * Json arrays are basically lists. They can contain
325 * any value, comma-separated, and end with a closing square bracket.
328 Json_Parse_Value(state);
329 } while (Json_Parse_NextToken(state) == ',');
331 if(Json_Parse_NextToken(state) == ']')
334 Json_Parse_Error(state, JSON_ERR_INVAL);
337 // Main function for the parser.
338 qjson_token_t *Json_Parse(const char *data)
340 struct qjson_state_s state =
351 Con_Printf(CON_ERROR "Json_Parse: Empty json file\n");
355 if(setjmp(json_error))
357 // actually not sure about this
361 if(Json_Parse_NextToken(&state) == '{')
362 Json_Parse_Object(&state);
365 Con_Printf(CON_ERROR "Json_Parse: Not a json file\n");
370 // TODO: Actually parse.
371 Con_Printf("Hmm, yes. This json is made of json\n");
376 void Json_Test_f(cmd_state_t *cmd)
378 Json_Parse(json_test_string);