use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / json / json.c
1 /*
2    This file is part of GNUnet
3    Copyright (C) 2014-2017 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file json/json.c
22  * @brief functions to parse JSON snippets
23  * @author Florian Dold
24  * @author Benedikt Mueller
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_json_lib.h"
29
30
31 /**
32  * Navigate and parse data in a JSON tree.  Tries to parse the @a root
33  * to find all of the values given in the @a spec.  If one of the
34  * entries in @a spec cannot be found or parsed, the name of the JSON
35  * field is returned in @a error_json_name, and the offset of the
36  * entry in @a spec is returned in @a error_line.
37  *
38  * @param root the JSON node to start the navigation at.
39  * @param spec parse specification array
40  * @param[out] error_json_name which JSON field was problematic
41  * @param[out] which index into @a spec did we encounter an error
42  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
43  */
44 int
45 GNUNET_JSON_parse (const json_t *root,
46                    struct GNUNET_JSON_Specification *spec,
47                    const char **error_json_name,
48                    unsigned int *error_line)
49 {
50   if (NULL == root)
51     return GNUNET_SYSERR;
52   for (unsigned int i = 0; NULL != spec[i].parser; i++)
53   {
54     json_t *pos;
55
56     if (NULL == spec[i].field)
57       pos = (json_t *) root;
58     else
59       pos = json_object_get (root, spec[i].field);
60     if ((NULL == pos) && (spec[i].is_optional))
61       continue;
62     if ((NULL == pos) ||
63         (GNUNET_OK != spec[i].parser (spec[i].cls, pos, &spec[i])))
64     {
65       if (NULL != error_json_name)
66         *error_json_name = spec[i].field;
67       if (NULL != error_line)
68         *error_line = i;
69       GNUNET_JSON_parse_free (spec);
70       return GNUNET_SYSERR;
71     }
72   }
73   return GNUNET_OK; /* all OK! */
74 }
75
76
77 /**
78  * Set the "optional" flag for a parser specification entry.
79  *
80  * @param spec specification to modify
81  * @return spec copy of @a spec with optional bit set
82  */
83 struct GNUNET_JSON_Specification
84 GNUNET_JSON_spec_mark_optional (struct GNUNET_JSON_Specification spec)
85 {
86   struct GNUNET_JSON_Specification ret = spec;
87
88   ret.is_optional = GNUNET_YES;
89   return ret;
90 }
91
92
93 /**
94  * Frees all elements allocated during a #GNUNET_JSON_parse()
95  * operation.
96  *
97  * @param spec specification of the parse operation
98  */
99 void
100 GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
101 {
102   for (unsigned int i = 0; NULL != spec[i].parser; i++)
103     if (NULL != spec[i].cleaner)
104       spec[i].cleaner (spec[i].cls, &spec[i]);
105 }
106
107
108 /**
109  * Set an option with a JSON value from the command line.
110  * A pointer to this function should be passed as part of the
111  * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
112  * of this type.
113  *
114  * @param ctx command line processing context
115  * @param scls additional closure (will point to the 'json_t *')
116  * @param option name of the option
117  * @param value actual value of the option as a string.
118  * @return #GNUNET_OK if parsing the value worked
119  */
120 static int
121 set_json (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
122           void *scls,
123           const char *option,
124           const char *value)
125 {
126   json_t **json = scls;
127   json_error_t error;
128
129   *json = json_loads (value, JSON_REJECT_DUPLICATES, &error);
130   if (NULL == *json)
131   {
132     fprintf (stderr,
133              _ ("Failed to parse JSON in option `%s': %s (%s)\n"),
134              option,
135              error.text,
136              error.source);
137     return GNUNET_SYSERR;
138   }
139   return GNUNET_OK;
140 }
141
142
143 /**
144  * Allow user to specify a JSON input value.
145  *
146  * @param shortName short name of the option
147  * @param name long name of the option
148  * @param argumentHelp help text for the option argument
149  * @param description long help text for the option
150  * @param[out] val set to the JSON specified at the command line
151  */
152 struct GNUNET_GETOPT_CommandLineOption
153 GNUNET_JSON_getopt (char shortName,
154                     const char *name,
155                     const char *argumentHelp,
156                     const char *description,
157                     json_t **json)
158 {
159   struct GNUNET_GETOPT_CommandLineOption clo = { .shortName = shortName,
160                                                  .name = name,
161                                                  .argumentHelp = argumentHelp,
162                                                  .description = description,
163                                                  .require_argument = 1,
164                                                  .processor = &set_json,
165                                                  .scls = (void *) json };
166
167   return clo;
168 }
169
170
171 /* end of json.c */