xref: /Universal-ctags/main/field.c (revision 2cd54e43f39d2a0265b53bbc00fc6b5aac30a701)
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 
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "ctags.h"
20 #include "debug.h"
21 #include "entry.h"
22 #include "entry_p.h"
23 #include "field.h"
24 #include "field_p.h"
25 #include "kind.h"
26 #include "options_p.h"
27 #include "parse_p.h"
28 #include "read.h"
29 #include "routines.h"
30 #include "trashbox.h"
31 #include "writer_p.h"
32 #include "xtag_p.h"
33 
34 #include "optscript.h"
35 #include "script_p.h"
36 
37 #define FIELD_NULL_LETTER_CHAR '-'
38 #define FIELD_NULL_LETTER_STRING "-"
39 
40 typedef struct sFieldObject {
41 	fieldDefinition *def;
42 	vString     *buffer;
43 	const char* nameWithPrefix;
44 	langType language;
45 	fieldType sibling;
46 } fieldObject;
47 
48 static const char *renderFieldName (const tagEntryInfo *const tag, const char *value, vString* b);
49 static const char *renderFieldNameNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b);
50 static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value, vString* b);
51 static const char *renderFieldInputNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
52 static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag, const char *value, vString* b);
53 static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value, vString* b);
54 static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
55 static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value, vString* b);
56 static const char *renderFieldScopeNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
57 static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value, vString* b);
58 static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value, vString* b);
59 static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value, vString* b);
60 static const char *renderFieldLineNumber (const tagEntryInfo *const tag, const char *value, vString* b);
61 static const char *renderFieldLanguage (const tagEntryInfo *const tag, const char *value, vString* b);
62 static const char *renderFieldAccess (const tagEntryInfo *const tag, const char *value, vString* b);
63 static const char *renderFieldKindLetter (const tagEntryInfo *const tag, const char *value, vString* b);
64 static const char *renderFieldImplementation (const tagEntryInfo *const tag, const char *value, vString* b);
65 static const char *renderFieldFile (const tagEntryInfo *const tag, const char *value, vString* b);
66 static const char *renderFieldPattern (const tagEntryInfo *const tag, const char *value, vString* b);
67 static const char *renderFieldRoles (const tagEntryInfo *const tag, const char *value, vString* b);
68 static const char *renderFieldRefMarker (const tagEntryInfo *const tag, const char *value, vString* b);
69 static const char *renderFieldExtras (const tagEntryInfo *const tag, const char *value, vString* b);
70 static const char *renderFieldXpath (const tagEntryInfo *const tag, const char *value, vString* b);
71 static const char *renderFieldScopeKindName(const tagEntryInfo *const tag, const char *value, vString* b);
72 static const char *renderFieldEnd (const tagEntryInfo *const tag, const char *value, vString* b);
73 static const char *renderFieldEpoch (const tagEntryInfo *const tag, const char *value, vString* b);
74 static const char *renderFieldNth (const tagEntryInfo *const tag, const char *value, vString* b);
75 
76 static bool doesContainAnyCharInName (const tagEntryInfo *const tag, const char *value, const char *chars);
77 static bool doesContainAnyCharInInput (const tagEntryInfo *const tag, const char*value, const char *chars);
78 static bool doesContainAnyCharInFieldScope (const tagEntryInfo *const tag, const char *value, const char *chars);
79 static bool doesContainAnyCharInSignature (const tagEntryInfo *const tag, const char *value, const char *chars);
80 
81 static bool     isTyperefFieldAvailable   (const tagEntryInfo *const tag);
82 static bool     isFileFieldAvailable      (const tagEntryInfo *const tag);
83 static bool     isInheritsFieldAvailable  (const tagEntryInfo *const tag);
84 static bool     isAccessFieldAvailable    (const tagEntryInfo *const tag);
85 static bool     isImplementationFieldAvailable (const tagEntryInfo *const tag);
86 static bool     isSignatureFieldAvailable (const tagEntryInfo *const tag);
87 static bool     isExtrasFieldAvailable    (const tagEntryInfo *const tag);
88 static bool     isXpathFieldAvailable     (const tagEntryInfo *const tag);
89 static bool     isEndFieldAvailable       (const tagEntryInfo *const tag);
90 static bool     isEpochAvailable          (const tagEntryInfo *const tag);
91 static bool     isNthAvailable            (const tagEntryInfo *const tag);
92 
93 static EsObject* getFieldValueForName (const tagEntryInfo *, const fieldDefinition *);
94 static EsObject* setFieldValueForName (tagEntryInfo *, const fieldDefinition *, const EsObject *);
95 static EsObject* getFieldValueForInput (const tagEntryInfo *, const fieldDefinition *);
96 static EsObject* getFieldValueForKind (const tagEntryInfo *, const fieldDefinition *);
97 static EsObject* getFieldValueForTyperef (const tagEntryInfo *, const fieldDefinition *);
98 static EsObject* setFieldValueForTyperef (tagEntryInfo *, const fieldDefinition *, const EsObject *);
99 static EsObject* checkFieldValueForTyperef (const fieldDefinition *, const EsObject *);
100 static EsObject* getFieldValueForScope (const tagEntryInfo *, const fieldDefinition *);
101 static EsObject* setFieldValueForScope (tagEntryInfo *, const fieldDefinition *, const EsObject *);
102 static EsObject* checkFieldValueForScope (const fieldDefinition *, const EsObject *);
103 static EsObject* getFieldValueForExtras (const tagEntryInfo *, const fieldDefinition *);
104 static EsObject* getFieldValueForAccess (const tagEntryInfo *, const fieldDefinition *);
105 static EsObject* setFieldValueForAccess (tagEntryInfo *, const fieldDefinition *, const EsObject *);
106 static EsObject* getFieldValueForSignature (const tagEntryInfo *, const fieldDefinition *);
107 static EsObject* setFieldValueForSignature (tagEntryInfo *, const fieldDefinition *, const EsObject *);
108 static EsObject* getFieldValueForRoles (const tagEntryInfo *, const fieldDefinition *);
109 static EsObject* getFieldValueForLineCommon (const tagEntryInfo *, const fieldDefinition *);
110 static EsObject* checkFieldValueForLineCommon (const fieldDefinition *, const EsObject *);
111 static EsObject* setFieldValueForLineCommon (tagEntryInfo *, const fieldDefinition *, const EsObject *);
112 static EsObject* setFieldValueForInherits (tagEntryInfo *, const fieldDefinition *, const EsObject *);
113 
114 #define WITH_DEFUALT_VALUE(str) ((str)?(str):FIELD_NULL_LETTER_STRING)
115 
116 static fieldDefinition fieldDefinitionsFixed [] = {
117 	[FIELD_NAME] = {
118 		.letter             = 'N',
119 		.name               = "name",
120 		.description        = "tag name",
121 		.enabled            = true,
122 		.render             = renderFieldName,
123 		.renderNoEscaping   = renderFieldNameNoEscape,
124 		.doesContainAnyChar = doesContainAnyCharInName,
125 		.isValueAvailable   = NULL,
126 		.dataType           = FIELDTYPE_STRING,
127 		.getterValueType    = NULL,
128 		.getValueObject     = getFieldValueForName,
129 		.setterValueType    = NULL,
130 		.checkValueForSetter= NULL,
131 		.setValueObject     = setFieldValueForName,
132 	},
133 	[FIELD_INPUT_FILE] = {
134 		.letter             = 'F',
135 		.name               = "input",
136 		.description        = "input file",
137 		.enabled            = true,
138 		.render             = renderFieldInput,
139 		.renderNoEscaping   = renderFieldInputNoEscape,
140 		.doesContainAnyChar = doesContainAnyCharInInput,
141 		.isValueAvailable   = NULL,
142 		.dataType           = FIELDTYPE_STRING,
143 		.getterValueType    = NULL,
144 		.getValueObject     = getFieldValueForInput,
145 		.setterValueType    = NULL,
146 		.checkValueForSetter= NULL,
147 		.setValueObject     = NULL,
148 	},
149 	[FIELD_PATTERN] = {
150 		.letter             = 'P',
151 		.name               = "pattern",
152 		.description        = "pattern",
153 		.enabled            = true,
154 		.render             = renderFieldPattern,
155 		.renderNoEscaping   = NULL,
156 		.doesContainAnyChar = NULL,
157 		.isValueAvailable   = NULL,
158 		.dataType           = FIELDTYPE_STRING|FIELDTYPE_BOOL,
159 	},
160 };
161 
162 static fieldDefinition fieldDefinitionsExuberant [] = {
163 	[FIELD_COMPACT_INPUT_LINE - FIELD_ECTAGS_START] = {
164 		.letter             = 'C',
165 		.name               = "compact",
166 		.description        = "compact input line (used only in xref output)",
167 		.enabled            = false,
168 		.render             = renderFieldCompactInputLine,
169 		.renderNoEscaping   = NULL,
170 		.doesContainAnyChar = NULL,
171 		.isValueAvailable   = NULL,
172 		.dataType           = FIELDTYPE_STRING,
173 	},
174 	[FIELD_FILE_SCOPE - FIELD_ECTAGS_START] = {
175 		.letter             = 'f',
176 		.name               = "file",
177 		.description        = "File-restricted scoping",
178 		.enabled            = true,
179 		.render             = renderFieldFile,
180 		.renderNoEscaping   = NULL,
181 		.doesContainAnyChar = NULL,
182 		.isValueAvailable   = isFileFieldAvailable,
183 		.dataType           = FIELDTYPE_BOOL,
184 	},
185 	[FIELD_KIND_LONG - FIELD_ECTAGS_START] = {
186 		.letter             = 'K',
187 		.name               = NULL,
188 		.description        = "Kind of tag in long-name form",
189 		.enabled            = false,
190 		.render             = renderFieldKindName,
191 		.renderNoEscaping   = NULL,
192 		.doesContainAnyChar = NULL,
193 		.isValueAvailable   = NULL,
194 		.dataType           = FIELDTYPE_STRING,
195 	},
196 	[FIELD_KIND - FIELD_ECTAGS_START] = {
197 		.letter             ='k',
198 		.name               = NULL,
199 		.description        = "Kind of tag in one-letter form",
200 		.enabled            = true,
201 		.render             = renderFieldKindLetter,
202 		.renderNoEscaping   = NULL,
203 		.doesContainAnyChar = NULL,
204 		.isValueAvailable   = NULL,
205 		.dataType           = FIELDTYPE_STRING,
206 	},
207 	[FIELD_LANGUAGE - FIELD_ECTAGS_START] = {
208 		.letter             = 'l',
209 		.name               = "language",
210 		.description        = "Language of input file containing tag",
211 		.enabled            = false,
212 		.render             = renderFieldLanguage,
213 		.renderNoEscaping   = NULL,
214 		.doesContainAnyChar = NULL,
215 		.dataType           = FIELDTYPE_STRING,
216 	},
217 	[FIELD_LINE_NUMBER - FIELD_ECTAGS_START] = {
218 		.letter             = 'n',
219 		.name               = "line",
220 		.description        = "Line number of tag definition",
221 		.enabled            = false,
222 		.render             = renderFieldLineNumber,
223 		.renderNoEscaping   = NULL,
224 		.doesContainAnyChar = NULL,
225 		.isValueAvailable   = NULL,
226 		.dataType           = FIELDTYPE_INTEGER,
227 		.getterValueType    = "int",
228 		.getValueObject     = getFieldValueForLineCommon,
229 		.setterValueType    = "matchloc|int",
230 		.checkValueForSetter= checkFieldValueForLineCommon,
231 		.setValueObject     = setFieldValueForLineCommon,
232 	},
233 	[FIELD_SCOPE - FIELD_ECTAGS_START] = {
234 		.letter				= 's',
235 		.name				= NULL,
236 		.description		= "[tags output] scope (kind:name) of tag definition, [xref and json output] name of scope",
237 		.enabled			= true,
238 		.render				= renderFieldScope,
239 		.renderNoEscaping	= renderFieldScopeNoEscape,
240 		.doesContainAnyChar = doesContainAnyCharInFieldScope,
241 		.isValueAvailable	= NULL,
242 		.dataType			= FIELDTYPE_STRING,
243 	},
244 	[FIELD_TYPE_REF - FIELD_ECTAGS_START] = {
245 		.letter				= 't',
246 		.name				= "typeref",
247 		.description		= "Type and name of a variable or typedef",
248 		.enabled			= true,
249 		.render				= renderFieldTyperef,
250 		.renderNoEscaping	= NULL,
251 		.doesContainAnyChar = NULL,
252 		.isValueAvailable	= isTyperefFieldAvailable,
253 		.dataType			= FIELDTYPE_STRING,
254 		.getterValueType    = "[string string]",
255 		.getValueObject     = getFieldValueForTyperef,
256 		.setterValueType    = "[string string]|string|index:int|false",
257 		.checkValueForSetter= checkFieldValueForTyperef,
258 		.setValueObject     = setFieldValueForTyperef,
259 	},
260 	[FIELD_KIND_KEY - FIELD_ECTAGS_START] = {
261 		.letter				= 'z',
262 		.name				= "kind",
263 		.description		= "[tags output] prepend \"kind:\" to k/ (or K/) field output, [xref and json output] kind in long-name form",
264 		.enabled			= false,
265 		/* Following renderer is for handling --_xformat=%{kind};
266 		   and is not for tags output. */
267 		.render				= renderFieldKindName,
268 		.renderNoEscaping	= NULL,
269 		.doesContainAnyChar = NULL,
270 		.isValueAvailable	= NULL,
271 		.dataType			= FIELDTYPE_STRING,
272 		.getterValueType    = "name",
273 		.getValueObject     = getFieldValueForKind,
274 		.setterValueType    = NULL,
275 		.checkValueForSetter= NULL,
276 		.setValueObject     = NULL,
277 	},
278 	[FIELD_INHERITANCE - FIELD_ECTAGS_START] = {
279 		.letter             = 'i',
280 		.name               = "inherits",
281 		.description        = "Inheritance information",
282 		.enabled            = false,
283 		.render             = renderFieldInherits,
284 		.renderNoEscaping   = NULL,
285 		.doesContainAnyChar = NULL,
286 		.isValueAvailable   = isInheritsFieldAvailable,
287 		.dataType           = FIELDTYPE_STRING|FIELDTYPE_BOOL,
288 		.getterValueType    = NULL,
289 		.getValueObject     = NULL,
290 		.setterValueType    = NULL,
291 		.checkValueForSetter= NULL,
292 		.setValueObject     = setFieldValueForInherits,
293 	},
294 	[FIELD_ACCESS - FIELD_ECTAGS_START] = {
295 		.letter             = 'a',
296 		.name               = "access",
297 		.description        = "Access (or export) of class members",
298 		.enabled            = false,
299 		.render             = renderFieldAccess,
300 		.renderNoEscaping   = NULL,
301 		.doesContainAnyChar = NULL,
302 		.isValueAvailable   = isAccessFieldAvailable,
303 		.dataType           = FIELDTYPE_STRING,
304 		.getterValueType    = NULL,
305 		.getValueObject     = getFieldValueForAccess,
306 		.setterValueType    = NULL,
307 		.checkValueForSetter= NULL,
308 		.setValueObject     = setFieldValueForAccess,
309 	},
310 	[FIELD_IMPLEMENTATION - FIELD_ECTAGS_START] = {
311 		.letter             = 'm',
312 		.name               = "implementation",
313 		.description        = "Implementation information",
314 		.enabled            = false,
315 		.render             = renderFieldImplementation,
316 		.renderNoEscaping   = NULL,
317 		.doesContainAnyChar = NULL,
318 		.isValueAvailable   = isImplementationFieldAvailable,
319 		.dataType           = FIELDTYPE_STRING,
320 
321 	},
322 	[FIELD_SIGNATURE - FIELD_ECTAGS_START] = {
323 		.letter				= 'S',
324 		.name				= "signature",
325 		.description		= "Signature of routine (e.g. prototype or parameter list)",
326 		.enabled			= false,
327 		.render				= renderFieldSignature,
328 		.renderNoEscaping	= renderFieldSignatureNoEscape,
329 		.doesContainAnyChar = doesContainAnyCharInSignature,
330 		.isValueAvailable	= isSignatureFieldAvailable,
331 		.dataType			= FIELDTYPE_STRING,
332 		.getterValueType    = NULL,
333 		.getValueObject     = getFieldValueForSignature,
334 		.setterValueType    = NULL,
335 		.checkValueForSetter= NULL,
336 		.setValueObject     = setFieldValueForSignature,
337 	},
338 };
339 
340 static fieldDefinition fieldDefinitionsUniversal [] = {
341 	[FIELD_REF_MARK - FIELDS_UCTAGS_START] = {
342 		.letter             = 'R',
343 		.name				= NULL,
344 		.description		= "Marker (R or D) representing whether tag is definition or reference",
345 		.enabled			= false,
346 		.render				= renderFieldRefMarker,
347 		.renderNoEscaping	= NULL,
348 		.doesContainAnyChar = NULL,
349 		.isValueAvailable	= NULL,
350 		.dataType			= FIELDTYPE_STRING,
351 	},
352 	[FIELD_SCOPE_KEY - FIELDS_UCTAGS_START] = {
353 		.letter             = 'Z',
354 		.name               = "scope",
355 		.description        = "[tags output] prepend \"scope:\" key to s/scope field output, [xref and json output] the same as s/ field",
356 		.enabled            = false,
357 		/* Following renderer is for handling --_xformat=%{scope};
358 		   and is not for tags output. */
359 		.render             = renderFieldScope,
360 		.renderNoEscaping   = renderFieldScopeNoEscape,
361 		.doesContainAnyChar = doesContainAnyCharInFieldScope,
362 		.isValueAvailable   = NULL,
363 		.dataType           = FIELDTYPE_STRING,
364 		.getterValueType    = "int",
365 		.getValueObject     = getFieldValueForScope,
366 		.setterValueType    = "int",
367 		.checkValueForSetter= checkFieldValueForScope,
368 		.setValueObject     = setFieldValueForScope,
369 	},
370 	[FIELD_SCOPE_KIND_LONG - FIELDS_UCTAGS_START] = {
371 		.letter				= 'p',
372 		.name				= "scopeKind",
373 		.description		= "[tags output] no effect, [xref and json output] kind of scope in long-name form",
374 		.enabled			= false,
375 		.render				= renderFieldScopeKindName,
376 		.renderNoEscaping	= NULL,
377 		.doesContainAnyChar = NULL,
378 		.isValueAvailable	= NULL,
379 		.dataType			= FIELDTYPE_STRING,
380 	},
381 	[FIELD_ROLES - FIELDS_UCTAGS_START] = {
382 		.letter             = 'r',
383 		.name               = "roles",
384 		.description        = "Roles",
385 		.enabled            = false,
386 		.render             = renderFieldRoles,
387 		.renderNoEscaping   = NULL,
388 		.doesContainAnyChar = NULL,
389 		.isValueAvailable   = NULL,
390 		.dataType           = FIELDTYPE_STRING,
391 		.getterValueType    = "[ role1:name ... rolen:name ]",
392 		.getValueObject     = getFieldValueForRoles,
393 		.setterValueType    = NULL,
394 		.checkValueForSetter= NULL,
395 		.setValueObject     = NULL,
396 	},
397 	[FIELD_EXTRAS - FIELDS_UCTAGS_START] = {
398 		.letter				= 'E',
399 		.name				= "extras",
400 		.description		= "Extra tag type information",
401 		.enabled			= false,
402 		.render				= renderFieldExtras,
403 		.renderNoEscaping	= NULL,
404 		.doesContainAnyChar = NULL,
405 		.isValueAvailable	= isExtrasFieldAvailable,
406 		.dataType			= FIELDTYPE_STRING,
407 		.getterValueType    = "[ extra1:name ... extran:name ]",
408 		.getValueObject     = getFieldValueForExtras,
409 		.setterValueType    = NULL,
410 		.checkValueForSetter= NULL,
411 		.setValueObject     = NULL,
412 	},
413 	[FIELD_XPATH - FIELDS_UCTAGS_START] = {
414 		.letter				= 'x',
415 		.name				= "xpath",
416 		.description		= "xpath for the tag",
417 		.enabled			= false,
418 		.render				= renderFieldXpath,
419 		.renderNoEscaping	= NULL,
420 		.doesContainAnyChar = NULL,
421 		.isValueAvailable	= isXpathFieldAvailable,
422 		.dataType			= FIELDTYPE_STRING,
423 	},
424 	[FIELD_END_LINE - FIELDS_UCTAGS_START] = {
425 		.letter				= 'e',
426 		.name				= "end",
427 		.description		= "end lines of various items",
428 		.enabled			= false,
429 		.render				= renderFieldEnd,
430 		.renderNoEscaping	= NULL,
431 		.doesContainAnyChar = NULL,
432 		.isValueAvailable	= isEndFieldAvailable,
433 		.dataType			= FIELDTYPE_INTEGER,
434 		.getterValueType    = "int",
435 		.getValueObject     = getFieldValueForLineCommon,
436 		.setterValueType    = "matchloc|int",
437 		.checkValueForSetter= checkFieldValueForLineCommon,
438 		.setValueObject     = setFieldValueForLineCommon,
439 
440 	},
441 	[FIELD_EPOCH - FIELDS_UCTAGS_START] = {
442 		.letter				= 'T',
443 		.name				= "epoch",
444 		.description		= "the last modified time of the input file (only for F/file kind tag)",
445 		.enabled			= true,
446 		.render				= renderFieldEpoch,
447 		.renderNoEscaping	= NULL,
448 		.doesContainAnyChar = NULL,
449 		.isValueAvailable	= isEpochAvailable,
450 		.dataType			= FIELDTYPE_INTEGER,
451 	},
452 	[FIELD_NTH - FIELDS_UCTAGS_START] = {
453 		.letter				= 'o',
454 		.name				= "nth",
455 		.description		= "the order in the parent scope",
456 		.enabled			= false,
457 		.render				= renderFieldNth,
458 		.renderNoEscaping	= NULL,
459 		.doesContainAnyChar = NULL,
460 		.isValueAvailable	= isNthAvailable,
461 		.dataType			= FIELDTYPE_INTEGER,
462 	},
463 };
464 
465 
466 static unsigned int       fieldObjectUsed = 0;
467 static unsigned int       fieldObjectAllocated = 0;
468 static fieldObject* fieldObjects = NULL;
469 
initFieldObjects(void)470 extern void initFieldObjects (void)
471 {
472 	unsigned int i;
473 	fieldObject *fobj;
474 
475 	Assert (fieldObjects == NULL);
476 
477 	fieldObjectAllocated
478 	  = ARRAY_SIZE (fieldDefinitionsFixed)
479 	  + ARRAY_SIZE (fieldDefinitionsExuberant)
480 	  + ARRAY_SIZE (fieldDefinitionsUniversal);
481 	fieldObjects = xMalloc (fieldObjectAllocated, fieldObject);
482 	DEFAULT_TRASH_BOX(&fieldObjects, eFreeIndirect);
483 
484 	fieldObjectUsed = 0;
485 
486 	for (i = 0; i < ARRAY_SIZE (fieldDefinitionsFixed); i++)
487 	{
488 		fobj = fieldObjects + i + fieldObjectUsed;
489 		fobj->def = fieldDefinitionsFixed + i;
490 		fobj->buffer = NULL;
491 		fobj->nameWithPrefix = fobj->def->name;
492 		fobj->language = LANG_IGNORE;
493 		fobj->sibling  = FIELD_UNKNOWN;
494 		fobj->def->ftype = i + fieldObjectUsed;
495 	}
496 	fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsFixed);
497 
498 	for (i = 0; i < ARRAY_SIZE (fieldDefinitionsExuberant); i++)
499 	{
500 		fobj = fieldObjects + i + fieldObjectUsed;
501 		fobj->def = fieldDefinitionsExuberant +i;
502 		fobj->buffer = NULL;
503 		fobj->nameWithPrefix = fobj->def->name;
504 		fobj->language = LANG_IGNORE;
505 		fobj->sibling  = FIELD_UNKNOWN;
506 		fobj->def->ftype = i + fieldObjectUsed;
507 	}
508 	fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsExuberant);
509 
510 	for (i = 0; i < ARRAY_SIZE (fieldDefinitionsUniversal); i++)
511 	{
512 		char *nameWithPrefix;
513 
514 		fobj = fieldObjects + i + fieldObjectUsed;
515 		fobj->def = fieldDefinitionsUniversal + i;
516 		fobj->buffer = NULL;
517 
518 		if (fobj->def->name)
519 		{
520 			nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (fobj->def->name) + 1);
521 			nameWithPrefix [0] = '\0';
522 			strcat (nameWithPrefix, CTAGS_FIELD_PREFIX);
523 			strcat (nameWithPrefix, fobj->def->name);
524 			fobj->nameWithPrefix = nameWithPrefix;
525 			DEFAULT_TRASH_BOX(nameWithPrefix, eFree);
526 		}
527 		else
528 			fobj->nameWithPrefix = NULL;
529 		fobj->language = LANG_IGNORE;
530 		fobj->sibling  = FIELD_UNKNOWN;
531 		fobj->def->ftype = i + fieldObjectUsed;
532 	}
533 	fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsUniversal);
534 
535 	Assert ( fieldObjectAllocated == fieldObjectUsed );
536 }
537 
getFieldObject(fieldType type)538 static fieldObject* getFieldObject(fieldType type)
539 {
540 	Assert ((0 <= type) && ((unsigned int)type < fieldObjectUsed));
541 	return fieldObjects + type;
542 }
543 
getFieldTypeForOption(char letter)544 extern fieldType getFieldTypeForOption (char letter)
545 {
546 	unsigned int i;
547 
548 	for (i = 0; i < fieldObjectUsed; i++)
549 	{
550 		if (fieldObjects [i].def->letter == letter)
551 			return i;
552 	}
553 	return FIELD_UNKNOWN;
554 }
555 
getFieldTypeForName(const char * name)556 extern fieldType getFieldTypeForName (const char *name)
557 {
558 	return getFieldTypeForNameAndLanguage (name, LANG_IGNORE);
559 }
560 
getFieldTypeForNameAndLanguage(const char * fieldName,langType language)561 extern fieldType getFieldTypeForNameAndLanguage (const char *fieldName, langType language)
562 {
563 	static bool initialized = false;
564 	unsigned int i;
565 
566 	if (fieldName == NULL)
567 		return FIELD_UNKNOWN;
568 
569 	if (language == LANG_AUTO && (initialized == false))
570 	{
571 		initialized = true;
572 		initializeParser (LANG_AUTO);
573 	}
574 	else if (language != LANG_IGNORE && (initialized == false))
575 		initializeParser (language);
576 
577 	for (i = 0; i < fieldObjectUsed; i++)
578 	{
579 		if (fieldObjects [i].def->name
580 		    && strcmp (fieldObjects [i].def->name, fieldName) == 0
581 		    && ((language == LANG_AUTO)
582 			|| (fieldObjects [i].language == language)))
583 			return i;
584 	}
585 
586 	return FIELD_UNKNOWN;
587 }
588 
getFieldDescription(fieldType type)589 extern const char* getFieldDescription (fieldType type)
590 {
591 	fieldObject* fobj;
592 
593 	fobj = getFieldObject (type);
594 	return fobj->def->description;
595 }
596 
getFieldName(fieldType type)597 extern const char* getFieldName(fieldType type)
598 {
599 	fieldObject* fobj;
600 
601 	fobj = getFieldObject (type);
602 	if (Option.putFieldPrefix)
603 		return fobj->nameWithPrefix;
604 	else
605 		return fobj->def->name;
606 }
607 
getFieldLetter(fieldType type)608 extern unsigned char getFieldLetter (fieldType type)
609 {
610 	fieldObject* fobj = getFieldObject (type);
611 
612 	return fobj->def->letter == '\0'
613 		? FIELD_NULL_LETTER_CHAR
614 		: fobj->def->letter;
615 }
616 
doesFieldHaveValue(fieldType type,const tagEntryInfo * tag)617 extern bool doesFieldHaveValue (fieldType type, const tagEntryInfo *tag)
618 {
619 	if (getFieldObject(type)->def->isValueAvailable)
620 		return getFieldObject(type)->def->isValueAvailable(tag);
621 	else
622 		return true;
623 }
624 
renderAsIs(vString * b CTAGS_ATTR_UNUSED,const char * s)625 static const char *renderAsIs (vString* b CTAGS_ATTR_UNUSED, const char *s)
626 {
627 	return s;
628 }
629 
renderEscapedString(const char * s,const tagEntryInfo * const tag CTAGS_ATTR_UNUSED,vString * b)630 static const char *renderEscapedString (const char *s,
631 					const tagEntryInfo *const tag CTAGS_ATTR_UNUSED,
632 					vString* b)
633 {
634 	vStringCatSWithEscaping (b, s);
635 	return vStringValue (b);
636 }
637 
renderEscapedName(const bool isTagName,const char * s,const tagEntryInfo * const tag,vString * b)638 static const char *renderEscapedName (const bool isTagName,
639 				      const char* s,
640 				      const tagEntryInfo *const tag,
641 				      vString* b)
642 {
643 	int unexpected_byte = 0;
644 
645 	if (isTagName && (!tag->isPseudoTag) &&  (*s == ' ' || *s == '!'))
646 	{
647 		/* Don't allow a leading space or exclamation mark as it conflicts with
648 		 * pseudo-tags when sorting.  Anything with a lower byte value is
649 		 * escaped by renderEscapedString() already. */
650 		unexpected_byte = *s;
651 		switch (*s)
652 		{
653 			case ' ': vStringCatS (b, "\\x20"); s++; break;
654 			case '!': vStringCatS (b, "\\x21"); s++; break;
655 			default: AssertNotReached();
656 		}
657 	}
658 	else
659 	{
660 		/* Find the first byte needing escaping for the warning message */
661 		const char *p = s;
662 
663 		while (*p > 0x1F && *p != 0x7F)
664 			p++;
665 		unexpected_byte = *p;
666 	}
667 
668 	if (unexpected_byte)
669 	{
670 		const kindDefinition *kdef = getTagKind (tag);
671 		verbose ("Unexpected character %#04x included in a tagEntryInfo: %s\n", unexpected_byte, s);
672 		verbose ("File: %s, Line: %lu, Lang: %s, Kind: %c\n",
673 			 tag->inputFileName, tag->lineNumber, getLanguageName(tag->langType), kdef->letter);
674 		verbose ("Escape the character\n");
675 	}
676 
677 	return renderEscapedString (s, tag, b);
678 }
679 
renderFieldName(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)680 static const char *renderFieldName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
681 {
682 	return renderEscapedName (true, tag->name, tag, b);
683 }
684 
renderFieldNameNoEscape(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)685 static const char *renderFieldNameNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
686 {
687 	return renderAsIs (b, tag->name);
688 }
689 
doesContainAnyCharInName(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,const char * chars)690 static bool doesContainAnyCharInName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
691 {
692 	return strpbrk (tag->name, chars)? true: false;
693 }
694 
renderFieldInput(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)695 static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
696 {
697 	const char *f = tag->inputFileName;
698 
699 	if (Option.lineDirectives && tag->sourceFileName)
700 		f = tag->sourceFileName;
701 	return renderEscapedString (f, tag, b);
702 }
703 
renderFieldInputNoEscape(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)704 static const char *renderFieldInputNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
705 {
706 	const char *f = tag->inputFileName;
707 
708 	if (Option.lineDirectives && tag->sourceFileName)
709 		f = tag->sourceFileName;
710 
711 	return renderAsIs (b, f);
712 }
713 
doesContainAnyCharInInput(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,const char * chars)714 static bool doesContainAnyCharInInput (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
715 {
716 	const char *f = tag->inputFileName;
717 
718 	if (Option.lineDirectives && tag->sourceFileName)
719 		f = tag->sourceFileName;
720 
721 	return strpbrk (f, chars)? true: false;
722 }
723 
renderFieldSignature(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)724 static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
725 {
726 	return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.signature),
727 				    tag, b);
728 }
729 
renderFieldSignatureNoEscape(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)730 static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
731 {
732 	return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.signature));
733 }
734 
doesContainAnyCharInSignature(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,const char * chars)735 static bool doesContainAnyCharInSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
736 {
737 	return (tag->extensionFields.signature && strpbrk(tag->extensionFields.signature, chars))
738 		? true
739 		: false;
740 }
741 
renderFieldScope(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)742 static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
743 {
744 	const char* scope;
745 
746 	getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
747 	return scope? renderEscapedName (false, scope, tag, b): NULL;
748 }
749 
renderFieldScopeNoEscape(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)750 static const char *renderFieldScopeNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
751 {
752 	const char* scope;
753 
754 	getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
755 	return scope? renderAsIs (b, scope): NULL;
756 }
757 
doesContainAnyCharInFieldScope(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,const char * chars)758 static bool doesContainAnyCharInFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
759 {
760 	const char* scope;
761 
762 	getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
763 	return (scope && strpbrk (scope, chars));
764 }
765 
766 
renderFieldInherits(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)767 static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
768 {
769 	return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.inheritance),
770 				    tag, b);
771 }
772 
renderFieldTyperef(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)773 static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
774 {
775 	/* Return "-" instead of "-:-". */
776 	if (tag->extensionFields.typeRef [0] == NULL
777 		&& tag->extensionFields.typeRef [1] == NULL)
778 		return renderAsIs (b, FIELD_NULL_LETTER_STRING);
779 
780 	vStringCatS (b, WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [0]));
781 	vStringPut  (b, ':');
782 	return renderEscapedName (false, WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [1]), tag, b);
783 }
784 
785 
renderFieldCommon(fieldType type,const tagEntryInfo * tag,int index,bool noEscaping)786 static const char* renderFieldCommon (fieldType type,
787 									  const tagEntryInfo *tag,
788 									  int index,
789 									  bool noEscaping)
790 {
791 	fieldObject *fobj = fieldObjects + type;
792 	const char *value;
793 	fieldRenderer rfn;
794 
795 	Assert (tag);
796 	Assert (index < 0 || ((unsigned int)index) < tag->usedParserFields);
797 
798 	if (index >= 0)
799 	{
800 		const tagField *f = getParserFieldForIndex (tag, index);
801 
802 		value = f->value;
803 	}
804 	else
805 		value = NULL;
806 
807 	if (noEscaping)
808 		rfn = fobj->def->renderNoEscaping;
809 	else
810 		rfn = fobj->def->render;
811 	Assert (rfn);
812 
813 	fobj->buffer = vStringNewOrClearWithAutoRelease (fobj->buffer);
814 	return rfn (tag, value, fobj->buffer);
815 }
816 
renderField(fieldType type,const tagEntryInfo * tag,int index)817 extern const char* renderField (fieldType type, const tagEntryInfo *tag, int index)
818 {
819 	return renderFieldCommon (type, tag, index, false);
820 }
821 
renderFieldNoEscaping(fieldType type,const tagEntryInfo * tag,int index)822 extern const char* renderFieldNoEscaping (fieldType type, const tagEntryInfo *tag, int index)
823 {
824 	return renderFieldCommon (type, tag, index, true);
825 }
826 
defaultDoesContainAnyChar(const tagEntryInfo * const tag CTAGS_ATTR_UNUSED,const char * value,const char * chars)827 static bool defaultDoesContainAnyChar (const tagEntryInfo *const tag CTAGS_ATTR_UNUSED, const char* value, const char* chars)
828 {
829 	return strpbrk (value, chars)? true: false;
830 }
831 
doesFieldHaveTabOrNewlineChar(fieldType type,const tagEntryInfo * tag,int index)832 extern bool  doesFieldHaveTabOrNewlineChar (fieldType type, const tagEntryInfo *tag, int index)
833 {
834 	fieldObject *fobj = fieldObjects + type;
835 	const char *value;
836 	bool (* doesContainAnyChar) (const tagEntryInfo *const, const char*, const char*) = fobj->def->doesContainAnyChar;
837 
838 	Assert (tag);
839 	Assert (index == NO_PARSER_FIELD || ((unsigned int)index) < tag->usedParserFields);
840 
841 	if (doesContainAnyChar == NULL)
842 	{
843 		if (index == NO_PARSER_FIELD)
844 			return false;
845 		else
846 			doesContainAnyChar = defaultDoesContainAnyChar;
847 	}
848 
849 	if (index >= 0)
850 	{
851 		const tagField *f = getParserFieldForIndex (tag, index);
852 
853 		value = f->value;
854 	}
855 	else
856 		value = NULL;
857 
858 	return (* doesContainAnyChar) (tag, value, "\t\n");
859 }
860 
861 /*  Writes "line", stripping leading and duplicate white space.
862  */
renderCompactInputLine(vString * b,const char * const line)863 static const char* renderCompactInputLine (vString *b,  const char *const line)
864 {
865 	bool lineStarted = false;
866 	const char *p;
867 	int c;
868 
869 	/*  Write everything up to, but not including, the newline.
870 	 */
871 	for (p = line, c = *p  ;  c != NEWLINE  &&  c != '\0'  ;  c = *++p)
872 	{
873 		if (lineStarted  || ! isspace (c))  /* ignore leading spaces */
874 		{
875 			lineStarted = true;
876 			if (isspace (c))
877 			{
878 				int next;
879 
880 				/*  Consume repeating white space.
881 				 */
882 				while (next = *(p+1) , isspace (next)  &&  next != NEWLINE)
883 					++p;
884 				c = ' ';  /* force space character for any white space */
885 			}
886 			if (c != CRETURN  ||  *(p + 1) != NEWLINE)
887 				vStringPut (b, c);
888 		}
889 	}
890 	return vStringValue (b);
891 }
892 
renderFieldKindName(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)893 static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
894 {
895 	const char* name = getTagKindName (tag);
896 	return renderAsIs (b, name);
897 }
898 
renderFieldCompactInputLine(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)899 static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag,
900 						const char *value CTAGS_ATTR_UNUSED,
901 						 vString* b)
902 {
903 	const char *line;
904 	static vString *tmp;
905 
906 	if (tag->isPseudoTag)
907 	{
908 		Assert (tag->pattern);
909 		return tag->pattern;
910 	}
911 
912 	tmp = vStringNewOrClearWithAutoRelease (tmp);
913 
914 	line = readLineFromBypassForTag (tmp, tag, NULL);
915 	if (line)
916 		renderCompactInputLine (b, line);
917 	else
918 	{
919 		/* If no associated line for tag is found, we cannot prepare
920 		 * parameter to writeCompactInputLine(). In this case we
921 		 * use an empty string as LINE.
922 		 */
923 		vStringClear (b);
924 	}
925 
926 	return vStringValue (b);
927 }
928 
renderFieldLineNumber(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)929 static const char *renderFieldLineNumber (const tagEntryInfo *const tag,
930 					  const char *value CTAGS_ATTR_UNUSED,
931 					  vString* b)
932 {
933 	long ln = tag->lineNumber;
934 	char buf[32] = {[0] = '\0'};
935 
936 	if (Option.lineDirectives && (tag->sourceLineNumberDifference != 0))
937 		ln += tag->sourceLineNumberDifference;
938 	snprintf (buf, sizeof(buf), "%ld", ln);
939 	vStringCatS (b, buf);
940 	return vStringValue (b);
941 }
942 
943 struct renderRoleData {
944 	vString* b;
945 	int nRoleWritten;
946 };
947 
renderRoleByIndex(const tagEntryInfo * const tag,int roleIndex,void * data)948 static void renderRoleByIndex (const tagEntryInfo *const tag, int roleIndex, void *data)
949 {
950 	struct renderRoleData *rdata = data;
951 
952 	if (!isLanguageRoleEnabled (tag->langType, tag->kindIndex, roleIndex))
953 		return;
954 
955 	if (rdata->nRoleWritten > 0)
956 		vStringPut(rdata->b, ',');
957 
958 	const roleDefinition * role = getTagRole(tag, roleIndex);
959 	renderRole (role, rdata->b);
960 	rdata->nRoleWritten++;
961 }
962 
foreachRoleBits(const tagEntryInfo * const tag,void (* fn)(const tagEntryInfo * const,int,void *),void * data)963 static roleBitsType foreachRoleBits (const tagEntryInfo *const tag,
964 									 void (* fn) (const tagEntryInfo *const, int, void *),
965 									 void *data)
966 {
967 	roleBitsType rbits = tag->extensionFields.roleBits;
968 	if (!rbits)
969 		return rbits;
970 
971 	int roleCount = countLanguageRoles (tag->langType, tag->kindIndex);
972 
973 	for (int roleIndex = 0; roleIndex < roleCount; roleIndex++)
974 	{
975 		if ((rbits >> roleIndex) & (roleBitsType)1)
976 			fn (tag, roleIndex, data);
977 	}
978 	return rbits;
979 }
980 
renderFieldRoles(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)981 static const char *renderFieldRoles (const tagEntryInfo *const tag,
982 				    const char *value CTAGS_ATTR_UNUSED,
983 				    vString* b)
984 {
985 	struct renderRoleData data = { .b = b, .nRoleWritten = 0 };
986 
987 	if (!foreachRoleBits (tag, renderRoleByIndex, &data))
988 		vStringCatS (b, ROLE_DEFINITION_NAME);
989 	return vStringValue (b);
990 }
991 
renderFieldLanguage(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)992 static const char *renderFieldLanguage (const tagEntryInfo *const tag,
993 					const char *value CTAGS_ATTR_UNUSED,
994 					vString* b)
995 {
996 	const char *l;
997 
998 	if (Option.lineDirectives && (tag->sourceLangType != LANG_IGNORE))
999 		l = getLanguageName(tag->sourceLangType);
1000 	else
1001 	{
1002 		Assert (tag->langType != LANG_IGNORE);
1003 		l = getLanguageName(tag->langType);
1004 	}
1005 
1006 	return renderAsIs (b, WITH_DEFUALT_VALUE(l));
1007 }
1008 
renderFieldAccess(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1009 static const char *renderFieldAccess (const tagEntryInfo *const tag,
1010 				      const char *value CTAGS_ATTR_UNUSED,
1011 				      vString* b)
1012 {
1013 	return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.access));
1014 }
1015 
renderFieldKindLetter(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1016 static const char *renderFieldKindLetter (const tagEntryInfo *const tag,
1017 					  const char *value CTAGS_ATTR_UNUSED,
1018 					  vString* b)
1019 {
1020 	static char c[2] = { [1] = '\0' };
1021 
1022 	c [0] = getTagKindLetter(tag);
1023 
1024 	return renderAsIs (b, c);
1025 }
1026 
renderFieldImplementation(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1027 static const char *renderFieldImplementation (const tagEntryInfo *const tag,
1028 					      const char *value CTAGS_ATTR_UNUSED,
1029 					      vString* b)
1030 {
1031 	return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.implementation));
1032 }
1033 
renderFieldFile(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1034 static const char *renderFieldFile (const tagEntryInfo *const tag,
1035 				    const char *value CTAGS_ATTR_UNUSED,
1036 				    vString* b)
1037 {
1038 	return renderAsIs (b, tag->isFileScope? "file": FIELD_NULL_LETTER_STRING);
1039 }
1040 
renderFieldPattern(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1041 static const char *renderFieldPattern (const tagEntryInfo *const tag,
1042 				       const char *value CTAGS_ATTR_UNUSED,
1043 				       vString* b)
1044 {
1045 	if (tag->isFileEntry)
1046 		return NULL;
1047 	else if (tag->pattern)
1048 		vStringCatS (b, tag->pattern);
1049 	else
1050 	{
1051 		char* tmp;
1052 
1053 		tmp = makePatternString (tag);
1054 		vStringCatS (b, tmp);
1055 		eFree (tmp);
1056 	}
1057 	return vStringValue (b);
1058 }
1059 
renderFieldRefMarker(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1060 static const char *renderFieldRefMarker (const tagEntryInfo *const tag,
1061 					 const char *value CTAGS_ATTR_UNUSED,
1062 					 vString* b)
1063 {
1064 	static char c[2] = { [1] = '\0' };
1065 
1066 	c [0] = (tag->extensionFields.roleBits)? 'R': 'D';
1067 
1068 	return renderAsIs (b, c);
1069 }
1070 
renderFieldExtras(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1071 static const char *renderFieldExtras (const tagEntryInfo *const tag,
1072 				     const char *value CTAGS_ATTR_UNUSED,
1073 				     vString* b)
1074 {
1075 	int i;
1076 	bool hasExtra = false;
1077 	int c = countXtags();
1078 
1079 	for (i = 0; i < c; i++)
1080 	{
1081 		const char *name = getXtagName (i);
1082 
1083 		if (!name)
1084 			continue;
1085 
1086 		if (isTagExtraBitMarked (tag, i))
1087 		{
1088 
1089 			if (hasExtra)
1090 				vStringPut (b, ',');
1091 			vStringCatS (b, name);
1092 			hasExtra = true;
1093 		}
1094 	}
1095 
1096 	if (hasExtra)
1097 		return vStringValue (b);
1098 	else
1099 		return NULL;
1100 }
1101 
renderFieldXpath(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1102 static const char *renderFieldXpath (const tagEntryInfo *const tag,
1103 				     const char *value CTAGS_ATTR_UNUSED,
1104 				     vString* b)
1105 {
1106 #ifdef HAVE_LIBXML
1107 	if (tag->extensionFields.xpath)
1108 		return renderEscapedString (tag->extensionFields.xpath,
1109 					    tag, b);
1110 #endif
1111 	return NULL;
1112 }
1113 
renderFieldScopeKindName(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1114 static const char *renderFieldScopeKindName(const tagEntryInfo *const tag,
1115 					    const char *value CTAGS_ATTR_UNUSED,
1116 					    vString* b)
1117 {
1118 	const char* kind;
1119 
1120 	getTagScopeInformation ((tagEntryInfo *const)tag, &kind, NULL);
1121 	return kind? renderAsIs (b, kind): NULL;
1122 }
1123 
renderFieldEnd(const tagEntryInfo * const tag,const char * value CTAGS_ATTR_UNUSED,vString * b)1124 static const char *renderFieldEnd (const tagEntryInfo *const tag,
1125 				   const char *value CTAGS_ATTR_UNUSED,
1126 				   vString* b)
1127 {
1128 	static char buf[21];
1129 
1130 	if (tag->extensionFields.endLine != 0)
1131 	{
1132 		sprintf (buf, "%lu", tag->extensionFields.endLine);
1133 		return renderAsIs (b, buf);
1134 	}
1135 	else
1136 		return NULL;
1137 }
1138 
renderFieldEpoch(const tagEntryInfo * const tag,const char * value,vString * b)1139 static const char *renderFieldEpoch (const tagEntryInfo *const tag,
1140 									  const char *value, vString* b)
1141 {
1142 #define buf_len 21
1143 	static char buf[buf_len];
1144 
1145 	if (snprintf (buf, buf_len, "%lld", (long long)tag->extensionFields.epoch) > 0)
1146 		return renderAsIs (b, buf);
1147 	else
1148 		return NULL;
1149 #undef buf_len
1150 }
1151 
renderFieldNth(const tagEntryInfo * const tag,const char * value,vString * b)1152 static const char *renderFieldNth (const tagEntryInfo *const tag,
1153 								   const char *value, vString* b)
1154 {
1155 #define buf_len 12
1156 	static char buf[buf_len];
1157 
1158 	if (tag->extensionFields.nth > NO_NTH_FIELD
1159 		&& snprintf (buf, buf_len, "%d", (int)tag->extensionFields.nth) > 0)
1160 		return renderAsIs (b, buf);
1161 	else
1162 		return NULL;
1163 #undef buf_len
1164 }
1165 
isTyperefFieldAvailable(const tagEntryInfo * const tag)1166 static bool     isTyperefFieldAvailable  (const tagEntryInfo *const tag)
1167 {
1168 	return (tag->extensionFields.typeRef [0] != NULL
1169 		&& tag->extensionFields.typeRef [1] != NULL)? true: false;
1170 }
1171 
isFileFieldAvailable(const tagEntryInfo * const tag)1172 static bool     isFileFieldAvailable  (const tagEntryInfo *const tag)
1173 {
1174 	return tag->isFileScope? true: false;
1175 }
1176 
isInheritsFieldAvailable(const tagEntryInfo * const tag)1177 static bool     isInheritsFieldAvailable (const tagEntryInfo *const tag)
1178 {
1179 	return (tag->extensionFields.inheritance != NULL)? true: false;
1180 }
1181 
isAccessFieldAvailable(const tagEntryInfo * const tag)1182 static bool     isAccessFieldAvailable   (const tagEntryInfo *const tag)
1183 {
1184 	return (tag->extensionFields.access != NULL)? true: false;
1185 }
1186 
isImplementationFieldAvailable(const tagEntryInfo * const tag)1187 static bool     isImplementationFieldAvailable (const tagEntryInfo *const tag)
1188 {
1189 	return (tag->extensionFields.implementation != NULL)? true: false;
1190 }
1191 
isSignatureFieldAvailable(const tagEntryInfo * const tag)1192 static bool     isSignatureFieldAvailable (const tagEntryInfo *const tag)
1193 {
1194 	return (tag->extensionFields.signature != NULL)? true: false;
1195 }
1196 
isExtrasFieldAvailable(const tagEntryInfo * const tag)1197 static bool     isExtrasFieldAvailable     (const tagEntryInfo *const tag)
1198 {
1199 	unsigned int i;
1200 
1201 	if (tag->extraDynamic)
1202 		return true;
1203 	for (i = 0; i < sizeof (tag->extra); i++)
1204 		if (tag->extra [i])
1205 			return true;
1206 
1207 	return false;
1208 }
1209 
isXpathFieldAvailable(const tagEntryInfo * const tag)1210 static bool     isXpathFieldAvailable      (const tagEntryInfo *const tag)
1211 {
1212 #ifdef HAVE_LIBXML
1213 	return (tag->extensionFields.xpath != NULL)? true: false;
1214 #else
1215 	return false;
1216 #endif
1217 }
1218 
isEndFieldAvailable(const tagEntryInfo * const tag)1219 static bool     isEndFieldAvailable       (const tagEntryInfo *const tag)
1220 {
1221 	return (tag->extensionFields.endLine != 0)? true: false;
1222 }
1223 
isEpochAvailable(const tagEntryInfo * const tag)1224 static bool isEpochAvailable (const tagEntryInfo *const tag)
1225 {
1226 	return (tag->kindIndex == KIND_FILE_INDEX)
1227 		? true
1228 		: false;
1229 }
1230 
isNthAvailable(const tagEntryInfo * const tag)1231 static bool isNthAvailable (const tagEntryInfo *const tag)
1232 {
1233 	Assert (tag->langType >= NO_NTH_FIELD);
1234 	return (tag->extensionFields.nth != NO_NTH_FIELD)? true: false;
1235 }
1236 
isFieldEnabled(fieldType type)1237 extern bool isFieldEnabled (fieldType type)
1238 {
1239 	return getFieldObject(type)->def->enabled;
1240 }
1241 
enableField(fieldType type,bool state)1242 extern bool enableField (fieldType type, bool state)
1243 {
1244 	fieldDefinition *def = getFieldObject(type)->def;
1245 	bool old = def->enabled;
1246 	getFieldObject(type)->def->enabled = state;
1247 
1248 	if (isCommonField (type))
1249 		verbose ("enable field \"%s\": %s\n",
1250 				 getFieldObject(type)->def->name,
1251 				 (state? "yes": "no"));
1252 	else
1253 		verbose ("enable field \"%s\"<%s>: %s\n",
1254 				 getFieldObject(type)->def->name,
1255 				 getLanguageName (getFieldOwner(type)),
1256 				 (state? "yes": "no"));
1257 	return old;
1258 }
1259 
isCommonField(fieldType type)1260 extern bool isCommonField (fieldType type)
1261 {
1262 	return (FIELD_BUILTIN_LAST < type)? false: true;
1263 }
1264 
getFieldOwner(fieldType type)1265 extern int     getFieldOwner (fieldType type)
1266 {
1267 	return getFieldObject(type)->language;
1268 }
1269 
getFieldDataType(fieldType type)1270 extern unsigned int getFieldDataType (fieldType type)
1271 {
1272 	return getFieldObject(type)->def->dataType;
1273 }
1274 
isFieldValueAvailableAlways(fieldType type)1275 extern bool isFieldValueAvailableAlways (fieldType type)
1276 {
1277 	return getFieldObject(type)->def->isValueAvailable == NULL;
1278 }
1279 
doesFieldHaveRenderer(fieldType type,bool noEscaping)1280 extern bool doesFieldHaveRenderer (fieldType type, bool noEscaping)
1281 {
1282 	if (noEscaping)
1283 		return getFieldObject(type)->def->renderNoEscaping? true: false;
1284 	else
1285 		return getFieldObject(type)->def->render? true: false;
1286 }
1287 
countFields(void)1288 extern int countFields (void)
1289 {
1290 	return fieldObjectUsed;
1291 }
1292 
nextSiblingField(fieldType type)1293 extern fieldType nextSiblingField (fieldType type)
1294 {
1295 	fieldObject *fobj;
1296 
1297 	fobj = fieldObjects + type;
1298 	return fobj->sibling;
1299 }
1300 
updateSiblingField(fieldType type,const char * name)1301 static void updateSiblingField (fieldType type, const char* name)
1302 {
1303 	int i;
1304 	fieldObject *fobj;
1305 
1306 	for (i = type; i > 0; i--)
1307 	{
1308 		fobj = fieldObjects + i - 1;
1309 		if (fobj->def->name && (strcmp (fobj->def->name, name) == 0))
1310 		{
1311 			Assert (fobj->sibling == FIELD_UNKNOWN);
1312 			fobj->sibling = type;
1313 			break;
1314 		}
1315 	}
1316 }
1317 
defaultRenderer(const tagEntryInfo * const tag CTAGS_ATTR_UNUSED,const char * value,vString * buffer CTAGS_ATTR_UNUSED)1318 static const char* defaultRenderer (const tagEntryInfo *const tag CTAGS_ATTR_UNUSED,
1319 				    const char *value,
1320 				    vString * buffer CTAGS_ATTR_UNUSED)
1321 {
1322 	return renderEscapedString (value, tag, buffer);
1323 }
1324 
defineField(fieldDefinition * def,langType language)1325 extern int defineField (fieldDefinition *def, langType language)
1326 {
1327 	fieldObject *fobj;
1328 	char *nameWithPrefix;
1329 	size_t i;
1330 
1331 	Assert (def);
1332 	Assert (def->name);
1333 	for (i = 0; i < strlen (def->name); i++)
1334 	{
1335 		Assert ( isalpha (def->name [i]) );
1336 	}
1337 	def->letter = NUL_FIELD_LETTER;
1338 
1339 	if (fieldObjectUsed == fieldObjectAllocated)
1340 	{
1341 		fieldObjectAllocated *= 2;
1342 		fieldObjects = xRealloc (fieldObjects, fieldObjectAllocated, fieldObject);
1343 	}
1344 	fobj = fieldObjects + (fieldObjectUsed);
1345 	def->ftype = fieldObjectUsed++;
1346 
1347 	if (def->render == NULL)
1348 	{
1349 		def->render = defaultRenderer;
1350 		def->renderNoEscaping = NULL;
1351 		def->doesContainAnyChar = NULL;
1352 	}
1353 
1354 	if (! def->dataType)
1355 		def->dataType = FIELDTYPE_STRING;
1356 
1357 	fobj->def = def;
1358 
1359 	fobj->buffer = NULL;
1360 
1361 	nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (def->name) + 1);
1362 	nameWithPrefix [0] = '\0';
1363 	strcat (nameWithPrefix, CTAGS_FIELD_PREFIX);
1364 	strcat (nameWithPrefix, def->name);
1365 	fobj->nameWithPrefix = nameWithPrefix;
1366 	DEFAULT_TRASH_BOX(nameWithPrefix, eFree);
1367 
1368 	fobj->language = language;
1369 	fobj->sibling  = FIELD_UNKNOWN;
1370 
1371 	updateSiblingField (def->ftype, def->name);
1372 	return def->ftype;
1373 }
1374 
1375 #define FIELD_COL_LETTER      0
1376 #define FIELD_COL_NAME        1
1377 #define FIELD_COL_ENABLED     2
1378 #define FIELD_COL_LANGUAGE    3
1379 #define FIELD_COL_JSTYPE      4
1380 #define FIELD_COL_FIXED       5
1381 #define FIELD_COL_OPERATOR    6
1382 #define FIELD_COL_DESCRIPTION 7
1383 
fieldColprintTableNew(void)1384 extern struct colprintTable * fieldColprintTableNew (void)
1385 {
1386 	return colprintTableNew ("L:LETTER", "L:NAME", "L:ENABLED",
1387 							 "L:LANGUAGE", "L:JSTYPE", "L:FIXED",
1388 							 "L:OP", "L:DESCRIPTION", NULL);
1389 }
1390 
fieldColprintAddLine(struct colprintTable * table,int i)1391 static void  fieldColprintAddLine (struct colprintTable *table, int i)
1392 {
1393 	fieldObject *fobj = getFieldObject(i);
1394 	fieldDefinition *fdef = fobj->def;
1395 
1396 	struct colprintLine *line = colprintTableGetNewLine(table);
1397 
1398 	colprintLineAppendColumnChar (line,
1399 								  (fdef->letter == NUL_FIELD_LETTER)
1400 								  ? FIELD_NULL_LETTER_CHAR
1401 								  : fdef->letter);
1402 
1403 	const char *name = getFieldName (i);
1404 	colprintLineAppendColumnCString (line, name? name: RSV_NONE);
1405 	colprintLineAppendColumnBool (line, fdef->enabled);
1406 	colprintLineAppendColumnCString (line,
1407 									 fobj->language == LANG_IGNORE
1408 									 ? RSV_NONE
1409 									 : getLanguageName (fobj->language));
1410 
1411 	char  typefields [] = "---";
1412 	{
1413 		unsigned int bmask, offset;
1414 		unsigned int type = getFieldDataType(i);
1415 		for (bmask = 1, offset = 0;
1416 			 bmask < FIELDTYPE_END_MARKER;
1417 			 bmask <<= 1, offset++)
1418 			if (type & bmask)
1419 				typefields[offset] = fieldDataTypeFalgs[offset];
1420 	}
1421 	colprintLineAppendColumnCString (line, typefields);
1422 	colprintLineAppendColumnBool (line, writerDoesTreatFieldAsFixed (i));
1423 
1424 	char operator[] = {'-', '-', '\0'};
1425 	if (fdef->getValueObject)
1426 		operator[0] = 'r';
1427 	if (fdef->setValueObject)
1428 		operator[1] = 'w';
1429 	colprintLineAppendColumnCString (line, operator);
1430 	colprintLineAppendColumnCString (line, fdef->description);
1431 }
1432 
fieldColprintAddCommonLines(struct colprintTable * table)1433 extern void fieldColprintAddCommonLines (struct colprintTable *table)
1434 {
1435 	for (int i = 0; i <= FIELD_BUILTIN_LAST; i++)
1436 		fieldColprintAddLine(table, i);
1437 }
1438 
fieldColprintAddLanguageLines(struct colprintTable * table,langType language)1439 extern void fieldColprintAddLanguageLines (struct colprintTable *table, langType language)
1440 {
1441 	for (unsigned int i = FIELD_BUILTIN_LAST + 1; i < fieldObjectUsed; i++)
1442 	{
1443 		fieldObject *fobj = getFieldObject(i);
1444 		if (fobj->language == language)
1445 			fieldColprintAddLine (table, i);
1446 	}
1447 }
1448 
fieldColprintCompareLines(struct colprintLine * a,struct colprintLine * b)1449 static int fieldColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
1450 {
1451 	const char *a_fixed  = colprintLineGetColumn (a, FIELD_COL_FIXED);
1452 	const char *b_fixed  = colprintLineGetColumn (b, FIELD_COL_FIXED);
1453 	const char *a_parser = colprintLineGetColumn (a, FIELD_COL_LANGUAGE);
1454 	const char *b_parser = colprintLineGetColumn (b, FIELD_COL_LANGUAGE);
1455 
1456 	if ((strcmp (a_fixed, "yes") == 0)
1457 		&& (strcmp (b_fixed, "yes") == 0))
1458 	{
1459 		/* name, input, pattern, compact */
1460 		const char *a_name  = colprintLineGetColumn (a, FIELD_COL_NAME);
1461 		const char *b_name  = colprintLineGetColumn (b, FIELD_COL_NAME);
1462 		const char *ref_name;
1463 		unsigned int a_index = ~0U;
1464 		unsigned int b_index = ~0U;
1465 
1466 		for (unsigned int i = 0; i < ARRAY_SIZE(fieldDefinitionsFixed); i++)
1467 		{
1468 			ref_name = fieldDefinitionsFixed [i].name;
1469 			if (strcmp (a_name, ref_name) == 0)
1470 				a_index = i;
1471 			if (strcmp (b_name, ref_name) == 0)
1472 				b_index = i;
1473 			if ((a_index != ~0U) || (b_index != ~0U))
1474 				break;
1475 		}
1476 
1477 		if (a_index < b_index)
1478 			return -1;
1479 		else if (a_index == b_index)
1480 			return 0;			/* ??? */
1481 		else
1482 			return 1;
1483 	}
1484 	else if ((strcmp (a_fixed, "yes") == 0)
1485 			  && (strcmp (b_fixed, "yes") != 0))
1486 		return -1;
1487 	else if ((strcmp (a_fixed, "yes") != 0)
1488 			 && (strcmp (b_fixed, "yes") == 0))
1489 		return 1;
1490 
1491 	if (strcmp (a_parser, RSV_NONE) == 0
1492 		&& strcmp (b_parser, RSV_NONE) != 0)
1493 		return -1;
1494 	else if (strcmp (a_parser, RSV_NONE) != 0
1495 			 && strcmp (b_parser, RSV_NONE) == 0)
1496 		return 1;
1497 	else if (strcmp (a_parser, RSV_NONE) != 0
1498 			 && strcmp (b_parser, RSV_NONE) != 0)
1499 	{
1500 		int r;
1501 		r = strcmp (a_parser, b_parser);
1502 		if (r != 0)
1503 			return r;
1504 
1505 		const char *a_name = colprintLineGetColumn (a, FIELD_COL_NAME);
1506 		const char *b_name = colprintLineGetColumn (b, FIELD_COL_NAME);
1507 
1508 		return strcmp(a_name, b_name);
1509 	}
1510 	else
1511 	{
1512 		const char *a_letter = colprintLineGetColumn (a, FIELD_COL_LETTER);
1513 		const char *b_letter = colprintLineGetColumn (b, FIELD_COL_LETTER);
1514 
1515 		return strcmp(a_letter, b_letter);
1516 	}
1517 }
1518 
fieldColprintTablePrint(struct colprintTable * table,bool withListHeader,bool machinable,FILE * fp)1519 extern void fieldColprintTablePrint (struct colprintTable *table,
1520 									 bool withListHeader, bool machinable, FILE *fp)
1521 {
1522 	colprintTableSort (table, fieldColprintCompareLines);
1523 	colprintTablePrint (table, 0, withListHeader, machinable, fp);
1524 }
1525 
getFieldGetterValueType(fieldType type)1526 extern const char * getFieldGetterValueType (fieldType type)
1527 {
1528 	fieldObject *fobj = getFieldObject (type);
1529 	return (fobj? fobj->def->getterValueType: NULL);
1530 }
1531 
getFieldValue(fieldType type,const tagEntryInfo * tag)1532 extern EsObject * getFieldValue (fieldType type, const tagEntryInfo *tag)
1533 {
1534 	fieldObject* fobj;
1535 
1536 	fobj = getFieldObject (type);
1537 	if (fobj && fobj->def->getValueObject)
1538 		return fobj->def->getValueObject (tag, fobj->def);
1539 	return es_nil;
1540 }
1541 
hasFieldGetter(fieldType type)1542 extern bool hasFieldGetter (fieldType type)
1543 {
1544 	fieldObject *fobj = getFieldObject (type);
1545 	return (fobj && fobj->def->getValueObject);
1546 }
1547 
getFieldSetterValueType(fieldType type)1548 extern const char * getFieldSetterValueType (fieldType type)
1549 {
1550 	fieldObject *fobj = getFieldObject (type);
1551 	return (fobj? fobj->def->setterValueType: NULL);
1552 }
1553 
setFieldValue(fieldType type,tagEntryInfo * tag,const EsObject * val)1554 extern EsObject * setFieldValue (fieldType type, tagEntryInfo *tag, const EsObject *val)
1555 {
1556 	fieldObject *fobj;
1557 
1558 	fobj = getFieldObject (type);
1559 	if (fobj && fobj->def->setValueObject)
1560 		return fobj->def->setValueObject (tag, fobj->def, val);
1561 	return es_false;
1562 }
1563 
hasFieldSetter(fieldType type)1564 extern bool hasFieldSetter (fieldType type)
1565 {
1566 	fieldObject *fobj = getFieldObject (type);
1567 	return (fobj && fobj->def->setValueObject);
1568 }
1569 
1570 
hasFieldValueCheckerForSetter(fieldType type)1571 extern bool hasFieldValueCheckerForSetter (fieldType type)
1572 {
1573 	fieldObject *fobj = getFieldObject (type);
1574 	return (fobj && fobj->def->checkValueForSetter);
1575 }
1576 
checkFieldValueForSetter(fieldType type,const EsObject * val)1577 extern EsObject* checkFieldValueForSetter (fieldType type, const EsObject *val)
1578 {
1579 	fieldObject *fobj = getFieldObject (type);
1580 	return fobj->def->checkValueForSetter (fobj->def, val);
1581 }
1582 
getFieldValueForName(const tagEntryInfo * tag,const fieldDefinition * fdef)1583 static EsObject* getFieldValueForName (const tagEntryInfo *tag, const fieldDefinition *fdef)
1584 {
1585 	return opt_string_new_from_cstr (tag->name);
1586 }
1587 
setFieldValueForName(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * val)1588 static EsObject* setFieldValueForName (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *val)
1589 {
1590 	eFree ((char*) tag->name);
1591 	const char *cstr = opt_string_get_cstr (val);
1592 	tag->name = eStrdup (cstr);
1593 	return es_false;
1594 }
1595 
getFieldValueForInput(const tagEntryInfo * tag,const fieldDefinition * fdef)1596 static EsObject* getFieldValueForInput (const tagEntryInfo *tag, const fieldDefinition *fdef)
1597 {
1598 	return opt_string_new_from_cstr (tag->inputFileName);
1599 }
1600 
getFieldValueForKind(const tagEntryInfo * tag,const fieldDefinition * fdef)1601 static EsObject* getFieldValueForKind (const tagEntryInfo *tag, const fieldDefinition *fdef)
1602 {
1603 	const char *kind_name = getLanguageKindName (tag->langType, tag->kindIndex);
1604 	return opt_name_new_from_cstr (kind_name);
1605 }
1606 
getFieldValueForTyperef(const tagEntryInfo * tag,const fieldDefinition * fdef)1607 static EsObject* getFieldValueForTyperef (const tagEntryInfo *tag, const fieldDefinition *fdef)
1608 {
1609 	if (tag->extensionFields.typeRef [0] == NULL
1610 		&& tag->extensionFields.typeRef [1] == NULL)
1611 		return es_nil;
1612 
1613 	EsObject *a = opt_array_new ();
1614 	EsObject *e0 = tag->extensionFields.typeRef [0]
1615 		? opt_string_new_from_cstr(tag->extensionFields.typeRef [0])
1616 		: es_false;
1617 	EsObject *e1 = tag->extensionFields.typeRef [1]
1618 		? opt_string_new_from_cstr(tag->extensionFields.typeRef [1])
1619 		: es_false;
1620 	opt_array_put (a, 0, e0);
1621 	opt_array_put (a, 1, e1);
1622 	es_object_unref (e0);
1623 	es_object_unref (e1);
1624 	return a;
1625 }
1626 
setFieldValueForTyperef(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1627 static EsObject* setFieldValueForTyperef (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1628 {
1629 	const char *tmp[2] = {NULL, NULL};
1630 
1631 	for (int i = 0 ; i < 2; i++)
1632 	{
1633 		if (tag->extensionFields.typeRef [i])
1634 			tmp [i] = tag->extensionFields.typeRef [i];
1635 	}
1636 
1637 	if (es_boolean_p (obj))
1638 	{
1639 		for (int i = 0 ; i < 2; i++)
1640 		{
1641 			if (tag->extensionFields.typeRef [i])
1642 				tag->extensionFields.typeRef [i] = NULL;
1643 		}
1644 	}
1645 	else if (es_object_get_type (obj) == OPT_TYPE_ARRAY)
1646 	{
1647 		for (int i = 0 ; i < 2; i++)
1648 		{
1649 			EsObject *e = opt_array_get (obj, i);
1650 			if (es_boolean_p (e))
1651 			{
1652 				if (tag->extensionFields.typeRef [i])
1653 					tag->extensionFields.typeRef [i] = NULL;
1654 			}
1655 			else if (es_object_get_type (e) == OPT_TYPE_STRING)
1656 			{
1657 				tag->extensionFields.typeRef [i] = eStrdup (opt_string_get_cstr (e));
1658 			}
1659 		}
1660 	}
1661 	else if (es_object_get_type (obj) == OPT_TYPE_STRING)
1662 	{
1663 		const char *str = opt_string_get_cstr (obj);
1664 		tag->extensionFields.typeRef [0] = eStrdup ("typename");
1665 		tag->extensionFields.typeRef [1] = eStrdup (str);
1666 	}
1667 	else if (es_integer_p (obj))
1668 	{
1669 		int index = es_integer_get (obj);
1670 		tagEntryInfo *e = getEntryInCorkQueue (index);
1671 		if (e)
1672 		{
1673 			const char *name = e->name;
1674 			const char *kindName = getLanguageKindName (e->langType, e->kindIndex);
1675 
1676 			tag->extensionFields.typeRef [0] = eStrdup (kindName);
1677 			tag->extensionFields.typeRef [1] = eStrdup (name);
1678 		}
1679 	}
1680 	else
1681 	{
1682 		AssertNotReached();
1683 		return OPT_ERR_TYPECHECK;
1684 	}
1685 
1686 	for (int i = 0; i < 2; i++)
1687 		if (tmp [i])
1688 			eFree ((char*)tmp[i]);
1689 
1690 	return es_false;
1691 }
1692 
checkFieldValueForTyperef(const fieldDefinition * fdef,const EsObject * obj)1693 static EsObject* checkFieldValueForTyperef (const fieldDefinition *fdef, const EsObject *obj)
1694 {
1695 	if (es_boolean_p (obj))
1696 	{
1697 		if (!es_object_equal (es_false, obj))
1698 			return OPT_ERR_TYPECHECK;
1699 	}
1700 	else if (es_object_get_type (obj) == OPT_TYPE_ARRAY)
1701 	{
1702 		if (opt_array_length (obj) != 2)
1703 			return OPT_ERR_TYPECHECK;
1704 
1705 		for (unsigned int i = 0; i < 2; i++)
1706 		{
1707 			EsObject *e = opt_array_get (obj, i);
1708 			if (es_object_get_type (e) != OPT_TYPE_STRING)
1709 				return OPT_ERR_TYPECHECK;
1710 		}
1711 	}
1712 	else if (es_object_get_type (obj) == OPT_TYPE_STRING)
1713 		;
1714 	else if (es_integer_p (obj))
1715 	{
1716 		int index = es_integer_get (obj);
1717 		if (index >= countEntryInCorkQueue ())
1718 			return OPTSCRIPT_ERR_NOTAGENTRY;
1719 	}
1720 	else
1721 		return OPT_ERR_TYPECHECK;
1722 	return es_false;
1723 }
1724 
getFieldValueForScope(const tagEntryInfo * tag,const fieldDefinition * fdef)1725 static EsObject* getFieldValueForScope (const tagEntryInfo *tag, const fieldDefinition *fdef)
1726 {
1727 	return es_integer_new (tag->extensionFields.scopeIndex);
1728 }
1729 
setFieldValueForScope(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1730 static EsObject* setFieldValueForScope (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1731 {
1732 	int index = es_integer_get (obj);
1733 	if (index < countEntryInCorkQueue ())
1734 	{
1735 		tag->extensionFields.scopeIndex = index;
1736 		return es_false;
1737 	}
1738 
1739 	return OPTSCRIPT_ERR_NOTAGENTRY;
1740 }
1741 
checkFieldValueForScope(const fieldDefinition * fdef,const EsObject * obj)1742 static EsObject* checkFieldValueForScope (const fieldDefinition *fdef, const EsObject *obj)
1743 {
1744 	if (!es_integer_p (obj))
1745 		return OPT_ERR_TYPECHECK;
1746 
1747 	if (es_integer_get (obj) < 0)
1748 		return OPT_ERR_RANGECHECK;
1749 
1750 	return es_false;
1751 }
1752 
getFieldValueForExtras(const tagEntryInfo * tag,const fieldDefinition * fdef)1753 static EsObject* getFieldValueForExtras (const tagEntryInfo *tag, const fieldDefinition *fdef)
1754 {
1755 	if (!isTagExtra (tag))
1756 		return es_nil;
1757 
1758 	EsObject* a = opt_array_new ();
1759 
1760 	for (int i = 0; i < countXtags (); i++)
1761 	{
1762 		if (!isTagExtraBitMarked (tag, i))
1763 			continue;
1764 
1765 		langType lang = getXtagOwner (i);
1766 		const char *lang_name = (lang == LANG_IGNORE)
1767 			? NULL
1768 			: getLanguageName (lang);
1769 		const char *extra_name = getXtagName (i);
1770 
1771 		EsObject *extra;
1772 		if (lang_name == NULL)
1773 			extra = opt_name_new_from_cstr (extra_name);
1774 		else
1775 		{
1776 			vString *tmp = vStringNewInit (lang_name);
1777 			vStringPut (tmp, '.');
1778 			vStringCatS (tmp, extra_name);
1779 			extra = opt_name_new_from_cstr (vStringValue (tmp));
1780 			vStringDelete (tmp);
1781 		}
1782 		opt_array_add (a, extra);
1783 		es_object_unref (extra);
1784 	}
1785 	return a;
1786 }
1787 
getFieldValueForCOMMON(const char * field,const tagEntryInfo * tag,const fieldDefinition * fdef)1788 static EsObject* getFieldValueForCOMMON (const char *field, const tagEntryInfo *tag, const fieldDefinition *fdef)
1789 {
1790 	if (!field)
1791 		return es_nil;
1792 	return (opt_name_new_from_cstr (field));
1793 }
1794 
setFieldValueForCOMMON(const char ** field,tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1795 static EsObject* setFieldValueForCOMMON (const char **field, tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1796 {
1797 	if (*field)
1798 		eFree ((char *)*field);
1799 
1800 	const char *str = opt_string_get_cstr (obj);
1801 	*field = eStrdup (str);
1802 	return es_false;
1803 }
1804 
getFieldValueForAccess(const tagEntryInfo * tag,const fieldDefinition * fdef)1805 static EsObject* getFieldValueForAccess (const tagEntryInfo *tag, const fieldDefinition *fdef)
1806 {
1807 	return getFieldValueForCOMMON(tag->extensionFields.access, tag, fdef);
1808 }
1809 
setFieldValueForAccess(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1810 static EsObject* setFieldValueForAccess (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1811 {
1812 	return setFieldValueForCOMMON(&tag->extensionFields.access, tag, fdef, obj);
1813 }
1814 
getFieldValueForSignature(const tagEntryInfo * tag,const fieldDefinition * fdef)1815 static EsObject* getFieldValueForSignature (const tagEntryInfo *tag, const fieldDefinition *fdef)
1816 {
1817 	return getFieldValueForCOMMON(tag->extensionFields.signature, tag, fdef);
1818 }
1819 
setFieldValueForSignature(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1820 static EsObject* setFieldValueForSignature (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1821 {
1822 	return setFieldValueForCOMMON(&tag->extensionFields.signature, tag, fdef, obj);
1823 }
1824 
makeRolesArray(const tagEntryInfo * const tag,int roleIndex,void * data)1825 static void makeRolesArray (const tagEntryInfo *const tag, int roleIndex, void *data)
1826 {
1827 	EsObject *a = data;
1828 
1829 	const roleDefinition *role = getTagRole (tag, roleIndex);
1830 	EsObject *r = opt_name_new_from_cstr (role->name);
1831 	opt_array_add (a, r);
1832 	es_object_unref (r);
1833 }
1834 
getFieldValueForRoles(const tagEntryInfo * tag,const fieldDefinition * fdef)1835 static EsObject* getFieldValueForRoles (const tagEntryInfo *tag, const fieldDefinition *fdef)
1836 {
1837 	EsObject *a = opt_array_new ();
1838 
1839 	if (!foreachRoleBits (tag, makeRolesArray, a))
1840 	{
1841 		EsObject *r = opt_name_new_from_cstr (ROLE_DEFINITION_NAME);
1842 		opt_array_add (a, r);
1843 		es_object_unref (r);
1844 	}
1845 	return a;
1846 }
1847 
getFieldValueForLineCommon(const tagEntryInfo * tag,const fieldDefinition * fdef)1848 static EsObject* getFieldValueForLineCommon (const tagEntryInfo *tag, const fieldDefinition *fdef)
1849 {
1850 	if (fdef->ftype == FIELD_END_LINE)
1851 		return ((int)tag->extensionFields.endLine == 0)
1852 			? es_nil
1853 			: es_integer_new ((int)tag->extensionFields.endLine);
1854 	else
1855 		return ((int)tag->lineNumber == 0)
1856 			? es_nil
1857 			: es_integer_new ((int)tag->lineNumber);
1858 }
1859 
checkFieldValueForLineCommon(const fieldDefinition * fdef,const EsObject * obj)1860 static EsObject* checkFieldValueForLineCommon (const fieldDefinition *fdef, const EsObject *obj)
1861 {
1862 	return es_false;
1863 }
1864 
setFieldValueForLineCommon(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1865 static EsObject* setFieldValueForLineCommon (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1866 {
1867 	int l;
1868 	if (es_object_get_type (obj) == OPT_TYPE_MATCHLOC)
1869 	{
1870 		matchLoc *loc = es_pointer_get (obj);
1871 		l = loc->line;
1872 	}
1873 	else if (es_integer_p (obj))
1874 	{
1875 		l = es_integer_get (obj);
1876 		if (l < 1)
1877 			return OPT_ERR_RANGECHECK;
1878 
1879 		/* If the new line number is too large,
1880 		   we cannot fill tag->filePosition wit
1881 		   getInputFilePositionForLine(); */
1882 		if (fdef->ftype == FIELD_LINE_NUMBER
1883 			&& l < getInputLineNumber())
1884 			return OPT_ERR_RANGECHECK;
1885 	}
1886 	else
1887 		return OPT_ERR_TYPECHECK;
1888 
1889 	if (fdef->ftype == FIELD_END_LINE)
1890 		tag->extensionFields.endLine = l;
1891 	else
1892 	{
1893 		tag->lineNumber = l;
1894 		tag->filePosition = getInputFilePositionForLine (l);
1895 	}
1896 
1897 	return es_false;
1898 }
1899 
setFieldValueForInherits(tagEntryInfo * tag,const fieldDefinition * fdef,const EsObject * obj)1900 static EsObject* setFieldValueForInherits (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj)
1901 {
1902 	if (es_object_get_type (obj) == OPT_TYPE_STRING)
1903 	{
1904 		if (tag->extensionFields.inheritance)
1905 			eFree ((void *)tag->extensionFields.inheritance);
1906 		const char *str = opt_string_get_cstr (obj);
1907 		tag->extensionFields.inheritance = eStrdup (str);
1908 	}
1909 	else if (es_object_equal (es_false, obj))
1910 	{
1911 		if (tag->extensionFields.inheritance)
1912 		{
1913 			eFree ((void *)tag->extensionFields.inheritance);
1914 			tag->extensionFields.inheritance = NULL;
1915 		}
1916 	}
1917 	else
1918 		return OPT_ERR_RANGECHECK; /* true is not acceptable. */
1919 
1920 	return es_false;
1921 }
1922