2 * Copyright (c) 2016, Aman Gupta
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * External interface to entry.c
10 #include "general.h" /* must always come first */
16 #include "options_p.h"
28 #ifndef json_boolean /* compat with jansson < 2.4 */
29 #define json_boolean(val) ((val) ? json_true() : json_false())
33 static int writeJsonEntry (tagWriter
*writer CTAGS_ATTR_UNUSED
,
34 MIO
* mio
, const tagEntryInfo
*const tag
,
37 static int writeJsonPtagEntry (tagWriter
*writer CTAGS_ATTR_UNUSED
,
38 MIO
* mio
, const ptagDesc
*desc
,
39 const char *const fileName
,
40 const char *const pattern
,
41 const char *const parserName
,
44 tagWriter jsonWriter
= {
45 .writeEntry
= writeJsonEntry
,
46 .writePtagEntry
= writeJsonPtagEntry
,
47 .printPtagByDefault
= true,
48 .preWriteEntry
= NULL
,
49 .postWriteEntry
= NULL
,
50 .rescanFailedEntry
= NULL
,
51 .treatFieldAsFixed
= NULL
,
52 .defaultFileName
= NULL
,
55 static const char* escapeFieldValueRaw (const tagEntryInfo
* tag
, fieldType ftype
, int fieldIndex
)
58 if (doesFieldHaveRenderer(ftype
, true))
59 v
= renderFieldNoEscaping (ftype
, tag
, fieldIndex
);
61 v
= renderField (ftype
, tag
, fieldIndex
);
66 static json_t
* escapeFieldValue (const tagEntryInfo
* tag
, fieldType ftype
, bool returnEmptyStringAsNoValue
)
68 const char *str
= escapeFieldValueRaw (tag
, ftype
, NO_PARSER_FIELD
);
72 unsigned int dt
= getFieldDataType(ftype
);
73 if (dt
& FIELDTYPE_STRING
)
75 if (dt
& FIELDTYPE_BOOL
&& str
[0] == '\0')
78 return json_string (str
);
80 else if (dt
& FIELDTYPE_INTEGER
)
84 if (strToLong (str
, 10, &tmp
))
85 return json_integer (tmp
);
89 else if (dt
& FIELDTYPE_BOOL
)
91 /* TODO: This must be fixed when new boolean field is added.
92 Currently only `file:' field use this. */
93 return json_boolean (strcmp ("-", str
)); /* "-" -> false */
98 else if (returnEmptyStringAsNoValue
)
104 static void renderExtensionFieldMaybe (int xftype
, const tagEntryInfo
*const tag
, json_t
*response
)
106 const char *fname
= getFieldName (xftype
);
108 if (fname
&& doesFieldHaveRenderer (xftype
, false) && isFieldEnabled (xftype
) && doesFieldHaveValue (xftype
, tag
))
112 case FIELD_LINE_NUMBER
:
113 json_object_set_new (response
, fname
,
114 json_integer (tag
->lineNumber
));
116 case FIELD_FILE_SCOPE
:
117 json_object_set_new (response
, fname
,
121 json_object_set_new (response
, fname
,
122 escapeFieldValue (tag
, xftype
, false));
127 static void addParserFields (json_t
*response
, const tagEntryInfo
*const tag
)
131 for (i
= 0; i
< tag
->usedParserFields
; i
++)
133 const tagField
*f
= getParserFieldForIndex(tag
, i
);
134 fieldType ftype
= f
->ftype
;
135 if (! isFieldEnabled (ftype
))
138 unsigned int dt
= getFieldDataType (ftype
);
140 if (dt
& FIELDTYPE_STRING
)
142 const char *str
= escapeFieldValueRaw (tag
, ftype
, i
);
143 if (dt
& FIELDTYPE_BOOL
&& str
[0] == '\0')
146 o
= json_string (str
);
148 else if (dt
& FIELDTYPE_INTEGER
)
150 /* NOT IMPLEMENTED YET */
154 else if (dt
& FIELDTYPE_BOOL
)
162 json_object_set_new (response
, getFieldName (ftype
), o
);
166 static void addExtensionFields (json_t
*response
, const tagEntryInfo
*const tag
)
170 /* FIELD_KIND has no name; getFieldName (FIELD_KIND) returns NULL.
171 FIELD_KIND_LONG does, too.
172 That cannot be changed to keep the compatibility of tags file format.
173 Use FIELD_KIND_KEY instead */
174 if (isFieldEnabled (FIELD_KIND
) || isFieldEnabled (FIELD_KIND_LONG
))
175 enableField (FIELD_KIND_KEY
, true, false);
177 /* FIELD_SCOPE has no name; getFieldName (FIELD_KIND_KEY) returns NULL.
178 That cannot be changed to keep the compatibility of tags file format.
179 Use FIELD_SCOPE_KEY and FIELD_SCOPE_KIND_LONG instead. */
180 if (isFieldEnabled (FIELD_SCOPE
))
182 enableField (FIELD_SCOPE_KEY
, true, false);
183 enableField (FIELD_SCOPE_KIND_LONG
, true, false);
186 for (k
= FIELD_EXTENSION_START
; k
<= FIELD_BUILTIN_LAST
; k
++)
187 renderExtensionFieldMaybe (k
, tag
, response
);
190 static int writeJsonEntry (tagWriter
*writer CTAGS_ATTR_UNUSED
,
191 MIO
* mio
, const tagEntryInfo
*const tag
,
192 void *clientData CTAGS_ATTR_UNUSED
)
195 json_t
*response
= json_pack ("{ss}", "_type", "tag");
197 if (isFieldEnabled (FIELD_NAME
))
199 json_t
*name
= json_string (tag
->name
);
202 json_object_set_new (response
, "name", name
);
204 if (isFieldEnabled (FIELD_INPUT_FILE
))
205 json_object_set_new (response
, "path", json_string (tag
->sourceFileName
));
206 if (isFieldEnabled (FIELD_PATTERN
))
208 json_t
*pat
= escapeFieldValue(tag
, FIELD_PATTERN
, true);
209 json_object_set_new (response
, "pattern", pat
);
212 if (includeExtensionFlags ())
214 addExtensionFields (response
, tag
);
215 addParserFields (response
, tag
);
218 /* Print nothing if RESPONSE has only "_type" field. */
219 if (json_object_size (response
) == 1)
222 char *buf
= json_dumps (response
, JSON_PRESERVE_ORDER
);
223 length
= mio_printf (mio
, "%s\n", buf
);
227 json_decref (response
);
232 static int writeJsonPtagEntry (tagWriter
*writer CTAGS_ATTR_UNUSED
,
233 MIO
* mio
, const ptagDesc
*desc
,
234 const char *const fileName
,
235 const char *const pattern
,
236 const char *const parserName
,
237 void *clientData CTAGS_ATTR_UNUSED
)
239 #define OPT(X) ((X)?(X):"")
244 response
= json_pack ("{ss ss ss ss ss}",
247 "parserName", parserName
,
248 "path", OPT(fileName
),
249 "pattern", OPT(pattern
));
253 response
= json_pack ("{ss ss ss ss}",
256 "path", OPT(fileName
),
257 "pattern", OPT(pattern
));
260 char *buf
= json_dumps (response
, JSON_PRESERVE_ORDER
);
261 int length
= mio_printf (mio
, "%s\n", buf
);
263 json_decref (response
);
269 extern bool ptagMakeJsonOutputVersion (ptagDesc
*desc
, langType language CTAGS_ATTR_UNUSED
,
270 const void *data CTAGS_ATTR_UNUSED
)
272 return writePseudoTag (desc
,
278 #else /* HAVE_JANSSON */
280 tagWriter jsonWriter
= {
282 .writePtagEntry
= NULL
,
283 .preWriteEntry
= NULL
,
284 .postWriteEntry
= NULL
,
285 .defaultFileName
= "-",
288 extern bool ptagMakeJsonOutputVersion (ptagDesc
*desc
, langType language CTAGS_ATTR_UNUSED
,
289 const void *data CTAGS_ATTR_UNUSED
)