Update to latest ctags main
[geany-mirror.git] / ctags / main / field.c
blob22a97d01a5e1837d10e9c43c3d71d129e8518cce
1 /*
3 * Copyright (c) 2015, Red Hat, Inc.
4 * Copyright (c) 2015, Masatake YAMATO
6 * Author: Masatake YAMATO <yamato@redhat.com>
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.
13 #include "general.h" /* must always come first */
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
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"
34 #define FIELD_NULL_LETTER_CHAR '-'
35 #define FIELD_NULL_LETTER_STRING "-"
37 typedef struct sFieldObject {
38 fieldDefinition *def;
39 vString *buffer;
40 const char* nameWithPrefix;
41 langType language;
42 fieldType sibling;
43 } fieldObject;
45 static const char *renderFieldName (const tagEntryInfo *const tag, const char *value, vString* b);
46 static const char *renderFieldNameNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b);
47 static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value, vString* b);
48 static const char *renderFieldInputNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
49 static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag, const char *value, vString* b);
50 static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value, vString* b);
51 static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
52 static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value, vString* b);
53 static const char *renderFieldScopeNoEscape (const tagEntryInfo *const tag, const char *value, vString* b);
54 static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value, vString* b);
55 static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value, vString* b);
56 static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value, vString* b);
57 static const char *renderFieldLineNumber (const tagEntryInfo *const tag, const char *value, vString* b);
58 static const char *renderFieldLanguage (const tagEntryInfo *const tag, const char *value, vString* b);
59 static const char *renderFieldAccess (const tagEntryInfo *const tag, const char *value, vString* b);
60 static const char *renderFieldKindLetter (const tagEntryInfo *const tag, const char *value, vString* b);
61 static const char *renderFieldImplementation (const tagEntryInfo *const tag, const char *value, vString* b);
62 static const char *renderFieldFile (const tagEntryInfo *const tag, const char *value, vString* b);
63 static const char *renderFieldPattern (const tagEntryInfo *const tag, const char *value, vString* b);
64 static const char *renderFieldRoles (const tagEntryInfo *const tag, const char *value, vString* b);
65 static const char *renderFieldRefMarker (const tagEntryInfo *const tag, const char *value, vString* b);
66 static const char *renderFieldExtras (const tagEntryInfo *const tag, const char *value, vString* b);
67 static const char *renderFieldXpath (const tagEntryInfo *const tag, const char *value, vString* b);
68 static const char *renderFieldScopeKindName(const tagEntryInfo *const tag, const char *value, vString* b);
69 static const char *renderFieldEnd (const tagEntryInfo *const tag, const char *value, vString* b);
71 static bool doesContainAnyCharInName (const tagEntryInfo *const tag, const char *value, const char *chars);
72 static bool doesContainAnyCharInInput (const tagEntryInfo *const tag, const char*value, const char *chars);
73 static bool doesContainAnyCharInFieldScope (const tagEntryInfo *const tag, const char *value, const char *chars);
74 static bool doesContainAnyCharInSignature (const tagEntryInfo *const tag, const char *value, const char *chars);
76 static bool isLanguageFieldAvailable (const tagEntryInfo *const tag);
77 static bool isTyperefFieldAvailable (const tagEntryInfo *const tag);
78 static bool isFileFieldAvailable (const tagEntryInfo *const tag);
79 static bool isInheritsFieldAvailable (const tagEntryInfo *const tag);
80 static bool isAccessFieldAvailable (const tagEntryInfo *const tag);
81 static bool isImplementationFieldAvailable (const tagEntryInfo *const tag);
82 static bool isSignatureFieldAvailable (const tagEntryInfo *const tag);
83 static bool isExtrasFieldAvailable (const tagEntryInfo *const tag);
84 static bool isXpathFieldAvailable (const tagEntryInfo *const tag);
85 static bool isEndFieldAvailable (const tagEntryInfo *const tag);
88 #define DEFINE_FIELD(L, N, V, H, DT, RE) \
89 DEFINE_FIELD_FULL (L, N, V, H, NULL, DT, RE, NULL, NULL)
90 #define DEFINE_FIELD_FULL(L, N, V, H, A, DT, RE, RN, DCAC) \
91 { \
92 .letter = L, \
93 .name = N, \
94 .description = H, \
95 .enabled = V, \
96 .render = RE, \
97 .renderNoEscaping= RN, \
98 .doesContainAnyChar = DCAC, \
99 .isValueAvailable = A, \
100 .dataType = DT, \
103 #define WITH_DEFUALT_VALUE(str) ((str)?(str):FIELD_NULL_LETTER_STRING)
105 static fieldDefinition fieldDefinitionsFixed [] = {
106 /* FIXED FIELDS */
107 DEFINE_FIELD_FULL ('N', "name", true,
108 "tag name",
109 NULL,
110 FIELDTYPE_STRING,
111 renderFieldName, renderFieldNameNoEscape,
112 doesContainAnyCharInName),
113 DEFINE_FIELD_FULL ('F', "input", true,
114 "input file",
115 NULL,
116 FIELDTYPE_STRING,
117 renderFieldInput, renderFieldInputNoEscape,
118 doesContainAnyCharInInput),
119 DEFINE_FIELD ('P', "pattern", true,
120 "pattern",
121 FIELDTYPE_STRING|FIELDTYPE_BOOL,
122 renderFieldPattern),
125 static fieldDefinition fieldDefinitionsExuberant [] = {
126 DEFINE_FIELD ('C', "compact", false,
127 "compact input line (used only in xref output)",
128 FIELDTYPE_STRING,
129 renderFieldCompactInputLine),
131 /* EXTENSION FIELDS */
132 DEFINE_FIELD_FULL ('a', "access", false,
133 "Access (or export) of class members",
134 isAccessFieldAvailable,
135 FIELDTYPE_STRING,
136 renderFieldAccess, NULL, NULL),
137 DEFINE_FIELD_FULL ('f', "file", true,
138 "File-restricted scoping",
139 isFileFieldAvailable,
140 FIELDTYPE_BOOL,
141 renderFieldFile, NULL, NULL),
142 DEFINE_FIELD_FULL ('i', "inherits", false,
143 "Inheritance information",
144 isInheritsFieldAvailable,
145 FIELDTYPE_STRING|FIELDTYPE_BOOL,
146 renderFieldInherits, NULL, NULL),
147 DEFINE_FIELD ('K', NULL, false,
148 "Kind of tag in long-name form",
149 FIELDTYPE_STRING,
150 renderFieldKindName),
151 DEFINE_FIELD ('k', NULL, true,
152 "Kind of tag in one-letter form",
153 FIELDTYPE_STRING,
154 renderFieldKindLetter),
155 DEFINE_FIELD_FULL ('l', "language", false,
156 "Language of input file containing tag",
157 isLanguageFieldAvailable,
158 FIELDTYPE_STRING,
159 renderFieldLanguage, NULL, NULL),
160 DEFINE_FIELD_FULL ('m', "implementation", false,
161 "Implementation information",
162 isImplementationFieldAvailable,
163 FIELDTYPE_STRING,
164 renderFieldImplementation, NULL, NULL),
165 DEFINE_FIELD ('n', "line", false,
166 "Line number of tag definition",
167 FIELDTYPE_INTEGER,
168 renderFieldLineNumber),
169 DEFINE_FIELD_FULL ('S', "signature", false,
170 "Signature of routine (e.g. prototype or parameter list)",
171 isSignatureFieldAvailable,
172 FIELDTYPE_STRING,
173 renderFieldSignature, renderFieldSignatureNoEscape,
174 doesContainAnyCharInSignature),
175 DEFINE_FIELD_FULL ('s', NULL, true,
176 "[tags output] scope (kind:name) of tag definition, [xref and json output] name of scope",
177 NULL,
178 FIELDTYPE_STRING,
179 renderFieldScope, renderFieldScopeNoEscape,
180 doesContainAnyCharInFieldScope),
181 DEFINE_FIELD_FULL ('t', "typeref", true,
182 "Type and name of a variable or typedef",
183 isTyperefFieldAvailable,
184 FIELDTYPE_STRING,
185 renderFieldTyperef, NULL, NULL),
186 DEFINE_FIELD ('z', "kind", false,
187 "[tags output] prepend \"kind:\" to k/ (or K/) field output, [xref and json output] kind in long-name form",
188 FIELDTYPE_STRING,
189 /* Following renderer is for handling --_xformat=%{kind};
190 and is not for tags output. */
191 renderFieldKindName),
194 static fieldDefinition fieldDefinitionsUniversal [] = {
195 DEFINE_FIELD ('r', "roles", false,
196 "Roles",
197 FIELDTYPE_STRING,
198 renderFieldRoles),
199 DEFINE_FIELD ('R', NULL, false,
200 "Marker (R or D) representing whether tag is definition or reference",
201 FIELDTYPE_STRING,
202 renderFieldRefMarker),
203 DEFINE_FIELD_FULL ('Z', "scope", false,
204 "[tags output] prepend \"scope:\" key to s/scope field output, [xref and json output] the same as s/ field",
205 NULL,
206 FIELDTYPE_STRING,
207 /* Following renderer is for handling --_xformat=%{scope};
208 and is not for tags output. */
209 renderFieldScope, renderFieldScopeNoEscape,
210 doesContainAnyCharInFieldScope),
211 DEFINE_FIELD_FULL ('E', "extras", false,
212 "Extra tag type information",
213 isExtrasFieldAvailable,
214 FIELDTYPE_STRING,
215 renderFieldExtras, NULL, NULL),
216 DEFINE_FIELD_FULL ('x', "xpath", false,
217 "xpath for the tag",
218 isXpathFieldAvailable,
219 FIELDTYPE_STRING,
220 renderFieldXpath, NULL, NULL),
221 DEFINE_FIELD ('p', "scopeKind", false,
222 "[tags output] no effect, [xref and json output] kind of scope in long-name form",
223 FIELDTYPE_STRING,
224 renderFieldScopeKindName),
225 DEFINE_FIELD_FULL ('e', "end", false,
226 "end lines of various items",
227 isEndFieldAvailable,
228 FIELDTYPE_INTEGER,
229 renderFieldEnd, NULL, NULL),
233 static unsigned int fieldObjectUsed = 0;
234 static unsigned int fieldObjectAllocated = 0;
235 static fieldObject* fieldObjects = NULL;
237 extern void initFieldObjects (void)
239 unsigned int i;
240 fieldObject *fobj;
242 Assert (fieldObjects == NULL);
244 fieldObjectAllocated
245 = ARRAY_SIZE (fieldDefinitionsFixed)
246 + ARRAY_SIZE (fieldDefinitionsExuberant)
247 + ARRAY_SIZE (fieldDefinitionsUniversal);
248 fieldObjects = xMalloc (fieldObjectAllocated, fieldObject);
249 DEFAULT_TRASH_BOX(&fieldObjects, eFreeIndirect);
251 fieldObjectUsed = 0;
253 for (i = 0; i < ARRAY_SIZE (fieldDefinitionsFixed); i++)
255 fobj = fieldObjects + i + fieldObjectUsed;
256 fobj->def = fieldDefinitionsFixed + i;
257 fobj->buffer = NULL;
258 fobj->nameWithPrefix = fobj->def->name;
259 fobj->language = LANG_IGNORE;
260 fobj->sibling = FIELD_UNKNOWN;
262 fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsFixed);
264 for (i = 0; i < ARRAY_SIZE (fieldDefinitionsExuberant); i++)
266 fobj = fieldObjects + i + fieldObjectUsed;
267 fobj->def = fieldDefinitionsExuberant +i;
268 fobj->buffer = NULL;
269 fobj->nameWithPrefix = fobj->def->name;
270 fobj->language = LANG_IGNORE;
271 fobj->sibling = FIELD_UNKNOWN;
273 fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsExuberant);
275 for (i = 0; i < ARRAY_SIZE (fieldDefinitionsUniversal); i++)
277 char *nameWithPrefix;
279 fobj = fieldObjects + i + fieldObjectUsed;
280 fobj->def = fieldDefinitionsUniversal + i;
281 fobj->buffer = NULL;
283 if (fobj->def->name)
285 nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (fobj->def->name) + 1);
286 nameWithPrefix [0] = '\0';
287 strcat (nameWithPrefix, CTAGS_FIELD_PREFIX);
288 strcat (nameWithPrefix, fobj->def->name);
289 fobj->nameWithPrefix = nameWithPrefix;
290 DEFAULT_TRASH_BOX(nameWithPrefix, eFree);
292 else
293 fobj->nameWithPrefix = NULL;
294 fobj->language = LANG_IGNORE;
295 fobj->sibling = FIELD_UNKNOWN;
297 fieldObjectUsed += ARRAY_SIZE (fieldDefinitionsUniversal);
299 Assert ( fieldObjectAllocated == fieldObjectUsed );
302 static fieldObject* getFieldObject(fieldType type)
304 Assert ((0 <= type) && ((unsigned int)type < fieldObjectUsed));
305 return fieldObjects + type;
308 extern fieldType getFieldTypeForOption (char letter)
310 unsigned int i;
312 for (i = 0; i < fieldObjectUsed; i++)
314 if (fieldObjects [i].def->letter == letter)
315 return i;
317 return FIELD_UNKNOWN;
320 extern fieldType getFieldTypeForName (const char *name)
322 return getFieldTypeForNameAndLanguage (name, LANG_IGNORE);
325 extern fieldType getFieldTypeForNameAndLanguage (const char *fieldName, langType language)
327 static bool initialized = false;
328 unsigned int i;
330 if (fieldName == NULL)
331 return FIELD_UNKNOWN;
333 if (language == LANG_AUTO && (initialized == false))
335 initialized = true;
336 initializeParser (LANG_AUTO);
338 else if (language != LANG_IGNORE && (initialized == false))
339 initializeParser (language);
341 for (i = 0; i < fieldObjectUsed; i++)
343 if (fieldObjects [i].def->name
344 && strcmp (fieldObjects [i].def->name, fieldName) == 0
345 && ((language == LANG_AUTO)
346 || (fieldObjects [i].language == language)))
347 return i;
350 return FIELD_UNKNOWN;
353 extern const char* getFieldDescription (fieldType type)
355 fieldObject* fobj;
357 fobj = getFieldObject (type);
358 return fobj->def->description;
361 extern const char* getFieldName(fieldType type)
363 fieldObject* fobj;
365 fobj = getFieldObject (type);
366 if (Option.putFieldPrefix)
367 return fobj->nameWithPrefix;
368 else
369 return fobj->def->name;
372 extern unsigned char getFieldLetter (fieldType type)
374 fieldObject* fobj = getFieldObject (type);
376 return fobj->def->letter == '\0'
377 ? FIELD_NULL_LETTER_CHAR
378 : fobj->def->letter;
381 extern bool doesFieldHaveValue (fieldType type, const tagEntryInfo *tag)
383 if (getFieldObject(type)->def->isValueAvailable)
384 return getFieldObject(type)->def->isValueAvailable(tag);
385 else
386 return true;
389 static const char *renderAsIs (vString* b CTAGS_ATTR_UNUSED, const char *s)
391 return s;
394 static const char *renderEscapedString (const char *s,
395 const tagEntryInfo *const tag CTAGS_ATTR_UNUSED,
396 vString* b)
398 vStringCatSWithEscaping (b, s);
399 return vStringValue (b);
402 static const char *renderEscapedName (const bool isTagName,
403 const char* s,
404 const tagEntryInfo *const tag,
405 vString* b)
407 int unexpected_byte = 0;
409 if (isTagName && (!tag->isPseudoTag) && (*s == ' ' || *s == '!'))
411 /* Don't allow a leading space or exclamation mark as it conflicts with
412 * pseudo-tags when sorting. Anything with a lower byte value is
413 * escaped by renderEscapedString() already. */
414 unexpected_byte = *s;
415 switch (*s)
417 case ' ': vStringCatS (b, "\\x20"); s++; break;
418 case '!': vStringCatS (b, "\\x21"); s++; break;
419 default: AssertNotReached();
422 else
424 /* Find the first byte needing escaping for the warning message */
425 const char *p = s;
427 while (*p > 0x1F && *p != 0x7F)
428 p++;
429 unexpected_byte = *p;
432 if (unexpected_byte)
434 const kindDefinition *kdef = getTagKind (tag);
435 verbose ("Unexpected character %#04x included in a tagEntryInfo: %s\n", unexpected_byte, s);
436 verbose ("File: %s, Line: %lu, Lang: %s, Kind: %c\n",
437 tag->inputFileName, tag->lineNumber, getLanguageName(tag->langType), kdef->letter);
438 verbose ("Escape the character\n");
441 return renderEscapedString (s, tag, b);
444 static const char *renderFieldName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
446 return renderEscapedName (true, tag->name, tag, b);
449 static const char *renderFieldNameNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
451 return renderAsIs (b, tag->name);
454 static bool doesContainAnyCharInName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
456 return strpbrk (tag->name, chars)? true: false;
459 static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
461 const char *f = tag->inputFileName;
463 if (Option.lineDirectives && tag->sourceFileName)
464 f = tag->sourceFileName;
465 return renderEscapedString (f, tag, b);
468 static const char *renderFieldInputNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
470 const char *f = tag->inputFileName;
472 if (Option.lineDirectives && tag->sourceFileName)
473 f = tag->sourceFileName;
475 return renderAsIs (b, f);
478 static bool doesContainAnyCharInInput (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
480 const char *f = tag->inputFileName;
482 if (Option.lineDirectives && tag->sourceFileName)
483 f = tag->sourceFileName;
485 return strpbrk (f, chars)? true: false;
488 static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
490 return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.signature),
491 tag, b);
494 static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
496 return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.signature));
499 static bool doesContainAnyCharInSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
501 return (tag->extensionFields.signature && strpbrk(tag->extensionFields.signature, chars))
502 ? true
503 : false;
506 static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
508 const char* scope;
510 getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
511 return scope? renderEscapedName (false, scope, tag, b): NULL;
514 static const char *renderFieldScopeNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
516 const char* scope;
518 getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
519 return scope? renderAsIs (b, scope): NULL;
522 static bool doesContainAnyCharInFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, const char *chars)
524 const char* scope;
526 getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope);
527 return (scope && strpbrk (scope, chars));
531 static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
533 return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.inheritance),
534 tag, b);
537 static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
539 /* Return "-" instead of "-:-". */
540 if (tag->extensionFields.typeRef [0] == NULL
541 && tag->extensionFields.typeRef [1] == NULL)
542 return renderAsIs (b, FIELD_NULL_LETTER_STRING);
544 vStringCatS (b, WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [0]));
545 vStringPut (b, ':');
546 return renderEscapedName (false, WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [1]), tag, b);
550 static const char* renderFieldCommon (fieldType type,
551 const tagEntryInfo *tag,
552 int index,
553 bool noEscaping)
555 fieldObject *fobj = fieldObjects + type;
556 const char *value;
557 fieldRenderer rfn;
559 Assert (tag);
560 Assert (index < 0 || ((unsigned int)index) < tag->usedParserFields);
562 if (index >= 0)
564 const tagField *f = getParserFieldForIndex (tag, index);
566 value = f->value;
568 else
569 value = NULL;
571 if (noEscaping)
572 rfn = fobj->def->renderNoEscaping;
573 else
574 rfn = fobj->def->render;
575 Assert (rfn);
577 fobj->buffer = vStringNewOrClearWithAutoRelease (fobj->buffer);
578 return rfn (tag, value, fobj->buffer);
581 extern const char* renderField (fieldType type, const tagEntryInfo *tag, int index)
583 return renderFieldCommon (type, tag, index, false);
586 extern const char* renderFieldNoEscaping (fieldType type, const tagEntryInfo *tag, int index)
588 return renderFieldCommon (type, tag, index, true);
591 static bool defaultDoesContainAnyChar (const tagEntryInfo *const tag CTAGS_ATTR_UNUSED, const char* value, const char* chars)
593 return strpbrk (value, chars)? true: false;
596 extern bool doesFieldHaveTabOrNewlineChar (fieldType type, const tagEntryInfo *tag, int index)
598 fieldObject *fobj = fieldObjects + type;
599 const char *value;
600 bool (* doesContainAnyChar) (const tagEntryInfo *const, const char*, const char*) = fobj->def->doesContainAnyChar;
602 Assert (tag);
603 Assert (index == NO_PARSER_FIELD || ((unsigned int)index) < tag->usedParserFields);
605 if (doesContainAnyChar == NULL)
607 if (index == NO_PARSER_FIELD)
608 return false;
609 else
610 doesContainAnyChar = defaultDoesContainAnyChar;
613 if (index >= 0)
615 const tagField *f = getParserFieldForIndex (tag, index);
617 value = f->value;
619 else
620 value = NULL;
622 return (* doesContainAnyChar) (tag, value, "\t\n");
625 /* Writes "line", stripping leading and duplicate white space.
627 static const char* renderCompactInputLine (vString *b, const char *const line)
629 bool lineStarted = false;
630 const char *p;
631 int c;
633 /* Write everything up to, but not including, the newline.
635 for (p = line, c = *p ; c != NEWLINE && c != '\0' ; c = *++p)
637 if (lineStarted || ! isspace (c)) /* ignore leading spaces */
639 lineStarted = true;
640 if (isspace (c))
642 int next;
644 /* Consume repeating white space.
646 while (next = *(p+1) , isspace (next) && next != NEWLINE)
647 ++p;
648 c = ' '; /* force space character for any white space */
650 if (c != CRETURN || *(p + 1) != NEWLINE)
651 vStringPut (b, c);
654 return vStringValue (b);
657 static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b)
659 const char* name = getTagKindName (tag);
660 return renderAsIs (b, name);
663 static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag,
664 const char *value CTAGS_ATTR_UNUSED,
665 vString* b)
667 const char *line;
668 static vString *tmp;
670 if (tag->isPseudoTag)
672 Assert (tag->pattern);
673 return tag->pattern;
676 tmp = vStringNewOrClearWithAutoRelease (tmp);
678 line = readLineFromBypassForTag (tmp, tag, NULL);
679 if (line)
680 renderCompactInputLine (b, line);
681 else
683 /* If no associated line for tag is found, we cannot prepare
684 * parameter to writeCompactInputLine(). In this case we
685 * use an empty string as LINE.
687 vStringClear (b);
690 return vStringValue (b);
693 static const char *renderFieldLineNumber (const tagEntryInfo *const tag,
694 const char *value CTAGS_ATTR_UNUSED,
695 vString* b)
697 long ln = tag->lineNumber;
698 char buf[32] = {[0] = '\0'};
700 if (Option.lineDirectives && (tag->sourceLineNumberDifference != 0))
701 ln += tag->sourceLineNumberDifference;
702 snprintf (buf, sizeof(buf), "%ld", ln);
703 vStringCatS (b, buf);
704 return vStringValue (b);
707 static const char *renderFieldRoles (const tagEntryInfo *const tag,
708 const char *value CTAGS_ATTR_UNUSED,
709 vString* b)
711 roleBitsType rbits = tag->extensionFields.roleBits;
712 const roleDefinition * role;
713 if (rbits)
715 int roleCount = countLanguageRoles (tag->langType, tag->kindIndex);
716 int nRoleWritten = 0;
718 for (int roleIndex = 0; roleIndex < roleCount; roleIndex++)
720 if (((rbits >> roleIndex) & (roleBitsType)1)
721 && isLanguageRoleEnabled (tag->langType, tag->kindIndex, roleIndex))
723 if (nRoleWritten > 0)
724 vStringPut(b, ',');
726 role = getTagRole(tag, roleIndex);
727 renderRole (role, b);
728 nRoleWritten++;
732 else
733 vStringCatS (b, ROLE_DEFINITION_NAME);
734 return vStringValue (b);
737 static const char *renderFieldLanguage (const tagEntryInfo *const tag,
738 const char *value CTAGS_ATTR_UNUSED,
739 vString* b)
741 const char *l;
743 if (Option.lineDirectives && (tag->sourceLangType != LANG_IGNORE))
744 l = getLanguageName(tag->sourceLangType);
745 else
746 l = getLanguageName(tag->langType);
748 return renderAsIs (b, WITH_DEFUALT_VALUE(l));
751 static const char *renderFieldAccess (const tagEntryInfo *const tag,
752 const char *value CTAGS_ATTR_UNUSED,
753 vString* b)
755 return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.access));
758 static const char *renderFieldKindLetter (const tagEntryInfo *const tag,
759 const char *value CTAGS_ATTR_UNUSED,
760 vString* b)
762 static char c[2] = { [1] = '\0' };
764 c [0] = getTagKindLetter(tag);
766 return renderAsIs (b, c);
769 static const char *renderFieldImplementation (const tagEntryInfo *const tag,
770 const char *value CTAGS_ATTR_UNUSED,
771 vString* b)
773 return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.implementation));
776 static const char *renderFieldFile (const tagEntryInfo *const tag,
777 const char *value CTAGS_ATTR_UNUSED,
778 vString* b)
780 return renderAsIs (b, tag->isFileScope? "file": FIELD_NULL_LETTER_STRING);
783 static const char *renderFieldPattern (const tagEntryInfo *const tag,
784 const char *value CTAGS_ATTR_UNUSED,
785 vString* b)
787 if (tag->isFileEntry)
788 return NULL;
789 else if (tag->pattern)
790 vStringCatS (b, tag->pattern);
791 else
793 char* tmp;
795 tmp = makePatternString (tag);
796 vStringCatS (b, tmp);
797 eFree (tmp);
799 return vStringValue (b);
802 static const char *renderFieldRefMarker (const tagEntryInfo *const tag,
803 const char *value CTAGS_ATTR_UNUSED,
804 vString* b)
806 static char c[2] = { [1] = '\0' };
808 c [0] = (tag->extensionFields.roleBits)? 'R': 'D';
810 return renderAsIs (b, c);
813 static const char *renderFieldExtras (const tagEntryInfo *const tag,
814 const char *value CTAGS_ATTR_UNUSED,
815 vString* b)
817 int i;
818 bool hasExtra = false;
819 int c = countXtags();
821 for (i = 0; i < c; i++)
823 const char *name = getXtagName (i);
825 if (!name)
826 continue;
828 if (isTagExtraBitMarked (tag, i))
831 if (hasExtra)
832 vStringPut (b, ',');
833 vStringCatS (b, name);
834 hasExtra = true;
838 if (hasExtra)
839 return vStringValue (b);
840 else
841 return NULL;
844 static const char *renderFieldXpath (const tagEntryInfo *const tag,
845 const char *value CTAGS_ATTR_UNUSED,
846 vString* b)
848 #ifdef HAVE_LIBXML
849 if (tag->extensionFields.xpath)
850 return renderEscapedString (tag->extensionFields.xpath,
851 tag, b);
852 #endif
853 return NULL;
856 static const char *renderFieldScopeKindName(const tagEntryInfo *const tag,
857 const char *value CTAGS_ATTR_UNUSED,
858 vString* b)
860 const char* kind;
862 getTagScopeInformation ((tagEntryInfo *const)tag, &kind, NULL);
863 return kind? renderAsIs (b, kind): NULL;
866 static const char *renderFieldEnd (const tagEntryInfo *const tag,
867 const char *value CTAGS_ATTR_UNUSED,
868 vString* b)
870 static char buf[21];
872 if (tag->extensionFields.endLine != 0)
874 sprintf (buf, "%lu", tag->extensionFields.endLine);
875 return renderAsIs (b, buf);
877 else
878 return NULL;
881 static bool isLanguageFieldAvailable (const tagEntryInfo *const tag)
883 return (tag->langType == LANG_IGNORE)? false: true;
886 static bool isTyperefFieldAvailable (const tagEntryInfo *const tag)
888 return (tag->extensionFields.typeRef [0] != NULL
889 && tag->extensionFields.typeRef [1] != NULL)? true: false;
892 static bool isFileFieldAvailable (const tagEntryInfo *const tag)
894 return tag->isFileScope? true: false;
897 static bool isInheritsFieldAvailable (const tagEntryInfo *const tag)
899 return (tag->extensionFields.inheritance != NULL)? true: false;
902 static bool isAccessFieldAvailable (const tagEntryInfo *const tag)
904 return (tag->extensionFields.access != NULL)? true: false;
907 static bool isImplementationFieldAvailable (const tagEntryInfo *const tag)
909 return (tag->extensionFields.implementation != NULL)? true: false;
912 static bool isSignatureFieldAvailable (const tagEntryInfo *const tag)
914 return (tag->extensionFields.signature != NULL)? true: false;
917 static bool isExtrasFieldAvailable (const tagEntryInfo *const tag)
919 unsigned int i;
920 for (i = 0; i < sizeof (tag->extra); i++)
922 if (tag->extra [i])
923 return true;
924 else if (tag->extraDynamic)
925 return true;
928 return false;
931 static bool isXpathFieldAvailable (const tagEntryInfo *const tag)
933 #ifdef HAVE_LIBXML
934 return (tag->extensionFields.xpath != NULL)? true: false;
935 #else
936 return false;
937 #endif
940 static bool isEndFieldAvailable (const tagEntryInfo *const tag)
942 return (tag->extensionFields.endLine != 0)? true: false;
945 extern bool isFieldEnabled (fieldType type)
947 return getFieldObject(type)->def->enabled;
950 extern bool enableField (fieldType type, bool state, bool warnIfFixedField)
952 fieldDefinition *def = getFieldObject(type)->def;
953 bool old = def->enabled;
954 if (writerDoesTreatFieldAsFixed (type))
956 if ((!state) && warnIfFixedField)
958 if (def->name && def->letter != NUL_FIELD_LETTER)
959 error(WARNING, "Cannot disable fixed field: '%c'{%s}",
960 def->letter, def->name);
961 else if (def->name)
962 error(WARNING, "Cannot disable fixed field: {%s}",
963 def->name);
964 else if (def->letter != NUL_FIELD_LETTER)
965 error(WARNING, "Cannot disable fixed field: '%c'",
966 getFieldObject(type)->def->letter);
967 else
968 AssertNotReached();
971 else
973 getFieldObject(type)->def->enabled = state;
975 if (isCommonField (type))
976 verbose ("enable field \"%s\": %s\n",
977 getFieldObject(type)->def->name,
978 (state? "yes": "no"));
979 else
980 verbose ("enable field \"%s\"<%s>: %s\n",
981 getFieldObject(type)->def->name,
982 getLanguageName (getFieldOwner(type)),
983 (state? "yes": "no"));
985 return old;
988 extern bool isCommonField (fieldType type)
990 return (FIELD_BUILTIN_LAST < type)? false: true;
993 extern int getFieldOwner (fieldType type)
995 return getFieldObject(type)->language;
998 extern unsigned int getFieldDataType (fieldType type)
1000 return getFieldObject(type)->def->dataType;
1003 extern bool doesFieldHaveRenderer (fieldType type, bool noEscaping)
1005 if (noEscaping)
1006 return getFieldObject(type)->def->renderNoEscaping? true: false;
1007 else
1008 return getFieldObject(type)->def->render? true: false;
1011 extern int countFields (void)
1013 return fieldObjectUsed;
1016 extern fieldType nextSiblingField (fieldType type)
1018 fieldObject *fobj;
1020 fobj = fieldObjects + type;
1021 return fobj->sibling;
1024 static void updateSiblingField (fieldType type, const char* name)
1026 int i;
1027 fieldObject *fobj;
1029 for (i = type; i > 0; i--)
1031 fobj = fieldObjects + i - 1;
1032 if (fobj->def->name && (strcmp (fobj->def->name, name) == 0))
1034 Assert (fobj->sibling == FIELD_UNKNOWN);
1035 fobj->sibling = type;
1036 break;
1041 static const char* defaultRenderer (const tagEntryInfo *const tag CTAGS_ATTR_UNUSED,
1042 const char *value,
1043 vString * buffer CTAGS_ATTR_UNUSED)
1045 return renderEscapedString (value, tag, buffer);
1048 extern int defineField (fieldDefinition *def, langType language)
1050 fieldObject *fobj;
1051 char *nameWithPrefix;
1052 size_t i;
1054 Assert (def);
1055 Assert (def->name);
1056 for (i = 0; i < strlen (def->name); i++)
1058 Assert ( isalpha (def->name [i]) );
1060 def->letter = NUL_FIELD_LETTER;
1062 if (fieldObjectUsed == fieldObjectAllocated)
1064 fieldObjectAllocated *= 2;
1065 fieldObjects = xRealloc (fieldObjects, fieldObjectAllocated, fieldObject);
1067 fobj = fieldObjects + (fieldObjectUsed);
1068 def->ftype = fieldObjectUsed++;
1070 if (def->render == NULL)
1072 def->render = defaultRenderer;
1073 def->renderNoEscaping = NULL;
1074 def->doesContainAnyChar = NULL;
1077 if (! def->dataType)
1078 def->dataType = FIELDTYPE_STRING;
1080 fobj->def = def;
1082 fobj->buffer = NULL;
1084 nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (def->name) + 1);
1085 nameWithPrefix [0] = '\0';
1086 strcat (nameWithPrefix, CTAGS_FIELD_PREFIX);
1087 strcat (nameWithPrefix, def->name);
1088 fobj->nameWithPrefix = nameWithPrefix;
1089 DEFAULT_TRASH_BOX(nameWithPrefix, eFree);
1091 fobj->language = language;
1092 fobj->sibling = FIELD_UNKNOWN;
1094 updateSiblingField (def->ftype, def->name);
1095 return def->ftype;
1098 #define FIELD_COL_LETTER 0
1099 #define FIELD_COL_NAME 1
1100 #define FIELD_COL_ENABLED 2
1101 #define FIELD_COL_LANGUAGE 3
1102 #define FIELD_COL_JSTYPE 4
1103 #define FIELD_COL_FIXED 5
1104 #define FIELD_COL_DESCRIPTION 6
1105 extern struct colprintTable * fieldColprintTableNew (void)
1107 return colprintTableNew ("L:LETTER", "L:NAME", "L:ENABLED",
1108 "L:LANGUAGE", "L:JSTYPE", "L:FIXED", "L:DESCRIPTION", NULL);
1111 static void fieldColprintAddLine (struct colprintTable *table, int i)
1113 fieldObject *fobj = getFieldObject(i);
1114 fieldDefinition *fdef = fobj->def;
1116 struct colprintLine *line = colprintTableGetNewLine(table);
1118 colprintLineAppendColumnChar (line,
1119 (fdef->letter == NUL_FIELD_LETTER)
1120 ? FIELD_NULL_LETTER_CHAR
1121 : fdef->letter);
1123 const char *name = getFieldName (i);
1124 colprintLineAppendColumnCString (line, name? name: RSV_NONE);
1125 colprintLineAppendColumnBool (line, fdef->enabled);
1126 colprintLineAppendColumnCString (line,
1127 fobj->language == LANG_IGNORE
1128 ? RSV_NONE
1129 : getLanguageName (fobj->language));
1131 char typefields [] = "---";
1133 unsigned int bmask, offset;
1134 unsigned int type = getFieldDataType(i);
1135 for (bmask = 1, offset = 0;
1136 bmask < FIELDTYPE_END_MARKER;
1137 bmask <<= 1, offset++)
1138 if (type & bmask)
1139 typefields[offset] = fieldDataTypeFalgs[offset];
1141 colprintLineAppendColumnCString (line, typefields);
1142 colprintLineAppendColumnBool (line, writerDoesTreatFieldAsFixed (i));
1143 colprintLineAppendColumnCString (line, fdef->description);
1146 extern void fieldColprintAddCommonLines (struct colprintTable *table)
1148 for (int i = 0; i <= FIELD_BUILTIN_LAST; i++)
1149 fieldColprintAddLine(table, i);
1152 extern void fieldColprintAddLanguageLines (struct colprintTable *table, langType language)
1154 for (unsigned int i = FIELD_BUILTIN_LAST + 1; i < fieldObjectUsed; i++)
1156 fieldObject *fobj = getFieldObject(i);
1157 if (fobj->language == language)
1158 fieldColprintAddLine (table, i);
1162 static int fieldColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
1164 const char *a_fixed = colprintLineGetColumn (a, FIELD_COL_FIXED);
1165 const char *b_fixed = colprintLineGetColumn (b, FIELD_COL_FIXED);
1166 const char *a_parser = colprintLineGetColumn (a, FIELD_COL_LANGUAGE);
1167 const char *b_parser = colprintLineGetColumn (b, FIELD_COL_LANGUAGE);
1169 if ((strcmp (a_fixed, "yes") == 0)
1170 && (strcmp (b_fixed, "yes") == 0))
1172 /* name, input, pattern, compact */
1173 const char *a_name = colprintLineGetColumn (a, FIELD_COL_NAME);
1174 const char *b_name = colprintLineGetColumn (b, FIELD_COL_NAME);
1175 const char *ref_name;
1176 unsigned int a_index = ~0U;
1177 unsigned int b_index = ~0U;
1179 for (unsigned int i = 0; i < ARRAY_SIZE(fieldDefinitionsFixed); i++)
1181 ref_name = fieldDefinitionsFixed [i].name;
1182 if (strcmp (a_name, ref_name) == 0)
1183 a_index = i;
1184 if (strcmp (b_name, ref_name) == 0)
1185 b_index = i;
1186 if ((a_index != ~0U) || (b_index != ~0U))
1187 break;
1190 if (a_index < b_index)
1191 return -1;
1192 else if (a_index == b_index)
1193 return 0; /* ??? */
1194 else
1195 return 1;
1197 else if ((strcmp (a_fixed, "yes") == 0)
1198 && (strcmp (b_fixed, "yes") != 0))
1199 return -1;
1200 else if ((strcmp (a_fixed, "yes") != 0)
1201 && (strcmp (b_fixed, "yes") == 0))
1202 return 1;
1204 if (strcmp (a_parser, RSV_NONE) == 0
1205 && strcmp (b_parser, RSV_NONE) != 0)
1206 return -1;
1207 else if (strcmp (a_parser, RSV_NONE) != 0
1208 && strcmp (b_parser, RSV_NONE) == 0)
1209 return 1;
1210 else if (strcmp (a_parser, RSV_NONE) != 0
1211 && strcmp (b_parser, RSV_NONE) != 0)
1213 int r;
1214 r = strcmp (a_parser, b_parser);
1215 if (r != 0)
1216 return r;
1218 const char *a_name = colprintLineGetColumn (a, FIELD_COL_NAME);
1219 const char *b_name = colprintLineGetColumn (b, FIELD_COL_NAME);
1221 return strcmp(a_name, b_name);
1223 else
1225 const char *a_letter = colprintLineGetColumn (a, FIELD_COL_LETTER);
1226 const char *b_letter = colprintLineGetColumn (b, FIELD_COL_LETTER);
1228 return strcmp(a_letter, b_letter);
1232 extern void fieldColprintTablePrint (struct colprintTable *table,
1233 bool withListHeader, bool machinable, FILE *fp)
1235 colprintTableSort (table, fieldColprintCompareLines);
1236 colprintTablePrint (table, 0, withListHeader, machinable, fp);