glitch in the license text detected by hyazinthe, thank you!
[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 /**
16  * @file json/json.c
17  * @brief functions to parse JSON snippets
18  * @author Florian Dold
19  * @author Benedikt Mueller
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
23 #include "gnunet_json_lib.h"
24
25
26 /**
27  * Navigate and parse data in a JSON tree.  Tries to parse the @a root
28  * to find all of the values given in the @a spec.  If one of the
29  * entries in @a spec cannot be found or parsed, the name of the JSON
30  * field is returned in @a error_json_name, and the offset of the
31  * entry in @a spec is returned in @a error_line.
32  *
33  * @param root the JSON node to start the navigation at.
34  * @param spec parse specification array
35  * @param[out] error_json_name which JSON field was problematic
36  * @param[out] which index into @a spec did we encounter an error
37  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
38  */
39 int
40 GNUNET_JSON_parse (const json_t *root,
41                    struct GNUNET_JSON_Specification *spec,
42                    const char **error_json_name,
43                    unsigned int *error_line)
44 {
45   unsigned int i;
46   json_t *pos;
47
48   if (NULL == root)
49     return GNUNET_SYSERR;
50   for (i=0;NULL != spec[i].parser;i++)
51   {
52     if (NULL == spec[i].field)
53       pos = (json_t *) root;
54     else
55       pos = json_object_get (root,
56                              spec[i].field);
57     if ( (NULL == pos) ||
58          (GNUNET_OK !=
59           spec[i].parser (spec[i].cls,
60                           pos,
61                           &spec[i])) )
62     {
63       if (NULL != error_json_name)
64         *error_json_name = spec[i].field;
65       if (NULL != error_line)
66         *error_line = i;
67       GNUNET_JSON_parse_free (spec);
68       return GNUNET_SYSERR;
69     }
70   }
71   return GNUNET_OK; /* all OK! */
72 }
73
74
75 /**
76  * Frees all elements allocated during a #GNUNET_JSON_parse()
77  * operation.
78  *
79  * @param spec specification of the parse operation
80  */
81 void
82 GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
83 {
84   for (unsigned int i=0;NULL != spec[i].parser;i++)
85     if (NULL != spec[i].cleaner)
86       spec[i].cleaner (spec[i].cls,
87                        &spec[i]);
88 }
89
90
91 /**
92  * Set an option with a JSON value from the command line.
93  * A pointer to this function should be passed as part of the
94  * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
95  * of this type.
96  *
97  * @param ctx command line processing context
98  * @param scls additional closure (will point to the 'json_t *')
99  * @param option name of the option
100  * @param value actual value of the option as a string.
101  * @return #GNUNET_OK if parsing the value worked
102  */
103 static int
104 set_json (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
105           void *scls,
106           const char *option,
107           const char *value)
108 {
109   json_t **json = scls;
110   json_error_t error;
111
112   *json = json_loads (value,
113                       JSON_REJECT_DUPLICATES,
114                       &error);
115   if (NULL == *json)
116   {
117     FPRINTF (stderr,
118              _("Failed to parse JSON in option `%s': %s (%s)\n"),
119              option,
120              error.text,
121              error.source);
122     return GNUNET_SYSERR;
123   }
124   return GNUNET_OK;
125 }
126
127
128 /**
129  * Allow user to specify a JSON input value.
130  *
131  * @param shortName short name of the option
132  * @param name long name of the option
133  * @param argumentHelp help text for the option argument
134  * @param description long help text for the option
135  * @param[out] val set to the JSON specified at the command line
136  */
137 struct GNUNET_GETOPT_CommandLineOption
138 GNUNET_JSON_getopt (char shortName,
139                     const char *name,
140                     const char *argumentHelp,
141                     const char *description,
142                     json_t **json)
143 {
144   struct GNUNET_GETOPT_CommandLineOption clo = {
145     .shortName =  shortName,
146     .name = name,
147     .argumentHelp = argumentHelp,
148     .description = description,
149     .require_argument = 1,
150     .processor = &set_json,
151     .scls = (void *) json
152   };
153
154   return clo;
155 }
156
157
158 /* end of json.c */