1 /*
2  *
3  *  Copyright (c) 2015, Red Hat, Inc.
4  *  Copyright (c) 2015, Masatake YAMATO
5  *
6  *  Author: Masatake YAMATO <yamato@redhat.com>
7  *
8  *   This source code is released for free distribution under the terms of the
9  *   GNU General Public License version 2 or (at your option) any later version.
10  *
11  */
12 
13 #include "general.h"  /* must always come first */
14 #include "ctags.h"
15 #include "debug.h"
16 #include "options.h"
17 #include "options_p.h"
18 #include "parse_p.h"
19 #include "routines.h"
20 #include "trashbox.h"
21 #include "writer_p.h"
22 #include "xtag.h"
23 #include "xtag_p.h"
24 
25 #include <string.h>
26 #include <ctype.h>
27 
28 typedef struct sXtagObject {
29 	xtagDefinition *def;
30 	langType language;
31 	xtagType sibling;
32 } xtagObject;
33 
isPseudoTagsEnabled(xtagDefinition * pdef CTAGS_ATTR_UNUSED)34 static bool isPseudoTagsEnabled (xtagDefinition *pdef CTAGS_ATTR_UNUSED)
35 {
36 	if (!writerCanPrintPtag())
37 		return false;
38 	if (!writerPrintPtagByDefault())
39 		return false;
40 
41 	return ! isDestinationStdout ();
42 }
43 
isPseudoTagsFixed(xtagDefinition * pdef CTAGS_ATTR_UNUSED)44 static bool isPseudoTagsFixed (xtagDefinition *pdef CTAGS_ATTR_UNUSED)
45 {
46 	if (!writerCanPrintPtag())
47 		return true;
48 	else
49 		return false;
50 }
51 
enableFileKind(xtagDefinition * pdef,bool state)52 static void enableFileKind (xtagDefinition *pdef, bool state)
53 {
54 	enableDefaultFileKind(state);
55 	pdef->enabled = state;
56 }
57 
58 static xtagDefinition xtagDefinitions [] = {
59 	{ true, 'F',  "fileScope",
60 	  "Include tags of file scope" },
61 	{ false, 'f', "inputFile",
62 	  "Include an entry for the base file name of every input file",
63 	  NULL,
64 	  NULL,
65 	  enableFileKind},
66 	{ false, 'p', "pseudo",
67 	  "Include pseudo tags",
68 	  isPseudoTagsEnabled,
69 	  isPseudoTagsFixed},
70 	{ false, 'q', "qualified",
71 	  "Include an extra class-qualified tag entry for each tag"},
72 	{ false, 'r', "reference",
73 	  "Include reference tags"},
74 	{ false, 'g', "guest",
75 	  "Include tags generated by guest parsers"},
76 	{ true, 's', "subparser",
77 	  "Include tags generated by subparsers"},
78 	{ true, '\0', "anonymous",
79 	  "Include tags for non-named objects like lambda"},
80 };
81 
82 static unsigned int       xtagObjectUsed;
83 static unsigned int       xtagObjectAllocated;
84 static xtagObject* xtagObjects;
85 
getXtagObject(xtagType type)86 static xtagObject* getXtagObject (xtagType type)
87 {
88 	Assert ((0 <= type) && ((unsigned int)type < xtagObjectUsed));
89 	return (xtagObjects + type);
90 }
91 
getXtagDefinition(xtagType type)92 extern xtagDefinition* getXtagDefinition (xtagType type)
93 {
94 	Assert ((0 <= type) && ((unsigned int)type < xtagObjectUsed));
95 
96 	return getXtagObject (type)->def;
97 }
98 
99 typedef bool (* xtagPredicate) (xtagObject *pobj, langType language, const void *user_data);
getXtagTypeGeneric(xtagPredicate predicate,langType language,const void * user_data)100 static xtagType  getXtagTypeGeneric (xtagPredicate predicate, langType language, const void *user_data)
101 {
102 	static bool initialized = false;
103 	unsigned int i;
104 
105 	if (language == LANG_AUTO && (initialized == false))
106 	{
107 		initialized = true;
108 		initializeParser (LANG_AUTO);
109 	}
110 	else if (language != LANG_IGNORE && (initialized == false))
111 		initializeParser (language);
112 
113 	for (i = 0; i < xtagObjectUsed; i++)
114 	{
115 		if (predicate (xtagObjects + i, language, user_data))
116 			return i;
117 	}
118 	return XTAG_UNKNOWN;
119 }
120 
xtagEqualByLetter(xtagObject * pobj,langType language CTAGS_ATTR_UNUSED,const void * user_data)121 static bool xtagEqualByLetter (xtagObject *pobj, langType language CTAGS_ATTR_UNUSED,
122 							   const void *user_data)
123 {
124 	return (pobj->def->letter == *((char *)user_data))? true: false;
125 }
126 
getXtagTypeForLetter(char letter)127 extern xtagType  getXtagTypeForLetter (char letter)
128 {
129 	return getXtagTypeGeneric (xtagEqualByLetter, LANG_IGNORE, &letter);
130 }
131 
xtagEqualByNameAndLanguage(xtagObject * pobj,langType language,const void * user_data)132 static bool xtagEqualByNameAndLanguage (xtagObject *pobj, langType language, const void *user_data)
133 {
134 	const char* name = user_data;
135 
136 	if ((language == LANG_AUTO || pobj->language == language)
137 		&& (strcmp (pobj->def->name, name) == 0))
138 		return true;
139 	else
140 		return false;
141 }
142 
getXtagTypeForNameAndLanguage(const char * name,langType language)143 extern xtagType  getXtagTypeForNameAndLanguage (const char *name, langType language)
144 {
145 	return getXtagTypeGeneric (xtagEqualByNameAndLanguage, language, name);
146 }
147 
xtagColprintTableNew(void)148 extern struct colprintTable * xtagColprintTableNew (void)
149 {
150 	return colprintTableNew ("L:LETTER", "L:NAME", "L:ENABLED",
151 							 "L:LANGUAGE", "L:FIXED", "L:DESCRIPTION", NULL);
152 }
153 
xtagColprintAddLine(struct colprintTable * table,int xtype)154 static void  xtagColprintAddLine (struct colprintTable *table, int xtype)
155 {
156 	xtagObject* xobj = getXtagObject (xtype);
157 	xtagDefinition *xdef = xobj->def;
158 
159 	struct colprintLine *line = colprintTableGetNewLine(table);
160 
161 	colprintLineAppendColumnChar (line,
162 								  (xdef->letter == NUL_XTAG_LETTER)
163 								  ? '-'
164 								  : xdef->letter);
165 	colprintLineAppendColumnCString (line, xdef->name);
166 	colprintLineAppendColumnBool (line, isXtagEnabled(xdef->xtype));
167 	colprintLineAppendColumnCString (line,
168 									 xobj->language == LANG_IGNORE
169 									 ? RSV_NONE
170 									 : getLanguageName (xobj->language));
171 	colprintLineAppendColumnBool (line, isXtagFixed(xdef->xtype));
172 	colprintLineAppendColumnCString (line, xdef->description);
173 }
174 
xtagColprintAddCommonLines(struct colprintTable * table)175 extern void xtagColprintAddCommonLines (struct colprintTable *table)
176 {
177 	for (int i = 0; i < XTAG_COUNT; i++)
178 		xtagColprintAddLine (table, i);
179 }
180 
xtagColprintAddLanguageLines(struct colprintTable * table,langType language)181 extern void xtagColprintAddLanguageLines (struct colprintTable *table, langType language)
182 {
183 	for (unsigned int i = XTAG_COUNT; i < xtagObjectUsed; i++)
184 	{
185 		xtagObject* xobj = getXtagObject (i);
186 
187 		if (xobj->language == language)
188 			xtagColprintAddLine (table, i);
189 	}
190 }
191 
xtagColprintCompareLines(struct colprintLine * a,struct colprintLine * b)192 static int xtagColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
193 {
194 	const char *a_parser = colprintLineGetColumn (a, 3);
195 	const char *b_parser = colprintLineGetColumn (b, 3);
196 
197 	if (strcmp (a_parser, RSV_NONE) == 0
198 		&& strcmp (b_parser, RSV_NONE) != 0)
199 		return -1;
200 	else if (strcmp (a_parser, RSV_NONE) != 0
201 			 && strcmp (b_parser, RSV_NONE) == 0)
202 		return 1;
203 	else if (strcmp (a_parser, RSV_NONE) != 0
204 			 && strcmp (b_parser, RSV_NONE) != 0)
205 	{
206 		int r;
207 		r = strcmp (a_parser, b_parser);
208 		if (r != 0)
209 			return r;
210 	}
211 	else
212 	{
213 		int r;
214 
215 		const char *a_letter = colprintLineGetColumn (a, 0);
216 		const char *b_letter = colprintLineGetColumn (b, 0);
217 		r = strcmp(a_letter, b_letter);
218 		if (r != 0)
219 			return r;
220 	}
221 
222 	const char *a_name = colprintLineGetColumn (a, 1);
223 	const char *b_name = colprintLineGetColumn (b, 1);
224 
225 	return strcmp(a_name, b_name);
226 }
227 
xtagColprintTablePrint(struct colprintTable * table,bool withListHeader,bool machinable,FILE * fp)228 extern void xtagColprintTablePrint (struct colprintTable *table,
229 									bool withListHeader, bool machinable, FILE *fp)
230 {
231 	colprintTableSort (table, xtagColprintCompareLines);
232 	colprintTablePrint (table, 0, withListHeader, machinable, fp);
233 }
234 
isXtagEnabled(xtagType type)235 extern bool isXtagEnabled (xtagType type)
236 {
237 	xtagDefinition* def = getXtagDefinition (type);
238 
239 	Assert (def);
240 
241 	if (def->isEnabled)
242 		return def->isEnabled (def);
243 	else
244 		return def->enabled;
245 }
246 
isXtagFixed(xtagType type)247 extern bool isXtagFixed (xtagType type)
248 {
249 	xtagDefinition* def = getXtagDefinition (type);
250 
251 	Assert (def);
252 
253 	if (def->isFixed)
254 		return def->isFixed (def);
255 
256 	return false;
257 }
258 
enableXtag(xtagType type,bool state)259 extern bool enableXtag (xtagType type, bool state)
260 {
261 	bool old;
262 	xtagDefinition* def = getXtagDefinition (type);
263 
264 	Assert (def);
265 
266 	old = isXtagEnabled (type);
267 
268 	if (isXtagFixed(type))
269 		def->enabled = old;
270 	else if (def->enable)
271 		def->enable (def, state);
272 	else
273 		def->enabled = state;
274 
275 	def->isEnabled = NULL;
276 
277 	return old;
278 }
279 
isCommonXtag(xtagType type)280 extern bool isCommonXtag (xtagType type)
281 {
282 	return (type < XTAG_COUNT)? true: false;
283 }
284 
getXtagOwner(xtagType type)285 extern langType getXtagOwner (xtagType type)
286 {
287 	return getXtagObject (type)->language;
288 }
289 
getXtagName(xtagType type)290 extern const char* getXtagName (xtagType type)
291 {
292 	xtagDefinition* def = getXtagDefinition (type);
293 	if (def)
294 		return def->name;
295 	else
296 		return NULL;
297 }
298 
getXtagDescription(xtagType type)299 extern const char* getXtagDescription (xtagType type)
300 {
301 	xtagDefinition* def = getXtagDefinition (type);
302 	if (def)
303 		return def->description;
304 	else
305 		return NULL;
306 }
307 
initXtagObjects(void)308 extern void initXtagObjects (void)
309 {
310 	xtagObject *xobj;
311 
312 	xtagObjectAllocated = ARRAY_SIZE (xtagDefinitions);
313 	xtagObjects = xMalloc (xtagObjectAllocated, xtagObject);
314 	DEFAULT_TRASH_BOX(&xtagObjects, eFreeIndirect);
315 
316 	for (unsigned int i = 0; i < ARRAY_SIZE (xtagDefinitions); i++)
317 	{
318 		xobj = xtagObjects + i;
319 		xobj->def = xtagDefinitions + i;
320 		xobj->def->xtype = i;
321 		xobj->language = LANG_IGNORE;
322 		xobj->sibling = XTAG_UNKNOWN;
323 		xtagObjectUsed++;
324 	}
325 }
326 
countXtags(void)327 extern int countXtags (void)
328 {
329 	return xtagObjectUsed;
330 }
331 
updateSiblingXtag(xtagType type,const char * name)332 static void updateSiblingXtag (xtagType type, const char* name)
333 {
334 	int i;
335 	xtagObject *xobj;
336 
337 	for (i = type; i > 0; i--)
338 	{
339 		xobj = xtagObjects + i - 1;
340 		if (xobj->def->name && (strcmp (xobj->def->name, name) == 0))
341 		{
342 			Assert (xobj->sibling == XTAG_UNKNOWN);
343 			xobj->sibling = type;
344 			break;
345 		}
346 	}
347 }
348 
defineXtag(xtagDefinition * def,langType language)349 extern int defineXtag (xtagDefinition *def, langType language)
350 {
351 	xtagObject *xobj;
352 	size_t i;
353 
354 	Assert (def);
355 	Assert (def->name);
356 	for (i = 0; i < strlen (def->name); i++)
357 	{
358 		Assert ( isalnum (def->name [i]) );
359 	}
360 	def->letter = NUL_XTAG_LETTER;
361 
362 	if (xtagObjectUsed == xtagObjectAllocated)
363 	{
364 		xtagObjectAllocated *= 2;
365 		xtagObjects = xRealloc (xtagObjects, xtagObjectAllocated, xtagObject);
366 	}
367 	xobj = xtagObjects + (xtagObjectUsed);
368 	def->xtype = xtagObjectUsed++;
369 	xobj->def = def;
370 	xobj->language = language;
371 	xobj->sibling  = XTAG_UNKNOWN;
372 
373 	updateSiblingXtag (def->xtype, def->name);
374 
375 	verbose ("Add extra[%d]: %s,%s in %s\n",
376 			 def->xtype,
377 			 def->name, def->description,
378 			 getLanguageName (language));
379 
380 	return def->xtype;
381 }
382 
nextSiblingXtag(xtagType type)383 extern xtagType nextSiblingXtag (xtagType type)
384 {
385 	xtagObject *xobj;
386 
387 	xobj = xtagObjects + type;
388 	return xobj->sibling;
389 }
390