2 * Copyright (c) 1996-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for managing input languages and
8 * dispatching files to the appropriate language parser.
14 #include "general.h" /* must always come first */
16 /* TODO: This definition should be removed. */
18 #include "options_p.h"
33 #include "parsers_p.h"
35 #include "promise_p.h"
41 #include "routines_p.h"
43 #include "subparser.h"
44 #include "subparser_p.h"
47 #include "trashbox_p.h"
61 SPEC_ALIAS
= SPEC_NAME
,
65 const char *specTypeName
[] = {
66 "none", "name", "extension", "pattern"
72 enum specType specType
;
75 typedef struct sParserObject
{
76 parserDefinition
*def
;
78 kindDefinition
* fileKind
;
80 stringList
* currentPatterns
; /* current list of file name patterns */
81 stringList
* currentExtensions
; /* current list of extensions */
82 stringList
* currentAliases
; /* current list of aliases */
84 unsigned int initialized
:1; /* initialize() is called or not */
85 unsigned int dontEmit
:1; /* run but don't emit tags.
86 This parser was disabled but a subparser on
87 this parser makes this parser run (to drive
89 unsigned int pseudoTagPrinted
:1; /* pseudo tags about this parser
91 unsigned int justRunForSchedulingBase
:1;
92 unsigned int used
; /* Used for printing language specific statistics. */
94 unsigned int anonymousIdentiferId
; /* managed by anon* functions */
96 struct slaveControlBlock
*slaveControlBlock
;
97 struct kindControlBlock
*kindControlBlock
;
98 struct lregexControlBlock
*lregexControlBlock
;
99 struct paramControlBlock
*paramControlBlock
;
101 langType pretendingAsLanguage
; /* OLDLANG in --_pretend-<NEWLANG>=<OLDLANG>
102 is set here if this parser is NEWLANG.
103 LANG_IGNORE is set if no pretending. */
104 langType pretendedAsLanguage
; /* NEWLANG in --_pretend-<NEWLANG>=<OLDLANG>
105 is set here if this parser is OLDLANG.
106 LANG_IGNORE is set if no being pretended. */
111 * FUNCTION PROTOTYPES
114 static void lazyInitialize (langType language
);
115 static void addParserPseudoTags (langType language
);
116 static void installKeywordTable (const langType language
);
117 static void installTagRegexTable (const langType language
);
118 static void installTagXpathTable (const langType language
);
119 static void anonResetMaybe (parserObject
*parser
);
120 static void setupAnon (void);
121 static void teardownAnon (void);
122 static void uninstallTagXpathTable (const langType language
);
123 static bool hasLanguageAnyRegexPatterns (const langType language
);
128 static parserDefinition
*FallbackParser (void);
129 static parserDefinition
*CTagsParser (void);
130 static parserDefinition
*CTagsSelfTestParser (void);
131 static parserDefinitionFunc
* BuiltInParsers
[] = {
132 #ifdef EXTERNAL_PARSER_LIST
134 #else /* ! EXTERNAL_PARSER_LIST */
135 CTagsParser
, /* This must be first entry. */
136 FallbackParser
, /* LANG_FALLBACK */
152 OPTLIB2C_PCRE2_PARSER_LIST
156 #endif /* EXTERNAL_PARSER_LIST */
158 static parserObject
* LanguageTable
= NULL
;
159 static unsigned int LanguageCount
= 0;
160 static hashTable
* LanguageHTable
= NULL
;
161 static kindDefinition defaultFileKind
= {
163 .letter
= KIND_FILE_DEFAULT_LETTER
,
164 .name
= KIND_FILE_DEFAULT_NAME
,
165 .description
= KIND_FILE_DEFAULT_NAME
,
168 static langType ctagsSelfTestLang
;
171 * FUNCTION DEFINITIONS
174 static bool isLanguageNameChar(int c
)
178 if (c
== '\'' || c
== '"' || c
== ';')
186 extern unsigned int countParsers (void)
188 return LanguageCount
;
191 extern int makeSimpleTag (
192 const vString
* const name
, const int kindIndex
)
194 return makeSimpleRefTag (name
, kindIndex
, ROLE_DEFINITION_INDEX
);
197 extern int makeSimpleRefTag (const vString
* const name
, const int kindIndex
,
202 Assert (roleIndex
< (int)countInputLanguageRoles(kindIndex
));
204 /* do not check for kind being disabled - that happens later in makeTagEntry() */
205 if (name
!= NULL
&& vStringLength (name
) > 0)
208 initRefTagEntry (&e
, vStringValue (name
), kindIndex
, roleIndex
);
210 r
= makeTagEntry (&e
);
215 extern int makeSimplePlaceholder(const vString
* const name
)
217 return makePlaceholder (vStringValue (name
));
220 extern bool isLanguageEnabled (const langType language
)
222 const parserDefinition
* const def
= LanguageTable
[language
].def
;
226 extern bool isLanguageVisible (const langType language
)
228 const parserDefinition
* const lang
= LanguageTable
[language
].def
;
230 return !lang
->invisible
;
234 * parserDescription mapping management
237 extern parserDefinition
* parserNew (const char* name
)
239 parserDefinition
* result
= xCalloc (1, parserDefinition
);
240 result
->name
= eStrdup (name
);
242 result
->enabled
= true;
246 extern bool doesLanguageAllowNullTag (const langType language
)
248 Assert (0 <= language
&& language
< (int) LanguageCount
);
249 return LanguageTable
[language
].def
->allowNullTag
;
252 extern bool doesLanguageRequestAutomaticFQTag (const langType language
)
254 Assert (0 <= language
&& language
< (int) LanguageCount
);
255 return LanguageTable
[language
].def
->requestAutomaticFQTag
;
258 static const char *getLanguageNameFull (const langType language
, bool noPretending
)
262 if (language
== LANG_IGNORE
)
266 Assert (0 <= language
&& language
< (int) LanguageCount
);
268 result
= LanguageTable
[language
].def
->name
;
271 langType real_language
= LanguageTable
[language
].pretendingAsLanguage
;
272 if (real_language
== LANG_IGNORE
)
273 result
= LanguageTable
[language
].def
->name
;
276 Assert (0 <= real_language
&& real_language
< (int) LanguageCount
);
277 result
= LanguageTable
[real_language
].def
->name
;
284 extern const char *getLanguageName (const langType language
)
286 return getLanguageNameFull (language
, false);
289 extern const char *getLanguageKindName (const langType language
, const int kindIndex
)
291 kindDefinition
* kdef
= getLanguageKind (language
, kindIndex
);
295 static kindDefinition kindGhost
= {
296 .letter
= KIND_GHOST_LETTER
,
297 .name
= KIND_GHOST_NAME
,
298 .description
= KIND_GHOST_NAME
,
301 extern int defineLanguageKind (const langType language
, kindDefinition
*def
,
302 freeKindDefFunc freeKindDef
)
304 return defineKind (LanguageTable
[language
].kindControlBlock
, def
, freeKindDef
);
307 extern unsigned int countLanguageKinds (const langType language
)
309 return countKinds (LanguageTable
[language
].kindControlBlock
);
312 extern unsigned int countLanguageRoles (const langType language
, int kindIndex
)
314 return countRoles (LanguageTable
[language
].kindControlBlock
, kindIndex
);
317 extern kindDefinition
* getLanguageKind (const langType language
, int kindIndex
)
319 kindDefinition
* kdef
;
321 Assert (0 <= language
&& language
< (int) LanguageCount
);
325 case KIND_FILE_INDEX
:
326 kdef
= LanguageTable
[language
].fileKind
;
328 case KIND_GHOST_INDEX
:
332 Assert (kindIndex
>= 0);
333 kdef
= getKind (LanguageTable
[language
].kindControlBlock
, kindIndex
);
338 extern kindDefinition
* getLanguageKindForLetter (const langType language
, char kindLetter
)
340 Assert (0 <= language
&& language
< (int) LanguageCount
);
341 if (kindLetter
== LanguageTable
[language
].fileKind
->letter
)
342 return LanguageTable
[language
].fileKind
;
343 else if (kindLetter
== KIND_GHOST_LETTER
)
346 return getKindForLetter (LanguageTable
[language
].kindControlBlock
, kindLetter
);
349 extern kindDefinition
* getLanguageKindForName (const langType language
, const char *kindName
)
351 Assert (0 <= language
&& language
< (int) LanguageCount
);
354 if (strcmp(kindName
, LanguageTable
[language
].fileKind
->name
) == 0)
355 return LanguageTable
[language
].fileKind
;
356 else if (strcmp(kindName
, KIND_GHOST_NAME
) == 0)
359 return getKindForName (LanguageTable
[language
].kindControlBlock
, kindName
);
362 extern roleDefinition
* getLanguageRole(const langType language
, int kindIndex
, int roleIndex
)
364 return getRole (LanguageTable
[language
].kindControlBlock
, kindIndex
, roleIndex
);
367 extern roleDefinition
* getLanguageRoleForName (const langType language
, int kindIndex
,
368 const char *roleName
)
370 return getRoleForName (LanguageTable
[language
].kindControlBlock
, kindIndex
, roleName
);
373 extern langType
getNamedLanguageFull (const char *const name
, size_t len
, bool noPretending
,
374 bool include_aliases
)
376 langType result
= LANG_IGNORE
;
378 Assert (name
!= NULL
);
382 parserDefinition
*def
= (parserDefinition
*)hashTableGetItem (LanguageHTable
, name
);
387 for (i
= 0 ; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
389 const parserDefinition
* const lang
= LanguageTable
[i
].def
;
391 vString
* vstr
= vStringNewInit (name
);
392 vStringTruncate (vstr
, len
);
394 if (strcasecmp (vStringValue (vstr
), lang
->name
) == 0)
396 else if (include_aliases
)
398 stringList
* const aliases
= LanguageTable
[i
].currentAliases
;
399 if (aliases
&& stringListCaseMatched (aliases
, vStringValue (vstr
)))
402 vStringDelete (vstr
);
405 if (result
!= LANG_IGNORE
407 && LanguageTable
[result
].pretendedAsLanguage
!= LANG_IGNORE
)
408 result
= LanguageTable
[result
].pretendedAsLanguage
;
413 extern langType
getNamedLanguage (const char *const name
, size_t len
)
415 return getNamedLanguageFull (name
, len
, false, false);
418 extern langType
getNamedLanguageOrAlias (const char *const name
, size_t len
)
420 return getNamedLanguageFull (name
, len
, false, true);
423 static langType
getNameOrAliasesLanguageAndSpec (const char *const key
, langType start_index
,
424 const char **const spec
, enum specType
*specType
)
426 langType result
= LANG_IGNORE
;
430 if (start_index
== LANG_AUTO
)
432 else if (start_index
== LANG_IGNORE
|| start_index
>= (int) LanguageCount
)
435 for (i
= start_index
; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
437 if (! isLanguageEnabled (i
))
440 const parserObject
* const parser
= LanguageTable
+ i
;
441 stringList
* const aliases
= parser
->currentAliases
;
444 if (parser
->def
->name
!= NULL
&& strcasecmp (key
, parser
->def
->name
) == 0)
447 *spec
= parser
->def
->name
;
448 *specType
= SPEC_NAME
;
450 else if (aliases
!= NULL
&& (tmp
= stringListFileFinds (aliases
, key
)))
453 *spec
= vStringValue(tmp
);
454 *specType
= SPEC_ALIAS
;
460 extern langType
getLanguageForCommand (const char *const command
, langType startFrom
)
462 const char *const tmp_command
= baseFilename (command
);
464 enum specType tmp_specType
;
466 return getNameOrAliasesLanguageAndSpec (tmp_command
, startFrom
,
467 (const char **const)&tmp_spec
,
471 static langType
getPatternLanguageAndSpec (const char *const baseName
, langType start_index
,
472 const char **const spec
, enum specType
*specType
)
474 langType result
= LANG_IGNORE
;
477 if (start_index
== LANG_AUTO
)
479 else if (start_index
== LANG_IGNORE
|| start_index
>= (int) LanguageCount
)
483 for (i
= start_index
; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
485 if (! isLanguageEnabled (i
))
488 parserObject
*parser
= LanguageTable
+ i
;
489 stringList
* const ptrns
= parser
->currentPatterns
;
492 if (ptrns
!= NULL
&& (tmp
= stringListFileFinds (ptrns
, baseName
)))
495 *spec
= vStringValue(tmp
);
496 *specType
= SPEC_PATTERN
;
501 for (i
= start_index
; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
503 if (! isLanguageEnabled (i
))
506 parserObject
*parser
= LanguageTable
+ i
;
507 stringList
* const exts
= parser
->currentExtensions
;
510 if (exts
!= NULL
&& (tmp
= stringListExtensionFinds (exts
,
511 fileExtension (baseName
))))
514 *spec
= vStringValue(tmp
);
515 *specType
= SPEC_EXTENSION
;
523 extern langType
getLanguageForFilename (const char *const filename
, langType startFrom
)
525 const char *const tmp_filename
= baseFilename (filename
);
527 enum specType tmp_specType
;
529 return getPatternLanguageAndSpec (tmp_filename
, startFrom
,
530 (const char **const)&tmp_spec
,
534 const char *scopeSeparatorFor (langType language
, int kindIndex
, int parentKindIndex
)
536 Assert (0 <= language
&& language
< (int) LanguageCount
);
538 parserObject
*parser
= LanguageTable
+ language
;
539 struct kindControlBlock
*kcb
= parser
->kindControlBlock
;
541 const scopeSeparator
*sep
= getScopeSeparator (kcb
, kindIndex
, parentKindIndex
);
542 return sep
? sep
->separator
: NULL
;
545 static bool processLangDefineScopesep(const langType language
,
546 const char *const option
,
547 const char *const parameter
)
549 parserObject
*parser
;
550 const char * p
= parameter
;
554 int parentKindex
= KIND_FILE_INDEX
;
556 int kindex
= KIND_FILE_INDEX
;
557 const char *separator
;
559 Assert (0 <= language
&& language
< (int) LanguageCount
);
560 parser
= LanguageTable
+ language
;
566 parentKletter
= p
[0];
568 if (parentKletter
== '\0')
569 error (FATAL
, "no scope separator specified in \"--%s\" option", option
);
570 else if (parentKletter
== '/')
571 parentKindex
= KIND_GHOST_INDEX
;
572 else if (parentKletter
== KIND_WILDCARD_LETTER
)
573 parentKindex
= KIND_WILDCARD_INDEX
;
574 else if (parentKletter
== KIND_FILE_DEFAULT_LETTER
)
576 "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind and no separator can be assigned to",
577 KIND_FILE_DEFAULT_LETTER
, option
, KIND_FILE_DEFAULT_NAME
);
578 else if (isalpha ((unsigned char) parentKletter
))
580 kindDefinition
*kdef
= getKindForLetter (parser
->kindControlBlock
, parentKletter
);
583 "the kind for letter `%c' specified in \"--%s\" option is not defined.",
584 parentKletter
, option
);
585 parentKindex
= kdef
->id
;
589 "the kind letter `%c` given in \"--%s\" option is not an alphabet",
590 parentKletter
, option
);
596 if (parentKindex
== KIND_GHOST_INDEX
)
602 "wrong separator specification in \"--%s\" option: no slash after parent kind letter `%c'",
603 option
, parentKletter
);
608 error (FATAL
, "no child kind letter in \"--%s\" option", option
);
609 else if (kletter
== '/')
611 "wrong separator specification in \"--%s\" option: don't specify slash char twice: %s",
613 else if (kletter
== ':')
615 "no child kind letter in \"--%s\" option", option
);
616 else if (kletter
== KIND_WILDCARD_LETTER
)
618 if (parentKindex
!= KIND_WILDCARD_INDEX
619 && parentKindex
!= KIND_GHOST_INDEX
)
621 "cannot use wild card for child kind unless parent kind is also wild card or empty");
622 kindex
= KIND_WILDCARD_INDEX
;
624 else if (kletter
== KIND_FILE_DEFAULT_LETTER
)
626 "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind and no separator can be assigned to",
627 KIND_FILE_DEFAULT_LETTER
, option
, KIND_FILE_DEFAULT_NAME
);
628 else if (isalpha ((unsigned char) kletter
))
630 kindDefinition
*kdef
= getKindForLetter (parser
->kindControlBlock
, kletter
);
633 "the kind for letter `%c' specified in \"--%s\" option is not defined.",
639 "the kind letter `%c` given in \"--%s\" option is not an alphabet",
645 if (parentKindex
== KIND_GHOST_INDEX
)
649 "wrong separator specification in \"--%s\" option: cannot find a colon after child kind: %s",
657 "wrong separator specification in \"--%s\" option: cannot find a colon after child kind: %s",
662 Assert (parentKindex
!= KIND_FILE_INDEX
);
663 Assert (kindex
!= KIND_FILE_INDEX
);
664 defineScopeSeparator (parser
->kindControlBlock
, kindex
, parentKindex
, separator
);
668 extern bool processScopesepOption (const char *const option
, const char * const parameter
)
672 language
= getLanguageComponentInOption (option
, "_scopesep-");
673 if (language
== LANG_IGNORE
)
676 return processLangDefineScopesep (language
, option
, parameter
);
679 static parserCandidate
* parserCandidateNew(unsigned int count CTAGS_ATTR_UNUSED
)
681 parserCandidate
* candidates
;
684 candidates
= xMalloc(LanguageCount
, parserCandidate
);
685 for (i
= 0; i
< LanguageCount
; i
++)
687 candidates
[i
].lang
= LANG_IGNORE
;
688 candidates
[i
].spec
= NULL
;
689 candidates
[i
].specType
= SPEC_NONE
;
694 /* If multiple parsers are found, return LANG_AUTO */
695 static unsigned int nominateLanguageCandidates (const char *const key
, parserCandidate
** candidates
)
699 const char* spec
= NULL
;
700 enum specType specType
= SPEC_NONE
;
702 *candidates
= parserCandidateNew(LanguageCount
);
704 for (count
= 0, i
= LANG_AUTO
; i
!= LANG_IGNORE
; )
706 i
= getNameOrAliasesLanguageAndSpec (key
, i
, &spec
, &specType
);
707 if (i
!= LANG_IGNORE
)
709 (*candidates
)[count
].lang
= i
++;
710 (*candidates
)[count
].spec
= spec
;
711 (*candidates
)[count
++].specType
= specType
;
719 nominateLanguageCandidatesForPattern(const char *const baseName
, parserCandidate
** candidates
)
724 enum specType specType
= SPEC_NONE
;
726 *candidates
= parserCandidateNew(LanguageCount
);
728 for (count
= 0, i
= LANG_AUTO
; i
!= LANG_IGNORE
; )
730 i
= getPatternLanguageAndSpec (baseName
, i
, &spec
, &specType
);
731 if (i
!= LANG_IGNORE
)
733 (*candidates
)[count
].lang
= i
++;
734 (*candidates
)[count
].spec
= spec
;
735 (*candidates
)[count
++].specType
= specType
;
741 static vString
* extractEmacsModeAtFirstLine(MIO
* input
);
743 /* The name of the language interpreter, either directly or as the argument
746 static vString
* determineInterpreter (const char* const cmd
)
748 vString
* const interpreter
= vStringNew ();
752 vStringClear (interpreter
);
753 for ( ; isspace ((unsigned char) *p
) ; ++p
)
755 for ( ; *p
!= '\0' && ! isspace ((unsigned char) *p
) ; ++p
)
756 vStringPut (interpreter
, *p
);
757 } while (strcmp (vStringValue (interpreter
), "env") == 0);
761 static vString
* extractInterpreter (MIO
* input
)
763 vString
* const vLine
= vStringNew ();
764 const char* const line
= readLineRaw (vLine
, input
);
765 vString
* interpreter
= NULL
;
767 if (line
!= NULL
&& line
[0] == '#' && line
[1] == '!')
769 /* "48.2.4.1 Specifying File Variables" of Emacs info:
770 ---------------------------------------------------
771 In shell scripts, the first line is used to
772 identify the script interpreter, so you
773 cannot put any local variables there. To
774 accommodate this, Emacs looks for local
775 variable specifications in the _second_
776 line if the first line specifies an
779 interpreter
= extractEmacsModeAtFirstLine(input
);
782 const char* const lastSlash
= strrchr (line
, '/');
783 const char *const cmd
= lastSlash
!= NULL
? lastSlash
+1 : line
+2;
784 interpreter
= determineInterpreter (cmd
);
787 vStringDelete (vLine
);
791 static bool isShellZsh (const char *p
)
793 p
= strstr (p
, "sh-set-shell");
796 p
+= strlen("sh-set-shell");
800 while (isspace ((unsigned char) *p
))
803 if (strncmp (p
, "\"zsh\"", 5) == 0
804 || strncmp (p
, "zsh", 3) == 0)
809 static vString
* determineEmacsModeAtFirstLine (const char* const line
)
811 vString
* mode
= vStringNew ();
813 const char* p
= strstr(line
, "-*-");
818 for ( ; isspace ((unsigned char) *p
) ; ++p
)
821 if (strncasecmp(p
, "mode:", strlen("mode:")) == 0)
823 /* -*- mode: MODE; -*- */
824 p
+= strlen("mode:");
825 for ( ; isspace ((unsigned char) *p
) ; ++p
)
827 for ( ; *p
!= '\0' && isLanguageNameChar ((unsigned char) *p
) ; ++p
)
828 vStringPut (mode
, *p
);
830 if ((strcmp(vStringValue (mode
), "sh") == 0
831 || strcmp(vStringValue (mode
), "shell-script") == 0)
833 vStringCopyS (mode
, "Zsh");
838 const char* end
= strstr (p
, "-*-");
843 for ( ; p
< end
&& isLanguageNameChar ((unsigned char) *p
) ; ++p
)
844 vStringPut (mode
, *p
);
846 for ( ; isspace ((unsigned char) *p
) ; ++p
)
848 if (strncmp(p
, "-*-", strlen("-*-")) != 0)
859 static vString
* extractEmacsModeAtFirstLine(MIO
* input
)
861 vString
* const vLine
= vStringNew ();
862 const char* const line
= readLineRaw (vLine
, input
);
863 vString
* mode
= NULL
;
865 mode
= determineEmacsModeAtFirstLine (line
);
866 vStringDelete (vLine
);
868 if (mode
&& (vStringLength(mode
) == 0))
876 static vString
* determineEmacsModeAtEOF (MIO
* const fp
)
878 vString
* const vLine
= vStringNew ();
880 bool headerFound
= false;
882 vString
* mode
= vStringNew ();
883 bool is_shell_mode
= false;
885 while ((line
= readLineRaw (vLine
, fp
)) != NULL
)
887 if (headerFound
&& ((p
= strstr (line
, "mode:")) != NULL
))
892 p
+= strlen ("mode:");
893 for ( ; isspace ((unsigned char) *p
) ; ++p
)
895 for ( ; *p
!= '\0' && isLanguageNameChar ((unsigned char) *p
) ; ++p
)
896 vStringPut (mode
, *p
);
898 is_shell_mode
= ((strcasecmp (vStringValue (mode
), "sh") == 0
899 || strcasecmp (vStringValue (mode
), "shell-script") == 0));
901 else if (headerFound
&& (p
= strstr(line
, "End:")))
903 else if (strstr (line
, "Local Variables:"))
905 else if (is_shell_mode
&& (p
= strstr (line
, "sh-set-shell")))
907 p
+= strlen("sh-set-shell");
908 while (isspace ((unsigned char) *p
))
910 if (strncmp (p
, "\"zsh\"", 5) == 0)
911 vStringCopyS (mode
, "Zsh");
914 vStringDelete (vLine
);
918 static vString
* extractEmacsModeLanguageAtEOF (MIO
* input
)
922 /* "48.2.4.1 Specifying File Variables" of Emacs info:
923 ---------------------------------------------------
924 you can define file local variables using a "local
925 variables list" near the end of the file. The start of the
926 local variables list should be no more than 3000 characters
927 from the end of the file, */
928 mio_seek(input
, -3000, SEEK_END
);
930 mode
= determineEmacsModeAtEOF (input
);
931 if (mode
&& (vStringLength (mode
) == 0))
933 vStringDelete (mode
);
940 static vString
* determineVimFileType (const char *const modeline
)
942 /* considerable combinations:
943 --------------------------
950 const char* const filetype_prefix
[] = {"filetype=", "ft="};
951 vString
* const filetype
= vStringNew ();
953 for (i
= 0; i
< ARRAY_SIZE(filetype_prefix
); i
++)
955 if ((p
= strrstr(modeline
, filetype_prefix
[i
])) == NULL
)
958 p
+= strlen(filetype_prefix
[i
]);
959 for ( ; *p
!= '\0' && isalnum ((unsigned char) *p
) ; ++p
)
960 vStringPut (filetype
, *p
);
966 static vString
* extractVimFileTypeCommon(MIO
* input
, bool eof
)
968 /* http://vimdoc.sourceforge.net/htmldoc/options.html#modeline
970 [text]{white}{vi:|vim:|ex:}[white]se[t] {options}:[text]
971 options=> filetype=TYPE or ft=TYPE
973 'modelines' 'mls' number (default 5)
976 If 'modeline' is on 'modelines' gives the number of lines that is
977 checked for set commands. */
979 vString
* filetype
= NULL
;
981 vString
* ring
[RING_SIZE
];
984 const char* const prefix
[] = {
988 for (i
= 0; i
< RING_SIZE
; i
++)
989 ring
[i
] = vStringNew ();
992 while ((readLineRaw (ring
[i
++], input
)) != NULL
)
1012 for (k
= 0; k
< ARRAY_SIZE(prefix
); k
++)
1013 if ((p
= strstr (vStringValue (ring
[j
]), prefix
[k
])) != NULL
)
1015 p
+= strlen(prefix
[k
]);
1016 for ( ; isspace ((unsigned char) *p
) ; ++p
)
1018 filetype
= determineVimFileType(p
);
1021 } while (((i
== RING_SIZE
)? (j
!= RING_SIZE
- 1): (j
!= i
)) && (!filetype
));
1023 for (i
= RING_SIZE
- 1; i
>= 0; i
--)
1024 vStringDelete (ring
[i
]);
1027 if (filetype
&& (vStringLength (filetype
) == 0))
1029 vStringDelete (filetype
);
1035 [text]{white}{vi:|vim:|ex:}[white]{options} */
1038 static vString
* extractVimFileTypeAtBOF(MIO
* input
)
1040 return extractVimFileTypeCommon (input
, false);
1043 static vString
* extractVimFileTypeAtEOF(MIO
* input
)
1045 return extractVimFileTypeCommon (input
, true);
1048 static vString
* extractMarkGeneric (MIO
* input
,
1049 vString
* (* determiner
)(const char *const, void *),
1052 vString
* const vLine
= vStringNew ();
1053 const char* const line
= readLineRaw (vLine
, input
);
1054 vString
* mode
= NULL
;
1057 mode
= determiner (line
, data
);
1059 vStringDelete (vLine
);
1063 static vString
* determineZshAutoloadTag (const char *const modeline
,
1064 void *data CTAGS_ATTR_UNUSED
)
1066 /* See "Autoloaded files" in zsh info.
1067 -------------------------------------
1069 #autoload [ OPTIONS ] */
1071 if (((strncmp (modeline
, "#compdef", 8) == 0)
1072 && isspace ((unsigned char) *(modeline
+ 8)))
1073 || ((strncmp (modeline
, "#autoload", 9) == 0)
1074 && (isspace ((unsigned char) *(modeline
+ 9))
1075 || *(modeline
+ 9) == '\0')))
1076 return vStringNewInit ("zsh");
1081 static vString
* extractZshAutoloadTag(MIO
* input
)
1083 return extractMarkGeneric (input
, determineZshAutoloadTag
, NULL
);
1086 static vString
* determinePHPMark(const char *const modeline
,
1087 void *data CTAGS_ATTR_UNUSED
)
1089 if (strncmp (modeline
, "<?php", 5) == 0)
1090 return vStringNewInit ("php");
1095 static vString
* extractPHPMark(MIO
* input
)
1097 return extractMarkGeneric (input
, determinePHPMark
, NULL
);
1102 const char *fileName
;
1107 #define GLC_FOPEN_IF_NECESSARY0(_glc_, _label_) do { \
1108 if (!(_glc_)->input) { \
1109 (_glc_)->input = getMio((_glc_)->fileName, "rb", false); \
1110 if (!(_glc_)->input) { \
1111 (_glc_)->err = true; \
1117 #define GLC_FOPEN_IF_NECESSARY(_glc_, _label_, _doesParserRequireMemoryStream_) \
1119 if (!(_glc_)->input) \
1120 GLC_FOPEN_IF_NECESSARY0 (_glc_, _label_); \
1121 if ((_doesParserRequireMemoryStream_) && \
1122 (mio_memory_get_data((_glc_)->input, NULL) == NULL)) \
1124 MIO *tmp_ = (_glc_)->input; \
1125 (_glc_)->input = mio_new_mio (tmp_, 0, -1); \
1127 if (!(_glc_)->input) { \
1128 (_glc_)->err = true; \
1134 #define GLC_FCLOSE(_glc_) do { \
1135 if ((_glc_)->input) { \
1136 mio_unref((_glc_)->input); \
1137 (_glc_)->input = NULL; \
1141 static const struct taster
{
1142 vString
* (* taste
) (MIO
*);
1144 } eager_tasters
[] = {
1146 .taste
= extractInterpreter
,
1147 .msg
= "interpreter",
1150 .taste
= extractZshAutoloadTag
,
1151 .msg
= "zsh autoload tag",
1154 .taste
= extractEmacsModeAtFirstLine
,
1155 .msg
= "emacs mode at the first line",
1158 .taste
= extractEmacsModeLanguageAtEOF
,
1159 .msg
= "emacs mode at the EOF",
1162 .taste
= extractVimFileTypeAtBOF
,
1163 .msg
= "vim modeline at the BOF",
1166 .taste
= extractVimFileTypeAtEOF
,
1167 .msg
= "vim modeline at the EOF",
1170 .taste
= extractPHPMark
,
1171 .msg
= "PHP marker",
1174 static langType
tasteLanguage (struct getLangCtx
*glc
, const struct taster
*const tasters
, int n_tasters
,
1175 langType
*fallback
);
1177 /* If all the candidates have the same specialized language selector, return
1178 * it. Otherwise, return NULL.
1181 hasTheSameSelector (langType lang
, selectLanguage candidate_selector
)
1183 selectLanguage
*selector
;
1185 selector
= LanguageTable
[ lang
].def
->selectLanguage
;
1186 if (selector
== NULL
)
1191 if (*selector
== candidate_selector
)
1198 static selectLanguage
1199 commonSelector (const parserCandidate
*candidates
, int n_candidates
)
1201 Assert (n_candidates
> 1);
1202 selectLanguage
*selector
;
1205 selector
= LanguageTable
[ candidates
[0].lang
].def
->selectLanguage
;
1206 if (selector
== NULL
)
1211 for (i
= 1; i
< n_candidates
; ++i
)
1212 if (! hasTheSameSelector (candidates
[i
].lang
, *selector
))
1214 if (i
== n_candidates
)
1222 /* Calls the selector and returns the integer value of the parser for the
1223 * language associated with the string returned by the selector.
1226 pickLanguageBySelection (selectLanguage selector
, MIO
*input
,
1227 parserCandidate
*candidates
,
1228 unsigned int nCandidates
)
1231 langType
*cs
= xMalloc(nCandidates
, langType
);
1234 for (i
= 0; i
< nCandidates
; i
++)
1235 cs
[i
] = candidates
[i
].lang
;
1236 lang
= selector(input
, cs
, nCandidates
);
1241 verbose (" selection: %s\n", lang
);
1242 return getNamedLanguage(lang
, 0);
1246 verbose (" no selection\n");
1251 static int compareParsersByName (const void *a
, const void* b
)
1253 const parserDefinition
*const *la
= a
, *const *lb
= b
;
1254 return strcasecmp ((*la
)->name
, (*lb
)->name
);
1257 static int sortParserCandidatesBySpecType (const void *a
, const void *b
)
1259 const parserCandidate
*ap
= a
, *bp
= b
;
1260 if (ap
->specType
> bp
->specType
)
1262 else if (ap
->specType
== bp
->specType
)
1264 /* qsort, the function calling this function,
1265 doesn't do "stable sort". To make the result of
1266 sorting predictable, compare the names of parsers
1267 when their specType is the same. */
1268 parserDefinition
*la
= LanguageTable
[ap
->lang
].def
;
1269 parserDefinition
*lb
= LanguageTable
[bp
->lang
].def
;
1270 return compareParsersByName (&la
, &lb
);
1276 static unsigned int sortAndFilterParserCandidates (parserCandidate
*candidates
,
1277 unsigned int n_candidates
)
1279 enum specType highestSpecType
;
1283 if (n_candidates
< 2)
1284 return n_candidates
;
1286 qsort (candidates
, n_candidates
, sizeof(*candidates
),
1287 sortParserCandidatesBySpecType
);
1289 highestSpecType
= candidates
[0].specType
;
1291 for (i
= 1; i
< n_candidates
; i
++)
1293 if (candidates
[i
].specType
== highestSpecType
)
1299 static void verboseReportCandidate (const char *header
,
1300 parserCandidate
*candidates
,
1301 unsigned int n_candidates
)
1304 verbose (" #%s: %u\n", header
, n_candidates
);
1305 for (i
= 0; i
< n_candidates
; i
++)
1306 verbose (" %u: %s (%s: \"%s\")\n",
1308 LanguageTable
[candidates
[i
].lang
].def
->name
,
1309 specTypeName
[candidates
[i
].specType
],
1310 candidates
[i
].spec
);
1313 static bool doesCandidatesRequireMemoryStream(const parserCandidate
*candidates
,
1318 for (i
= 0; i
< n_candidates
; i
++)
1319 if (doesParserRequireMemoryStream (candidates
[i
].lang
))
1325 static langType
getSpecLanguageCommon (const char *const spec
, struct getLangCtx
*glc
,
1326 unsigned int nominate (const char *const, parserCandidate
**),
1330 parserCandidate
*candidates
;
1331 unsigned int n_candidates
;
1334 *fallback
= LANG_IGNORE
;
1336 n_candidates
= (*nominate
)(spec
, &candidates
);
1337 verboseReportCandidate ("candidates",
1338 candidates
, n_candidates
);
1340 n_candidates
= sortAndFilterParserCandidates (candidates
, n_candidates
);
1341 verboseReportCandidate ("candidates after sorting and filtering",
1342 candidates
, n_candidates
);
1344 if (n_candidates
== 1)
1346 language
= candidates
[0].lang
;
1348 else if (n_candidates
> 1)
1350 selectLanguage selector
= commonSelector(candidates
, n_candidates
);
1351 bool memStreamRequired
= doesCandidatesRequireMemoryStream (candidates
,
1354 GLC_FOPEN_IF_NECESSARY(glc
, fopen_error
, memStreamRequired
);
1356 verbose (" selector: %p\n", selector
);
1357 language
= pickLanguageBySelection(selector
, glc
->input
, candidates
, n_candidates
);
1359 verbose (" selector: NONE\n");
1361 language
= LANG_IGNORE
;
1364 Assert(language
!= LANG_AUTO
);
1367 *fallback
= candidates
[0].lang
;
1371 language
= LANG_IGNORE
;
1380 static langType
getSpecLanguage (const char *const spec
,
1381 struct getLangCtx
*glc
,
1384 return getSpecLanguageCommon(spec
, glc
, nominateLanguageCandidates
,
1388 static langType
getPatternLanguage (const char *const baseName
,
1389 struct getLangCtx
*glc
,
1392 return getSpecLanguageCommon(baseName
, glc
,
1393 nominateLanguageCandidatesForPattern
,
1397 /* This function tries to figure out language contained in a file by
1398 * running a series of tests, trying to find some clues in the file.
1401 tasteLanguage (struct getLangCtx
*glc
, const struct taster
*const tasters
, int n_tasters
,
1407 *fallback
= LANG_IGNORE
;
1408 for (i
= 0; i
< n_tasters
; ++i
) {
1412 mio_rewind(glc
->input
);
1413 spec
= tasters
[i
].taste(glc
->input
);
1416 verbose (" %s: %s\n", tasters
[i
].msg
, vStringValue (spec
));
1417 language
= getSpecLanguage (vStringValue (spec
), glc
,
1418 (fallback
&& (*fallback
== LANG_IGNORE
))? fallback
: NULL
);
1419 vStringDelete (spec
);
1420 if (language
!= LANG_IGNORE
)
1429 struct GetLanguageRequest
{
1430 enum { GLR_OPEN
, GLR_DISCARD
, GLR_REUSE
, } type
;
1431 const char *const fileName
;
1437 getFileLanguageForRequestInternal (struct GetLanguageRequest
*req
)
1439 const char *const fileName
= req
->fileName
;
1442 /* ctags tries variety ways(HINTS) to choose a proper language
1443 for given fileName. If multiple candidates are chosen in one of
1444 the hint, a SELECTOR common between the candidate languages
1447 "selection failure" means a selector common between the
1448 candidates doesn't exist or the common selector returns NULL.
1450 "hint failure" means the hint finds no candidate or
1451 "selection failure" occurs though the hint finds multiple
1454 If a hint chooses multiple candidates, and selection failure is
1455 occurred, the hint records one of the candidates as FALLBACK for
1456 the hint. (The candidates are stored in an array. The first
1457 element of the array is recorded. However, there is no
1458 specification about the order of elements in the array.)
1460 If all hints are failed, FALLBACKs of the hints are examined.
1461 Which fallbacks should be chosen? `enum hint' defines the order. */
1469 langType fallback
[N_HINTS
];
1471 struct getLangCtx glc
= {
1472 .fileName
= fileName
,
1473 .input
= (req
->type
== GLR_REUSE
)? mio_ref (req
->mio
): NULL
,
1476 const char* const baseName
= baseFilename (fileName
);
1477 char *templateBaseName
= NULL
;
1478 fileStatus
*fstatus
= NULL
;
1480 for (i
= 0; i
< N_HINTS
; i
++)
1481 fallback
[i
] = LANG_IGNORE
;
1483 verbose ("Get file language for %s\n", fileName
);
1485 verbose (" pattern: %s\n", baseName
);
1486 language
= getPatternLanguage (baseName
, &glc
,
1487 fallback
+ HINT_FILENAME
);
1488 if (language
!= LANG_IGNORE
|| glc
.err
)
1492 const char* const tExt
= ".in";
1493 templateBaseName
= baseFilenameSansExtensionNew (fileName
, tExt
);
1494 if (templateBaseName
)
1496 verbose (" pattern + template(%s): %s\n", tExt
, templateBaseName
);
1497 GLC_FOPEN_IF_NECESSARY(&glc
, cleanup
, false);
1498 mio_rewind(glc
.input
);
1499 language
= getPatternLanguage(templateBaseName
, &glc
,
1500 fallback
+ HINT_TEMPLATE
);
1501 if (language
!= LANG_IGNORE
)
1506 /* If the input is already opened, we don't have to verify the existence. */
1507 if (glc
.input
|| ((fstatus
= eStat (fileName
)) && fstatus
->exists
))
1509 if ((fstatus
&& fstatus
->isExecutable
) || Option
.guessLanguageEagerly
)
1511 GLC_FOPEN_IF_NECESSARY (&glc
, cleanup
, false);
1512 language
= tasteLanguage(&glc
, eager_tasters
, 1,
1513 fallback
+ HINT_INTERP
);
1515 if (language
!= LANG_IGNORE
)
1518 if (Option
.guessLanguageEagerly
)
1520 GLC_FOPEN_IF_NECESSARY(&glc
, cleanup
, false);
1521 language
= tasteLanguage(&glc
,
1523 ARRAY_SIZE(eager_tasters
) - 1,
1524 fallback
+ HINT_OTHER
);
1530 if (req
->type
== GLR_OPEN
&& glc
.input
)
1532 req
->mio
= mio_ref (glc
.input
);
1534 fstatus
= eStat (fileName
);
1536 req
->mtime
= fstatus
->mtime
;
1540 eStatFree (fstatus
);
1541 if (templateBaseName
)
1542 eFree (templateBaseName
);
1545 language
== LANG_IGNORE
&& i
< N_HINTS
;
1548 language
= fallback
[i
];
1549 if (language
!= LANG_IGNORE
)
1550 verbose (" fallback[hint = %d]: %s\n", i
, getLanguageName (language
));
1553 if (language
== LANG_IGNORE
1554 && isLanguageEnabled (LANG_FALLBACK
))
1556 language
= LANG_FALLBACK
;
1557 verbose (" last resort: using \"%s\" parser\n",
1558 getLanguageName (LANG_FALLBACK
));
1563 static langType
getFileLanguageForRequest (struct GetLanguageRequest
*req
)
1565 langType l
= Option
.language
;
1568 return getFileLanguageForRequestInternal(req
);
1569 else if (! isLanguageEnabled (l
))
1572 "%s parser specified with --language-force is disabled",
1573 getLanguageName (l
));
1574 /* For suppressing warnings. */
1578 return Option
.language
;
1581 extern langType
getLanguageForFilenameAndContents (const char *const fileName
)
1583 struct GetLanguageRequest req
= {
1584 .type
= GLR_DISCARD
,
1585 .fileName
= fileName
,
1589 return getFileLanguageForRequest (&req
);
1592 typedef void (*languageCallback
) (langType language
, void* user_data
);
1593 static void foreachLanguage(languageCallback callback
, void *user_data
)
1595 langType result
= LANG_IGNORE
;
1598 for (i
= 0 ; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
1600 const parserDefinition
* const lang
= LanguageTable
[i
].def
;
1601 if (lang
->name
!= NULL
)
1602 callback(i
, user_data
);
1606 static void printLanguageMap (const langType language
, FILE *fp
)
1610 parserObject
*parser
= LanguageTable
+ language
;
1611 stringList
* map
= parser
->currentPatterns
;
1612 Assert (0 <= language
&& language
< (int) LanguageCount
);
1613 for (i
= 0 ; map
!= NULL
&& i
< stringListCount (map
) ; ++i
)
1615 fprintf (fp
, "%s(%s)", (first
? "" : " "),
1616 vStringValue (stringListItem (map
, i
)));
1619 map
= parser
->currentExtensions
;
1620 for (i
= 0 ; map
!= NULL
&& i
< stringListCount (map
) ; ++i
)
1622 fprintf (fp
, "%s.%s", (first
? "" : " "),
1623 vStringValue (stringListItem (map
, i
)));
1628 extern void installLanguageMapDefault (const langType language
)
1630 parserObject
* parser
;
1631 Assert (0 <= language
&& language
< (int) LanguageCount
);
1632 parser
= LanguageTable
+ language
;
1633 if (parser
->currentPatterns
!= NULL
)
1634 stringListDelete (parser
->currentPatterns
);
1635 if (parser
->currentExtensions
!= NULL
)
1636 stringListDelete (parser
->currentExtensions
);
1638 if (parser
->def
->patterns
== NULL
)
1639 parser
->currentPatterns
= stringListNew ();
1642 parser
->currentPatterns
=
1643 stringListNewFromArgv (parser
->def
->patterns
);
1645 if (parser
->def
->extensions
== NULL
)
1646 parser
->currentExtensions
= stringListNew ();
1649 parser
->currentExtensions
=
1650 stringListNewFromArgv (parser
->def
->extensions
);
1654 printLanguageMap (language
, vfp
);
1660 extern void installLanguageMapDefaults (void)
1663 for (i
= 0 ; i
< LanguageCount
; ++i
)
1665 verbose (" %s: ", getLanguageName (i
));
1666 installLanguageMapDefault (i
);
1670 extern void installLanguageAliasesDefault (const langType language
)
1672 parserObject
* parser
;
1673 Assert (0 <= language
&& language
< (int) LanguageCount
);
1674 parser
= LanguageTable
+ language
;
1675 if (parser
->currentAliases
!= NULL
)
1676 stringListDelete (parser
->currentAliases
);
1678 if (parser
->def
->aliases
== NULL
)
1679 parser
->currentAliases
= stringListNew ();
1682 parser
->currentAliases
=
1683 stringListNewFromArgv (parser
->def
->aliases
);
1686 if (parser
->currentAliases
!= NULL
)
1687 for (unsigned int i
= 0 ; i
< stringListCount (parser
->currentAliases
) ; ++i
)
1688 fprintf (vfp
, " %s", vStringValue (
1689 stringListItem (parser
->currentAliases
, i
)));
1694 extern void installLanguageAliasesDefaults (void)
1697 for (i
= 0 ; i
< LanguageCount
; ++i
)
1699 verbose (" %s: ", getLanguageName (i
));
1700 installLanguageAliasesDefault (i
);
1704 extern void clearLanguageMap (const langType language
)
1706 Assert (0 <= language
&& language
< (int) LanguageCount
);
1707 stringListClear ((LanguageTable
+ language
)->currentPatterns
);
1708 stringListClear ((LanguageTable
+ language
)->currentExtensions
);
1711 extern void clearLanguageAliases (const langType language
)
1713 Assert (0 <= language
&& language
< (int) LanguageCount
);
1715 parserObject
* parser
= (LanguageTable
+ language
);
1716 if (parser
->currentAliases
)
1717 stringListClear (parser
->currentAliases
);
1720 static bool removeLanguagePatternMap1(const langType language
, const char *const pattern
)
1722 bool result
= false;
1723 stringList
* const ptrn
= (LanguageTable
+ language
)->currentPatterns
;
1725 if (ptrn
!= NULL
&& stringListDeleteItemExtension (ptrn
, pattern
))
1727 verbose (" (removed from %s)", getLanguageName (language
));
1733 extern bool removeLanguagePatternMap (const langType language
, const char *const pattern
)
1735 bool result
= false;
1737 if (language
== LANG_AUTO
)
1740 for (i
= 0 ; i
< LanguageCount
&& ! result
; ++i
)
1741 result
= removeLanguagePatternMap1 (i
, pattern
) || result
;
1744 result
= removeLanguagePatternMap1 (language
, pattern
);
1748 extern void addLanguagePatternMap (const langType language
, const char* ptrn
,
1749 bool exclusiveInAllLanguages
)
1751 vString
* const str
= vStringNewInit (ptrn
);
1752 parserObject
* parser
;
1753 Assert (0 <= language
&& language
< (int) LanguageCount
);
1754 parser
= LanguageTable
+ language
;
1755 if (exclusiveInAllLanguages
)
1756 removeLanguagePatternMap (LANG_AUTO
, ptrn
);
1757 stringListAdd (parser
->currentPatterns
, str
);
1760 static bool removeLanguageExtensionMap1 (const langType language
, const char *const extension
)
1762 bool result
= false;
1763 stringList
* const exts
= (LanguageTable
+ language
)->currentExtensions
;
1765 if (exts
!= NULL
&& stringListDeleteItemExtension (exts
, extension
))
1767 verbose (" (removed from %s)", getLanguageName (language
));
1773 extern bool removeLanguageExtensionMap (const langType language
, const char *const extension
)
1775 bool result
= false;
1777 if (language
== LANG_AUTO
)
1780 for (i
= 0 ; i
< LanguageCount
; ++i
)
1781 result
= removeLanguageExtensionMap1 (i
, extension
) || result
;
1784 result
= removeLanguageExtensionMap1 (language
, extension
);
1788 extern void addLanguageExtensionMap (
1789 const langType language
, const char* extension
,
1790 bool exclusiveInAllLanguages
)
1792 vString
* const str
= vStringNewInit (extension
);
1793 Assert (0 <= language
&& language
< (int) LanguageCount
);
1794 if (exclusiveInAllLanguages
)
1795 removeLanguageExtensionMap (LANG_AUTO
, extension
);
1796 stringListAdd ((LanguageTable
+ language
)->currentExtensions
, str
);
1799 extern void addLanguageAlias (const langType language
, const char* alias
)
1801 vString
* const str
= vStringNewInit (alias
);
1802 parserObject
* parser
;
1803 Assert (0 <= language
&& language
< (int) LanguageCount
);
1804 parser
= LanguageTable
+ language
;
1805 if (parser
->currentAliases
== NULL
)
1806 parser
->currentAliases
= stringListNew ();
1807 stringListAdd (parser
->currentAliases
, str
);
1810 extern void enableLanguage (const langType language
, const bool state
)
1812 Assert (0 <= language
&& language
< (int) LanguageCount
);
1813 LanguageTable
[language
].def
->enabled
= state
;
1817 extern void traceLanguage (langType language
)
1819 Assert (0 <= language
&& language
< (int) LanguageCount
);
1820 LanguageTable
[language
].def
->traced
= true;
1822 extern bool isLanguageTraced (langType language
)
1824 Assert (0 <= language
&& language
< (int) LanguageCount
);
1825 return LanguageTable
[language
].def
->traced
;
1827 #endif /* DO_TRACING */
1829 extern void enableLanguages (const bool state
)
1832 for (i
= 0 ; i
< LanguageCount
; ++i
)
1833 enableLanguage (i
, state
);
1836 static void installFieldDefinition (const langType language
)
1839 parserDefinition
* parser
;
1841 Assert (0 <= language
&& language
< (int) LanguageCount
);
1842 parser
= LanguageTable
[language
].def
;
1844 if (parser
->fieldTable
!= NULL
)
1846 for (i
= 0; i
< parser
->fieldCount
; i
++)
1847 defineField (& parser
->fieldTable
[i
], language
);
1851 static void installXtagDefinition (const langType language
)
1854 parserDefinition
* parser
;
1856 Assert (0 <= language
&& language
< (int) LanguageCount
);
1857 parser
= LanguageTable
[language
].def
;
1859 if (parser
->xtagTable
!= NULL
)
1861 for (i
= 0; i
< parser
->xtagCount
; i
++)
1862 defineXtag (& parser
->xtagTable
[i
], language
);
1866 static void initializeParserOne (langType lang
)
1868 parserObject
*const parser
= LanguageTable
+ lang
;
1870 if (parser
->initialized
)
1873 verbose ("Initialize parser: %s\n", parser
->def
->name
);
1874 parser
->initialized
= true;
1876 installKeywordTable (lang
);
1877 installTagXpathTable (lang
);
1878 installFieldDefinition (lang
);
1879 installXtagDefinition (lang
);
1881 /* regex definitions refers xtag definitions.
1882 So installing RegexTable must be after installing
1883 xtag definitions. */
1884 installTagRegexTable (lang
);
1886 if (parser
->def
->initialize
!= NULL
)
1887 parser
->def
->initialize (lang
);
1889 initializeDependencies (parser
->def
, parser
->slaveControlBlock
);
1891 Assert (parser
->fileKind
!= NULL
);
1892 Assert (!doesParserUseKind (parser
->kindControlBlock
, parser
->fileKind
->letter
));
1897 /* lazyInitialize() installs findRegexTags() to parser->parser.
1898 findRegexTags() should be installed to a parser if the parser is
1899 optlib based(created by --langdef) and has some regex patterns(defined
1900 with --regex-<LANG>). findRegexTags() makes regex matching work.
1902 If a parser can be initialized during evaluating options,
1903 --fields-<LANG>=+{something}, for an example.
1904 If such option is evaluated first, evaluating --regex-<LANG>=...
1905 option doesn't cause installing findRegexTags. As the result
1906 regex matching doesn't work. lazyInitialize was called only
1907 once when --fields-<LANG>=+{something} was evaluated. In the
1908 timing ctags had not seen --regex-<LANG>=.... Even though
1909 ctags saw --regex-<LANG>=.... after initializing, there
1910 was no chance to install findRegexTags() to parser->parser.
1912 Following code block gives extra chances to call lazyInitialize)
1913 which installs findRegexTags() to parser->parser. */
1914 if (parser
->def
->initialize
== lazyInitialize
)
1915 parser
->def
->initialize (lang
);
1918 extern void initializeParser (langType lang
)
1920 if (lang
== LANG_AUTO
)
1923 for (i
= 0; i
< countParsers(); i
++)
1924 initializeParserOne (i
);
1927 initializeParserOne (lang
);
1930 static void linkDependenciesAtInitializeParsing (parserDefinition
*const parser
)
1933 parserDependency
*d
;
1935 parserDefinition
*lowerParser
;
1936 parserObject
*upperParser
;
1938 for (i
= 0; i
< parser
->dependencyCount
; i
++)
1940 d
= parser
->dependencies
+ i
;
1942 if (d
->type
== DEPTYPE_FOREIGNER
)
1945 langType lower
= getNamedLanguage (d
->upperParser
, 0);
1946 if (lower
== LANG_IGNORE
)
1948 "Unknown language: \"%s\" as a foreigner for %s",
1949 d
->upperParser
, parser
->name
);
1951 lowerParser
= LanguageTable
[lower
].def
;
1955 upper
= getNamedLanguage (d
->upperParser
, 0);
1956 lowerParser
= parser
;
1959 upperParser
= LanguageTable
+ upper
;
1961 verbose ("link dependencies: type = %s, upper = %s, lower = %s\n",
1962 dependencyTypeString(d
->type
),
1963 upperParser
->def
->name
, lowerParser
->name
);
1964 linkDependencyAtInitializeParsing (d
->type
, upperParser
->def
,
1965 upperParser
->slaveControlBlock
,
1966 upperParser
->kindControlBlock
,
1968 (LanguageTable
+ lowerParser
->id
)->kindControlBlock
,
1973 /* Used in both builtin and optlib parsers. */
1974 static void initializeParsingCommon (parserDefinition
*def
, bool is_builtin
)
1976 parserObject
*parser
;
1979 verbose ("%s%s", LanguageCount
> 0 ? ", " : "", def
->name
);
1981 verbose ("Add optlib parser: %s\n", def
->name
);
1983 def
->id
= LanguageCount
++;
1984 parser
= LanguageTable
+ def
->id
;
1987 hashTablePutItem (LanguageHTable
, def
->name
, def
);
1989 parser
->fileKind
= &defaultFileKind
;
1991 parser
->kindControlBlock
= allocKindControlBlock (def
);
1992 parser
->slaveControlBlock
= allocSlaveControlBlock (def
);
1993 parser
->lregexControlBlock
= allocLregexControlBlock (def
);
1994 parser
->paramControlBlock
= allocParamControlBlock (def
);
1997 static char *acceptableLangName(char *name
)
1999 for (char *c
= name
; *c
!= '\0'; c
++)
2001 if (isalnum ((unsigned char)*c
))
2003 else if (*c
== '+' || *c
== '#')
2011 extern void initializeParsing (void)
2013 unsigned int builtInCount
;
2016 builtInCount
= ARRAY_SIZE (BuiltInParsers
);
2017 LanguageTable
= xMalloc (builtInCount
, parserObject
);
2018 memset(LanguageTable
, 0, builtInCount
* sizeof (parserObject
));
2019 for (i
= 0; i
< builtInCount
; ++i
)
2021 LanguageTable
[i
].pretendingAsLanguage
= LANG_IGNORE
;
2022 LanguageTable
[i
].pretendedAsLanguage
= LANG_IGNORE
;
2025 LanguageHTable
= hashTableNew (127,
2030 DEFAULT_TRASH_BOX(LanguageHTable
, hashTableDelete
);
2032 verbose ("Installing parsers: ");
2033 for (i
= 0 ; i
< builtInCount
; ++i
)
2035 parserDefinition
* const def
= (*BuiltInParsers
[i
]) ();
2039 Assert (def
->name
[0] != '\0');
2040 Assert (strcmp (def
->name
, RSV_LANG_ALL
));
2041 Assert (acceptableLangName (def
->name
) == NULL
);
2043 if (def
->method
& METHOD_NOT_CRAFTED
)
2044 def
->parser
= findRegexTags
;
2046 /* parser definition must define one and only one parsing routine */
2047 Assert ((!!def
->parser
) + (!!def
->parser2
) == 1);
2049 initializeParsingCommon (def
, true);
2054 for (i
= 0; i
< builtInCount
; ++i
)
2055 linkDependenciesAtInitializeParsing (LanguageTable
[i
].def
);
2058 extern void freeParserResources (void)
2061 for (i
= 0 ; i
< LanguageCount
; ++i
)
2063 parserObject
* const parser
= LanguageTable
+ i
;
2065 if (parser
->def
->finalize
)
2066 (parser
->def
->finalize
)((langType
)i
, (bool)parser
->initialized
);
2068 uninstallTagXpathTable (i
);
2070 freeLregexControlBlock (parser
->lregexControlBlock
);
2071 freeKindControlBlock (parser
->kindControlBlock
);
2072 parser
->kindControlBlock
= NULL
;
2074 finalizeDependencies (parser
->def
, parser
->slaveControlBlock
);
2075 freeSlaveControlBlock (parser
->slaveControlBlock
);
2076 parser
->slaveControlBlock
= NULL
;
2078 freeParamControlBlock (parser
->paramControlBlock
);
2080 freeList (&parser
->currentPatterns
);
2081 freeList (&parser
->currentExtensions
);
2082 freeList (&parser
->currentAliases
);
2084 eFree (parser
->def
->name
);
2085 parser
->def
->name
= NULL
;
2086 eFree (parser
->def
);
2089 if (LanguageTable
!= NULL
)
2090 eFree (LanguageTable
);
2091 LanguageTable
= NULL
;
2095 static void doNothing (void)
2099 static void optlibRunBaseParser (void)
2101 scheduleRunningBaseparser (0);
2104 static bool optlibIsDedicatedSubparser (parserDefinition
* def
)
2106 return (def
->dependencies
2107 && (def
->dependencies
->type
== DEPTYPE_SUBPARSER
)
2108 && ((subparser
*)def
->dependencies
->data
)->direction
& SUBPARSER_SUB_RUNS_BASE
);
2111 static void lazyInitialize (langType language
)
2113 parserDefinition
* def
;
2115 Assert (0 <= language
&& language
< (int) LanguageCount
);
2116 def
= LanguageTable
[language
].def
;
2118 def
->parser
= doNothing
;
2120 if (def
->method
& METHOD_REGEX
)
2122 if (optlibIsDedicatedSubparser (def
))
2123 def
->parser
= optlibRunBaseParser
;
2125 def
->parser
= findRegexTags
;
2129 extern void enableDefaultFileKind (bool state
)
2131 defaultFileKind
.enabled
= state
;
2137 struct preLangDefFlagData
2139 const char *const name
;
2141 subparserRunDirection direction
;
2143 intArray
*foreignLanguages
;
2144 unsigned int versionCurrent
;
2145 unsigned int versionAge
;
2148 static void pre_lang_def_flag_base_long (const char* const optflag
, const char* const param
, void* data
)
2150 struct preLangDefFlagData
* flag_data
= data
;
2153 if (param
[0] == '\0')
2155 error (WARNING
, "No base parser specified for \"%s\" flag of --langdef option", optflag
);
2159 base
= getNamedLanguage (param
, 0);
2160 if (base
== LANG_IGNORE
)
2162 error (WARNING
, "Unknown language(%s) is specified for \"%s\" flag of --langdef option",
2168 langType cpreproc
= getNamedLanguage ("CPreProcessor", 0);
2169 if (base
== cpreproc
)
2171 /* See Tmain/optscript-preludes-stack.d */
2173 "Because of an internal limitation, Making a sub parser based on the CPreProcessor parser is not allowed: %s",
2178 flag_data
->base
= eStrdup(param
);
2181 #define LANGDEF_FLAG_DEDICATED "dedicated"
2182 #define LANGDEF_FLAG_SHARED "shared"
2183 #define LANGDEF_FLAG_BIDIR "bidirectional"
2184 static void pre_lang_def_flag_direction_long (const char* const optflag
, const char* const param CTAGS_ATTR_UNUSED
, void* data
)
2186 struct preLangDefFlagData
* flag_data
= data
;
2188 if (strcmp(optflag
, LANGDEF_FLAG_DEDICATED
) == 0)
2189 flag_data
->direction
= SUBPARSER_SUB_RUNS_BASE
;
2190 else if (strcmp(optflag
, LANGDEF_FLAG_SHARED
) == 0)
2191 flag_data
->direction
= SUBPARSER_BASE_RUNS_SUB
;
2192 else if (strcmp(optflag
, LANGDEF_FLAG_BIDIR
) == 0)
2193 flag_data
->direction
= SUBPARSER_BI_DIRECTION
;
2195 AssertNotReached ();
2198 static void pre_lang_def_flag_autoFQTag_long (const char* const optflag
,
2199 const char* const param CTAGS_ATTR_UNUSED
,
2202 struct preLangDefFlagData
* flag_data
= data
;
2203 flag_data
->autoFQTag
= true;
2206 static void pre_lang_def_flag_foreignLanguage_long (const char* const optflag
,
2207 const char* const param
,
2210 struct preLangDefFlagData
* flag_data
= data
;
2213 error (WARNING
, "value for '%s' flag is empty", optflag
);
2217 langType lang
= getNamedLanguage (param
, 0);
2218 if (lang
== LANG_IGNORE
)
2219 error (FATAL
, "language named '%s' is not found or not initialized yet",
2222 verbose ("Foreign language for %s: %s\n", flag_data
->name
, getLanguageName (lang
));
2223 intArrayAdd (flag_data
->foreignLanguages
, lang
);
2226 static void pre_lang_def_flag_version_long (const char* const optflag CTAGS_ATTR_UNUSED
,
2227 const char* const param
,
2230 struct preLangDefFlagData
* flag_data
= data
;
2231 char * verstr
= eStrdup (param
);
2232 char * age
= strchr(verstr
, '.');
2234 error (FATAL
, "Faile to parse the version number ('.') for language \"%s\": %s",
2235 flag_data
->name
, param
);
2239 if (!strToUInt (verstr
, 10, &flag_data
->versionCurrent
))
2240 error (FATAL
, "Faile to parse the version number (the current part) for language \"%s\": %s",
2241 flag_data
->name
, param
);
2243 if (!strToUInt (age
, 10, &flag_data
->versionAge
))
2244 error (FATAL
, "Faile to parse the version number (the age part) for language \"%s\": %s",
2245 flag_data
->name
, param
);
2250 static flagDefinition PreLangDefFlagDef
[] = {
2251 { '\0', "base", NULL
, pre_lang_def_flag_base_long
,
2252 "BASEPARSER", "utilize as a base parser"},
2253 { '\0', LANGDEF_FLAG_DEDICATED
, NULL
,
2254 pre_lang_def_flag_direction_long
,
2255 NULL
, "make the base parser dedicated to this subparser"},
2256 { '\0', LANGDEF_FLAG_SHARED
, NULL
,
2257 pre_lang_def_flag_direction_long
,
2258 NULL
, "share the base parser with the other subparsers"
2260 { '\0', LANGDEF_FLAG_BIDIR
, NULL
,
2261 pre_lang_def_flag_direction_long
,
2262 NULL
, "utilize the base parser both 'dedicated' and 'shared' way"
2264 { '\0', "_autoFQTag", NULL
, pre_lang_def_flag_autoFQTag_long
,
2265 NULL
, "make full qualified tags automatically based on scope information"},
2266 { '\0', "_foreignLanguage", NULL
, pre_lang_def_flag_foreignLanguage_long
,
2267 "LANG", "initialize another parser" },
2268 { '\0', "version", NULL
, pre_lang_def_flag_version_long
,
2269 NULL
, "set the version of the parser (current.age)"},
2272 static void optlibFreeDep (langType lang
, bool initialized CTAGS_ATTR_UNUSED
)
2274 parserDefinition
* pdef
= LanguageTable
[lang
].def
;
2276 for (size_t i
= 0; i
< pdef
->dependencyCount
; i
++)
2278 parserDependency
*dep
= pdef
->dependencies
+ i
;
2280 eFree ((char *)dep
->upperParser
); /* Dirty cast */
2281 dep
->upperParser
= NULL
;
2289 if (pdef
->dependencies
)
2291 eFree (pdef
->dependencies
);
2292 pdef
->dependencies
= NULL
;
2296 static parserDefinition
* OptlibParser(const char *name
, const char *base
,
2297 subparserRunDirection direction
,
2298 intArray
*foreignLanguages
)
2300 parserDefinition
*def
;
2301 parserDependency
*dep
= NULL
;
2303 def
= parserNew (name
);
2304 def
->initialize
= lazyInitialize
;
2305 def
->method
= METHOD_NOT_CRAFTED
;
2307 size_t dep_count
= (base
? 1: 0) + intArrayCount (foreignLanguages
);
2311 dep
= xCalloc (dep_count
, parserDependency
);
2312 def
->dependencies
= dep
;
2313 def
->dependencyCount
= dep_count
;
2314 def
->finalize
= optlibFreeDep
;
2319 subparser
*sub
= xCalloc (1, subparser
);
2321 sub
->direction
= direction
;
2322 dep
[0].type
= DEPTYPE_SUBPARSER
;
2323 dep
[0].upperParser
= eStrdup (base
);
2327 for (size_t i
= 0 ; i
< intArrayCount (foreignLanguages
); i
++)
2329 size_t index
= (base
? 1: 0) + i
;
2330 langType lang
= intArrayItem (foreignLanguages
, i
);
2331 Assert (lang
!= LANG_IGNORE
2332 && lang
!= LANG_AUTO
2333 && lang
< (int) LanguageCount
);
2335 dep
[index
].type
= DEPTYPE_FOREIGNER
;
2336 dep
[index
].upperParser
= eStrdup (getLanguageName (lang
));
2337 dep
[index
].data
= NULL
;
2343 extern void processLanguageDefineOption (
2344 const char *const option
, const char *const parameter
)
2348 parserDefinition
* def
;
2350 flags
= strchr (parameter
, LONG_FLAGS_OPEN
);
2352 name
= eStrndup (parameter
, flags
- parameter
);
2354 name
= eStrdup (parameter
);
2356 /* Veirfy that the name of new language is acceptable or not. */
2358 if (name
[0] == '\0')
2361 error (FATAL
, "No language specified for \"%s\" option", option
);
2363 else if (getNamedLanguage (name
, 0) != LANG_IGNORE
)
2365 /* name cannot be freed because it is used in the FATAL message. */
2366 error (FATAL
, "Language \"%s\" already defined", name
);
2368 else if (strcmp(name
, RSV_LANG_ALL
) == 0)
2371 error (FATAL
, "\"" RSV_LANG_ALL
"\" is reserved; don't use it as the name for defining a new language");
2373 else if (strcmp(name
, RSV_NONE
) == 0)
2376 error (FATAL
, "\"" RSV_NONE
"\" is reserved; don't use it as the name for defining a new language");
2379 else if ((unacceptable
= acceptableLangName(name
)))
2381 char c
= *unacceptable
;
2383 /* name cannot be freed because it is used in the FATAL message. */
2385 * We accept # and + because they are already used in C# parser and C++ parser.
2386 * {... is already trimmed at the beginning of this function. */
2387 if ((c
== '`') || (c
== '\''))
2388 error (FATAL
, "don't use \"%c\" in a language name (%s)", c
, name
);
2390 error (FATAL
, "don't use `%c' in a language name (%s)", c
, name
);
2393 LanguageTable
= xRealloc (LanguageTable
, LanguageCount
+ 1, parserObject
);
2394 memset (LanguageTable
+ LanguageCount
, 0, sizeof(parserObject
));
2396 struct preLangDefFlagData data
= {
2399 .direction
= SUBPARSER_UNKNOWN_DIRECTION
,
2401 .versionCurrent
= 0,
2404 data
.foreignLanguages
= intArrayNew ();
2406 flagsEval (flags
, PreLangDefFlagDef
, ARRAY_SIZE (PreLangDefFlagDef
), &data
);
2408 if (data
.base
== NULL
&& data
.direction
!= SUBPARSER_UNKNOWN_DIRECTION
)
2409 error (WARNING
, "Ignore the direction of subparser because \"{base=}\" is not given");
2411 if (data
.base
&& data
.direction
== SUBPARSER_UNKNOWN_DIRECTION
)
2412 data
.direction
= SUBPARSER_BASE_RUNS_SUB
;
2414 def
= OptlibParser (name
, data
.base
, data
.direction
,
2415 data
.foreignLanguages
);
2419 def
->requestAutomaticFQTag
= data
.autoFQTag
;
2420 def
->versionCurrent
= data
.versionCurrent
;
2421 def
->versionAge
= data
.versionAge
;
2423 initializeParsingCommon (def
, false);
2424 linkDependenciesAtInitializeParsing (def
);
2426 LanguageTable
[def
->id
].currentPatterns
= stringListNew ();
2427 LanguageTable
[def
->id
].currentExtensions
= stringListNew ();
2428 LanguageTable
[def
->id
].pretendingAsLanguage
= LANG_IGNORE
;
2429 LanguageTable
[def
->id
].pretendedAsLanguage
= LANG_IGNORE
;
2431 intArrayDelete (data
.foreignLanguages
);
2435 extern bool doesLanguageHaveForeignDependency (const langType lang
,
2436 const langType foreignLang
)
2438 Assert (lang
!= LANG_IGNORE
2439 && lang
!= LANG_AUTO
2440 && lang
< (int) LanguageCount
);
2441 Assert (foreignLang
!= LANG_IGNORE
2442 && foreignLang
!= LANG_AUTO
2443 && foreignLang
< (int) LanguageCount
);
2446 parserDefinition
* pdef
= LanguageTable
[lang
].def
;
2448 for (size_t i
= 0; i
< pdef
->dependencyCount
; i
++)
2450 parserDependency
*dep
= pdef
->dependencies
+ i
;
2452 if (dep
->type
== DEPTYPE_FOREIGNER
)
2454 if (getNamedLanguage (dep
->upperParser
, 0) == foreignLang
)
2462 extern bool isLanguageKindEnabled (const langType language
, int kindIndex
)
2464 kindDefinition
* kdef
= getLanguageKind (language
, kindIndex
);
2465 return kdef
->enabled
;
2468 extern bool isLanguageRoleEnabled (const langType language
, int kindIndex
, int roleIndex
)
2470 return isRoleEnabled(LanguageTable
[language
].kindControlBlock
,
2471 kindIndex
, roleIndex
);
2474 extern bool isLanguageKindRefOnly (const langType language
, int kindIndex
)
2476 kindDefinition
* def
= getLanguageKind(language
, kindIndex
);
2477 return def
->referenceOnly
;
2480 static void resetLanguageKinds (const langType language
, const bool mode
)
2482 const parserObject
* parser
;
2484 Assert (0 <= language
&& language
< (int) LanguageCount
);
2485 parser
= LanguageTable
+ language
;
2489 struct kindControlBlock
*kcb
= parser
->kindControlBlock
;
2491 for (i
= 0 ; i
< countKinds (kcb
) ; ++i
)
2493 kindDefinition
*kdef
= getKind (kcb
, i
);
2494 enableKind (kdef
, mode
);
2499 static bool enableLanguageKindForLetter (
2500 const langType language
, const int kind
, const bool mode
)
2502 bool result
= false;
2503 kindDefinition
* const def
= getLanguageKindForLetter (language
, kind
);
2506 enableKind (def
, mode
);
2512 static bool enableLanguageKindForName (
2513 const langType language
, const char * const name
, const bool mode
)
2515 bool result
= false;
2516 kindDefinition
* const def
= getLanguageKindForName (language
, name
);
2519 enableKind (def
, mode
);
2525 static void processLangKindDefinition (
2526 const langType language
, const char *const option
,
2527 const char *const parameter
)
2529 const char *p
= parameter
;
2532 static vString
*longName
;
2533 bool inLongName
= false;
2537 Assert (0 <= language
&& language
< (int) LanguageCount
);
2539 initializeParser (language
);
2542 resetLanguageKinds (language
, true);
2545 else if (*p
!= '+' && *p
!= '-')
2546 resetLanguageKinds (language
, false);
2548 longName
= vStringNewOrClearWithAutoRelease (longName
);
2550 while ((c
= (unsigned char) *p
++) != '\0')
2556 vStringPut (longName
, c
);
2562 vStringPut (longName
, c
);
2569 "unexpected character in kind specification: \'%c\'",
2576 "unexpected character in kind specification: \'%c\'",
2578 k
= vStringValue (longName
);
2579 r
= enableLanguageKindForName (language
, k
, mode
);
2581 error (WARNING
, "Unsupported kind: '%s' for --%s option",
2585 vStringClear (longName
);
2589 vStringPut (longName
, c
);
2592 r
= enableLanguageKindForLetter (language
, c
, mode
);
2594 error (WARNING
, "Unsupported kind: '%c' for --%s option",
2602 static void freeKdef (kindDefinition
*kdef
)
2605 eFree (kdef
->description
);
2609 static char *extractDescriptionAndFlags(const char *input
, const char **flags
)
2611 vString
*vdesc
= vStringNew();
2612 bool escaped
= false;
2617 while (*input
!= '\0')
2621 vStringPut (vdesc
, *input
);
2625 else if (*input
== '\\')
2627 else if (*input
== LONG_FLAGS_OPEN
)
2634 vStringPut (vdesc
, *input
);
2637 return vStringDeleteUnwrap(vdesc
);
2640 static void pre_kind_def_flag_refonly_long (const char* const optflag
,
2641 const char* const param
, void* data
)
2643 kindDefinition
*kdef
= data
;
2644 kdef
->referenceOnly
= true;
2647 static flagDefinition PreKindDefFlagDef
[] = {
2648 { '\0', "_refonly", NULL
, pre_kind_def_flag_refonly_long
,
2649 NULL
, "use this kind reference tags only"},
2652 static bool processLangDefineKind(const langType language
,
2653 const char *const option
,
2654 const char *const parameter
)
2656 parserObject
*parser
;
2658 kindDefinition
*kdef
;
2660 const char * p
= parameter
;
2663 const char *name_start
;
2664 const char *marker_end
;
2669 Assert (0 <= language
&& language
< (int) LanguageCount
);
2670 parser
= LanguageTable
+ language
;
2675 error (FATAL
, "no kind definition specified in \"--%s\" option", option
);
2679 error (FATAL
, "no kind letter specified in \"--%s\" option", option
);
2680 if (/* See #1697. isalnum expects 0~255 as the range of characters. */
2681 !isalpha ((unsigned char)letter
)
2683 error (FATAL
, "the kind letter given in \"--%s\" option is not an alphabet", option
);
2684 else if (letter
== KIND_FILE_DEFAULT_LETTER
)
2685 error (FATAL
, "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind",
2686 KIND_FILE_DEFAULT_LETTER
, option
, KIND_FILE_DEFAULT_NAME
);
2687 else if (getKindForLetter (parser
->kindControlBlock
, letter
))
2689 error (WARNING
, "the kind for letter `%c' specified in \"--%s\" option is already defined.",
2695 error (FATAL
, "wrong kind definition in \"--%s\" option: no comma after letter", option
);
2699 error (FATAL
, "no kind name specified in \"--%s\" option", option
);
2700 marker_end
= strchr (p
, ',');
2702 error (FATAL
, "no kind description specified in \"--%s\" option", option
);
2705 while (p
!= marker_end
)
2707 if (p
== name_start
)
2709 if (!isalpha((unsigned char) *p
))
2711 char *name_in_msg
= eStrndup (name_start
, marker_end
- name_start
);
2713 "a kind name doesn't start with an alphabetical character: "
2714 "'%s' in \"--%s\" option",
2715 name_in_msg
, option
);
2720 if (!isalnum ((unsigned char) *p
))
2722 char *name_in_msg
= eStrndup (name_start
, marker_end
- name_start
);
2724 "non-alphanumeric char is used as part of kind name: "
2725 "'%s' in \"--%s\" option",
2726 name_in_msg
, option
);
2732 if (marker_end
== name_start
)
2733 error (FATAL
, "the kind name in \"--%s\" option is empty", option
);
2735 name_len
= marker_end
- name_start
;
2736 if (strncmp (name_start
, KIND_FILE_DEFAULT_NAME
, name_len
) == 0)
2738 "the kind name " KIND_FILE_DEFAULT_NAME
" in \"--%s\" option is reserved",
2741 name
= eStrndup (name_start
, name_len
);
2742 if (getKindForName (parser
->kindControlBlock
, name
))
2744 error (WARNING
, "the kind for name `%s' specified in \"--%s\" option is already defined.",
2751 if (p
[0] == '\0' || p
[0] == LONG_FLAGS_OPEN
)
2752 error (FATAL
, "found an empty kind description in \"--%s\" option", option
);
2754 description
= extractDescriptionAndFlags (p
, &flags
);
2756 kdef
= xCalloc (1, kindDefinition
);
2757 kdef
->enabled
= true;
2758 kdef
->letter
= letter
;
2760 kdef
->description
= description
;
2762 flagsEval (flags
, PreKindDefFlagDef
, ARRAY_SIZE (PreKindDefFlagDef
), kdef
);
2764 defineKind (parser
->kindControlBlock
, kdef
, freeKdef
);
2768 static void freeRdef (roleDefinition
*rdef
)
2771 eFree (rdef
->description
);
2775 static bool processLangDefineRole(const langType language
,
2776 const char *const kindSpec
,
2777 const char *const option
,
2778 const char *const parameter
)
2780 parserObject
*parser
;
2782 kindDefinition
*kdef
;
2783 roleDefinition
*rdef
;
2787 Assert (0 <= language
&& language
< (int) LanguageCount
);
2790 parser
= LanguageTable
+ language
;
2792 if (*kindSpec
== '{')
2794 const char *end
= strchr (kindSpec
, '}');
2796 error (FATAL
, "no '}' representing the end of kind name in --%s option: %s",
2798 if (*(end
+ 1) != '\0')
2799 error (FATAL
, "garbage after the kind specification %s in --%s option",
2801 char *kindName
= eStrndup (kindSpec
+ 1, end
- (kindSpec
+ 1));
2802 if (strcmp (kindName
, KIND_FILE_DEFAULT_NAME
) == 0)
2803 error (FATAL
, "don't define a role for %c/%s kind; it has no role: --%s",
2804 KIND_FILE_DEFAULT_LETTER
, KIND_FILE_DEFAULT_NAME
,
2806 kdef
= getKindForName (parser
->kindControlBlock
, kindName
);
2808 error (FATAL
, "the kind for name `%s' specified in \"--%s\" option is not defined.",
2814 char kletter
= *kindSpec
;
2815 if (!isalnum ((unsigned char)kletter
))
2816 error (FATAL
, "the kind letter given in \"--%s\" option is not an alphabet or a number", option
);
2817 else if (kletter
== KIND_FILE_DEFAULT_LETTER
)
2818 error (FATAL
, "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind, and no role can be attached to it",
2819 KIND_FILE_DEFAULT_LETTER
, option
, KIND_FILE_DEFAULT_NAME
);
2820 else if (*(kindSpec
+ 1) != '\0')
2821 error (FATAL
, "more than one letters are specified as a kind spec in \"--%s\" option: use `{' and `}' for specifying a kind name",
2824 kdef
= getKindForLetter (parser
->kindControlBlock
, kletter
);
2827 error (FATAL
, "the kind for letter `%c' specified in \"--%s\" option is not defined.",
2833 const char * p
= parameter
;
2834 const char *tmp_end
= strchr (p
, ',');
2836 error (FATAL
, "no role description specified in \"--%s\" option", option
);
2838 const char * tmp_start
= p
;
2839 while (p
!= tmp_end
)
2841 if (!isalnum ((unsigned char) *p
))
2842 error (FATAL
, "unacceptable char as part of role name in \"--%s\" option: %c",
2847 if (tmp_end
== tmp_start
)
2848 error (FATAL
, "the role name in \"--%s\" option is empty", option
);
2850 name
= eStrndup (tmp_start
, tmp_end
- tmp_start
);
2851 if (getRoleForName (parser
->kindControlBlock
, kdef
->id
, name
))
2853 error (WARNING
, "the role for name `%s' specified in \"--%s\" option is already defined.",
2860 if (p
[0] == '\0' || p
[0] == LONG_FLAGS_OPEN
)
2861 error (FATAL
, "found an empty role description in \"--%s\" option", option
);
2864 description
= extractDescriptionAndFlags (p
, &flags
);
2866 rdef
= xCalloc (1, roleDefinition
);
2867 rdef
->enabled
= true;
2869 rdef
->description
= description
;
2872 flagsEval (flags
, NULL
, 0, rdef
);
2874 defineRole (parser
->kindControlBlock
, kdef
->id
, rdef
, freeRdef
);
2879 extern bool processKinddefOption (const char *const option
, const char * const parameter
)
2883 language
= getLanguageComponentInOption (option
, "kinddef-");
2884 if (language
== LANG_IGNORE
)
2887 return processLangDefineKind (language
, option
, parameter
);
2890 extern bool processRoledefOption (const char *const option
, const char * const parameter
)
2892 #define PREFIX "_roledef-"
2893 #define PREFIX_LEN strlen(PREFIX)
2895 langType language
= getLanguageComponentInOption (option
, PREFIX
);
2896 if (language
== LANG_IGNORE
)
2899 Assert (0 <= language
&& language
< (int) LanguageCount
);
2900 const char* kindSpec
= option
+ PREFIX_LEN
+ strlen (getLanguageName (language
));
2901 if (*kindSpec
== '\0')
2902 error (FATAL
, "no kind is specifined in \"--%s=%s\"", option
, parameter
);
2903 if (*kindSpec
!= '.')
2904 error (FATAL
, "no delimiter (.) where a kindspec starts is found in \"--%s\": %c",
2908 return processLangDefineRole (language
, kindSpec
, option
, parameter
);
2913 struct langKindDefinitionStruct
{
2914 const char *const option
;
2915 const char *const parameter
;
2917 static void processLangKindDefinitionEach(
2918 langType lang
, void* user_data
)
2920 struct langKindDefinitionStruct
*arg
= user_data
;
2921 processLangKindDefinition (lang
, arg
->option
, arg
->parameter
);
2924 static bool parameterEnablingAllOrFileKind (const char *const option
,
2925 const char *const parameter
,
2926 bool following_plus_or_minus_op
)
2928 size_t file_long_flag_len
= strlen(KIND_FILE_DEFAULT_NAME
);
2930 switch (parameter
[0])
2932 /* Though only '*' is documented as an acceptable kind spec for
2933 * --kinds-all option in our man page, we accept '\0' here because
2934 * it will be useful for testing purpose. */
2936 if (following_plus_or_minus_op
)
2937 error(FATAL
, "no kind specification after + (or -) in --%s option",
2943 if (following_plus_or_minus_op
)
2944 error(FATAL
, "don't repeat + (nor -) in --%s option",
2947 return parameterEnablingAllOrFileKind (option
, parameter
+ 1, true);
2948 case KIND_WILDCARD_LETTER
:
2949 if (following_plus_or_minus_op
)
2950 error(FATAL
, "don't use '*' after + (nor -) in --%s option",
2953 return parameterEnablingAllOrFileKind (option
, parameter
+ 1, false);
2954 case KIND_FILE_DEFAULT_LETTER
:
2955 return parameterEnablingAllOrFileKind (option
, parameter
+ 1, false);
2957 if (strncmp (parameter
+ 1, KIND_FILE_DEFAULT_NAME
, file_long_flag_len
) == 0
2958 && parameter
[1 + file_long_flag_len
] == '}')
2959 return parameterEnablingAllOrFileKind (option
,
2960 parameter
+ 1 + file_long_flag_len
+ 1,
2967 extern bool processKindsOption (
2968 const char *const option
, const char *const parameter
)
2970 #define PREFIX "kinds-"
2971 #define PREFIX_LEN strlen(PREFIX)
2973 bool handled
= false;
2974 struct langKindDefinitionStruct arg
= {
2976 .parameter
= parameter
,
2980 const char* const dash
= strchr (option
, '-');
2982 (strcmp (dash
+ 1, "kinds") == 0 || strcmp (dash
+ 1, "types") == 0))
2984 size_t len
= dash
- option
;
2985 char *langName
= eStrndup (option
, len
);
2987 if ((len
== 3) && (strcmp (langName
, RSV_LANG_ALL
) == 0))
2990 "\"--%s\" option is obsolete; use \"--kinds-%s\" instead",
2992 if (!parameterEnablingAllOrFileKind (option
, parameter
, false))
2993 error (FATAL
, "only '*', 'F', \"{file}\" or their combination is acceptable as kind letter for --%s", option
);
2994 foreachLanguage(processLangKindDefinitionEach
, &arg
);
2998 language
= getNamedLanguage (langName
, 0);
2999 if (language
== LANG_IGNORE
)
3000 error (WARNING
, "Unknown language \"%s\" in \"%s\" option", langName
, option
);
3002 processLangKindDefinition (language
, option
, parameter
);
3007 else if ( strncmp (option
, PREFIX
, PREFIX_LEN
) == 0 )
3011 lang
= option
+ PREFIX_LEN
;
3012 if (lang
[0] == '\0')
3013 error (WARNING
, "No language given in \"%s\" option", option
);
3014 else if (strcmp (lang
, RSV_LANG_ALL
) == 0)
3016 if (!parameterEnablingAllOrFileKind (option
, parameter
, false))
3017 error (FATAL
, "only '*', 'F', \"{file}\" or their combination is acceptable as kind letter for --%s", option
);
3018 foreachLanguage(processLangKindDefinitionEach
, &arg
);
3022 language
= getNamedLanguage (lang
, 0);
3023 if (language
== LANG_IGNORE
)
3024 error (WARNING
, "Unknown language \"%s\" in \"%s\" option", lang
, option
);
3026 processLangKindDefinition (language
, option
, parameter
);
3036 * The argument specification for --roles-<LANG>:<KIND>= option
3037 * =====================================================================
3041 * => Disable all roles of all kinds in all languages.
3045 * => Enable all roles of all kinds in all languages.
3049 * => Disable all roles of all kinds.
3051 * --roles-<LANG>.*=*
3053 * => Enable all roles of all kinds.
3055 * --roles-<LANG>.{kind}=
3057 * => Disable all roles of the kind specified with a letter.
3059 * --roles-<LANG>.{kind}=*
3060 * --roles-<LANG>.k=*
3061 * => Enable all roles of the kind specified with a letter.
3063 * --roles-<LANG>.{kind}=[+|-]{role}
3064 * --roles-<LANG>.k=[+|-]{role}
3065 * => Enable/disable the role of the kind specified with a letter.
3068 * Examples of combination
3069 * ---------------------------------------------------------------------
3071 * --roles-<LANG>.k0=+{role0}-{role1}{role2}
3072 * --roles-<LANG>.{kind1}=+{role0}-{role1}{role2}
3075 * How --roledef should be change to align --roles-<LANG> notation
3076 * ---------------------------------------------------------------------
3078 * --_roledef-<LANG>.k=role,description
3079 * --_roledef-<LANG>.{kind}=role,description
3082 * --_roledef-<LANG>=k.role,description
3085 * How --param should be change to align --roles-<LANG> notation
3086 * ---------------------------------------------------------------------
3088 * --param-<LANG>.name=argument
3091 * --param-<LANG>:name=argument
3094 * How --paramdef should be to align --roles-<LANG> notation
3095 * ---------------------------------------------------------------------
3097 * --_paramdef-<LANG>.name=[ default (desription) ]
3100 * Discussion: which shoule we use . or : ?
3101 * ---------------------------------------------------------------------
3103 * `.' is better because `:' implies fields.
3106 struct langKindRoleDefinitionStruct
{
3108 const char *const option
;
3109 const char *const parameter
;
3112 typedef void (*kindCallback
) (langType language
, int kindIndex
, void* user_data
);
3113 static void foreachKind(langType language
, kindCallback callback
, void *user_data
)
3115 unsigned int c
= countLanguageKinds (language
);
3116 for (unsigned int i
= 0; i
< c
; i
++)
3117 callback (language
, (int)i
, user_data
);
3120 static void resetKindRoles (const langType language
, int kindIndex
, const bool mode
)
3122 Assert (0 <= language
&& language
< (int) LanguageCount
);
3123 unsigned int c
= countLanguageRoles (language
, kindIndex
);
3125 for (unsigned int i
= 0; i
< c
; i
++)
3127 roleDefinition
* rdef
= getLanguageRole (language
, kindIndex
, (int)i
);
3128 enableRole (rdef
, mode
);
3132 static void resetKindRolesAsCallback (const langType language
, int kindIndex
, void *user_data
)
3134 bool mode
= (bool)user_data
;
3135 resetKindRoles (language
, kindIndex
, mode
);
3138 static void processLangKindRoleDefinition (
3139 const langType language
, const int kindIndex
, const char *const option
,
3140 const char *const parameter
)
3142 Assert (0 <= language
&& language
< (int) LanguageCount
);
3143 Assert (kindIndex
!= KIND_GHOST_INDEX
);
3144 initializeParser (language
);
3146 const char *p
= parameter
;
3151 resetKindRoles (language
, kindIndex
, false);
3154 else if (*p
!= '+' && *p
!= '-' )
3155 resetKindRoles (language
, kindIndex
, false);
3172 char *q
= strchr (p
, '}');
3175 error (FATAL
, "no '}' representing the end of role name in --%s option: %s",
3178 error (FATAL
, "empty role for the kind letter: %c",
3179 getLanguageKind (language
, kindIndex
)->letter
);
3181 char *rname
= eStrndup (p
, q
- p
);
3182 roleDefinition
*rdef
= getLanguageRoleForName (language
, kindIndex
, rname
);
3184 error (WARNING
, "no such role: \"%s\" in kind \'%c\' in language \"%s\"",
3185 rname
, getLanguageKind (language
, kindIndex
)->letter
,
3186 getLanguageName (language
));
3188 enableRole (rdef
, mode
);
3194 resetKindRoles (language
, kindIndex
, true);
3198 error (FATAL
, "unexpected character %c in --%s=%s option",
3199 *p
, option
, parameter
);
3203 static void processLangKindRoleDefinitionEach (langType language
, void* user_data
)
3205 struct langKindRoleDefinitionStruct
*arg
= user_data
;
3207 if (arg
->kindIndex
== KIND_GHOST_INDEX
)
3209 initializeParser (language
);
3210 foreachKind (language
, resetKindRolesAsCallback
,
3211 ((*(arg
->parameter
) == '*')? (void *)true: (void *)false));
3214 processLangKindRoleDefinition (language
, arg
->kindIndex
,
3215 arg
->option
, arg
->parameter
);
3218 extern bool processRolesOption (const char *const option
, const char *const parameter
)
3220 #define PREFIX "roles-"
3221 #define PREFIX_LEN strlen(PREFIX)
3223 if ( strncmp (option
, PREFIX
, PREFIX_LEN
) != 0 )
3226 const char* lang
= option
+ PREFIX_LEN
;
3227 if (lang
[0] == '\0')
3229 error (WARNING
, "no language given in \"%s\" option", option
);
3236 * => Disable all roles of all kinds in all languages.
3240 * => Enable all roles of all kinds in all languages.
3242 if (strncmp (lang
, RSV_LANG_ALL
, strlen(RSV_LANG_ALL
)) == 0)
3244 if (lang
[strlen (RSV_LANG_ALL
)] == '\0'
3245 || (strcmp (lang
+ strlen (RSV_LANG_ALL
), ".*") == 0))
3247 if (*parameter
== '\0'
3248 || strcmp(parameter
, "*") == 0)
3250 struct langKindRoleDefinitionStruct arg
= {
3251 .kindIndex
= KIND_GHOST_INDEX
,
3253 .parameter
= parameter
,
3255 foreachLanguage (processLangKindRoleDefinitionEach
, &arg
);
3259 error (FATAL
, "only '*' or '' (empty string) is acceptable as an argument for --%s: %s",
3263 else if (lang
[strlen(RSV_LANG_ALL
)] == '.')
3264 error (FATAL
, "only '*' or '' (empty string) is acceptable as a kind spec for --%sall: --%s",
3269 /* Decide the language. */
3271 const char *dot
= strchr (lang
, '.');
3273 language
= getNamedLanguage (lang
, dot
- lang
);
3275 language
= getNamedLanguage (lang
, 0);
3277 if (language
== LANG_IGNORE
)
3279 char *lang0
= dot
? eStrndup (lang
, dot
- lang
): NULL
;
3280 error (WARNING
, "unknown language \"%s\" in --%s option",
3281 (lang0
? lang0
: lang
), option
);
3290 * => Disable all roles of all kinds.
3292 * --roles-<LANG>.*=*
3294 * => Enable all roles of all kinds.
3296 if (dot
== NULL
|| (strcmp (dot
, ".*") == 0))
3298 if (*parameter
== '\0'
3299 || strcmp(parameter
, "*") == 0)
3301 foreachKind (language
, resetKindRolesAsCallback
,
3302 ((*parameter
== '*')? (void*)true: (void*)false));
3306 error (FATAL
, "only '*' or '' (empty string) is acceptable as an argument for --%s: %s",
3311 /* Decide the kind of the language. */
3312 parserObject
*parser
= LanguageTable
+ language
;
3313 int kindIndex
= KIND_GHOST_INDEX
;
3314 const char *kind
= dot
+ 1;
3317 const char *name_end
= strchr (kind
, '}');
3318 if (name_end
== NULL
)
3319 error (FATAL
, "no '}' representing the end of kind name in --%s option: %s",
3321 char *kindName
= eStrndup (kind
+ 1, name_end
- (kind
+ 1));
3322 if (strcmp (kindName
, KIND_FILE_DEFAULT_NAME
) == 0)
3324 error (WARNING
, "don't enable/disable a role in %c/%s kind; it has no role: --%s",
3325 KIND_FILE_DEFAULT_LETTER
, KIND_FILE_DEFAULT_NAME
,
3329 kindIndex
= getKindIndexForName (parser
->kindControlBlock
, kindName
);
3330 if (kindIndex
== KIND_GHOST_INDEX
)
3333 error (WARNING
, "no such kind name as specified in --%s option", option
);
3336 if (*(name_end
+ 1) != '\0')
3337 error (FATAL
, "garbage after the kind specification {%s} in --%s option",
3341 else if (isalpha ((unsigned char)*kind
))
3343 if (*kind
== KIND_FILE_DEFAULT_LETTER
)
3345 error (WARNING
, "don't enable/disable a role in %c/%s kind; it has no role: --%s",
3346 KIND_FILE_DEFAULT_LETTER
, KIND_FILE_DEFAULT_NAME
,
3350 kindIndex
= getKindIndexForLetter (parser
->kindControlBlock
, *kind
);
3351 if (kindIndex
== KIND_GHOST_INDEX
)
3353 error (WARNING
, "no such kind letter as specified in --%s option", option
);
3356 if (*(kind
+ 1) != '\0')
3357 error (FATAL
, "garbage after the kind specification '%c' in --%s option",
3361 error (FATAL
, "'%c', unexpected character in --%s", *kind
, option
);
3365 * --roles-<LANG>.{kind}=
3367 * => Disable all roles of the kind specified with a letter.
3369 * --roles-<LANG>.{kind}=*
3370 * --roles-<LANG>.k=*
3371 * => Enable all roles of the kind specified with a letter.
3373 * --roles-<LANG>.{kind}=[+|-|]{role}
3374 * --roles-<LANG>.k=[+|-|]{role}
3375 * => Enable/disable the role of the kind specified with a letter.
3377 processLangKindRoleDefinition (language
, kindIndex
, option
, parameter
);
3384 extern void printLanguageRoles (const langType language
, const char* kindspecs
,
3385 bool withListHeader
, bool machinable
, FILE *fp
)
3387 struct colprintTable
*table
= roleColprintTableNew();
3388 parserObject
*parser
;
3390 initializeParser (language
);
3392 if (language
== LANG_AUTO
)
3394 for (unsigned int i
= 0 ; i
< LanguageCount
; ++i
)
3396 if (!isLanguageVisible (i
))
3399 parser
= LanguageTable
+ i
;
3400 roleColprintAddRoles (table
, parser
->kindControlBlock
, kindspecs
);
3405 parser
= LanguageTable
+ language
;
3406 roleColprintAddRoles (table
, parser
->kindControlBlock
, kindspecs
);
3409 roleColprintTablePrint (table
, (language
!= LANG_AUTO
),
3410 withListHeader
, machinable
, fp
);
3411 colprintTableDelete (table
);
3414 static void printKinds (langType language
, bool indent
,
3415 struct colprintTable
* table
)
3417 const parserObject
*parser
;
3418 struct kindControlBlock
*kcb
;
3419 Assert (0 <= language
&& language
< (int) LanguageCount
);
3421 initializeParser (language
);
3422 parser
= LanguageTable
+ language
;
3423 kcb
= parser
->kindControlBlock
;
3426 kindColprintAddLanguageLines (table
, kcb
);
3429 for (unsigned int i
= 0 ; i
< countKinds(kcb
) ; ++i
)
3430 printKind (getKind(kcb
, i
), indent
);
3434 extern void printLanguageKinds (const langType language
, bool allKindFields
,
3435 bool withListHeader
, bool machinable
, FILE *fp
)
3437 struct colprintTable
* table
= NULL
;
3440 table
= kindColprintTableNew ();
3442 if (language
== LANG_AUTO
)
3444 for (unsigned int i
= 0 ; i
< LanguageCount
; ++i
)
3446 const parserDefinition
* const lang
= LanguageTable
[i
].def
;
3448 if (lang
->invisible
)
3452 printf ("%s%s\n", lang
->name
, isLanguageEnabled (i
) ? "" : " [disabled]");
3453 printKinds (i
, true, table
);
3457 printKinds (language
, false, table
);
3461 kindColprintTablePrint(table
, (language
== LANG_AUTO
)? 0: 1,
3462 withListHeader
, machinable
, fp
);
3463 colprintTableDelete (table
);
3467 extern bool processParamOption (
3468 const char *const option
, const char *const value
)
3474 language
= getLanguageComponentInOption (option
, "param-");
3475 if (language
== LANG_IGNORE
)
3478 sep
= option
+ strlen ("param-") + strlen (getLanguageName (language
));
3479 /* `:' is only for keeping self compatibility */
3480 if (! (*sep
== '.' || *sep
== ':' ))
3481 error (FATAL
, "no separator(.) is given for %s=%s", option
, value
);
3484 if (value
== NULL
|| value
[0] == '\0')
3485 error (FATAL
, "no value is given for %s", option
);
3487 if (applyLanguageParam (language
, name
, value
))
3488 propagateParamToOptscript (LanguageTable
[language
].lregexControlBlock
,
3493 static void freePdef (paramDefinition
*pdef
)
3495 eFree ((void *)pdef
->name
);
3496 eFree ((void *)pdef
->desc
);
3500 static bool processLangDefineParam (const langType language
,
3501 const char *const option
,
3502 const char *const parameter
)
3504 parserObject
*parser
;
3506 paramDefinition
*pdef
;
3507 const char * p
= parameter
;
3508 const char *name_end
;
3512 Assert (0 <= language
&& language
< (int) LanguageCount
);
3516 error (FATAL
, "no parameter definition specified in \"--%s\" option", option
);
3518 name_end
= strchr (p
, ',');
3520 error (FATAL
, "no parameter description specified in \"--%s\" option", option
);
3521 else if (name_end
== p
)
3522 error (FATAL
, "the parameter name in \"--%s\" option is empty", option
);
3524 for (; p
< name_end
; p
++)
3526 if (!isalnum ((unsigned char) *p
) && *p
!= '_')
3527 error (FATAL
, "unacceptable char as part of extra name in \"--%s\" option",
3532 if (p
[0] == '\0' || p
[0] == LONG_FLAGS_OPEN
)
3533 error (FATAL
, "parameter description in \"--%s\" option is empty", option
);
3535 desc
= extractDescriptionAndFlags (p
, &flags
);
3537 pdef
= xCalloc (1, paramDefinition
);
3538 pdef
->name
= eStrndup (parameter
, name_end
- parameter
);
3543 flagsEval (flags
, NULL
, 0, pdef
);
3546 parser
= LanguageTable
+ language
;
3547 defineParam (parser
->paramControlBlock
, pdef
, freePdef
);
3551 extern bool processParamdefOption (const char *const option
, const char *const value
)
3555 language
= getLanguageComponentInOption (option
, "_paramdef-");
3556 if (language
== LANG_IGNORE
)
3559 return processLangDefineParam (language
, option
, value
);
3562 static void printParams (struct colprintTable
*table
, langType language
)
3564 Assert (0 <= language
&& language
< (int) LanguageCount
);
3566 initializeParser (language
);
3567 paramColprintAddParams (table
,
3568 LanguageTable
[language
].paramControlBlock
);
3571 extern void printLanguageParams (const langType language
,
3572 bool withListHeader
, bool machinable
, FILE *fp
)
3574 struct colprintTable
*table
= paramColprintTableNew();
3576 if (language
== LANG_AUTO
)
3578 for (unsigned int i
= 0; i
< LanguageCount
; ++i
)
3580 const parserDefinition
* const lang
= LanguageTable
[i
].def
;
3582 if (lang
->invisible
)
3585 printParams (table
, i
);
3589 printParams (table
, language
);
3591 paramColprintTablePrint (table
, (language
!= LANG_AUTO
),
3592 withListHeader
, machinable
, fp
);
3593 colprintTableDelete (table
);
3596 static void processLangAliasOption (const langType language
,
3597 const char *const parameter
)
3600 const parserObject
* parser
;
3602 Assert (0 <= language
&& language
< (int) LanguageCount
);
3603 parser
= LanguageTable
+ language
;
3605 if (parameter
[0] == '\0')
3607 clearLanguageAliases (language
);
3608 verbose ("clear aliases for %s\n", parser
->def
->name
);
3610 else if (strcmp (parameter
, RSV_LANGMAP_DEFAULT
) == 0)
3612 installLanguageAliasesDefault (language
);
3613 verbose ("reset aliases for %s\n", parser
->def
->name
);
3615 else if (parameter
[0] == '+')
3617 alias
= parameter
+ 1;
3618 addLanguageAlias(language
, alias
);
3619 verbose ("add an alias %s to %s\n", alias
, parser
->def
->name
);
3621 else if (parameter
[0] == '-')
3623 if (parser
->currentAliases
)
3625 alias
= parameter
+ 1;
3626 if (stringListDeleteItemExtension (parser
->currentAliases
, alias
))
3628 verbose ("remove an alias %s from %s\n", alias
, parser
->def
->name
);
3635 clearLanguageAliases (language
);
3636 addLanguageAlias(language
, alias
);
3637 verbose ("set alias %s to %s\n", alias
, parser
->def
->name
);
3642 extern bool processAliasOption (
3643 const char *const option
, const char *const parameter
)
3649 #define PREFIX "alias-"
3650 if (strcmp (option
, "alias-" RSV_LANG_ALL
) == 0)
3652 if ((parameter
[0] == '\0')
3653 || (strcmp (parameter
, RSV_LANGMAP_DEFAULT
) == 0))
3655 for (unsigned int i
= 0; i
< LanguageCount
; i
++)
3657 clearLanguageAliases (i
);
3658 verbose ("clear aliases for %s\n", getLanguageName(i
));
3661 if (parameter
[0] != '\0')
3663 verbose (" Installing default language aliases:\n");
3664 installLanguageAliasesDefaults ();
3669 error (WARNING
, "Use \"%s\" option for reset (\"default\") or clearing (\"\")", option
);
3675 language
= getLanguageComponentInOption (option
, "alias-");
3676 if (language
== LANG_IGNORE
)
3680 processLangAliasOption (language
, parameter
);
3684 static void printMaps (const langType language
, langmapType type
)
3686 const parserObject
* parser
;
3689 parser
= LanguageTable
+ language
;
3690 printf ("%-8s", parser
->def
->name
);
3691 if (parser
->currentPatterns
!= NULL
&& (type
& LMAP_PATTERN
))
3692 for (i
= 0 ; i
< stringListCount (parser
->currentPatterns
) ; ++i
)
3693 printf (" %s", vStringValue (
3694 stringListItem (parser
->currentPatterns
, i
)));
3695 if (parser
->currentExtensions
!= NULL
&& (type
& LMAP_EXTENSION
))
3696 for (i
= 0 ; i
< stringListCount (parser
->currentExtensions
) ; ++i
)
3697 printf (" *.%s", vStringValue (
3698 stringListItem (parser
->currentExtensions
, i
)));
3702 static struct colprintTable
*mapColprintTableNew (langmapType type
)
3704 if ((type
& LMAP_ALL
) == LMAP_ALL
)
3705 return colprintTableNew ("L:LANGUAGE", "L:TYPE", "L:MAP", NULL
);
3706 else if (type
& LMAP_PATTERN
)
3707 return colprintTableNew ("L:LANGUAGE", "L:PATTERN", NULL
);
3708 else if (type
& LMAP_EXTENSION
)
3709 return colprintTableNew ("L:LANGUAGE", "L:EXTENSION", NULL
);
3712 AssertNotReached ();
3717 static void mapColprintAddLanguage (struct colprintTable
* table
,
3719 const parserObject
* parser
)
3721 struct colprintLine
* line
;
3725 if ((type
& LMAP_PATTERN
) && (0 < (count
= stringListCount (parser
->currentPatterns
))))
3727 for (i
= 0; i
< count
; i
++)
3729 line
= colprintTableGetNewLine (table
);
3730 vString
*pattern
= stringListItem (parser
->currentPatterns
, i
);
3732 colprintLineAppendColumnCString (line
, parser
->def
->name
);
3733 if (type
& LMAP_EXTENSION
)
3734 colprintLineAppendColumnCString (line
, "pattern");
3735 colprintLineAppendColumnVString (line
, pattern
);
3739 if ((type
& LMAP_EXTENSION
) && (0 < (count
= stringListCount (parser
->currentExtensions
))))
3741 for (i
= 0; i
< count
; i
++)
3743 line
= colprintTableGetNewLine (table
);
3744 vString
*extension
= stringListItem (parser
->currentExtensions
, i
);
3746 colprintLineAppendColumnCString (line
, parser
->def
->name
);
3747 if (type
& LMAP_PATTERN
)
3748 colprintLineAppendColumnCString (line
, "extension");
3749 colprintLineAppendColumnVString (line
, extension
);
3754 extern void printLanguageMaps (const langType language
, langmapType type
,
3755 bool withListHeader
, bool machinable
, FILE *fp
)
3757 /* DON'T SORT THE LIST
3759 The order of listing should be equal to the order of matching
3760 for the parser selection. */
3762 struct colprintTable
* table
= NULL
;
3763 if (type
& LMAP_TABLE_OUTPUT
)
3764 table
= mapColprintTableNew(type
);
3766 if (language
== LANG_AUTO
)
3768 for (unsigned int i
= 0 ; i
< LanguageCount
; ++i
)
3770 if (!isLanguageVisible (i
))
3773 if (type
& LMAP_TABLE_OUTPUT
)
3775 const parserObject
* parser
= LanguageTable
+ i
;
3777 mapColprintAddLanguage (table
, type
, parser
);
3780 printMaps (i
, type
);
3785 Assert (0 <= language
&& language
< (int) LanguageCount
);
3787 if (type
& LMAP_TABLE_OUTPUT
)
3789 const parserObject
* parser
= LanguageTable
+ language
;
3791 mapColprintAddLanguage (table
, type
, parser
);
3794 printMaps (language
, type
);
3798 if (type
& LMAP_TABLE_OUTPUT
)
3800 colprintTablePrint (table
, (language
== LANG_AUTO
)? 0: 1,
3801 withListHeader
, machinable
, fp
);
3802 colprintTableDelete (table
);
3806 static struct colprintTable
*aliasColprintTableNew (void)
3808 return colprintTableNew ("L:LANGUAGE", "L:ALIAS", NULL
);
3811 static void aliasColprintAddLanguage (struct colprintTable
* table
,
3812 const parserObject
* parser
)
3816 if (parser
->currentAliases
&& (0 < (count
= stringListCount (parser
->currentAliases
))))
3818 for (unsigned int i
= 0; i
< count
; i
++)
3820 struct colprintLine
* line
= colprintTableGetNewLine (table
);
3821 vString
*alias
= stringListItem (parser
->currentAliases
, i
);
3823 colprintLineAppendColumnCString (line
, parser
->def
->name
);
3824 colprintLineAppendColumnVString (line
, alias
);
3829 extern void printLanguageAliases (const langType language
,
3830 bool withListHeader
, bool machinable
, FILE *fp
)
3832 /* DON'T SORT THE LIST
3834 The order of listing should be equal to the order of matching
3835 for the parser selection. */
3837 struct colprintTable
* table
= aliasColprintTableNew();
3838 const parserObject
* parser
;
3840 if (language
== LANG_AUTO
)
3842 for (unsigned int i
= 0; i
< LanguageCount
; ++i
)
3844 parser
= LanguageTable
+ i
;
3845 if (parser
->def
->invisible
)
3848 aliasColprintAddLanguage (table
, parser
);
3853 Assert (0 <= language
&& language
< (int) LanguageCount
);
3854 parser
= LanguageTable
+ language
;
3855 aliasColprintAddLanguage (table
, parser
);
3858 colprintTablePrint (table
, (language
== LANG_AUTO
)? 0: 1,
3859 withListHeader
, machinable
, fp
);
3860 colprintTableDelete (table
);
3863 static void printLanguage (const langType language
, parserDefinition
** ltable
)
3865 const parserDefinition
* lang
;
3866 Assert (0 <= language
&& language
< (int) LanguageCount
);
3867 lang
= ltable
[language
];
3869 if (lang
->invisible
)
3872 printf ("%s%s\n", lang
->name
, isLanguageEnabled (lang
->id
) ? "" : " [disabled]");
3875 extern void printLanguageList (void)
3878 parserDefinition
**ltable
;
3880 ltable
= xMalloc (LanguageCount
, parserDefinition
*);
3881 for (i
= 0 ; i
< LanguageCount
; ++i
)
3882 ltable
[i
] = LanguageTable
[i
].def
;
3883 qsort (ltable
, LanguageCount
, sizeof (parserDefinition
*), compareParsersByName
);
3885 for (i
= 0 ; i
< LanguageCount
; ++i
)
3886 printLanguage (i
, ltable
);
3891 static void xtagDefinitionDestroy (xtagDefinition
*xdef
)
3893 eFree ((void *)xdef
->name
);
3894 eFree ((void *)xdef
->description
);
3898 static bool processLangDefineExtra (const langType language
,
3899 const char *const option
,
3900 const char *const parameter
)
3902 xtagDefinition
*xdef
;
3903 const char * p
= parameter
;
3904 const char *name_end
;
3908 Assert (0 <= language
&& language
< (int) LanguageCount
);
3912 error (FATAL
, "no extra definition specified in \"--%s\" option", option
);
3914 name_end
= strchr (p
, ',');
3916 error (FATAL
, "no extra description specified in \"--%s\" option", option
);
3917 else if (name_end
== p
)
3918 error (FATAL
, "the extra name in \"--%s\" option is empty", option
);
3920 for (; p
< name_end
; p
++)
3922 if (!isalnum ((unsigned char) *p
))
3923 error (FATAL
, "unacceptable char as part of extra name in \"--%s\" option",
3928 if (p
[0] == '\0' || p
[0] == LONG_FLAGS_OPEN
)
3929 error (FATAL
, "extra description in \"--%s\" option is empty", option
);
3931 desc
= extractDescriptionAndFlags (p
, &flags
);
3933 xdef
= xCalloc (1, xtagDefinition
);
3934 xdef
->enabled
= false;
3935 xdef
->letter
= NUL_XTAG_LETTER
;
3936 xdef
->name
= eStrndup (parameter
, name_end
- parameter
);
3937 xdef
->description
= desc
;
3938 xdef
->isEnabled
= NULL
;
3939 DEFAULT_TRASH_BOX(xdef
, xtagDefinitionDestroy
);
3942 flagsEval (flags
, NULL
, 0, xdef
);
3944 defineXtag (xdef
, language
);
3949 extern bool processExtradefOption (const char *const option
, const char *const parameter
)
3953 language
= getLanguageComponentInOption (option
, "_" "extradef-");
3954 if (language
== LANG_IGNORE
)
3957 return processLangDefineExtra (language
, option
, parameter
);
3960 static void fieldDefinitionDestroy (fieldDefinition
*fdef
)
3962 eFree ((void *)fdef
->description
);
3963 eFree ((void *)fdef
->name
);
3967 static bool processLangDefineField (const langType language
,
3968 const char *const option
,
3969 const char *const parameter
)
3971 fieldDefinition
*fdef
;
3972 const char * p
= parameter
;
3973 const char *name_end
;
3977 Assert (0 <= language
&& language
< (int) LanguageCount
);
3981 error (FATAL
, "no field definition specified in \"--%s\" option", option
);
3983 name_end
= strchr (p
, ',');
3985 error (FATAL
, "no field description specified in \"--%s\" option", option
);
3986 else if (name_end
== p
)
3987 error (FATAL
, "the field name in \"--%s\" option is empty", option
);
3989 for (; p
< name_end
; p
++)
3991 if (!isalpha ((unsigned char) *p
))
3992 error (FATAL
, "unacceptable char as part of field name in \"--%s\" option",
3997 if (p
[0] == '\0' || p
[0] == LONG_FLAGS_OPEN
)
3998 error (FATAL
, "field description in \"--%s\" option is empty", option
);
4000 desc
= extractDescriptionAndFlags (p
, &flags
);
4002 fdef
= xCalloc (1, fieldDefinition
);
4003 fdef
->enabled
= false;
4004 fdef
->letter
= NUL_FIELD_LETTER
;
4005 fdef
->name
= eStrndup(parameter
, name_end
- parameter
);
4006 fdef
->description
= desc
;
4007 fdef
->isValueAvailable
= NULL
;
4008 fdef
->getValueObject
= NULL
;
4009 fdef
->getterValueType
= NULL
;
4010 fdef
->setValueObject
= NULL
;
4011 fdef
->setterValueType
= NULL
;
4012 fdef
->checkValueForSetter
= NULL
;
4013 fdef
->dataType
= FIELDTYPE_STRING
; /* TODO */
4014 fdef
->ftype
= FIELD_UNKNOWN
;
4015 DEFAULT_TRASH_BOX(fdef
, fieldDefinitionDestroy
);
4018 flagsEval (flags
, NULL
, 0, fdef
);
4020 defineField (fdef
, language
);
4025 extern bool processFielddefOption (const char *const option
, const char *const parameter
)
4029 language
= getLanguageComponentInOption (option
, "_fielddef-");
4030 if (language
== LANG_IGNORE
)
4033 return processLangDefineField (language
, option
, parameter
);
4040 static rescanReason
createTagsForFile (const langType language
,
4041 const unsigned int passCount
)
4043 parserDefinition
*const lang
= LanguageTable
[language
].def
;
4044 rescanReason rescan
= RESCAN_NONE
;
4046 resetInputFile (language
, passCount
> 1);
4048 Assert (lang
->parser
|| lang
->parser2
);
4050 notifyInputStart ();
4052 if (lang
->parser
!= NULL
)
4054 else if (lang
->parser2
!= NULL
)
4055 rescan
= lang
->parser2 (passCount
);
4062 extern void notifyLanguageRegexInputStart (langType language
)
4064 parserObject
*pobj
= LanguageTable
+ language
;
4066 notifyRegexInputStart(pobj
->lregexControlBlock
);
4069 extern void notifyLanguageRegexInputEnd (langType language
)
4071 parserObject
*pobj
= LanguageTable
+ language
;
4073 notifyRegexInputEnd(pobj
->lregexControlBlock
);
4076 static unsigned int parserCorkFlags (parserDefinition
*parser
)
4081 r
|= parser
->useCork
;
4083 if (doesLanguageExpectCorkInRegex (parser
->id
)
4084 || parser
->requestAutomaticFQTag
)
4087 pushLanguage (parser
->id
);
4088 foreachSubparser(tmp
, true)
4090 langType t
= getSubparserLanguage (tmp
);
4091 r
|= parserCorkFlags (LanguageTable
[t
].def
);
4097 static void setupLanguageSubparsersInUse (const langType language
)
4101 setupSubparsersInUse ((LanguageTable
+ language
)->slaveControlBlock
);
4102 foreachSubparser(tmp
, true)
4104 langType t
= getSubparserLanguage (tmp
);
4105 enterSubparser (tmp
);
4106 setupLanguageSubparsersInUse(t
);
4111 static subparser
* teardownLanguageSubparsersInUse (const langType language
)
4115 foreachSubparser(tmp
, true)
4117 langType t
= getSubparserLanguage (tmp
);
4118 enterSubparser (tmp
);
4119 teardownLanguageSubparsersInUse(t
);
4122 return teardownSubparsersInUse ((LanguageTable
+ language
)->slaveControlBlock
);
4125 static void initializeParserStats (parserObject
*parser
)
4127 if (Option
.printTotals
> 1 && parser
->used
== 0 && parser
->def
->initStats
)
4128 parser
->def
->initStats (parser
->def
->id
);
4132 extern void printParserStatisticsIfUsed (langType language
)
4134 parserObject
*parser
= &(LanguageTable
[language
]);
4138 if (parser
->def
->printStats
)
4140 fprintf(stderr
, "\nSTATISTICS of %s\n", getLanguageName (language
));
4141 fputs("==============================================\n", stderr
);
4142 parser
->def
->printStats (language
);
4144 printLanguageMultitableStatistics (language
);
4148 static bool createTagsWithFallback1 (const langType language
,
4149 langType
*exclusive_subparser
)
4151 bool tagFileResized
= false;
4152 unsigned long numTags
;
4154 int lastPromise
= getLastPromise ();
4155 unsigned int passCount
= 0;
4156 rescanReason whyRescan
;
4157 parserObject
*parser
;
4158 unsigned int corkFlags
;
4159 bool useCork
= false;
4161 initializeParser (language
);
4162 parser
= &(LanguageTable
[language
]);
4164 setupLanguageSubparsersInUse (language
);
4166 corkFlags
= parserCorkFlags (parser
->def
);
4167 useCork
= corkFlags
& CORK_QUEUE
;
4169 corkTagFile(corkFlags
);
4171 if (isXtagEnabled (XTAG_PSEUDO_TAGS
))
4172 addParserPseudoTags (language
);
4173 initializeParserStats (parser
);
4174 numTags
= numTagsAdded ();
4175 tagFilePosition (&tagfpos
);
4177 anonResetMaybe (parser
);
4178 parser
->justRunForSchedulingBase
= 0;
4180 while ( ( whyRescan
=
4181 createTagsForFile (language
, ++passCount
) )
4187 corkTagFile(corkFlags
);
4191 if (whyRescan
== RESCAN_FAILED
)
4193 /* Restore prior state of tag file.
4195 setTagFilePosition (&tagfpos
, true);
4196 setNumTagsAdded (numTags
);
4197 writerRescanFailed (numTags
);
4198 tagFileResized
= true;
4199 breakPromisesAfter(lastPromise
);
4201 else if (whyRescan
== RESCAN_APPEND
)
4203 tagFilePosition (&tagfpos
);
4204 numTags
= numTagsAdded ();
4205 lastPromise
= getLastPromise ();
4209 if (!parser
->justRunForSchedulingBase
4210 /* Force applying regex patterns */
4211 && hasLanguageAnyRegexPatterns (language
))
4212 while (readLineFromInputFile () != NULL
)
4219 subparser
*s
= teardownLanguageSubparsersInUse (language
);
4220 if (exclusive_subparser
&& s
)
4221 *exclusive_subparser
= getSubparserLanguage (s
);
4224 return tagFileResized
;
4227 extern bool runParserInNarrowedInputStream (const langType language
,
4228 unsigned long startLine
, long startCharOffset
,
4229 unsigned long endLine
, long endCharOffset
,
4230 unsigned long sourceLineOffset
,
4233 bool tagFileResized
;
4235 verbose ("runParserInNarrowedInputStream: %s; "
4237 "start(line: %lu, offset: %ld, srcline: %lu)"
4239 "end(line: %lu, offset: %ld)\n",
4240 getLanguageName (language
),
4241 getInputFileName (),
4242 startLine
, startCharOffset
, sourceLineOffset
,
4243 endLine
, endCharOffset
);
4245 pushNarrowedInputStream (
4246 doesParserRequireMemoryStream (language
),
4247 startLine
, startCharOffset
,
4248 endLine
, endCharOffset
,
4251 tagFileResized
= createTagsWithFallback1 (language
, NULL
);
4252 popNarrowedInputStream ();
4253 return tagFileResized
;
4257 static bool createTagsWithFallback (
4258 const char *const fileName
, const langType language
,
4259 MIO
*mio
, time_t mtime
, bool *failureInOpenning
)
4261 langType exclusive_subparser
= LANG_IGNORE
;
4262 bool tagFileResized
= false;
4264 Assert (0 <= language
&& language
< (int) LanguageCount
);
4266 if (!openInputFile (fileName
, language
, mio
, mtime
))
4268 *failureInOpenning
= true;
4271 *failureInOpenning
= false;
4273 tagFileResized
= createTagsWithFallback1 (language
,
4274 &exclusive_subparser
);
4275 tagFileResized
= forcePromises()? true: tagFileResized
;
4277 pushLanguage ((exclusive_subparser
== LANG_IGNORE
)
4279 : exclusive_subparser
);
4280 makeFileTag (fileName
);
4284 return tagFileResized
;
4287 static void printGuessedParser (const char* const fileName
, langType language
)
4289 const char *parserName
;
4291 if (language
== LANG_IGNORE
)
4293 Option
.printLanguage
= ((int)true) + 1;
4294 parserName
= RSV_NONE
;
4298 parserName
= getLanguageName (language
);
4301 printf("%s: %s\n", fileName
, parserName
);
4305 static char **EncodingMap
;
4306 static unsigned int EncodingMapMax
;
4308 static void addLanguageEncoding (const langType language
,
4309 const char *const encoding
)
4311 if (language
> EncodingMapMax
|| EncodingMapMax
== 0)
4314 int istart
= (EncodingMapMax
== 0)? 0: EncodingMapMax
+ 1;
4315 EncodingMap
= xRealloc (EncodingMap
, (language
+ 1), char*);
4316 for (i
= istart
; i
<= language
; ++i
)
4318 EncodingMap
[i
] = NULL
;
4320 EncodingMapMax
= language
;
4322 if (EncodingMap
[language
])
4323 eFree (EncodingMap
[language
]);
4324 EncodingMap
[language
] = eStrdup(encoding
);
4325 if (!Option
.outputEncoding
)
4326 Option
.outputEncoding
= eStrdup("UTF-8");
4329 extern bool processLanguageEncodingOption (const char *const option
, const char *const parameter
)
4333 language
= getLanguageComponentInOption (option
, "input-encoding-");
4334 if (language
== LANG_IGNORE
)
4337 addLanguageEncoding (language
, parameter
);
4341 extern void freeEncodingResources (void)
4346 for (i
= 0 ; i
<= EncodingMapMax
; ++i
)
4348 if (EncodingMap
[i
])
4349 eFree (EncodingMap
[i
]);
4351 eFree (EncodingMap
);
4353 if (Option
.inputEncoding
)
4354 eFree (Option
.inputEncoding
);
4355 if (Option
.outputEncoding
)
4356 eFree (Option
.outputEncoding
);
4359 extern const char *getLanguageEncoding (const langType language
)
4361 if (EncodingMap
&& language
<= EncodingMapMax
&& EncodingMap
[language
])
4362 return EncodingMap
[language
];
4364 return Option
.inputEncoding
;
4368 static void addParserPseudoTags (langType language
)
4370 parserObject
*parser
= LanguageTable
+ language
;
4371 if (!parser
->pseudoTagPrinted
)
4373 for (int i
= 0; i
< PTAG_COUNT
; i
++)
4375 if (isPtagParserSpecific (i
))
4376 makePtagIfEnabled (i
, language
, parser
);
4378 parser
->pseudoTagPrinted
= 1;
4382 extern bool doesParserRequireMemoryStream (const langType language
)
4384 Assert (0 <= language
&& language
< (int) LanguageCount
);
4385 parserDefinition
*const lang
= LanguageTable
[language
].def
;
4388 if (lang
->tagXpathTableCount
> 0
4389 || lang
->useMemoryStreamInput
)
4391 verbose ("%s requires a memory stream for input\n", lang
->name
);
4395 for (i
= 0; i
< lang
->dependencyCount
; i
++)
4397 parserDependency
*d
= lang
->dependencies
+ i
;
4398 if (d
->type
== DEPTYPE_SUBPARSER
&&
4399 ((subparser
*)(d
->data
))->direction
& SUBPARSER_SUB_RUNS_BASE
)
4401 langType baseParser
;
4402 baseParser
= getNamedLanguage (d
->upperParser
, 0);
4403 if (doesParserRequireMemoryStream(baseParser
))
4405 verbose ("%s/%s requires a memory stream for input\n", lang
->name
,
4406 LanguageTable
[baseParser
].def
->name
);
4415 extern bool parseFile (const char *const fileName
)
4417 TRACE_ENTER_TEXT("Parsing file %s",fileName
);
4418 bool bRet
= parseFileWithMio (fileName
, NULL
, NULL
);
4423 static bool parseMio (const char *const fileName
, langType language
, MIO
* mio
, time_t mtime
, bool useSourceFileTagPath
,
4426 bool tagFileResized
= false;
4427 bool failureInOpenning
= false;
4429 setupWriter (clientData
);
4433 initParserTrashBox ();
4435 tagFileResized
= createTagsWithFallback (fileName
, language
, mio
, mtime
, &failureInOpenning
);
4437 finiParserTrashBox ();
4441 if (useSourceFileTagPath
&& (!failureInOpenning
))
4442 return teardownWriter (getSourceFileTagPath())? true: tagFileResized
;
4444 return teardownWriter(fileName
);
4447 extern bool parseFileWithMio (const char *const fileName
, MIO
*mio
,
4450 bool tagFileResized
= false;
4452 struct GetLanguageRequest req
= {
4453 .type
= mio
? GLR_REUSE
: GLR_OPEN
,
4454 .fileName
= fileName
,
4457 memset (&req
.mtime
, 0, sizeof (req
.mtime
));
4459 language
= getFileLanguageForRequest (&req
);
4460 Assert (language
!= LANG_AUTO
);
4462 if (Option
.printLanguage
)
4464 printGuessedParser (fileName
, language
);
4465 return tagFileResized
;
4468 if (language
== LANG_IGNORE
)
4469 verbose ("ignoring %s (unknown language/language disabled)\n",
4473 Assert(isLanguageEnabled (language
));
4475 if (Option
.filter
&& ! Option
.interactive
)
4479 /* TODO: checkUTF8BOM can be used to update the encodings. */
4480 openConverter (getLanguageEncoding (language
), Option
.outputEncoding
);
4482 tagFileResized
= parseMio (fileName
, language
, req
.mio
, req
.mtime
, true, clientData
);
4483 if (Option
.filter
&& ! Option
.interactive
)
4484 closeTagFile (tagFileResized
);
4485 addTotals (1, 0L, 0L);
4492 if (req
.type
== GLR_OPEN
&& req
.mio
)
4493 mio_unref (req
.mio
);
4495 return tagFileResized
;
4498 extern bool parseRawBuffer(const char *fileName
, unsigned char *buffer
,
4499 size_t bufferSize
, const langType language
, void *clientData
)
4505 mio
= mio_new_memory (buffer
, bufferSize
, NULL
, NULL
);
4507 r
= parseMio (fileName
, language
, mio
, (time_t)0, false, clientData
);
4515 static void matchLanguageMultilineRegexCommon (const langType language
,
4516 bool (* func
) (struct lregexControlBlock
*, const vString
* const),
4517 const vString
* const allLines
)
4521 func ((LanguageTable
+ language
)->lregexControlBlock
, allLines
);
4522 foreachSubparser(tmp
, true)
4524 langType t
= getSubparserLanguage (tmp
);
4525 enterSubparser (tmp
);
4526 matchLanguageMultilineRegexCommon (t
, func
, allLines
);
4531 extern void matchLanguageMultilineRegex (const langType language
,
4532 const vString
* const allLines
)
4534 matchLanguageMultilineRegexCommon(language
, matchMultilineRegex
, allLines
);
4537 extern void matchLanguageMultitableRegex (const langType language
,
4538 const vString
* const allLines
)
4540 matchLanguageMultilineRegexCommon(language
, matchMultitableRegex
, allLines
);
4543 extern void processLanguageMultitableExtendingOption (langType language
, const char *const parameter
)
4549 tmp
= strchr(parameter
, '+');
4552 error (FATAL
, "no separator(+) found: %s", parameter
);
4554 if (tmp
== parameter
)
4555 error (FATAL
, "the name of source table is empty in table extending: %s", parameter
);
4559 error (FATAL
, "the name of dist table is empty in table extending: %s", parameter
);
4561 dist
= eStrndup(parameter
, tmp
- parameter
);
4562 extendRegexTable(((LanguageTable
+ language
)->lregexControlBlock
), src
, dist
);
4566 static bool lregexQueryParserAndSubparsers (const langType language
, bool (* predicate
) (struct lregexControlBlock
*))
4571 r
= predicate ((LanguageTable
+ language
)->lregexControlBlock
);
4574 foreachSubparser(tmp
, true)
4576 langType t
= getSubparserLanguage (tmp
);
4577 enterSubparser (tmp
);
4578 r
= lregexQueryParserAndSubparsers (t
, predicate
);
4589 extern bool hasLanguagePostRunRegexPatterns (const langType language
)
4591 return lregexQueryParserAndSubparsers (language
, regexIsPostRun
);
4594 extern bool hasLanguageMultilineRegexPatterns (const langType language
)
4596 return lregexQueryParserAndSubparsers (language
, regexNeedsMultilineBuffer
);
4599 static bool hasLanguageAnyRegexPatterns (const langType language
)
4601 return lregexQueryParserAndSubparsers (language
, lregexControlBlockHasAny
);
4604 extern void addLanguageCallbackRegex (const langType language
, const char *const regex
, const char *const flags
,
4605 const regexCallback callback
, bool *disabled
, void *userData
)
4607 addCallbackRegex ((LanguageTable
+language
)->lregexControlBlock
, regex
, flags
, callback
, disabled
, userData
);
4610 extern bool doesLanguageExpectCorkInRegex (const langType language
)
4612 bool hasScopeAction
;
4614 pushLanguage (language
);
4615 hasScopeAction
= lregexQueryParserAndSubparsers (language
, doesExpectCorkInRegex
);
4618 return hasScopeAction
;
4621 extern void matchLanguageRegex (const langType language
, const vString
* const line
, bool postrun
)
4625 matchRegex ((LanguageTable
+ language
)->lregexControlBlock
, line
, postrun
);
4626 foreachSubparser(tmp
, true)
4628 langType t
= getSubparserLanguage (tmp
);
4629 enterSubparser (tmp
);
4630 matchLanguageRegex (t
, line
, postrun
);
4635 extern bool processLanguageRegexOption (langType language
,
4636 enum regexParserType regptype
,
4637 const char *const parameter
)
4639 processTagRegexOption ((LanguageTable
+language
)->lregexControlBlock
,
4640 regptype
, parameter
);
4645 extern bool processTabledefOption (const char *const option
, const char *const parameter
)
4649 language
= getLanguageComponentInOption (option
, "_tabledef-");
4650 if (language
== LANG_IGNORE
)
4653 if (parameter
== NULL
|| parameter
[0] == '\0')
4654 error (FATAL
, "A parameter is needed after \"%s\" option", option
);
4656 addRegexTable((LanguageTable
+language
)->lregexControlBlock
, parameter
);
4660 extern void useRegexMethod (const langType language
)
4662 parserDefinition
* lang
;
4664 Assert (0 <= language
&& language
< (int) LanguageCount
);
4665 lang
= LanguageTable
[language
].def
;
4666 lang
->method
|= METHOD_REGEX
;
4669 static void useXpathMethod (const langType language
)
4671 parserDefinition
* lang
;
4673 Assert (0 <= language
&& language
< (int) LanguageCount
);
4674 lang
= LanguageTable
[language
].def
;
4675 lang
->method
|= METHOD_XPATH
;
4678 static void installTagRegexTable (const langType language
)
4680 parserObject
* parser
;
4681 parserDefinition
* lang
;
4684 Assert (0 <= language
&& language
< (int) LanguageCount
);
4685 parser
= LanguageTable
+ language
;
4689 if (lang
->tagRegexTable
!= NULL
)
4691 /* ctags_cli_main() calls initRegexOptscript ().
4692 * However, mini-geany deasn't call ctags_cli_main().
4693 * So we call initRegexOptscript () here.
4695 initRegexOptscript ();
4697 for (i
= 0; i
< lang
->tagRegexCount
; ++i
)
4699 if (lang
->tagRegexTable
[i
].mline
)
4700 addTagMultiLineRegex (parser
->lregexControlBlock
,
4701 lang
->tagRegexTable
[i
].regex
,
4702 lang
->tagRegexTable
[i
].name
,
4703 lang
->tagRegexTable
[i
].kinds
,
4704 lang
->tagRegexTable
[i
].flags
,
4705 (lang
->tagRegexTable
[i
].disabled
));
4707 addTagRegex (parser
->lregexControlBlock
,
4708 lang
->tagRegexTable
[i
].regex
,
4709 lang
->tagRegexTable
[i
].name
,
4710 lang
->tagRegexTable
[i
].kinds
,
4711 lang
->tagRegexTable
[i
].flags
,
4712 (lang
->tagRegexTable
[i
].disabled
));
4717 static void installKeywordTable (const langType language
)
4719 parserDefinition
* lang
;
4722 Assert (0 <= language
&& language
< (int) LanguageCount
);
4723 lang
= LanguageTable
[language
].def
;
4725 if (lang
->keywordTable
!= NULL
)
4727 for (i
= 0; i
< lang
->keywordCount
; ++i
)
4728 addKeyword (lang
->keywordTable
[i
].name
,
4730 lang
->keywordTable
[i
].id
);
4734 static void installTagXpathTable (const langType language
)
4736 parserDefinition
* lang
;
4739 Assert (0 <= language
&& language
< (int) LanguageCount
);
4740 lang
= LanguageTable
[language
].def
;
4742 if (lang
->tagXpathTableTable
!= NULL
)
4744 for (i
= 0; i
< lang
->tagXpathTableCount
; ++i
)
4745 for (j
= 0; j
< lang
->tagXpathTableTable
[i
].count
; ++j
)
4746 addTagXpath (language
, lang
->tagXpathTableTable
[i
].table
+ j
);
4747 useXpathMethod (language
);
4751 static void uninstallTagXpathTable (const langType language
)
4753 parserDefinition
* lang
;
4756 Assert (0 <= language
&& language
< (int) LanguageCount
);
4757 lang
= LanguageTable
[language
].def
;
4759 if (lang
->tagXpathTableTable
!= NULL
)
4761 for (i
= 0; i
< lang
->tagXpathTableCount
; ++i
)
4762 for (j
= 0; j
< lang
->tagXpathTableTable
[i
].count
; ++j
)
4763 removeTagXpath (language
, lang
->tagXpathTableTable
[i
].table
+ j
);
4767 const tagXpathTableTable
*getXpathTableTable (const langType language
, unsigned int nth
)
4769 parserDefinition
* lang
;
4771 Assert (0 <= language
&& language
< (int) LanguageCount
);
4772 lang
= LanguageTable
[language
].def
;
4774 Assert (nth
< lang
->tagXpathTableCount
);
4775 return lang
->tagXpathTableTable
+ nth
;
4778 extern unsigned int getXpathFileSpecCount (const langType language
)
4780 parserDefinition
* lang
;
4782 Assert (0 <= language
&& language
< (int) LanguageCount
);
4783 lang
= LanguageTable
[language
].def
;
4785 return lang
->xpathFileSpecCount
;
4788 extern xpathFileSpec
* getXpathFileSpec (const langType language
, unsigned int nth
)
4790 parserDefinition
* lang
;
4792 Assert (0 <= language
&& language
< (int) LanguageCount
);
4793 lang
= LanguageTable
[language
].def
;
4795 Assert (nth
< lang
->xpathFileSpecCount
);
4796 return lang
->xpathFileSpecs
+ nth
;
4799 extern bool makeKindSeparatorsPseudoTags (const langType language
,
4800 const ptagDesc
*pdesc
)
4802 parserObject
* parser
;
4803 parserDefinition
* lang
;
4804 struct kindControlBlock
*kcb
;
4805 kindDefinition
*kind
;
4806 unsigned int kindCount
;
4811 Assert (0 <= language
&& language
< (int) LanguageCount
);
4812 parser
= LanguageTable
+ language
;
4814 kcb
= parser
->kindControlBlock
;
4815 kindCount
= countKinds(kcb
);
4820 for (i
= 0; i
< kindCount
; ++i
)
4822 kind
= getKind (kcb
, i
);
4823 for (j
= 0; j
< kind
->separatorCount
; ++j
)
4825 char name
[3] = {[1] = '\0', [2] = '\0'};
4826 const kindDefinition
*upperKind
;
4827 const scopeSeparator
*sep
;
4829 sep
= kind
->separators
+ j
;
4831 if (sep
->parentKindIndex
== KIND_WILDCARD_INDEX
)
4833 name
[0] = KIND_WILDCARD_LETTER
;
4834 name
[1] = kind
->letter
;
4836 else if (sep
->parentKindIndex
== KIND_GHOST_INDEX
)
4838 /* This is root separator: no upper item is here. */
4839 name
[0] = kind
->letter
;
4843 upperKind
= getLanguageKind (language
,
4844 sep
->parentKindIndex
);
4848 name
[0] = upperKind
->letter
;
4849 name
[1] = kind
->letter
;
4853 r
= writePseudoTag (pdesc
, sep
->separator
? sep
->separator
: "",
4854 name
, lang
->name
) || r
;
4861 struct makeKindDescriptionPseudoTagData
{
4862 const char* langName
;
4863 const ptagDesc
*pdesc
;
4867 static bool makeKindDescriptionPseudoTag (kindDefinition
*kind
,
4870 struct makeKindDescriptionPseudoTagData
*data
= user_data
;
4871 vString
*letter_and_name
;
4873 letter_and_name
= vStringNew ();
4875 vStringPut (letter_and_name
, kind
-> letter
);
4876 vStringPut (letter_and_name
, ',');
4877 vStringCatS (letter_and_name
, kind
-> name
);
4879 data
->written
|= writePseudoTag (data
->pdesc
, vStringValue (letter_and_name
),
4880 kind
->description
? kind
->description
: kind
->name
,
4883 vStringDelete (letter_and_name
);
4888 static bool makeRoleDescriptionPseudoTag (kindDefinition
*kind
,
4889 roleDefinition
*role
,
4892 struct makeKindDescriptionPseudoTagData
*data
= user_data
;
4894 vString
*parser_and_kind_name
= vStringNewInit (data
->langName
);
4895 vStringCatS (parser_and_kind_name
, PSEUDO_TAG_SEPARATOR
);
4896 vStringCatS (parser_and_kind_name
, kind
->name
);
4898 data
->written
|= writePseudoTag (data
->pdesc
, role
->name
,
4899 role
->description
? role
->description
: role
->name
,
4900 vStringValue (parser_and_kind_name
));
4902 vStringDelete (parser_and_kind_name
);
4907 extern bool makeKindDescriptionsPseudoTags (const langType language
,
4908 const ptagDesc
*pdesc
)
4910 parserObject
*parser
;
4911 struct kindControlBlock
*kcb
;
4912 parserDefinition
* lang
;
4913 kindDefinition
*kind
;
4914 unsigned int kindCount
, i
;
4915 struct makeKindDescriptionPseudoTagData data
;
4917 Assert (0 <= language
&& language
< (int) LanguageCount
);
4918 parser
= LanguageTable
+ language
;
4919 kcb
= parser
->kindControlBlock
;
4922 kindCount
= countKinds(kcb
);
4924 data
.langName
= lang
->name
;
4926 data
.written
= false;
4928 for (i
= 0; i
< kindCount
; ++i
)
4930 if (!isLanguageKindEnabled (language
, i
))
4933 kind
= getKind (kcb
, i
);
4934 if (language
== ctagsSelfTestLang
4935 && (kind
== NULL
|| kind
->name
== NULL
))
4937 /* The Self test parser may have broken kinds.
4941 makeKindDescriptionPseudoTag (kind
, &data
);
4944 return data
.written
;
4947 static bool makeFieldDescriptionPseudoTag (const langType language
,
4949 const ptagDesc
*pdesc
)
4951 const char *name
= getFieldName (f
);
4953 if (name
== NULL
|| name
[0] == '\0')
4956 return writePseudoTag (pdesc
, name
,
4957 getFieldDescription (f
),
4958 language
== LANG_IGNORE
? NULL
: getLanguageName (language
));
4961 extern bool makeFieldDescriptionsPseudoTags (const langType language
,
4962 const ptagDesc
*pdesc
)
4964 bool written
= false;
4965 for (unsigned int i
= 0; i
< countFields (); i
++)
4967 if (getFieldLanguage (i
) == language
4968 && isFieldEnabled (i
))
4970 if (makeFieldDescriptionPseudoTag (language
, i
, pdesc
))
4977 static bool makeExtraDescriptionPseudoTag (const langType language
,
4979 const ptagDesc
*pdesc
)
4981 const char *name
= getXtagName (x
);
4983 if (name
== NULL
|| name
[0] == '\0')
4986 return writePseudoTag (pdesc
, name
,
4987 getXtagDescription (x
),
4988 language
== LANG_IGNORE
? NULL
: getLanguageName (language
));
4991 extern bool makeExtraDescriptionsPseudoTags (const langType language
,
4992 const ptagDesc
*pdesc
)
4994 bool written
= false;
4995 for (unsigned int i
= 0; i
< countXtags (); i
++)
4997 if (getXtagLanguage (i
) == language
4998 && isXtagEnabled (i
))
5000 if (makeExtraDescriptionPseudoTag (language
, i
, pdesc
))
5007 extern bool makeRoleDescriptionsPseudoTags (const langType language
,
5008 const ptagDesc
*pdesc
)
5010 parserObject
*parser
;
5011 struct kindControlBlock
*kcb
;
5012 parserDefinition
* lang
;
5013 kindDefinition
*kind
;
5014 struct makeKindDescriptionPseudoTagData data
;
5016 Assert (0 <= language
&& language
< (int) LanguageCount
);
5017 parser
= LanguageTable
+ language
;
5018 kcb
= parser
->kindControlBlock
;
5021 unsigned int kindCount
= countKinds(kcb
);
5023 data
.langName
= lang
->name
;
5025 data
.written
= false;
5027 for (unsigned int i
= 0; i
< kindCount
; ++i
)
5029 if (!isLanguageKindEnabled (language
, i
))
5032 kind
= getKind (kcb
, i
);
5034 unsigned int roleCount
= countRoles (kcb
, i
);
5035 for (unsigned int j
= 0; j
< roleCount
; ++j
)
5037 if (isRoleEnabled (kcb
, i
, j
))
5039 roleDefinition
*role
= getRole (kcb
, i
, j
);
5040 makeRoleDescriptionPseudoTag (kind
, role
, &data
);
5045 return data
.written
;
5048 extern unsigned int getLanguageVersionCurrent (const langType language
)
5050 parserObject
*parser
;
5051 parserDefinition
* lang
;
5052 Assert (0 <= language
&& language
< (int) LanguageCount
);
5053 parser
= LanguageTable
+ language
;
5055 return lang
->versionCurrent
;
5058 extern unsigned int getLanguageVersionAge (const langType language
)
5060 parserObject
*parser
;
5061 parserDefinition
* lang
;
5062 Assert (0 <= language
&& language
< (int) LanguageCount
);
5063 parser
= LanguageTable
+ language
;
5065 return lang
->versionAge
;
5069 * Copyright (c) 2016, Szymon Tomasz Stefanek
5071 * This source code is released for free distribution under the terms of the
5072 * GNU General Public License version 2 or (at your option) any later version.
5074 * Anonymous name generator
5076 static ptrArray
*parsersUsedInCurrentInput
;
5078 static void setupAnon (void)
5080 parsersUsedInCurrentInput
= ptrArrayNew (NULL
);
5083 static void teardownAnon (void)
5085 ptrArrayDelete (parsersUsedInCurrentInput
);
5088 static void anonResetMaybe (parserObject
*parser
)
5090 if (ptrArrayHas (parsersUsedInCurrentInput
, parser
))
5093 parser
-> anonymousIdentiferId
= 0;
5094 ptrArrayAdd (parsersUsedInCurrentInput
, parser
);
5097 static unsigned int anonHash(const unsigned char *str
)
5099 unsigned int hash
= 5381;
5103 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
5108 extern void anonHashString (const char *filename
, char buf
[9])
5110 sprintf(buf
, "%08x", anonHash((const unsigned char *)filename
));
5113 extern void anonConcatFull (vString
*buffer
, langType lang
, int kind
)
5115 anonGenerateFull (buffer
, NULL
, lang
, kind
);
5118 extern void anonGenerateFull (vString
*buffer
, const char *prefix
, langType lang
, int kind
)
5120 Assert(lang
!= LANG_IGNORE
);
5121 parserObject
* parser
= LanguageTable
+ ((lang
== LANG_AUTO
)? getInputLanguage (): lang
);
5122 parser
-> anonymousIdentiferId
++;
5128 vStringCopyS(buffer
, prefix
);
5130 anonHashString (getInputFileName(), buf
);
5131 sprintf(szNum
,"%s%02x%02x",buf
,parser
-> anonymousIdentiferId
, kind
);
5132 vStringCatS(buffer
,szNum
);
5135 extern vString
*anonGenerateNewFull (const char *prefix
, langType lang
, int kind
)
5137 vString
*buffer
= vStringNew ();
5139 anonGenerateFull (buffer
, prefix
, lang
, kind
);
5143 extern bool applyLanguageParam (const langType language
, const char *name
, const char *args
)
5145 Assert (0 <= language
&& language
< (int) LanguageCount
);
5147 initializeParserOne (language
);
5148 return applyParam (LanguageTable
[language
].paramControlBlock
, name
, args
);
5151 extern subparser
*getNextSubparser(subparser
*last
,
5152 bool includingNoneCraftedParser
)
5154 langType lang
= getInputLanguage ();
5155 parserObject
*parser
= LanguageTable
+ lang
;
5160 r
= getFirstSubparser(parser
->slaveControlBlock
);
5167 t
= getSubparserLanguage(r
);
5168 if (isLanguageEnabled (t
) &&
5169 (includingNoneCraftedParser
5170 || ((((LanguageTable
+ t
)->def
->method
) & METHOD_NOT_CRAFTED
) == 0)))
5173 return getNextSubparser (r
, includingNoneCraftedParser
);
5176 extern slaveParser
*getNextSlaveParser(slaveParser
*last
)
5178 langType lang
= getInputLanguage ();
5179 parserObject
*parser
= LanguageTable
+ lang
;
5183 r
= getFirstSlaveParser(parser
->slaveControlBlock
);
5190 extern void scheduleRunningBaseparser (int dependencyIndex
)
5192 langType current
= getInputLanguage ();
5193 parserObject
*current_pobj
= LanguageTable
+ current
;
5194 parserDefinition
*current_parser
= current_pobj
->def
;
5195 parserDependency
*dep
= NULL
;
5197 current_pobj
->justRunForSchedulingBase
= 1;
5199 if (dependencyIndex
== RUN_DEFAULT_SUBPARSERS
)
5201 for (unsigned int i
= 0; i
< current_parser
->dependencyCount
; ++i
)
5202 if (current_parser
->dependencies
[i
].type
== DEPTYPE_SUBPARSER
)
5204 dep
= current_parser
->dependencies
+ i
;
5209 dep
= current_parser
->dependencies
+ dependencyIndex
;
5214 const char *base_name
= dep
->upperParser
;
5215 langType base
= getNamedLanguage (base_name
, 0);
5216 parserObject
*base_parser
= LanguageTable
+ base
;
5218 if (dependencyIndex
== RUN_DEFAULT_SUBPARSERS
)
5219 useDefaultSubparsers(base_parser
->slaveControlBlock
);
5221 useSpecifiedSubparser (base_parser
->slaveControlBlock
,
5224 if (!isLanguageEnabled (base
))
5226 enableLanguage (base
, true);
5227 base_parser
->dontEmit
= true;
5228 verbose ("force enable \"%s\" as base parser\n", base_parser
->def
->name
);
5234 verbose ("scheduleRunningBaseparser %s with subparsers: ", base_name
);
5235 pushLanguage (base
);
5236 foreachSubparser(tmp
, true)
5238 langType t
= getSubparserLanguage (tmp
);
5239 verbose ("%s ", getLanguageName (t
));
5246 makePromise(base_name
, THIN_STREAM_SPEC
);
5249 extern bool isParserMarkedNoEmission (void)
5251 langType lang
= getInputLanguage();
5252 parserObject
*parser
= LanguageTable
+ lang
;
5254 return parser
->dontEmit
;
5258 extern subparser
* getSubparserRunningBaseparser (void)
5260 langType current
= getInputLanguage ();
5261 parserObject
*current_parser
= LanguageTable
+ current
;
5262 subparser
*s
= getFirstSubparser (current_parser
->slaveControlBlock
);
5264 if (s
&& s
->schedulingBaseparserExplicitly
)
5270 extern void printLanguageSubparsers (const langType language
,
5271 bool withListHeader
, bool machinable
, FILE *fp
)
5273 for (int i
= 0; i
< (int) LanguageCount
; i
++)
5274 initializeParserOne (i
);
5276 struct colprintTable
* table
= subparserColprintTableNew();
5277 parserObject
*parser
;
5279 if (language
== LANG_AUTO
)
5281 for (int i
= 0; i
< (int) LanguageCount
; i
++)
5283 parser
= LanguageTable
+ i
;
5284 if (parser
->def
->invisible
)
5287 subparserColprintAddSubparsers (table
,
5288 parser
->slaveControlBlock
);
5293 parser
= (LanguageTable
+ language
);
5294 subparserColprintAddSubparsers (table
,
5295 parser
->slaveControlBlock
);
5298 subparserColprintTablePrint (table
,
5299 withListHeader
, machinable
,
5301 colprintTableDelete (table
);
5304 extern void printLangdefFlags (bool withListHeader
, bool machinable
, FILE *fp
)
5306 struct colprintTable
* table
;
5308 table
= flagsColprintTableNew ();
5310 flagsColprintAddDefinitions (table
, PreLangDefFlagDef
, ARRAY_SIZE (PreLangDefFlagDef
));
5312 flagsColprintTablePrint (table
, withListHeader
, machinable
, fp
);
5313 colprintTableDelete(table
);
5316 extern void printKinddefFlags (bool withListHeader
, bool machinable
, FILE *fp
)
5318 struct colprintTable
* table
;
5320 table
= flagsColprintTableNew ();
5322 flagsColprintAddDefinitions (table
, PreKindDefFlagDef
, ARRAY_SIZE (PreKindDefFlagDef
));
5324 flagsColprintTablePrint (table
, withListHeader
, machinable
, fp
);
5325 colprintTableDelete(table
);
5328 extern void printLanguageMultitableStatistics (langType language
)
5330 parserObject
* const parser
= LanguageTable
+ language
;
5331 printMultitableStatistics (parser
->lregexControlBlock
);
5334 extern void addLanguageRegexTable (const langType language
, const char *name
)
5336 parserObject
* const parser
= LanguageTable
+ language
;
5337 addRegexTable (parser
->lregexControlBlock
, name
);
5340 extern void addLanguageTagMultiTableRegex(const langType language
,
5341 const char* const table_name
,
5342 const char* const regex
,
5343 const char* const name
, const char* const kinds
, const char* const flags
,
5346 parserObject
* const parser
= LanguageTable
+ language
;
5347 addTagMultiTableRegex (parser
->lregexControlBlock
, table_name
, regex
,
5348 name
, kinds
, flags
, disabled
);
5351 extern void addLanguageOptscriptToHook (langType language
, enum scriptHook hook
, const char *const src
)
5353 addOptscriptToHook (LanguageTable
[language
].lregexControlBlock
, hook
, src
);
5356 static bool processHookOption (const char *const option
, const char *const parameter
, const char *prefix
,
5357 enum scriptHook hook
)
5359 langType language
= getLanguageComponentInOption (option
, prefix
);
5360 if (language
== LANG_IGNORE
)
5363 if (parameter
== NULL
|| parameter
[0] == '\0')
5364 error (FATAL
, "A parameter is needed after \"%s\" option", option
);
5366 const char * code
= flagsEval (parameter
, NULL
, 0, NULL
);
5368 error (FATAL
, "Cannot recognized a code block surrounded by `{{' and `}}' after \"%s\" option", option
);
5369 addLanguageOptscriptToHook (language
, hook
, code
);
5374 extern bool processPreludeOption (const char *const option
, const char *const parameter
)
5376 return processHookOption (option
, parameter
, "_prelude-", SCRIPT_HOOK_PRELUDE
);
5379 extern bool processSequelOption (const char *const option
, const char *const parameter
)
5381 return processHookOption (option
, parameter
, "_sequel-", SCRIPT_HOOK_SEQUEL
);
5384 extern bool processPretendOption (const char *const option
, const char *const parameter
)
5386 langType new_language
, old_language
;
5388 #define pretendOptionPrefix "_pretend-"
5389 new_language
= getLanguageComponentInOptionFull (option
, pretendOptionPrefix
, true);
5390 if (new_language
== LANG_IGNORE
)
5393 if (parameter
== NULL
|| parameter
[0] == '\0')
5394 error (FATAL
, "A parameter is needed after \"%s\" option", option
);
5396 old_language
= getNamedLanguageFull (parameter
, 0, true, false);
5397 if (old_language
== LANG_IGNORE
)
5398 error (FATAL
, "Unknown language \"%s\" in option \"--%s=%s\"",
5399 parameter
, option
, parameter
);
5401 if (LanguageTable
[new_language
].pretendingAsLanguage
!= LANG_IGNORE
)
5403 error (FATAL
, "%s parser pretends as %s already\n",
5404 getLanguageNameFull (new_language
, true),
5405 getLanguageNameFull (LanguageTable
[new_language
].pretendingAsLanguage
, true));
5407 if (LanguageTable
[old_language
].pretendedAsLanguage
!= LANG_IGNORE
)
5409 error (FATAL
, "%s parser is pretended as %s already\n",
5410 getLanguageNameFull (old_language
, true),
5411 getLanguageNameFull (LanguageTable
[old_language
].pretendedAsLanguage
, true));
5414 verbose ("%s pretends %s\n",
5415 getLanguageNameFull (new_language
, true),
5416 getLanguageNameFull (old_language
, true));
5418 LanguageTable
[new_language
].pretendingAsLanguage
= old_language
;
5419 LanguageTable
[old_language
].pretendedAsLanguage
= new_language
;
5421 verbose ("force enabling %s\n",
5422 getLanguageNameFull (new_language
, true));
5423 enableLanguage (new_language
, true);
5425 verbose ("force disabling %s\n",
5426 getLanguageNameFull (old_language
, true));
5427 enableLanguage (old_language
, false);
5432 extern unsigned int getLanguageCorkUsage (langType lang
)
5434 parserObject
* const parser
= LanguageTable
+ lang
;
5435 return parserCorkFlags (parser
->def
);
5439 * The universal fallback parser.
5440 * If any parser doesn't handle the input, this parser is
5441 * used for the input when --languages=+Unknown is given.
5442 * writer-etags enables this parser implicitly.
5444 static parserDefinition
*FallbackParser (void)
5446 parserDefinition
*const def
= parserNew ("Unknown");
5447 def
->extensions
= NULL
;
5448 def
->kindTable
= NULL
;
5451 /* A user can extend this parser with --regex-Unknown=...
5452 * or --langdef=MyParser{base=Unknown}.
5454 * TODO: if following conditions are met, dontFindTags()
5455 * defined below can be used.
5456 * - any regex pattern is not defined,
5457 * - any sub parser is not defined, and
5458 * - end: field is not enabled.
5460 def
->parser
= findRegexTags
;
5462 def
->method
= METHOD_REGEX
;
5467 * A dummy parser for printing pseudo tags in xref output
5469 static void dontFindTags (void)
5473 static kindDefinition CtagsKinds
[] = {
5474 {true, 'p', "ptag", "pseudo tags"},
5477 static parserDefinition
*CTagsParser (void)
5479 parserDefinition
*const def
= parserNew ("UniversalCtags");
5480 def
->extensions
= NULL
;
5481 def
->kindTable
= CtagsKinds
;
5482 def
->kindCount
= ARRAY_SIZE(CtagsKinds
);
5483 def
->parser
= dontFindTags
;
5484 def
->invisible
= true;
5489 * A parser for CTagsSelfTest (CTST)
5491 #define SELF_TEST_PARSER "CTagsSelfTest"
5492 #if defined(DEBUG) && defined(HAVE_SECCOMP)
5493 extern void getppid(void);
5496 static bool CTST_GatherStats
;
5497 static int CTST_num_handled_char
;
5506 #if defined(DEBUG) && defined(HAVE_SECCOMP)
5523 static roleDefinition CTST_BrokenRoles
[] = {
5524 {true, "broken", "broken" },
5528 R_DISABLED_KIND_DISABLED_ROLE
,
5529 R_DISABLED_KIND_ENABLED_ROLE
,
5530 } CTST_DisabledKindRole
;
5532 static roleDefinition CTST_DisabledKindRoles
[] = {
5533 { false, "disabled", "disabled role attached to disabled kind" },
5534 { true, "enabled", "enabled role attached to disabled kind" },
5538 R_ENABLED_KIND_DISABLED_ROLE
,
5539 R_ENABLED_KIND_ENABLED_ROLE
,
5540 } CTST_EnabledKindRole
;
5542 static roleDefinition CTST_EnabledKindRoles
[] = {
5543 { false, "disabled", "disabled role attached to enabled kind" },
5544 { true, "enabled", "enabled role attached to enabled kind" },
5548 R_ROLES_KIND_A_ROLE
,
5549 R_ROLES_KIND_B_ROLE
,
5550 R_ROLES_KIND_C_ROLE
,
5551 R_ROLES_KIND_D_ROLE
,
5552 } CTST_RolesKindRole
;
5554 static roleDefinition CTST_RolesKindRoles
[] = {
5555 { true, "a", "A role" },
5556 { true, "b", "B role" },
5557 { false, "c", "C role" },
5558 { true, "d", "D role" },
5562 R_ROLES_DISABLED_KIND_A_ROLE
,
5563 R_ROLES_DISABLED_KIND_B_ROLE
,
5564 } CTST_RolesDisableKindRole
;
5567 static roleDefinition CTST_RolesDisabledKindRoles
[] = {
5568 { true, "A", "A role" },
5569 { true, "B", "B role" },
5572 static kindDefinition CTST_Kinds
[KIND_COUNT
] = {
5573 /* `a' is reserved for kinddef testing */
5574 {true, 'b', "broken tag", "name with unwanted characters",
5575 .referenceOnly
= false, ATTACH_ROLES (CTST_BrokenRoles
) },
5576 {true, KIND_NULL_LETTER
, "no letter", "kind with no letter"
5577 /* use '@' when testing. */
5579 {true, 'L', NULL
, "kind with no long name" },
5580 {true, 'N', "nothingSpecial", "emit a normal tag" },
5581 {true, 'B', NULL
, "beginning of an area for a guest" },
5582 {true, 'E', NULL
, "end of an area for a guest" },
5583 #if defined(DEBUG) && defined(HAVE_SECCOMP)
5584 {true, 'P', "callGetPPid", "trigger calling getppid(2) that seccomp sandbox disallows"},
5586 {true, 'Q', "quit", "stop the parsing"},
5587 {false,'d', "disabled", "a kind disabled by default",
5588 .referenceOnly
= false, ATTACH_ROLES (CTST_DisabledKindRoles
)},
5589 {true, 'e', "enabled", "a kind enabled by default",
5590 .referenceOnly
= false, ATTACH_ROLES (CTST_EnabledKindRoles
)},
5591 {true, 'r', "roles", "emit a tag with multi roles",
5592 .referenceOnly
= true, ATTACH_ROLES (CTST_RolesKindRoles
)},
5593 {false, 'R', "rolesDisabled", "emit a tag with multi roles(disabled by default)",
5594 .referenceOnly
= true, ATTACH_ROLES (CTST_RolesDisabledKindRoles
)},
5595 {true, 'f', "fieldMaker", "tag for testing field:" },
5596 {true, 'n', "triggerNotice", "trigger notice output"},
5601 F_BOOLEAN_AND_STRING_FIELD
,
5605 static fieldDefinition CTSTFields
[COUNT_FIELD
] = {
5607 .description
= "field for testing boolean type",
5608 .dataType
= FIELDTYPE_BOOL
,
5611 { .name
= "sbField",
5612 .description
= "field for testing string|boolean type",
5613 .dataType
= FIELDTYPE_STRING
|FIELDTYPE_BOOL
,
5618 static void createCTSTTags (void)
5621 const unsigned char *line
;
5624 unsigned long lb
= 0;
5625 unsigned long le
= 0;
5627 int found_enabled_disabled
[2] = {0, 0};
5631 TRACE_ENTER_TEXT("Parsing starts");
5633 while (!quit
&& (line
= readLineFromInputFile ()) != NULL
)
5637 for (i
= 0; i
< KIND_COUNT
; i
++)
5638 if ((c
== CTST_Kinds
[i
].letter
&& i
!= K_NO_LETTER
)
5639 || (c
== '@' && i
== K_NO_LETTER
))
5641 if (CTST_GatherStats
)
5642 CTST_num_handled_char
++;
5647 initTagEntry (&e
, "one\nof\rbroken\tname", i
);
5648 e
.extensionFields
.scopeKindIndex
= K_BROKEN
;
5649 e
.extensionFields
.scopeName
= "\\Broken\tContext";
5651 initTagEntry (&e
, "only\nnewline", i
);
5653 initTagEntry (&e
, "only\ttab", i
);
5655 initTagEntry (&e
, "newline-in-scope", i
);
5656 e
.extensionFields
.scopeKindIndex
= K_BROKEN
;
5657 e
.extensionFields
.scopeName
= "parent\nscope";
5659 initTagEntry (&e
, "tab-in-scope", i
);
5660 e
.extensionFields
.scopeKindIndex
= K_BROKEN
;
5661 e
.extensionFields
.scopeName
= "parent\tscope";
5665 initTagEntry (&e
, "abnormal kindDefinition testing (no letter)", i
);
5668 case K_NO_LONG_NAME
:
5669 initTagEntry (&e
, "abnormal kindDefinition testing (no long name)", i
);
5672 case K_NOTHING_SPECIAL
:
5675 initTagEntry (&e
, "NOTHING_SPECIAL", i
);
5679 case K_GUEST_BEGINNING
:
5680 lb
= getInputLineNumber ();
5683 le
= getInputLineNumber ();
5684 makePromise (SELF_TEST_PARSER
, lb
+ 1, 0, le
, 0, lb
+ 1);
5686 #if defined(DEBUG) && defined(HAVE_SECCOMP)
5687 case K_CALL_GETPPID
:
5699 if (found_enabled_disabled
[i
== K_DISABLED
]++ == 0)
5701 role
= ROLE_DEFINITION_INDEX
;
5702 name
= (i
== K_DISABLED
)
5703 ? "disable-kind-no-role"
5704 : "enabled-kind-no-role";
5706 else if (found_enabled_disabled
[i
== K_DISABLED
]++ == 1)
5708 role
= (i
== K_DISABLED
)
5709 ? R_DISABLED_KIND_DISABLED_ROLE
5710 : R_ENABLED_KIND_DISABLED_ROLE
;
5711 name
= (i
== K_DISABLED
)
5712 ? "disable-kind-disabled-role"
5713 : "enabled-kind-disabled-role";
5717 role
= (i
== K_DISABLED
)
5718 ? R_DISABLED_KIND_ENABLED_ROLE
5719 : R_ENABLED_KIND_ENABLED_ROLE
;
5720 name
= (i
== K_DISABLED
)
5721 ? "disable-kind-enabled-role"
5722 : "enabled-kind-enabled-role";
5724 initRefTagEntry (&e
, name
, i
, role
);
5730 char *name
= "multiRolesTarget";
5734 initTagEntry (&e
, name
, i
);
5735 assignRole(&e
, R_ROLES_KIND_A_ROLE
);
5736 assignRole(&e
, R_ROLES_KIND_C_ROLE
);
5737 assignRole(&e
, R_ROLES_KIND_D_ROLE
);
5738 qindex
= makeTagEntry (&e
);
5739 qe
= getEntryInCorkQueue (qindex
);
5741 assignRole(qe
, R_ROLES_KIND_B_ROLE
);
5744 case K_ROLES_DISABLED
:
5746 char *name
= "multiRolesDisabledTarget";
5748 initRefTagEntry (&e
, name
, i
, R_ROLES_DISABLED_KIND_A_ROLE
);
5750 initRefTagEntry (&e
, name
, i
, R_ROLES_DISABLED_KIND_B_ROLE
);
5754 case K_FIELD_TESTING
:
5757 char name
[]= {'\0', 't', 'a', 'g', '\0' };
5760 initTagEntry (&e
, name
, i
);
5761 attachParserField (&e
,
5762 CTSTFields
[F_BOOLEAN_FIELD
].ftype
, "");
5766 initTagEntry (&e
, name
, i
);
5770 initTagEntry (&e
, name
, i
);
5771 attachParserField (&e
,
5772 CTSTFields
[F_BOOLEAN_AND_STRING_FIELD
].ftype
, "val");
5776 initTagEntry (&e
, name
, i
);
5777 attachParserField (&e
,
5778 CTSTFields
[F_BOOLEAN_AND_STRING_FIELD
].ftype
, "");
5783 case K_TRIGGER_NOTICE
:
5784 notice ("notice output for testing: %s", CTST_Kinds
[i
].name
);
5796 static void initStatsCTST (langType lang CTAGS_ATTR_UNUSED
)
5798 CTST_GatherStats
= true;
5801 static void printStatsCTST (langType lang CTAGS_ATTR_UNUSED
)
5803 fprintf (stderr
, "The number of handled chars: %d\n",
5804 CTST_num_handled_char
);
5807 static void initCTST (langType language
)
5809 ctagsSelfTestLang
= language
;
5812 static parserDefinition
*CTagsSelfTestParser (void)
5814 static const char *const extensions
[] = { NULL
};
5815 parserDefinition
*const def
= parserNew (SELF_TEST_PARSER
);
5816 def
->extensions
= extensions
;
5817 def
->kindTable
= CTST_Kinds
;
5818 def
->kindCount
= KIND_COUNT
;
5819 def
->parser
= createCTSTTags
;
5820 def
->initialize
= initCTST
;
5821 def
->invisible
= true;
5822 def
->useMemoryStreamInput
= true;
5823 def
->useCork
= CORK_QUEUE
;
5824 def
->initStats
= initStatsCTST
;
5825 def
->printStats
= printStatsCTST
;
5826 def
->fieldTable
= CTSTFields
;
5827 def
->fieldCount
= ARRAY_SIZE (CTSTFields
);