xref: /Universal-ctags/main/parse.c (revision b5cc9e0d37e2944d6d0965d2f6edcd66ec509fac)
1d4c6f1e6SMasatake YAMATO /*
2d4c6f1e6SMasatake YAMATO *   Copyright (c) 1996-2003, Darren Hiebert
3d4c6f1e6SMasatake YAMATO *
4d4c6f1e6SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
6d4c6f1e6SMasatake YAMATO *
7d316cd59SMasatake YAMATO *   This module contains functions for managing input languages and
8d4c6f1e6SMasatake YAMATO *   dispatching files to the appropriate language parser.
9d4c6f1e6SMasatake YAMATO */
10d4c6f1e6SMasatake YAMATO 
11d4c6f1e6SMasatake YAMATO /*
12d4c6f1e6SMasatake YAMATO *   INCLUDE FILES
13d4c6f1e6SMasatake YAMATO */
14d4c6f1e6SMasatake YAMATO #include "general.h"  /* must always come first */
15d4c6f1e6SMasatake YAMATO 
1621996d92SMasatake YAMATO /* TODO: This definition should be removed. */
1721996d92SMasatake YAMATO #define OPTION_WRITE
1821996d92SMasatake YAMATO #include "options_p.h"
1921996d92SMasatake YAMATO 
20d4c6f1e6SMasatake YAMATO #include <string.h>
21d4c6f1e6SMasatake YAMATO 
22db2bf481SMasatake YAMATO #include "ctags.h"
23d4c6f1e6SMasatake YAMATO #include "debug.h"
248cbf052bSMasatake YAMATO #include "entry_p.h"
25c08c70d0SMasatake YAMATO #include "field_p.h"
26bf281e9cSMasatake YAMATO #include "flags_p.h"
27f140c7c3SMasatake YAMATO #include "htable.h"
28c379c5d2SMasatake YAMATO #include "keyword.h"
29ec40f18bSMasatake YAMATO #include "lxpath_p.h"
300d502ef0SMasatake YAMATO #include "param.h"
3199ac24f8SMasatake YAMATO #include "param_p.h"
320d502ef0SMasatake YAMATO #include "parse_p.h"
3315c69d21SMasatake YAMATO #include "parsers_p.h"
344fa68e36SMasatake YAMATO #include "promise.h"
35e3416868SMasatake YAMATO #include "promise_p.h"
360d81da14SMasatake YAMATO #include "ptag_p.h"
373c91b1eaSMasatake YAMATO #include "ptrarray.h"
38d4c6f1e6SMasatake YAMATO #include "read.h"
39b5df137eSMasatake YAMATO #include "read_p.h"
40d4c6f1e6SMasatake YAMATO #include "routines.h"
4129e40fb6SMasatake YAMATO #include "routines_p.h"
42df2449f1SMasatake YAMATO #include "stats_p.h"
43a53e10d8SMasatake YAMATO #include "subparser.h"
44bc924efdSMasatake YAMATO #include "subparser_p.h"
45d33423e3SSzymon Tomasz Stefanek #include "trace.h"
466749a76eSMasatake YAMATO #include "trashbox.h"
47869a1bbcSMasatake YAMATO #include "trashbox_p.h"
48d4c6f1e6SMasatake YAMATO #include "vstring.h"
492acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
50f38d6693SMasatake YAMATO # include "mbcs_p.h"
512acdcfa1SYasuhiro Matsumoto #endif
5267d1f12fSJiří Techet #include "writer_p.h"
53e2a3289bSMasatake YAMATO #include "xtag_p.h"
54d4c6f1e6SMasatake YAMATO 
55d4c6f1e6SMasatake YAMATO /*
5695512ba5SMasatake YAMATO  * DATA TYPES
5795512ba5SMasatake YAMATO  */
5895512ba5SMasatake YAMATO enum specType {
5995512ba5SMasatake YAMATO 	SPEC_NONE,
6095512ba5SMasatake YAMATO 	SPEC_NAME,
6195512ba5SMasatake YAMATO 	SPEC_ALIAS = SPEC_NAME,
6295512ba5SMasatake YAMATO 	SPEC_EXTENSION,
6395512ba5SMasatake YAMATO 	SPEC_PATTERN,
6495512ba5SMasatake YAMATO };
6595512ba5SMasatake YAMATO const char *specTypeName [] = {
6695512ba5SMasatake YAMATO 	"none", "name", "extension", "pattern"
6795512ba5SMasatake YAMATO };
6895512ba5SMasatake YAMATO 
6995512ba5SMasatake YAMATO typedef struct {
7095512ba5SMasatake YAMATO 	langType lang;
7195512ba5SMasatake YAMATO 	const char* spec;
7295512ba5SMasatake YAMATO 	enum specType specType;
7395512ba5SMasatake YAMATO }  parserCandidate;
7495512ba5SMasatake YAMATO 
75e02be843SMasatake YAMATO typedef struct sParserObject {
76e02be843SMasatake YAMATO 	parserDefinition *def;
77efe089d4SMasatake YAMATO 
78b29ae60fSMasatake YAMATO 	kindDefinition* fileKind;
79b29ae60fSMasatake YAMATO 
80efe089d4SMasatake YAMATO 	stringList* currentPatterns;   /* current list of file name patterns */
81efe089d4SMasatake YAMATO 	stringList* currentExtensions; /* current list of extensions */
82efe089d4SMasatake YAMATO 	stringList* currentAliases;    /* current list of aliases */
83efe089d4SMasatake YAMATO 
84e61266e4SMasatake YAMATO 	unsigned int initialized:1;    /* initialize() is called or not */
85bf013ea8SMasatake YAMATO 	unsigned int dontEmit:1;	   /* run but don't emit tags.
86bf013ea8SMasatake YAMATO 									  This parser was disabled but a subparser on
87bf013ea8SMasatake YAMATO 									  this parser makes this parser run (to drive
88bf013ea8SMasatake YAMATO 									  the subparser). */
898df191b2SMasatake YAMATO 	unsigned int pseudoTagPrinted:1;   /* pseudo tags about this parser
908df191b2SMasatake YAMATO 										  is emitted or not. */
91a9c91f4dSMasatake YAMATO 	unsigned int used;			/* Used for printing language specific statistics. */
92e61266e4SMasatake YAMATO 
9397a77b13SMasatake YAMATO 	unsigned int anonymousIdentiferId; /* managed by anon* functions */
94faa60990SMasatake YAMATO 
95edc12faeSMasatake YAMATO 	struct slaveControlBlock *slaveControlBlock;
967bef4da4SMasatake YAMATO 	struct kindControlBlock  *kindControlBlock;
97bce55cc7SMasatake YAMATO 	struct lregexControlBlock *lregexControlBlock;
98f02166dcSMasatake YAMATO 
99f02166dcSMasatake YAMATO 	langType pretendingAsLanguage; /* OLDLANG in --_pretend-<NEWLANG>=<OLDLANG>
100f02166dcSMasatake YAMATO 									  is set here if this parser is NEWLANG.
101f02166dcSMasatake YAMATO 									  LANG_IGNORE is set if no pretending. */
102f02166dcSMasatake YAMATO 	langType pretendedAsLanguage;  /* NEWLANG in --_pretend-<NEWLANG>=<OLDLANG>
103f02166dcSMasatake YAMATO 									  is set here if this parser is OLDLANG.
104f02166dcSMasatake YAMATO 									  LANG_IGNORE is set if no being pretended. */
105f02166dcSMasatake YAMATO 
106e02be843SMasatake YAMATO } parserObject;
107e02be843SMasatake YAMATO 
10895512ba5SMasatake YAMATO /*
10903270f1eSMasatake YAMATO  * FUNCTION PROTOTYPES
11003270f1eSMasatake YAMATO  */
111ad1a3891SMasatake YAMATO 
112d0471042SMasatake YAMATO static void lazyInitialize (langType language);
113bc1a5e1bSMasatake YAMATO static void addParserPseudoTags (langType language);
114d453869fSMasatake YAMATO static void installKeywordTable (const langType language);
115d453869fSMasatake YAMATO static void installTagRegexTable (const langType language);
116d453869fSMasatake YAMATO static void installTagXpathTable (const langType language);
11797a77b13SMasatake YAMATO static void anonResetMaybe (parserObject *parser);
11887b7bfceSMasatake YAMATO static void setupAnon (void);
11987b7bfceSMasatake YAMATO static void teardownAnon (void);
120eb480042SMasatake YAMATO static void uninstallTagXpathTable (const langType language);
12103270f1eSMasatake YAMATO 
12203270f1eSMasatake YAMATO /*
123d4c6f1e6SMasatake YAMATO *   DATA DEFINITIONS
124d4c6f1e6SMasatake YAMATO */
12582791c20SMasatake YAMATO static parserDefinition *FallbackParser (void);
126b9636b4dSMasatake YAMATO static parserDefinition *CTagsParser (void);
1270435a2b5SMasatake YAMATO static parserDefinition *CTagsSelfTestParser (void);
1280435a2b5SMasatake YAMATO static parserDefinitionFunc* BuiltInParsers[] = {
12978d1a3f3SJiří Techet #ifdef EXTERNAL_PARSER_LIST
13078d1a3f3SJiří Techet 	EXTERNAL_PARSER_LIST
13178d1a3f3SJiří Techet #else  /* ! EXTERNAL_PARSER_LIST */
13221153b4dSJiří Techet 	CTagsParser,				/* This must be first entry. */
13321153b4dSJiří Techet 	FallbackParser,				/* LANG_FALLBACK */
13421153b4dSJiří Techet 	CTagsSelfTestParser,
13582791c20SMasatake YAMATO 
136a086aff1SMasatake YAMATO 	PARSER_LIST,
137a086aff1SMasatake YAMATO 	XML_PARSER_LIST
138288cd67dSMasatake YAMATO #ifdef HAVE_LIBXML
139288cd67dSMasatake YAMATO 	,
140288cd67dSMasatake YAMATO #endif
141288cd67dSMasatake YAMATO 	YAML_PARSER_LIST
142288cd67dSMasatake YAMATO #ifdef HAVE_LIBYAML
143288cd67dSMasatake YAMATO 	,
144288cd67dSMasatake YAMATO #endif
1450c014297SMasatake YAMATO        PEG_PARSER_LIST
1460c014297SMasatake YAMATO #ifdef HAVE_PACKCC
1470c014297SMasatake YAMATO        ,
1480c014297SMasatake YAMATO #endif
149*d876d176SMasatake YAMATO 	   OPTLIB2C_PCRE2_PARSER_LIST
150*d876d176SMasatake YAMATO #ifdef HAVE_PCRE2
151*d876d176SMasatake YAMATO       ,
152*d876d176SMasatake YAMATO #endif
15378d1a3f3SJiří Techet #endif	/* EXTERNAL_PARSER_LIST */
1540435a2b5SMasatake YAMATO };
155e02be843SMasatake YAMATO static parserObject* LanguageTable = NULL;
156d4c6f1e6SMasatake YAMATO static unsigned int LanguageCount = 0;
157f140c7c3SMasatake YAMATO static hashTable* LanguageHTable = NULL;
158e112e8abSMasatake YAMATO static kindDefinition defaultFileKind = {
159ce990805SThomas Braun 	.enabled     = false,
1607e1bd430SMasatake YAMATO 	.letter      = KIND_FILE_DEFAULT_LETTER,
1617e1bd430SMasatake YAMATO 	.name        = KIND_FILE_DEFAULT_NAME,
1627e1bd430SMasatake YAMATO 	.description = KIND_FILE_DEFAULT_NAME,
1636ed0ba68SMasatake YAMATO };
164d4c6f1e6SMasatake YAMATO 
165d4c6f1e6SMasatake YAMATO /*
166d4c6f1e6SMasatake YAMATO *   FUNCTION DEFINITIONS
167d4c6f1e6SMasatake YAMATO */
168d4c6f1e6SMasatake YAMATO 
isLanguageNameChar(int c)169da8c4965SMasatake YAMATO static bool isLanguageNameChar(int c)
170da8c4965SMasatake YAMATO {
171da8c4965SMasatake YAMATO 	if (isgraph(c))
172da8c4965SMasatake YAMATO 	{
173da8c4965SMasatake YAMATO 		if (c == '\'' || c == '"' || c == ';')
174da8c4965SMasatake YAMATO 			return false;
175da8c4965SMasatake YAMATO 		return true;
176da8c4965SMasatake YAMATO 	}
177da8c4965SMasatake YAMATO 	else
178da8c4965SMasatake YAMATO 		return false;
179da8c4965SMasatake YAMATO }
180da8c4965SMasatake YAMATO 
countParsers(void)181ad1a3891SMasatake YAMATO extern unsigned int countParsers (void)
182ad1a3891SMasatake YAMATO {
183ad1a3891SMasatake YAMATO 	return LanguageCount;
184ad1a3891SMasatake YAMATO }
185ad1a3891SMasatake YAMATO 
makeSimpleTag(const vString * const name,const int kindIndex)1867049fd45SMasatake YAMATO extern int makeSimpleTag (
18716a2541cSMasatake YAMATO 		const vString* const name, const int kindIndex)
188d4c6f1e6SMasatake YAMATO {
18924b256e3SMasatake YAMATO 	return makeSimpleRefTag (name, kindIndex, ROLE_DEFINITION_INDEX);
190d4c6f1e6SMasatake YAMATO }
191d4c6f1e6SMasatake YAMATO 
makeSimpleRefTag(const vString * const name,const int kindIndex,int roleIndex)19216a2541cSMasatake YAMATO extern int makeSimpleRefTag (const vString* const name, const int kindIndex,
1937868fb2eSMasatake YAMATO 			     int roleIndex)
1947868fb2eSMasatake YAMATO {
195f6027918SMasatake YAMATO 	int r = CORK_NIL;
1967868fb2eSMasatake YAMATO 
1974c64e833SMasatake YAMATO 	Assert (roleIndex < (int)countInputLanguageRoles(kindIndex));
1987868fb2eSMasatake YAMATO 
199250d94d4SMasatake YAMATO 	/* do not check for kind being disabled - that happens later in makeTagEntry() */
200250d94d4SMasatake YAMATO 	if (name != NULL  &&  vStringLength (name) > 0)
2017868fb2eSMasatake YAMATO 	{
2027868fb2eSMasatake YAMATO 	    tagEntryInfo e;
20316a2541cSMasatake YAMATO 	    initRefTagEntry (&e, vStringValue (name), kindIndex, roleIndex);
2047868fb2eSMasatake YAMATO 
2057868fb2eSMasatake YAMATO 	    r = makeTagEntry (&e);
2067868fb2eSMasatake YAMATO 	}
2077868fb2eSMasatake YAMATO 	return r;
2087868fb2eSMasatake YAMATO }
2097868fb2eSMasatake YAMATO 
makeSimplePlaceholder(const vString * const name)210a7c2b428SMasatake YAMATO extern int makeSimplePlaceholder(const vString* const name)
211a7c2b428SMasatake YAMATO {
212a7c2b428SMasatake YAMATO 	return makePlaceholder (vStringValue (name));
213a7c2b428SMasatake YAMATO }
214a7c2b428SMasatake YAMATO 
isLanguageEnabled(const langType language)215ce990805SThomas Braun extern bool isLanguageEnabled (const langType language)
216d4c6f1e6SMasatake YAMATO {
217d8a63e0bSMasatake YAMATO 	const parserDefinition* const def = LanguageTable [language].def;
218d8a63e0bSMasatake YAMATO 	return def->enabled;
219d4c6f1e6SMasatake YAMATO }
220d4c6f1e6SMasatake YAMATO 
isLanguageVisible(const langType language)22183f24c3bSMasatake YAMATO extern bool isLanguageVisible (const langType language)
22283f24c3bSMasatake YAMATO {
22383f24c3bSMasatake YAMATO 	const parserDefinition* const lang = LanguageTable [language].def;
22483f24c3bSMasatake YAMATO 
22583f24c3bSMasatake YAMATO 	return !lang->invisible;
22683f24c3bSMasatake YAMATO }
22783f24c3bSMasatake YAMATO 
228d4c6f1e6SMasatake YAMATO /*
229d4c6f1e6SMasatake YAMATO *   parserDescription mapping management
230d4c6f1e6SMasatake YAMATO */
231d4c6f1e6SMasatake YAMATO 
parserNew(const char * name)232b29ae60fSMasatake YAMATO extern parserDefinition* parserNew (const char* name)
2336ed0ba68SMasatake YAMATO {
234d4c6f1e6SMasatake YAMATO 	parserDefinition* result = xCalloc (1, parserDefinition);
235d4c6f1e6SMasatake YAMATO 	result->name = eStrdup (name);
2366ed0ba68SMasatake YAMATO 
237ce990805SThomas Braun 	result->enabled = true;
238d4c6f1e6SMasatake YAMATO 	return result;
239d4c6f1e6SMasatake YAMATO }
240d4c6f1e6SMasatake YAMATO 
doesLanguageAllowNullTag(const langType language)241ce990805SThomas Braun extern bool doesLanguageAllowNullTag (const langType language)
2427bd64c1dSMasatake YAMATO {
2437bd64c1dSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
244e02be843SMasatake YAMATO 	return LanguageTable [language].def->allowNullTag;
2457bd64c1dSMasatake YAMATO }
2467bd64c1dSMasatake YAMATO 
doesLanguageRequestAutomaticFQTag(const langType language)247ce990805SThomas Braun extern bool doesLanguageRequestAutomaticFQTag (const langType language)
248bd7610b4SMasatake YAMATO {
249bd7610b4SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
250e02be843SMasatake YAMATO 	return LanguageTable [language].def->requestAutomaticFQTag;
251bd7610b4SMasatake YAMATO }
252bd7610b4SMasatake YAMATO 
getLanguageNameFull(const langType language,bool noPretending)253f02166dcSMasatake YAMATO static const char *getLanguageNameFull (const langType language, bool noPretending)
254d4c6f1e6SMasatake YAMATO {
255d4c6f1e6SMasatake YAMATO 	const char* result;
256f02166dcSMasatake YAMATO 
257d4c6f1e6SMasatake YAMATO 	if (language == LANG_IGNORE)
258d4c6f1e6SMasatake YAMATO 		result = "unknown";
259d4c6f1e6SMasatake YAMATO 	else
260d4c6f1e6SMasatake YAMATO 	{
261d4c6f1e6SMasatake YAMATO 		Assert (0 <= language  &&  language < (int) LanguageCount);
262f02166dcSMasatake YAMATO 		if (noPretending)
263e02be843SMasatake YAMATO 			result = LanguageTable [language].def->name;
264f02166dcSMasatake YAMATO 		else
265f02166dcSMasatake YAMATO 		{
266f02166dcSMasatake YAMATO 			langType real_language = LanguageTable [language].pretendingAsLanguage;
267f02166dcSMasatake YAMATO 			if (real_language == LANG_IGNORE)
268f02166dcSMasatake YAMATO 				result = LanguageTable [language].def->name;
269f02166dcSMasatake YAMATO 			else
270f02166dcSMasatake YAMATO 			{
271f02166dcSMasatake YAMATO 				Assert (0 <= real_language  &&  real_language < (int) LanguageCount);
272f02166dcSMasatake YAMATO 				result = LanguageTable [real_language].def->name;
273f02166dcSMasatake YAMATO 			}
274f02166dcSMasatake YAMATO 		}
275d4c6f1e6SMasatake YAMATO 	}
276d4c6f1e6SMasatake YAMATO 	return result;
277d4c6f1e6SMasatake YAMATO }
278d4c6f1e6SMasatake YAMATO 
getLanguageName(const langType language)279f02166dcSMasatake YAMATO extern const char *getLanguageName (const langType language)
280f02166dcSMasatake YAMATO {
281f02166dcSMasatake YAMATO 	return getLanguageNameFull (language, false);
282f02166dcSMasatake YAMATO }
283f02166dcSMasatake YAMATO 
getLanguageKindName(const langType language,const int kindIndex)284bea76990SMasatake YAMATO extern const char *getLanguageKindName (const langType language, const int kindIndex)
285bea76990SMasatake YAMATO {
286bea76990SMasatake YAMATO 	kindDefinition* kdef = getLanguageKind (language, kindIndex);
287bea76990SMasatake YAMATO 	return kdef->name;
288bea76990SMasatake YAMATO }
28911cbaeceSMasatake YAMATO 
29011cbaeceSMasatake YAMATO static kindDefinition kindGhost = {
2917e1bd430SMasatake YAMATO 	.letter = KIND_GHOST_LETTER,
2927e1bd430SMasatake YAMATO 	.name = KIND_GHOST_NAME,
2937e1bd430SMasatake YAMATO 	.description = KIND_GHOST_NAME,
29411cbaeceSMasatake YAMATO };
29511cbaeceSMasatake YAMATO 
defineLanguageKind(const langType language,kindDefinition * def,freeKindDefFunc freeKindDef)296cd2c516cSMasatake YAMATO extern int defineLanguageKind (const langType language, kindDefinition *def,
297cd2c516cSMasatake YAMATO 							   freeKindDefFunc freeKindDef)
298cd2c516cSMasatake YAMATO {
299cd2c516cSMasatake YAMATO 	return defineKind (LanguageTable [language].kindControlBlock, def, freeKindDef);
300cd2c516cSMasatake YAMATO }
301cd2c516cSMasatake YAMATO 
countLanguageKinds(const langType language)3020f23950dSMasatake YAMATO extern unsigned int countLanguageKinds (const langType language)
3030f23950dSMasatake YAMATO {
3040f23950dSMasatake YAMATO 	return countKinds (LanguageTable [language].kindControlBlock);
3050f23950dSMasatake YAMATO }
3060f23950dSMasatake YAMATO 
countLanguageRoles(const langType language,int kindIndex)3070f23950dSMasatake YAMATO extern unsigned int countLanguageRoles (const langType language, int kindIndex)
3080f23950dSMasatake YAMATO {
3090f23950dSMasatake YAMATO 	return countRoles (LanguageTable [language].kindControlBlock, kindIndex);
3100f23950dSMasatake YAMATO }
3110f23950dSMasatake YAMATO 
getLanguageKind(const langType language,int kindIndex)312f92e6bf2SMasatake YAMATO extern kindDefinition* getLanguageKind (const langType language, int kindIndex)
313e6c10a73SMasatake YAMATO {
3147e1b89c3SMasatake YAMATO 	kindDefinition* kdef;
3158dc26879SMasatake YAMATO 
3168dc26879SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3178dc26879SMasatake YAMATO 
3187e1b89c3SMasatake YAMATO 	switch (kindIndex)
3197e1b89c3SMasatake YAMATO 	{
3207e1b89c3SMasatake YAMATO 	case KIND_FILE_INDEX:
3217e1b89c3SMasatake YAMATO 		kdef = LanguageTable [language].fileKind;
3227e1b89c3SMasatake YAMATO 		break;
32311cbaeceSMasatake YAMATO 	case KIND_GHOST_INDEX:
32411cbaeceSMasatake YAMATO 		kdef = &kindGhost;
32511cbaeceSMasatake YAMATO 		break;
3267e1b89c3SMasatake YAMATO 	default:
327037a0e99SMasatake YAMATO 		Assert (kindIndex >= 0);
3287e1b89c3SMasatake YAMATO 		kdef = getKind (LanguageTable [language].kindControlBlock, kindIndex);
3297e1b89c3SMasatake YAMATO 	}
3307e1b89c3SMasatake YAMATO 	return kdef;
3317e1b89c3SMasatake YAMATO }
3328dc26879SMasatake YAMATO 
getLanguageKindForLetter(const langType language,char kindLetter)3337e1b89c3SMasatake YAMATO extern kindDefinition* getLanguageKindForLetter (const langType language, char kindLetter)
3347e1b89c3SMasatake YAMATO {
3357e1b89c3SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3367e1b89c3SMasatake YAMATO 	if (kindLetter == LanguageTable [language].fileKind->letter)
3377e1b89c3SMasatake YAMATO 		return LanguageTable [language].fileKind;
3387e1bd430SMasatake YAMATO 	else if (kindLetter == KIND_GHOST_LETTER)
33911cbaeceSMasatake YAMATO 		return &kindGhost;
3407e1b89c3SMasatake YAMATO 	else
3417e1b89c3SMasatake YAMATO 		return getKindForLetter (LanguageTable [language].kindControlBlock, kindLetter);
3428dc26879SMasatake YAMATO }
3438dc26879SMasatake YAMATO 
getLanguageKindForName(const langType language,const char * kindName)344c9dd5111SMasatake YAMATO extern kindDefinition* getLanguageKindForName (const langType language, const char *kindName)
345c9dd5111SMasatake YAMATO {
346c9dd5111SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
347c9dd5111SMasatake YAMATO 	Assert (kindName);
348c9dd5111SMasatake YAMATO 
349c9dd5111SMasatake YAMATO 	if (strcmp(kindName, LanguageTable [language].fileKind->name) == 0)
350c9dd5111SMasatake YAMATO 		return LanguageTable [language].fileKind;
3517e1bd430SMasatake YAMATO 	else if (strcmp(kindName, KIND_GHOST_NAME) == 0)
352c9dd5111SMasatake YAMATO 		return &kindGhost;
353c9dd5111SMasatake YAMATO 	else
354c9dd5111SMasatake YAMATO 		return getKindForName (LanguageTable [language].kindControlBlock, kindName);
355c9dd5111SMasatake YAMATO }
356c9dd5111SMasatake YAMATO 
getLanguageRole(const langType language,int kindIndex,int roleIndex)35713457258SMasatake YAMATO extern roleDefinition* getLanguageRole(const langType language, int kindIndex, int roleIndex)
35813457258SMasatake YAMATO {
35913457258SMasatake YAMATO 	return getRole (LanguageTable [language].kindControlBlock, kindIndex, roleIndex);
36013457258SMasatake YAMATO }
36113457258SMasatake YAMATO 
getLanguageRoleForName(const langType language,int kindIndex,const char * roleName)36284f3a057SMasatake YAMATO extern roleDefinition* getLanguageRoleForName (const langType language, int kindIndex,
36384f3a057SMasatake YAMATO 											   const char *roleName)
36484f3a057SMasatake YAMATO {
36584f3a057SMasatake YAMATO 	return getRoleForName (LanguageTable [language].kindControlBlock, kindIndex, roleName);
36684f3a057SMasatake YAMATO }
36784f3a057SMasatake YAMATO 
getNamedLanguageFull(const char * const name,size_t len,bool noPretending,bool include_aliases)3689a391711SMasatake YAMATO extern langType getNamedLanguageFull (const char *const name, size_t len, bool noPretending,
3699a391711SMasatake YAMATO 									  bool include_aliases)
370d4c6f1e6SMasatake YAMATO {
371d4c6f1e6SMasatake YAMATO 	langType result = LANG_IGNORE;
372d4c6f1e6SMasatake YAMATO 	unsigned int i;
373d4c6f1e6SMasatake YAMATO 	Assert (name != NULL);
3745a55f03bSMasatake YAMATO 
375f140c7c3SMasatake YAMATO 	if (len == 0)
376f140c7c3SMasatake YAMATO 	{
377f140c7c3SMasatake YAMATO 		parserDefinition *def = (parserDefinition *)hashTableGetItem (LanguageHTable, name);
378f140c7c3SMasatake YAMATO 		if (def)
379f140c7c3SMasatake YAMATO 			result = def->id;
380f140c7c3SMasatake YAMATO 	}
381f140c7c3SMasatake YAMATO 	else
382d4c6f1e6SMasatake YAMATO 		for (i = 0  ;  i < LanguageCount  &&  result == LANG_IGNORE  ;  ++i)
383d4c6f1e6SMasatake YAMATO 		{
384e02be843SMasatake YAMATO 			const parserDefinition* const lang = LanguageTable [i].def;
385f140c7c3SMasatake YAMATO 			Assert (lang->name);
3865a55f03bSMasatake YAMATO 			vString* vstr = vStringNewInit (name);
3875a55f03bSMasatake YAMATO 			vStringTruncate (vstr, len);
3885a55f03bSMasatake YAMATO 
3895a55f03bSMasatake YAMATO 			if (strcasecmp (vStringValue (vstr), lang->name) == 0)
3905a55f03bSMasatake YAMATO 				result = i;
3919a391711SMasatake YAMATO 			else if (include_aliases)
3929a391711SMasatake YAMATO 			{
3939a391711SMasatake YAMATO 				stringList* const aliases = LanguageTable [i].currentAliases;
3949a391711SMasatake YAMATO 				if (aliases && stringListCaseMatched (aliases, vStringValue (vstr)))
3959a391711SMasatake YAMATO 					result = i;
3969a391711SMasatake YAMATO 			}
3975a55f03bSMasatake YAMATO 			vStringDelete (vstr);
3985a55f03bSMasatake YAMATO 		}
399f02166dcSMasatake YAMATO 
400f02166dcSMasatake YAMATO 	if (result != LANG_IGNORE
401f02166dcSMasatake YAMATO 		&& (!noPretending)
402f02166dcSMasatake YAMATO 		&& LanguageTable [result].pretendedAsLanguage != LANG_IGNORE)
403f02166dcSMasatake YAMATO 		result = LanguageTable [result].pretendedAsLanguage;
404f02166dcSMasatake YAMATO 
405d4c6f1e6SMasatake YAMATO 	return result;
406d4c6f1e6SMasatake YAMATO }
407d4c6f1e6SMasatake YAMATO 
getNamedLanguage(const char * const name,size_t len)408f02166dcSMasatake YAMATO extern langType getNamedLanguage (const char *const name, size_t len)
409f02166dcSMasatake YAMATO {
4109a391711SMasatake YAMATO 	return getNamedLanguageFull (name, len, false, false);
4119a391711SMasatake YAMATO }
4129a391711SMasatake YAMATO 
getNamedLanguageOrAlias(const char * const name,size_t len)4139a391711SMasatake YAMATO extern langType getNamedLanguageOrAlias (const char *const name, size_t len)
4149a391711SMasatake YAMATO {
4159a391711SMasatake YAMATO 	return getNamedLanguageFull (name, len, false, true);
416f02166dcSMasatake YAMATO }
417f02166dcSMasatake YAMATO 
getNameOrAliasesLanguageAndSpec(const char * const key,langType start_index,const char ** const spec,enum specType * specType)41895512ba5SMasatake YAMATO static langType getNameOrAliasesLanguageAndSpec (const char *const key, langType start_index,
41995512ba5SMasatake YAMATO 						 const char **const spec, enum specType *specType)
420d4c6f1e6SMasatake YAMATO {
421d4c6f1e6SMasatake YAMATO 	langType result = LANG_IGNORE;
422d4c6f1e6SMasatake YAMATO 	unsigned int i;
423d4c6f1e6SMasatake YAMATO 
424d4c6f1e6SMasatake YAMATO 
425d4c6f1e6SMasatake YAMATO 	if (start_index == LANG_AUTO)
426d4c6f1e6SMasatake YAMATO 	        start_index = 0;
427d4c6f1e6SMasatake YAMATO 	else if (start_index == LANG_IGNORE || start_index >= (int) LanguageCount)
428d4c6f1e6SMasatake YAMATO 		return result;
429d4c6f1e6SMasatake YAMATO 
430d4c6f1e6SMasatake YAMATO 	for (i = start_index  ;  i < LanguageCount  &&  result == LANG_IGNORE  ;  ++i)
431d4c6f1e6SMasatake YAMATO 	{
432d8a63e0bSMasatake YAMATO 		if (! isLanguageEnabled (i))
433d8a63e0bSMasatake YAMATO 			continue;
434d8a63e0bSMasatake YAMATO 
435efe089d4SMasatake YAMATO 		const parserObject* const parser = LanguageTable + i;
436efe089d4SMasatake YAMATO 		stringList* const aliases = parser->currentAliases;
437d4c6f1e6SMasatake YAMATO 		vString* tmp;
438d4c6f1e6SMasatake YAMATO 
439efe089d4SMasatake YAMATO 		if (parser->def->name != NULL && strcasecmp (key, parser->def->name) == 0)
440d4c6f1e6SMasatake YAMATO 		{
441d4c6f1e6SMasatake YAMATO 			result = i;
442efe089d4SMasatake YAMATO 			*spec = parser->def->name;
44395512ba5SMasatake YAMATO 			*specType = SPEC_NAME;
444d4c6f1e6SMasatake YAMATO 		}
445d4c6f1e6SMasatake YAMATO 		else if (aliases != NULL  &&  (tmp = stringListFileFinds (aliases, key)))
446d4c6f1e6SMasatake YAMATO 		{
447d4c6f1e6SMasatake YAMATO 			result = i;
448d4c6f1e6SMasatake YAMATO 			*spec = vStringValue(tmp);
44995512ba5SMasatake YAMATO 			*specType = SPEC_ALIAS;
450d4c6f1e6SMasatake YAMATO 		}
451d4c6f1e6SMasatake YAMATO 	}
452d4c6f1e6SMasatake YAMATO 	return result;
453d4c6f1e6SMasatake YAMATO }
454d4c6f1e6SMasatake YAMATO 
getLanguageForCommand(const char * const command,langType startFrom)455334e072fSMasatake YAMATO extern langType getLanguageForCommand (const char *const command, langType startFrom)
456334e072fSMasatake YAMATO {
457334e072fSMasatake YAMATO 	const char *const tmp_command = baseFilename (command);
458334e072fSMasatake YAMATO 	char *tmp_spec;
459334e072fSMasatake YAMATO 	enum specType tmp_specType;
460334e072fSMasatake YAMATO 
461334e072fSMasatake YAMATO 	return getNameOrAliasesLanguageAndSpec (tmp_command, startFrom,
462334e072fSMasatake YAMATO 											(const char **const)&tmp_spec,
463334e072fSMasatake YAMATO 											&tmp_specType);
464334e072fSMasatake YAMATO }
465334e072fSMasatake YAMATO 
getPatternLanguageAndSpec(const char * const baseName,langType start_index,const char ** const spec,enum specType * specType)46695512ba5SMasatake YAMATO static langType getPatternLanguageAndSpec (const char *const baseName, langType start_index,
46795512ba5SMasatake YAMATO 					   const char **const spec, enum specType *specType)
468d4c6f1e6SMasatake YAMATO {
469d4c6f1e6SMasatake YAMATO 	langType result = LANG_IGNORE;
470d4c6f1e6SMasatake YAMATO 	unsigned int i;
471d4c6f1e6SMasatake YAMATO 
472d4c6f1e6SMasatake YAMATO 	if (start_index == LANG_AUTO)
473d4c6f1e6SMasatake YAMATO 	        start_index = 0;
474d4c6f1e6SMasatake YAMATO 	else if (start_index == LANG_IGNORE || start_index >= (int) LanguageCount)
475d4c6f1e6SMasatake YAMATO 		return result;
476d4c6f1e6SMasatake YAMATO 
477d4c6f1e6SMasatake YAMATO 	*spec = NULL;
478d4c6f1e6SMasatake YAMATO 	for (i = start_index  ;  i < LanguageCount  &&  result == LANG_IGNORE  ;  ++i)
479d4c6f1e6SMasatake YAMATO 	{
480d8a63e0bSMasatake YAMATO 		if (! isLanguageEnabled (i))
481d8a63e0bSMasatake YAMATO 			continue;
482d8a63e0bSMasatake YAMATO 
483efe089d4SMasatake YAMATO 		parserObject *parser = LanguageTable + i;
484efe089d4SMasatake YAMATO 		stringList* const ptrns = parser->currentPatterns;
485d4c6f1e6SMasatake YAMATO 		vString* tmp;
486d4c6f1e6SMasatake YAMATO 
487d4c6f1e6SMasatake YAMATO 		if (ptrns != NULL && (tmp = stringListFileFinds (ptrns, baseName)))
488d4c6f1e6SMasatake YAMATO 		{
489d4c6f1e6SMasatake YAMATO 			result = i;
490d4c6f1e6SMasatake YAMATO 			*spec = vStringValue(tmp);
49195512ba5SMasatake YAMATO 			*specType = SPEC_PATTERN;
49295512ba5SMasatake YAMATO 			goto found;
493d4c6f1e6SMasatake YAMATO 		}
494d4c6f1e6SMasatake YAMATO 	}
49595512ba5SMasatake YAMATO 
49695512ba5SMasatake YAMATO 	for (i = start_index  ;  i < LanguageCount  &&  result == LANG_IGNORE  ;  ++i)
49795512ba5SMasatake YAMATO 	{
498d8a63e0bSMasatake YAMATO 		if (! isLanguageEnabled (i))
499d8a63e0bSMasatake YAMATO 			continue;
500d8a63e0bSMasatake YAMATO 
501efe089d4SMasatake YAMATO 		parserObject *parser = LanguageTable + i;
502efe089d4SMasatake YAMATO 		stringList* const exts = parser->currentExtensions;
50395512ba5SMasatake YAMATO 		vString* tmp;
50495512ba5SMasatake YAMATO 
50595512ba5SMasatake YAMATO 		if (exts != NULL && (tmp = stringListExtensionFinds (exts,
50695512ba5SMasatake YAMATO 								     fileExtension (baseName))))
50795512ba5SMasatake YAMATO 		{
50895512ba5SMasatake YAMATO 			result = i;
50995512ba5SMasatake YAMATO 			*spec = vStringValue(tmp);
51095512ba5SMasatake YAMATO 			*specType = SPEC_EXTENSION;
51195512ba5SMasatake YAMATO 			goto found;
51295512ba5SMasatake YAMATO 		}
51395512ba5SMasatake YAMATO 	}
51495512ba5SMasatake YAMATO found:
515d4c6f1e6SMasatake YAMATO 	return result;
516d4c6f1e6SMasatake YAMATO }
517d4c6f1e6SMasatake YAMATO 
getLanguageForFilename(const char * const filename,langType startFrom)518416c5e6bSMasatake YAMATO extern langType getLanguageForFilename (const char *const filename, langType startFrom)
519416c5e6bSMasatake YAMATO {
520416c5e6bSMasatake YAMATO 	const char *const tmp_filename = baseFilename (filename);
521416c5e6bSMasatake YAMATO 	char *tmp_spec;
522416c5e6bSMasatake YAMATO 	enum specType tmp_specType;
523416c5e6bSMasatake YAMATO 
524416c5e6bSMasatake YAMATO 	return getPatternLanguageAndSpec (tmp_filename, startFrom,
525416c5e6bSMasatake YAMATO 									  (const char **const)&tmp_spec,
526416c5e6bSMasatake YAMATO 									  &tmp_specType);
527416c5e6bSMasatake YAMATO }
528416c5e6bSMasatake YAMATO 
scopeSeparatorFor(langType language,int kindIndex,int parentKindIndex)529314c9d31SMasatake YAMATO const char *scopeSeparatorFor (langType language, int kindIndex, int parentKindIndex)
530314c9d31SMasatake YAMATO {
531314c9d31SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
532314c9d31SMasatake YAMATO 
533314c9d31SMasatake YAMATO 	parserObject *parser = LanguageTable + language;
534314c9d31SMasatake YAMATO 	struct kindControlBlock *kcb = parser->kindControlBlock;
535314c9d31SMasatake YAMATO 
536314c9d31SMasatake YAMATO 	const scopeSeparator *sep = getScopeSeparator (kcb, kindIndex, parentKindIndex);
537314c9d31SMasatake YAMATO 	return sep? sep->separator: NULL;
538314c9d31SMasatake YAMATO }
539314c9d31SMasatake YAMATO 
processLangDefineScopesep(const langType language,const char * const option,const char * const parameter)540acf93fd6SMasatake YAMATO static bool processLangDefineScopesep(const langType language,
541acf93fd6SMasatake YAMATO 								  const char *const option,
542acf93fd6SMasatake YAMATO 								  const char *const parameter)
543acf93fd6SMasatake YAMATO {
544acf93fd6SMasatake YAMATO 	parserObject *parser;
545acf93fd6SMasatake YAMATO 	const char * p = parameter;
546acf93fd6SMasatake YAMATO 
547acf93fd6SMasatake YAMATO 
548acf93fd6SMasatake YAMATO 	char parentKletter;
549acf93fd6SMasatake YAMATO 	int parentKindex = KIND_FILE_INDEX;
550acf93fd6SMasatake YAMATO 	char kletter;
551acf93fd6SMasatake YAMATO 	int kindex = KIND_FILE_INDEX;
552acf93fd6SMasatake YAMATO 	const char *separator;
553acf93fd6SMasatake YAMATO 
554acf93fd6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
555acf93fd6SMasatake YAMATO 	parser = LanguageTable + language;
556acf93fd6SMasatake YAMATO 
557acf93fd6SMasatake YAMATO 
558acf93fd6SMasatake YAMATO 	/*
559acf93fd6SMasatake YAMATO 	 * Parent
560acf93fd6SMasatake YAMATO 	 */
561acf93fd6SMasatake YAMATO 	parentKletter = p[0];
562acf93fd6SMasatake YAMATO 
563acf93fd6SMasatake YAMATO 	if (parentKletter == '\0')
564acf93fd6SMasatake YAMATO 		error (FATAL, "no scope separator specified in \"--%s\" option", option);
565acf93fd6SMasatake YAMATO 	else if (parentKletter == '/')
566acf93fd6SMasatake YAMATO 		parentKindex = KIND_GHOST_INDEX;
5677e1bd430SMasatake YAMATO 	else if (parentKletter == KIND_WILDCARD_LETTER)
568acf93fd6SMasatake YAMATO 		parentKindex = KIND_WILDCARD_INDEX;
5697e1bd430SMasatake YAMATO 	else if (parentKletter == KIND_FILE_DEFAULT_LETTER)
570acf93fd6SMasatake YAMATO 		error (FATAL,
57147df83bdSMasatake YAMATO 			   "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind and no separator can be assigned to",
57247df83bdSMasatake YAMATO 			   KIND_FILE_DEFAULT_LETTER, option, KIND_FILE_DEFAULT_NAME);
573acf93fd6SMasatake YAMATO 	else if (isalpha (parentKletter))
574acf93fd6SMasatake YAMATO 	{
575acf93fd6SMasatake YAMATO 		kindDefinition *kdef = getKindForLetter (parser->kindControlBlock, parentKletter);
576acf93fd6SMasatake YAMATO 		if (kdef == NULL)
577acf93fd6SMasatake YAMATO 			error (FATAL,
578acf93fd6SMasatake YAMATO 				   "the kind for letter `%c' specified in \"--%s\" option is not defined.",
579acf93fd6SMasatake YAMATO 				   parentKletter, option);
580acf93fd6SMasatake YAMATO 		parentKindex = kdef->id;
581acf93fd6SMasatake YAMATO 	}
582acf93fd6SMasatake YAMATO 	else
583acf93fd6SMasatake YAMATO 		error (FATAL,
584acf93fd6SMasatake YAMATO 			   "the kind letter `%c` given in \"--%s\" option is not an alphabet",
585acf93fd6SMasatake YAMATO 			   parentKletter, option);
586acf93fd6SMasatake YAMATO 
587acf93fd6SMasatake YAMATO 
588acf93fd6SMasatake YAMATO 	/*
589acf93fd6SMasatake YAMATO 	 * Child
590acf93fd6SMasatake YAMATO 	 */
591acf93fd6SMasatake YAMATO 	if (parentKindex == KIND_GHOST_INDEX)
592acf93fd6SMasatake YAMATO 		kletter = p[1];
593acf93fd6SMasatake YAMATO 	else
594acf93fd6SMasatake YAMATO 	{
595acf93fd6SMasatake YAMATO 		if (p[1] != '/')
596acf93fd6SMasatake YAMATO 			error (FATAL,
597acf93fd6SMasatake YAMATO 				   "wrong separator specification in \"--%s\" option: no slash after parent kind letter `%c'",
598acf93fd6SMasatake YAMATO 				   option, parentKletter);
599acf93fd6SMasatake YAMATO 		kletter = p[2];
600acf93fd6SMasatake YAMATO 	}
601acf93fd6SMasatake YAMATO 
602acf93fd6SMasatake YAMATO 	if (kletter == '\0')
603acf93fd6SMasatake YAMATO 		error (FATAL, "no child kind letter in \"--%s\" option", option);
604acf93fd6SMasatake YAMATO 	else if (kletter == '/')
605acf93fd6SMasatake YAMATO 		error (FATAL,
606acf93fd6SMasatake YAMATO 			   "wrong separator specification in \"--%s\" option: don't specify slash char twice: %s",
607acf93fd6SMasatake YAMATO 			   option, parameter);
608acf93fd6SMasatake YAMATO 	else if (kletter == ':')
609acf93fd6SMasatake YAMATO 		error (FATAL,
610acf93fd6SMasatake YAMATO 			   "no child kind letter in \"--%s\" option", option);
6117e1bd430SMasatake YAMATO 	else if (kletter == KIND_WILDCARD_LETTER)
612acf93fd6SMasatake YAMATO 	{
613acf93fd6SMasatake YAMATO 		if (parentKindex != KIND_WILDCARD_INDEX
614acf93fd6SMasatake YAMATO 			&& parentKindex != KIND_GHOST_INDEX)
615acf93fd6SMasatake YAMATO 			error (FATAL,
616acf93fd6SMasatake YAMATO 				   "cannot use wild card for child kind unless parent kind is also wild card or empty");
617acf93fd6SMasatake YAMATO 		kindex = KIND_WILDCARD_INDEX;
618acf93fd6SMasatake YAMATO 	}
6197e1bd430SMasatake YAMATO 	else if (kletter == KIND_FILE_DEFAULT_LETTER)
620acf93fd6SMasatake YAMATO 		error (FATAL,
62147df83bdSMasatake YAMATO 			   "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind and no separator can be assigned to",
62247df83bdSMasatake YAMATO 			   KIND_FILE_DEFAULT_LETTER, option, KIND_FILE_DEFAULT_NAME);
623acf93fd6SMasatake YAMATO 	else if (isalpha (kletter))
624acf93fd6SMasatake YAMATO 	{
625acf93fd6SMasatake YAMATO 		kindDefinition *kdef = getKindForLetter (parser->kindControlBlock, kletter);
626acf93fd6SMasatake YAMATO 		if (kdef == NULL)
627acf93fd6SMasatake YAMATO 			error (FATAL,
628acf93fd6SMasatake YAMATO 				   "the kind for letter `%c' specified in \"--%s\" option is not defined.",
629acf93fd6SMasatake YAMATO 				   kletter, option);
630acf93fd6SMasatake YAMATO 		kindex = kdef->id;
631acf93fd6SMasatake YAMATO 	}
632acf93fd6SMasatake YAMATO 	else
633acf93fd6SMasatake YAMATO 		error (FATAL,
634acf93fd6SMasatake YAMATO 			   "the kind letter `%c` given in \"--%s\" option is not an alphabet",
635acf93fd6SMasatake YAMATO 			   kletter, option);
636acf93fd6SMasatake YAMATO 
637acf93fd6SMasatake YAMATO 	/*
638acf93fd6SMasatake YAMATO 	 * Separator
639acf93fd6SMasatake YAMATO 	 */
640acf93fd6SMasatake YAMATO 	if (parentKindex == KIND_GHOST_INDEX)
641acf93fd6SMasatake YAMATO 	{
642acf93fd6SMasatake YAMATO 		if (p[2] != ':')
643acf93fd6SMasatake YAMATO 			error (FATAL,
644acf93fd6SMasatake YAMATO 				   "wrong separator specification in \"--%s\" option: cannot find a colon after child kind: %s",
645acf93fd6SMasatake YAMATO 				   option, parameter);
646acf93fd6SMasatake YAMATO 		separator = p + 3;
647acf93fd6SMasatake YAMATO 	}
648acf93fd6SMasatake YAMATO 	else
649acf93fd6SMasatake YAMATO 	{
650acf93fd6SMasatake YAMATO 		if (p[3] != ':')
651acf93fd6SMasatake YAMATO 			error (FATAL,
652acf93fd6SMasatake YAMATO 				   "wrong separator specification in \"--%s\" option: cannot find a colon after child kind: %s",
653acf93fd6SMasatake YAMATO 				   option, parameter);
654acf93fd6SMasatake YAMATO 		separator = p + 4;
655acf93fd6SMasatake YAMATO 	}
656acf93fd6SMasatake YAMATO 
657acf93fd6SMasatake YAMATO 	Assert (parentKindex != KIND_FILE_INDEX);
658acf93fd6SMasatake YAMATO 	Assert (kindex != KIND_FILE_INDEX);
659acf93fd6SMasatake YAMATO 	defineScopeSeparator (parser->kindControlBlock, kindex, parentKindex, separator);
660acf93fd6SMasatake YAMATO 	return true;
661acf93fd6SMasatake YAMATO }
662acf93fd6SMasatake YAMATO 
processScopesepOption(const char * const option,const char * const parameter)663acf93fd6SMasatake YAMATO extern bool processScopesepOption (const char *const option, const char * const parameter)
664acf93fd6SMasatake YAMATO {
665acf93fd6SMasatake YAMATO 	langType language;
666acf93fd6SMasatake YAMATO 
667acf93fd6SMasatake YAMATO 	language = getLanguageComponentInOption (option, "_scopesep-");
668acf93fd6SMasatake YAMATO 	if (language == LANG_IGNORE)
669acf93fd6SMasatake YAMATO 		return false;
670acf93fd6SMasatake YAMATO 
671acf93fd6SMasatake YAMATO 	return processLangDefineScopesep (language, option, parameter);
672acf93fd6SMasatake YAMATO }
673acf93fd6SMasatake YAMATO 
parserCandidateNew(unsigned int count CTAGS_ATTR_UNUSED)6748ccb7ee9SJiří Techet static parserCandidate* parserCandidateNew(unsigned int count CTAGS_ATTR_UNUSED)
675d4c6f1e6SMasatake YAMATO {
676d4c6f1e6SMasatake YAMATO 	parserCandidate* candidates;
677d4c6f1e6SMasatake YAMATO 	unsigned int i;
678d4c6f1e6SMasatake YAMATO 
679d4c6f1e6SMasatake YAMATO 	candidates= xMalloc(LanguageCount, parserCandidate);
680d4c6f1e6SMasatake YAMATO 	for (i = 0; i < LanguageCount; i++)
681d4c6f1e6SMasatake YAMATO 	{
682d4c6f1e6SMasatake YAMATO 		candidates[i].lang = LANG_IGNORE;
683d4c6f1e6SMasatake YAMATO 		candidates[i].spec = NULL;
68495512ba5SMasatake YAMATO 		candidates[i].specType = SPEC_NONE;
685d4c6f1e6SMasatake YAMATO 	}
686d4c6f1e6SMasatake YAMATO 	return candidates;
687d4c6f1e6SMasatake YAMATO }
688d4c6f1e6SMasatake YAMATO 
689d4c6f1e6SMasatake YAMATO /* If multiple parsers are found, return LANG_AUTO */
nominateLanguageCandidates(const char * const key,parserCandidate ** candidates)690d4c6f1e6SMasatake YAMATO static unsigned int nominateLanguageCandidates (const char *const key, parserCandidate** candidates)
691d4c6f1e6SMasatake YAMATO {
692d4c6f1e6SMasatake YAMATO 	unsigned int count;
693d4c6f1e6SMasatake YAMATO 	langType i;
6944e174950SVitor Antunes 	const char* spec = NULL;
69595512ba5SMasatake YAMATO 	enum specType specType = SPEC_NONE;
696d4c6f1e6SMasatake YAMATO 
697d4c6f1e6SMasatake YAMATO 	*candidates = parserCandidateNew(LanguageCount);
698d4c6f1e6SMasatake YAMATO 
699d4c6f1e6SMasatake YAMATO 	for (count = 0, i = LANG_AUTO; i != LANG_IGNORE; )
700d4c6f1e6SMasatake YAMATO 	{
70195512ba5SMasatake YAMATO 		i = getNameOrAliasesLanguageAndSpec (key, i, &spec, &specType);
702d4c6f1e6SMasatake YAMATO 		if (i != LANG_IGNORE)
703d4c6f1e6SMasatake YAMATO 		{
704d4c6f1e6SMasatake YAMATO 			(*candidates)[count].lang = i++;
70595512ba5SMasatake YAMATO 			(*candidates)[count].spec = spec;
70695512ba5SMasatake YAMATO 			(*candidates)[count++].specType = specType;
707d4c6f1e6SMasatake YAMATO 		}
708d4c6f1e6SMasatake YAMATO 	}
709d4c6f1e6SMasatake YAMATO 
710d4c6f1e6SMasatake YAMATO 	return count;
711d4c6f1e6SMasatake YAMATO }
712d4c6f1e6SMasatake YAMATO 
713d4c6f1e6SMasatake YAMATO static unsigned int
nominateLanguageCandidatesForPattern(const char * const baseName,parserCandidate ** candidates)714d4c6f1e6SMasatake YAMATO nominateLanguageCandidatesForPattern(const char *const baseName, parserCandidate** candidates)
715d4c6f1e6SMasatake YAMATO {
716d4c6f1e6SMasatake YAMATO 	unsigned int count;
717d4c6f1e6SMasatake YAMATO 	langType i;
718d4c6f1e6SMasatake YAMATO 	const char* spec;
71995512ba5SMasatake YAMATO 	enum specType specType = SPEC_NONE;
720d4c6f1e6SMasatake YAMATO 
721d4c6f1e6SMasatake YAMATO 	*candidates = parserCandidateNew(LanguageCount);
722d4c6f1e6SMasatake YAMATO 
723d4c6f1e6SMasatake YAMATO 	for (count = 0, i = LANG_AUTO; i != LANG_IGNORE; )
724d4c6f1e6SMasatake YAMATO 	{
72595512ba5SMasatake YAMATO 		i = getPatternLanguageAndSpec (baseName, i, &spec, &specType);
726d4c6f1e6SMasatake YAMATO 		if (i != LANG_IGNORE)
727d4c6f1e6SMasatake YAMATO 		{
728d4c6f1e6SMasatake YAMATO 			(*candidates)[count].lang = i++;
72995512ba5SMasatake YAMATO 			(*candidates)[count].spec = spec;
73095512ba5SMasatake YAMATO 			(*candidates)[count++].specType = specType;
731d4c6f1e6SMasatake YAMATO 		}
732d4c6f1e6SMasatake YAMATO 	}
733d4c6f1e6SMasatake YAMATO 	return count;
734d4c6f1e6SMasatake YAMATO }
735d4c6f1e6SMasatake YAMATO 
736509a47dbSJiří Techet static vString* extractEmacsModeAtFirstLine(MIO* input);
737d4c6f1e6SMasatake YAMATO 
738d4c6f1e6SMasatake YAMATO /*  The name of the language interpreter, either directly or as the argument
739d4c6f1e6SMasatake YAMATO  *  to "env".
740d4c6f1e6SMasatake YAMATO  */
determineInterpreter(const char * const cmd)741d4c6f1e6SMasatake YAMATO static vString* determineInterpreter (const char* const cmd)
742d4c6f1e6SMasatake YAMATO {
743d4c6f1e6SMasatake YAMATO 	vString* const interpreter = vStringNew ();
744d4c6f1e6SMasatake YAMATO 	const char* p = cmd;
745d4c6f1e6SMasatake YAMATO 	do
746d4c6f1e6SMasatake YAMATO 	{
747d4c6f1e6SMasatake YAMATO 		vStringClear (interpreter);
748d4c6f1e6SMasatake YAMATO 		for ( ;  isspace ((int) *p)  ;  ++p)
749d4c6f1e6SMasatake YAMATO 			;  /* no-op */
750d4c6f1e6SMasatake YAMATO 		for ( ;  *p != '\0'  &&  ! isspace ((int) *p)  ;  ++p)
751d4c6f1e6SMasatake YAMATO 			vStringPut (interpreter, (int) *p);
752d4c6f1e6SMasatake YAMATO 	} while (strcmp (vStringValue (interpreter), "env") == 0);
753d4c6f1e6SMasatake YAMATO 	return interpreter;
754d4c6f1e6SMasatake YAMATO }
755d4c6f1e6SMasatake YAMATO 
extractInterpreter(MIO * input)756509a47dbSJiří Techet static vString* extractInterpreter (MIO* input)
757d4c6f1e6SMasatake YAMATO {
758d4c6f1e6SMasatake YAMATO 	vString* const vLine = vStringNew ();
75978e93ff0SMasatake YAMATO 	const char* const line = readLineRaw (vLine, input);
760d4c6f1e6SMasatake YAMATO 	vString* interpreter = NULL;
761d4c6f1e6SMasatake YAMATO 
762d4c6f1e6SMasatake YAMATO 	if (line != NULL  &&  line [0] == '#'  &&  line [1] == '!')
763d4c6f1e6SMasatake YAMATO 	{
764d4c6f1e6SMasatake YAMATO 		/* "48.2.4.1 Specifying File Variables" of Emacs info:
765d4c6f1e6SMasatake YAMATO 		   ---------------------------------------------------
766d4c6f1e6SMasatake YAMATO 		   In shell scripts, the first line is used to
767d4c6f1e6SMasatake YAMATO 		   identify the script interpreter, so you
768d4c6f1e6SMasatake YAMATO 		   cannot put any local variables there.  To
769d4c6f1e6SMasatake YAMATO 		   accommodate this, Emacs looks for local
770d4c6f1e6SMasatake YAMATO 		   variable specifications in the _second_
771d4c6f1e6SMasatake YAMATO 		   line if the first line specifies an
772d4c6f1e6SMasatake YAMATO 		   interpreter.  */
773d4c6f1e6SMasatake YAMATO 
774100a966cSMasatake YAMATO 		interpreter = extractEmacsModeAtFirstLine(input);
775d4c6f1e6SMasatake YAMATO 		if (!interpreter)
776d4c6f1e6SMasatake YAMATO 		{
777d4c6f1e6SMasatake YAMATO 			const char* const lastSlash = strrchr (line, '/');
778d4c6f1e6SMasatake YAMATO 			const char *const cmd = lastSlash != NULL ? lastSlash+1 : line+2;
779d4c6f1e6SMasatake YAMATO 			interpreter = determineInterpreter (cmd);
780d4c6f1e6SMasatake YAMATO 		}
781d4c6f1e6SMasatake YAMATO 	}
782d4c6f1e6SMasatake YAMATO 	vStringDelete (vLine);
783d4c6f1e6SMasatake YAMATO 	return interpreter;
784d4c6f1e6SMasatake YAMATO }
785d4c6f1e6SMasatake YAMATO 
determineEmacsModeAtFirstLine(const char * const line)786d4c6f1e6SMasatake YAMATO static vString* determineEmacsModeAtFirstLine (const char* const line)
787d4c6f1e6SMasatake YAMATO {
788d4c6f1e6SMasatake YAMATO 	vString* mode = vStringNew ();
789d4c6f1e6SMasatake YAMATO 
790d4c6f1e6SMasatake YAMATO 	const char* p = strstr(line, "-*-");
791d4c6f1e6SMasatake YAMATO 	if (p == NULL)
792fba4ae34SMasatake YAMATO 		goto out;
793d4c6f1e6SMasatake YAMATO 	p += strlen("-*-");
794d4c6f1e6SMasatake YAMATO 
795d4c6f1e6SMasatake YAMATO 	for ( ;  isspace ((int) *p)  ;  ++p)
796d4c6f1e6SMasatake YAMATO 		;  /* no-op */
797d4c6f1e6SMasatake YAMATO 
798d5f594ccSMasatake YAMATO 	if (strncasecmp(p, "mode:", strlen("mode:")) == 0)
799d4c6f1e6SMasatake YAMATO 	{
800d4c6f1e6SMasatake YAMATO 		/* -*- mode: MODE; -*- */
801d4c6f1e6SMasatake YAMATO 		p += strlen("mode:");
802d4c6f1e6SMasatake YAMATO 		for ( ;  isspace ((int) *p)  ;  ++p)
803d4c6f1e6SMasatake YAMATO 			;  /* no-op */
804da8c4965SMasatake YAMATO 		for ( ;  *p != '\0'  &&  isLanguageNameChar ((int) *p)  ;  ++p)
805d4c6f1e6SMasatake YAMATO 			vStringPut (mode, (int) *p);
806d4c6f1e6SMasatake YAMATO 	}
807d4c6f1e6SMasatake YAMATO 	else
808d4c6f1e6SMasatake YAMATO 	{
809d4c6f1e6SMasatake YAMATO 		/* -*- MODE -*- */
810fba4ae34SMasatake YAMATO 		const char* end = strstr (p, "-*-");
811fba4ae34SMasatake YAMATO 
812fba4ae34SMasatake YAMATO 		if (end == NULL)
813fba4ae34SMasatake YAMATO 			goto out;
814fba4ae34SMasatake YAMATO 
815da8c4965SMasatake YAMATO 		for ( ;  p < end &&  isLanguageNameChar ((int) *p)  ;  ++p)
816d4c6f1e6SMasatake YAMATO 			vStringPut (mode, (int) *p);
817d4c6f1e6SMasatake YAMATO 
818d4c6f1e6SMasatake YAMATO 		for ( ;  isspace ((int) *p)  ;  ++p)
819d4c6f1e6SMasatake YAMATO 			;  /* no-op */
820d4c6f1e6SMasatake YAMATO 		if (strncmp(p, "-*-", strlen("-*-")) != 0)
821d4c6f1e6SMasatake YAMATO 			vStringClear (mode);
822d4c6f1e6SMasatake YAMATO 	}
823d4c6f1e6SMasatake YAMATO 
824fba4ae34SMasatake YAMATO 	vStringLower (mode);
825fba4ae34SMasatake YAMATO 
826fba4ae34SMasatake YAMATO out:
827d4c6f1e6SMasatake YAMATO 	return mode;
828d4c6f1e6SMasatake YAMATO 
829d4c6f1e6SMasatake YAMATO }
830d4c6f1e6SMasatake YAMATO 
extractEmacsModeAtFirstLine(MIO * input)831509a47dbSJiří Techet static vString* extractEmacsModeAtFirstLine(MIO* input)
832d4c6f1e6SMasatake YAMATO {
833d4c6f1e6SMasatake YAMATO 	vString* const vLine = vStringNew ();
83478e93ff0SMasatake YAMATO 	const char* const line = readLineRaw (vLine, input);
835d4c6f1e6SMasatake YAMATO 	vString* mode = NULL;
836d4c6f1e6SMasatake YAMATO 	if (line != NULL)
837d4c6f1e6SMasatake YAMATO 		mode = determineEmacsModeAtFirstLine (line);
838d4c6f1e6SMasatake YAMATO 	vStringDelete (vLine);
839d4c6f1e6SMasatake YAMATO 
840d4c6f1e6SMasatake YAMATO 	if (mode && (vStringLength(mode) == 0))
841d4c6f1e6SMasatake YAMATO 	{
842d4c6f1e6SMasatake YAMATO 		vStringDelete(mode);
843d4c6f1e6SMasatake YAMATO 		mode = NULL;
844d4c6f1e6SMasatake YAMATO 	}
845d4c6f1e6SMasatake YAMATO 	return mode;
846d4c6f1e6SMasatake YAMATO }
847d4c6f1e6SMasatake YAMATO 
determineEmacsModeAtEOF(MIO * const fp)848509a47dbSJiří Techet static vString* determineEmacsModeAtEOF (MIO* const fp)
849d4c6f1e6SMasatake YAMATO {
850d4c6f1e6SMasatake YAMATO 	vString* const vLine = vStringNew ();
851d4c6f1e6SMasatake YAMATO 	const char* line;
852ce990805SThomas Braun 	bool headerFound = false;
853d4c6f1e6SMasatake YAMATO 	const char* p;
854d4c6f1e6SMasatake YAMATO 	vString* mode = vStringNew ();
855d4c6f1e6SMasatake YAMATO 
85678e93ff0SMasatake YAMATO 	while ((line = readLineRaw (vLine, fp)) != NULL)
857d4c6f1e6SMasatake YAMATO 	{
858d4c6f1e6SMasatake YAMATO 		if (headerFound && ((p = strstr (line, "mode:")) != NULL))
859d4c6f1e6SMasatake YAMATO 		{
860d4c6f1e6SMasatake YAMATO 			vStringClear (mode);
861ce990805SThomas Braun 			headerFound = false;
862d4c6f1e6SMasatake YAMATO 
863d4c6f1e6SMasatake YAMATO 			p += strlen ("mode:");
864d4c6f1e6SMasatake YAMATO 			for ( ;  isspace ((int) *p)  ;  ++p)
865d4c6f1e6SMasatake YAMATO 				;  /* no-op */
866da8c4965SMasatake YAMATO 			for ( ;  *p != '\0'  &&  isLanguageNameChar ((int) *p)  ;  ++p)
867d4c6f1e6SMasatake YAMATO 				vStringPut (mode, (int) *p);
868d4c6f1e6SMasatake YAMATO 		}
869d4c6f1e6SMasatake YAMATO 		else if (headerFound && (p = strstr(line, "End:")))
870ce990805SThomas Braun 			headerFound = false;
871d4c6f1e6SMasatake YAMATO 		else if (strstr (line, "Local Variables:"))
872ce990805SThomas Braun 			headerFound = true;
873d4c6f1e6SMasatake YAMATO 	}
874d4c6f1e6SMasatake YAMATO 	vStringDelete (vLine);
875d4c6f1e6SMasatake YAMATO 	return mode;
876d4c6f1e6SMasatake YAMATO }
877d4c6f1e6SMasatake YAMATO 
extractEmacsModeLanguageAtEOF(MIO * input)878509a47dbSJiří Techet static vString* extractEmacsModeLanguageAtEOF (MIO* input)
879d4c6f1e6SMasatake YAMATO {
880d4c6f1e6SMasatake YAMATO 	vString* mode;
881d4c6f1e6SMasatake YAMATO 
882d4c6f1e6SMasatake YAMATO 	/* "48.2.4.1 Specifying File Variables" of Emacs info:
883d4c6f1e6SMasatake YAMATO 	   ---------------------------------------------------
884d4c6f1e6SMasatake YAMATO 	   you can define file local variables using a "local
885d4c6f1e6SMasatake YAMATO 	   variables list" near the end of the file.  The start of the
886d4c6f1e6SMasatake YAMATO 	   local variables list should be no more than 3000 characters
887d4c6f1e6SMasatake YAMATO 	   from the end of the file, */
888509a47dbSJiří Techet 	mio_seek(input, -3000, SEEK_END);
889d4c6f1e6SMasatake YAMATO 
890d4c6f1e6SMasatake YAMATO 	mode = determineEmacsModeAtEOF (input);
891d4c6f1e6SMasatake YAMATO 	if (mode && (vStringLength (mode) == 0))
892d4c6f1e6SMasatake YAMATO 	{
893d4c6f1e6SMasatake YAMATO 		vStringDelete (mode);
894d4c6f1e6SMasatake YAMATO 		mode = NULL;
895d4c6f1e6SMasatake YAMATO 	}
896d4c6f1e6SMasatake YAMATO 
897d4c6f1e6SMasatake YAMATO 	return mode;
898d4c6f1e6SMasatake YAMATO }
899d4c6f1e6SMasatake YAMATO 
determineVimFileType(const char * const modeline)900d4c6f1e6SMasatake YAMATO static vString* determineVimFileType (const char *const modeline)
901d4c6f1e6SMasatake YAMATO {
902d4c6f1e6SMasatake YAMATO 	/* considerable combinations:
903d4c6f1e6SMasatake YAMATO 	   --------------------------
904d4c6f1e6SMasatake YAMATO 	   ... filetype=
905d4c6f1e6SMasatake YAMATO 	   ... ft= */
906d4c6f1e6SMasatake YAMATO 
907d4c6f1e6SMasatake YAMATO 	unsigned int i;
908d4c6f1e6SMasatake YAMATO 	const char* p;
909d4c6f1e6SMasatake YAMATO 
910d4c6f1e6SMasatake YAMATO 	const char* const filetype_prefix[] = {"filetype=", "ft="};
911d4c6f1e6SMasatake YAMATO 	vString* const filetype = vStringNew ();
912d4c6f1e6SMasatake YAMATO 
913d4c6f1e6SMasatake YAMATO 	for (i = 0; i < ARRAY_SIZE(filetype_prefix); i++)
914d4c6f1e6SMasatake YAMATO 	{
915d4c6f1e6SMasatake YAMATO 		if ((p = strrstr(modeline, filetype_prefix[i])) == NULL)
916d4c6f1e6SMasatake YAMATO 			continue;
917d4c6f1e6SMasatake YAMATO 
918d4c6f1e6SMasatake YAMATO 		p += strlen(filetype_prefix[i]);
919d4c6f1e6SMasatake YAMATO 		for ( ;  *p != '\0'  &&  isalnum ((int) *p)  ;  ++p)
920d4c6f1e6SMasatake YAMATO 			vStringPut (filetype, (int) *p);
921d4c6f1e6SMasatake YAMATO 		break;
922d4c6f1e6SMasatake YAMATO 	}
923d4c6f1e6SMasatake YAMATO 	return filetype;
924d4c6f1e6SMasatake YAMATO }
925d4c6f1e6SMasatake YAMATO 
extractVimFileType(MIO * input)926509a47dbSJiří Techet static vString* extractVimFileType(MIO* input)
927d4c6f1e6SMasatake YAMATO {
928d4c6f1e6SMasatake YAMATO 	/* http://vimdoc.sourceforge.net/htmldoc/options.html#modeline
929d4c6f1e6SMasatake YAMATO 
930d4c6f1e6SMasatake YAMATO 	   [text]{white}{vi:|vim:|ex:}[white]se[t] {options}:[text]
931d4c6f1e6SMasatake YAMATO 	   options=> filetype=TYPE or ft=TYPE
932d4c6f1e6SMasatake YAMATO 
933d4c6f1e6SMasatake YAMATO 	   'modelines' 'mls'	number	(default 5)
934d4c6f1e6SMasatake YAMATO 			global
935d4c6f1e6SMasatake YAMATO 			{not in Vi}
936d4c6f1e6SMasatake YAMATO 	    If 'modeline' is on 'modelines' gives the number of lines that is
937d4c6f1e6SMasatake YAMATO 	    checked for set commands. */
938d4c6f1e6SMasatake YAMATO 
939d4c6f1e6SMasatake YAMATO 	vString* filetype = NULL;
940d4c6f1e6SMasatake YAMATO #define RING_SIZE 5
941d4c6f1e6SMasatake YAMATO 	vString* ring[RING_SIZE];
942d4c6f1e6SMasatake YAMATO 	int i, j;
943d4c6f1e6SMasatake YAMATO 	unsigned int k;
944d4c6f1e6SMasatake YAMATO 	const char* const prefix[] = {
945d4c6f1e6SMasatake YAMATO 		"vim:", "vi:", "ex:"
946d4c6f1e6SMasatake YAMATO 	};
947d4c6f1e6SMasatake YAMATO 
948d4c6f1e6SMasatake YAMATO 	for (i = 0; i < RING_SIZE; i++)
949d4c6f1e6SMasatake YAMATO 		ring[i] = vStringNew ();
950d4c6f1e6SMasatake YAMATO 
951d4c6f1e6SMasatake YAMATO 	i = 0;
95278e93ff0SMasatake YAMATO 	while ((readLineRaw (ring[i++], input)) != NULL)
953d4c6f1e6SMasatake YAMATO 		if (i == RING_SIZE)
954d4c6f1e6SMasatake YAMATO 			i = 0;
955d4c6f1e6SMasatake YAMATO 
956d4c6f1e6SMasatake YAMATO 	j = i;
957d4c6f1e6SMasatake YAMATO 	do
958d4c6f1e6SMasatake YAMATO 	{
959d4c6f1e6SMasatake YAMATO 		const char* p;
960d4c6f1e6SMasatake YAMATO 
961d4c6f1e6SMasatake YAMATO 		j--;
962d4c6f1e6SMasatake YAMATO 		if (j < 0)
963d4c6f1e6SMasatake YAMATO 			j = RING_SIZE - 1;
964d4c6f1e6SMasatake YAMATO 
965d4c6f1e6SMasatake YAMATO 		for (k = 0; k < ARRAY_SIZE(prefix); k++)
966d4c6f1e6SMasatake YAMATO 			if ((p = strstr (vStringValue (ring[j]), prefix[k])) != NULL)
967d4c6f1e6SMasatake YAMATO 			{
968d4c6f1e6SMasatake YAMATO 				p += strlen(prefix[k]);
969d4c6f1e6SMasatake YAMATO 				for ( ;  isspace ((int) *p)  ;  ++p)
970d4c6f1e6SMasatake YAMATO 					;  /* no-op */
971d4c6f1e6SMasatake YAMATO 				filetype = determineVimFileType(p);
972d4c6f1e6SMasatake YAMATO 				break;
973d4c6f1e6SMasatake YAMATO 			}
974d4c6f1e6SMasatake YAMATO 	} while (((i == RING_SIZE)? (j != RING_SIZE - 1): (j != i)) && (!filetype));
975d4c6f1e6SMasatake YAMATO 
976d4c6f1e6SMasatake YAMATO 	for (i = RING_SIZE - 1; i >= 0; i--)
977d4c6f1e6SMasatake YAMATO 		vStringDelete (ring[i]);
978d4c6f1e6SMasatake YAMATO #undef RING_SIZE
979d4c6f1e6SMasatake YAMATO 
980d4c6f1e6SMasatake YAMATO 	if (filetype && (vStringLength (filetype) == 0))
981d4c6f1e6SMasatake YAMATO 	{
982d4c6f1e6SMasatake YAMATO 		vStringDelete (filetype);
983d4c6f1e6SMasatake YAMATO 		filetype = NULL;
984d4c6f1e6SMasatake YAMATO 	}
985d4c6f1e6SMasatake YAMATO 	return filetype;
986d4c6f1e6SMasatake YAMATO 
987d4c6f1e6SMasatake YAMATO 	/* TODO:
988d4c6f1e6SMasatake YAMATO 	   [text]{white}{vi:|vim:|ex:}[white]{options} */
989d4c6f1e6SMasatake YAMATO }
990d4c6f1e6SMasatake YAMATO 
extractMarkGeneric(MIO * input,vString * (* determiner)(const char * const,void *),void * data)991e5025b6dSMasatake YAMATO static vString* extractMarkGeneric (MIO* input,
992e5025b6dSMasatake YAMATO 									vString * (* determiner)(const char *const, void *),
993e5025b6dSMasatake YAMATO 									void *data)
994e5025b6dSMasatake YAMATO {
995e5025b6dSMasatake YAMATO 	vString* const vLine = vStringNew ();
996e5025b6dSMasatake YAMATO 	const char* const line = readLineRaw (vLine, input);
997e5025b6dSMasatake YAMATO 	vString* mode = NULL;
998e5025b6dSMasatake YAMATO 
999e5025b6dSMasatake YAMATO 	if (line)
1000e5025b6dSMasatake YAMATO 		mode = determiner (line, data);
1001e5025b6dSMasatake YAMATO 
1002e5025b6dSMasatake YAMATO 	vStringDelete (vLine);
1003e5025b6dSMasatake YAMATO 	return mode;
1004e5025b6dSMasatake YAMATO }
1005e5025b6dSMasatake YAMATO 
determineZshAutoloadTag(const char * const modeline,void * data CTAGS_ATTR_UNUSED)1006e5025b6dSMasatake YAMATO static vString* determineZshAutoloadTag (const char *const modeline,
1007e5025b6dSMasatake YAMATO 										 void *data CTAGS_ATTR_UNUSED)
1008d4c6f1e6SMasatake YAMATO {
1009d4c6f1e6SMasatake YAMATO 	/* See "Autoloaded files" in zsh info.
1010d4c6f1e6SMasatake YAMATO 	   -------------------------------------
1011d4c6f1e6SMasatake YAMATO 	   #compdef ...
1012d4c6f1e6SMasatake YAMATO 	   #autoload [ OPTIONS ] */
1013d4c6f1e6SMasatake YAMATO 
1014d4c6f1e6SMasatake YAMATO 	if (((strncmp (modeline, "#compdef", 8) == 0) && isspace (*(modeline + 8)))
1015d4c6f1e6SMasatake YAMATO 	    || ((strncmp (modeline, "#autoload", 9) == 0)
1016d4c6f1e6SMasatake YAMATO 		&& (isspace (*(modeline + 9)) || *(modeline + 9) == '\0')))
1017d4c6f1e6SMasatake YAMATO 		return vStringNewInit ("zsh");
1018d4c6f1e6SMasatake YAMATO 	else
1019d4c6f1e6SMasatake YAMATO 		return NULL;
1020d4c6f1e6SMasatake YAMATO }
1021d4c6f1e6SMasatake YAMATO 
extractZshAutoloadTag(MIO * input)1022509a47dbSJiří Techet static vString* extractZshAutoloadTag(MIO* input)
1023d4c6f1e6SMasatake YAMATO {
1024e5025b6dSMasatake YAMATO 	return extractMarkGeneric (input, determineZshAutoloadTag, NULL);
1025d4c6f1e6SMasatake YAMATO }
1026d4c6f1e6SMasatake YAMATO 
determinePHPMark(const char * const modeline,void * data CTAGS_ATTR_UNUSED)1027e5025b6dSMasatake YAMATO static vString* determinePHPMark(const char *const modeline,
1028e5025b6dSMasatake YAMATO 		void *data CTAGS_ATTR_UNUSED)
1029e5025b6dSMasatake YAMATO {
1030e5025b6dSMasatake YAMATO 	if (strncmp (modeline, "<?php", 5) == 0)
1031e5025b6dSMasatake YAMATO 		return vStringNewInit ("php");
1032e5025b6dSMasatake YAMATO 	else
1033e5025b6dSMasatake YAMATO 		return NULL;
1034e5025b6dSMasatake YAMATO }
1035e5025b6dSMasatake YAMATO 
extractPHPMark(MIO * input)1036e5025b6dSMasatake YAMATO static vString* extractPHPMark(MIO* input)
1037e5025b6dSMasatake YAMATO {
1038e5025b6dSMasatake YAMATO 	return extractMarkGeneric (input, determinePHPMark, NULL);
1039e5025b6dSMasatake YAMATO }
1040e5025b6dSMasatake YAMATO 
1041e5025b6dSMasatake YAMATO 
1042d4c6f1e6SMasatake YAMATO struct getLangCtx {
1043d4c6f1e6SMasatake YAMATO     const char *fileName;
1044509a47dbSJiří Techet     MIO        *input;
1045ce990805SThomas Braun     bool     err;
1046d4c6f1e6SMasatake YAMATO };
1047d4c6f1e6SMasatake YAMATO 
1048ad63d66dSMasatake YAMATO #define GLC_FOPEN_IF_NECESSARY0(_glc_, _label_) do {        \
1049d4c6f1e6SMasatake YAMATO     if (!(_glc_)->input) {                                  \
1050ce990805SThomas Braun 	    (_glc_)->input = getMio((_glc_)->fileName, "rb", false);	\
1051d4c6f1e6SMasatake YAMATO         if (!(_glc_)->input) {                              \
1052ce990805SThomas Braun             (_glc_)->err = true;                            \
1053d4c6f1e6SMasatake YAMATO             goto _label_;                                   \
1054d4c6f1e6SMasatake YAMATO         }                                                   \
1055d4c6f1e6SMasatake YAMATO     }                                                       \
1056d4c6f1e6SMasatake YAMATO } while (0)                                                 \
1057d4c6f1e6SMasatake YAMATO 
1058ad63d66dSMasatake YAMATO #define GLC_FOPEN_IF_NECESSARY(_glc_, _label_, _doesParserRequireMemoryStream_) \
1059ad63d66dSMasatake YAMATO 	do {								\
1060ad63d66dSMasatake YAMATO 		if (!(_glc_)->input)					\
1061ad63d66dSMasatake YAMATO 			GLC_FOPEN_IF_NECESSARY0 (_glc_, _label_);	\
1062ad63d66dSMasatake YAMATO 		if ((_doesParserRequireMemoryStream_) &&		\
10631cffa7e6SMasatake YAMATO 		    (mio_memory_get_data((_glc_)->input, NULL) == NULL)) \
1064ad63d66dSMasatake YAMATO 		{							\
1065ad63d66dSMasatake YAMATO 			MIO *tmp_ = (_glc_)->input;			\
1066915d6979SJiří Techet 			(_glc_)->input = mio_new_mio (tmp_, 0, -1);	\
1067b978efd6SMasatake YAMATO 			mio_unref (tmp_);				\
1068ad63d66dSMasatake YAMATO 			if (!(_glc_)->input) {				\
1069ce990805SThomas Braun 				(_glc_)->err = true;			\
1070ad63d66dSMasatake YAMATO 				goto _label_;				\
1071ad63d66dSMasatake YAMATO 			}						\
1072ad63d66dSMasatake YAMATO 		}							\
1073ad63d66dSMasatake YAMATO 	} while (0)
1074ad63d66dSMasatake YAMATO 
1075d4c6f1e6SMasatake YAMATO #define GLC_FCLOSE(_glc_) do {                              \
1076d4c6f1e6SMasatake YAMATO     if ((_glc_)->input) {                                   \
1077b978efd6SMasatake YAMATO         mio_unref((_glc_)->input);                             \
1078d4c6f1e6SMasatake YAMATO         (_glc_)->input = NULL;                              \
1079d4c6f1e6SMasatake YAMATO     }                                                       \
1080d4c6f1e6SMasatake YAMATO } while (0)
1081d4c6f1e6SMasatake YAMATO 
1082d4c6f1e6SMasatake YAMATO static const struct taster {
1083509a47dbSJiří Techet 	vString* (* taste) (MIO *);
1084d4c6f1e6SMasatake YAMATO         const char     *msg;
1085d4c6f1e6SMasatake YAMATO } eager_tasters[] = {
1086d4c6f1e6SMasatake YAMATO         {
1087d4c6f1e6SMasatake YAMATO 		.taste  = extractInterpreter,
1088d4c6f1e6SMasatake YAMATO 		.msg    = "interpreter",
1089d4c6f1e6SMasatake YAMATO         },
1090d4c6f1e6SMasatake YAMATO 	{
1091d4c6f1e6SMasatake YAMATO 		.taste  = extractZshAutoloadTag,
1092d4c6f1e6SMasatake YAMATO 		.msg    = "zsh autoload tag",
1093d4c6f1e6SMasatake YAMATO 	},
1094d4c6f1e6SMasatake YAMATO         {
1095100a966cSMasatake YAMATO 		.taste  = extractEmacsModeAtFirstLine,
1096d4c6f1e6SMasatake YAMATO 		.msg    = "emacs mode at the first line",
1097d4c6f1e6SMasatake YAMATO         },
1098d4c6f1e6SMasatake YAMATO         {
1099d4c6f1e6SMasatake YAMATO 		.taste  = extractEmacsModeLanguageAtEOF,
1100d4c6f1e6SMasatake YAMATO 		.msg    = "emacs mode at the EOF",
1101d4c6f1e6SMasatake YAMATO         },
1102d4c6f1e6SMasatake YAMATO         {
1103d4c6f1e6SMasatake YAMATO 		.taste  = extractVimFileType,
1104d4c6f1e6SMasatake YAMATO 		.msg    = "vim modeline",
1105d4c6f1e6SMasatake YAMATO         },
1106e5025b6dSMasatake YAMATO 		{
1107e5025b6dSMasatake YAMATO 		.taste  = extractPHPMark,
1108e5025b6dSMasatake YAMATO 		.msg    = "PHP marker",
1109e5025b6dSMasatake YAMATO 		}
1110d4c6f1e6SMasatake YAMATO };
1111fbbe6498SMasatake YAMATO static langType tasteLanguage (struct getLangCtx *glc, const struct taster *const tasters, int n_tasters,
1112fbbe6498SMasatake YAMATO 			      langType *fallback);
1113d4c6f1e6SMasatake YAMATO 
11148e73dfedSDmitri Tikhonov /* If all the candidates have the same specialized language selector, return
11158e73dfedSDmitri Tikhonov  * it.  Otherwise, return NULL.
11168e73dfedSDmitri Tikhonov  */
1117ce990805SThomas Braun static bool
hasTheSameSelector(langType lang,selectLanguage candidate_selector)11185a38b5ceSMasatake YAMATO hasTheSameSelector (langType lang, selectLanguage candidate_selector)
11195a38b5ceSMasatake YAMATO {
11205a38b5ceSMasatake YAMATO 	selectLanguage *selector;
11215a38b5ceSMasatake YAMATO 
1122e02be843SMasatake YAMATO 	selector = LanguageTable[ lang ].def->selectLanguage;
11235a38b5ceSMasatake YAMATO 	if (selector == NULL)
1124ce990805SThomas Braun 		return false;
11255a38b5ceSMasatake YAMATO 
11265a38b5ceSMasatake YAMATO 	while (*selector)
11275a38b5ceSMasatake YAMATO 	{
11285a38b5ceSMasatake YAMATO 		if (*selector == candidate_selector)
1129ce990805SThomas Braun 			return true;
11305a38b5ceSMasatake YAMATO 		selector++;
11315a38b5ceSMasatake YAMATO 	}
1132ce990805SThomas Braun 	return false;
11335a38b5ceSMasatake YAMATO }
11345a38b5ceSMasatake YAMATO 
11358e73dfedSDmitri Tikhonov static selectLanguage
commonSelector(const parserCandidate * candidates,int n_candidates)11368e73dfedSDmitri Tikhonov commonSelector (const parserCandidate *candidates, int n_candidates)
11378e73dfedSDmitri Tikhonov {
11388e73dfedSDmitri Tikhonov     Assert (n_candidates > 1);
11395a38b5ceSMasatake YAMATO     selectLanguage *selector;
11408e73dfedSDmitri Tikhonov     int i;
11415a38b5ceSMasatake YAMATO 
1142e02be843SMasatake YAMATO     selector = LanguageTable[ candidates[0].lang ].def->selectLanguage;
11435a38b5ceSMasatake YAMATO     if (selector == NULL)
11448e73dfedSDmitri Tikhonov 	    return NULL;
11455a38b5ceSMasatake YAMATO 
11465a38b5ceSMasatake YAMATO     while (*selector)
11475a38b5ceSMasatake YAMATO     {
11485a38b5ceSMasatake YAMATO 	    for (i = 1; i < n_candidates; ++i)
11495a38b5ceSMasatake YAMATO 		    if (! hasTheSameSelector (candidates[i].lang, *selector))
11505a38b5ceSMasatake YAMATO 			    break;
11515a38b5ceSMasatake YAMATO 	    if (i == n_candidates)
11525a38b5ceSMasatake YAMATO 		    return *selector;
11535a38b5ceSMasatake YAMATO 	    selector++;
11548e73dfedSDmitri Tikhonov     }
11555a38b5ceSMasatake YAMATO     return NULL;
11565a38b5ceSMasatake YAMATO }
11575a38b5ceSMasatake YAMATO 
11588e73dfedSDmitri Tikhonov 
11598e73dfedSDmitri Tikhonov /* Calls the selector and returns the integer value of the parser for the
11608e73dfedSDmitri Tikhonov  * language associated with the string returned by the selector.
11618e73dfedSDmitri Tikhonov  */
11628e73dfedSDmitri Tikhonov static int
pickLanguageBySelection(selectLanguage selector,MIO * input,parserCandidate * candidates,unsigned int nCandidates)11634d58dfe8SMasatake YAMATO pickLanguageBySelection (selectLanguage selector, MIO *input,
11644d58dfe8SMasatake YAMATO 						 parserCandidate *candidates,
11654d58dfe8SMasatake YAMATO 						 unsigned int nCandidates)
11668e73dfedSDmitri Tikhonov {
11674d58dfe8SMasatake YAMATO 	const char *lang;
11684d58dfe8SMasatake YAMATO 	langType *cs = xMalloc(nCandidates, langType);
116946ab94ccSMasatake YAMATO 	unsigned int i;
11704d58dfe8SMasatake YAMATO 
11714d58dfe8SMasatake YAMATO 	for (i = 0; i < nCandidates; i++)
11724d58dfe8SMasatake YAMATO 		cs[i] = candidates[i].lang;
11734d58dfe8SMasatake YAMATO     lang = selector(input, cs, nCandidates);
11744d58dfe8SMasatake YAMATO 	eFree (cs);
11754d58dfe8SMasatake YAMATO 
1176792c8196SDmitri Tikhonov     if (lang)
1177cc8eef97SMasatake YAMATO     {
1178cc8eef97SMasatake YAMATO         verbose ("		selection: %s\n", lang);
11795a55f03bSMasatake YAMATO         return getNamedLanguage(lang, 0);
1180cc8eef97SMasatake YAMATO     }
1181792c8196SDmitri Tikhonov     else
1182cc8eef97SMasatake YAMATO     {
11838213b2c6SMasatake YAMATO 	verbose ("		no selection\n");
1184792c8196SDmitri Tikhonov         return LANG_IGNORE;
11858e73dfedSDmitri Tikhonov     }
1186cc8eef97SMasatake YAMATO }
11878e73dfedSDmitri Tikhonov 
compareParsersByName(const void * a,const void * b)11885d1ff680SMasatake YAMATO static int compareParsersByName (const void *a, const void* b)
11895d1ff680SMasatake YAMATO {
119059f256efSK.Takata 	const parserDefinition *const *la = a, *const *lb = b;
11915d1ff680SMasatake YAMATO 	return strcasecmp ((*la)->name, (*lb)->name);
11925d1ff680SMasatake YAMATO }
11935d1ff680SMasatake YAMATO 
sortParserCandidatesBySpecType(const void * a,const void * b)119495512ba5SMasatake YAMATO static int sortParserCandidatesBySpecType (const void *a, const void *b)
119595512ba5SMasatake YAMATO {
119695512ba5SMasatake YAMATO 	const parserCandidate *ap = a, *bp = b;
119795512ba5SMasatake YAMATO 	if (ap->specType > bp->specType)
119895512ba5SMasatake YAMATO 		return -1;
119995512ba5SMasatake YAMATO 	else if (ap->specType == bp->specType)
12005d1ff680SMasatake YAMATO 	{
12015d1ff680SMasatake YAMATO 		/* qsort, the function calling this function,
12025d1ff680SMasatake YAMATO 		   doesn't do "stable sort". To make the result of
12035d1ff680SMasatake YAMATO 		   sorting predictable, compare the names of parsers
12045d1ff680SMasatake YAMATO 		   when their specType is the same. */
1205e02be843SMasatake YAMATO 		parserDefinition *la = LanguageTable [ap->lang].def;
1206e02be843SMasatake YAMATO 		parserDefinition *lb = LanguageTable [bp->lang].def;
12075d1ff680SMasatake YAMATO 		return compareParsersByName (&la, &lb);
12085d1ff680SMasatake YAMATO 	}
120995512ba5SMasatake YAMATO 	else
121095512ba5SMasatake YAMATO 		return 1;
121195512ba5SMasatake YAMATO }
121295512ba5SMasatake YAMATO 
sortAndFilterParserCandidates(parserCandidate * candidates,unsigned int n_candidates)121395512ba5SMasatake YAMATO static unsigned int sortAndFilterParserCandidates (parserCandidate  *candidates,
121495512ba5SMasatake YAMATO 						   unsigned int n_candidates)
121595512ba5SMasatake YAMATO {
121695512ba5SMasatake YAMATO 	enum specType highestSpecType;
1217e5f9cc19SMasatake YAMATO 	unsigned int i;
121895512ba5SMasatake YAMATO 	unsigned int r;
121995512ba5SMasatake YAMATO 
122095512ba5SMasatake YAMATO 	if (n_candidates < 2)
122195512ba5SMasatake YAMATO 		return n_candidates;
122295512ba5SMasatake YAMATO 
122395512ba5SMasatake YAMATO 	qsort (candidates, n_candidates, sizeof(*candidates),
122495512ba5SMasatake YAMATO 	       sortParserCandidatesBySpecType);
122595512ba5SMasatake YAMATO 
122695512ba5SMasatake YAMATO 	highestSpecType = candidates [0].specType;
122795512ba5SMasatake YAMATO 	r = 1;
122895512ba5SMasatake YAMATO 	for (i = 1; i < n_candidates; i++)
122995512ba5SMasatake YAMATO 	{
123095512ba5SMasatake YAMATO 		if (candidates[i].specType == highestSpecType)
123195512ba5SMasatake YAMATO 			r++;
123295512ba5SMasatake YAMATO 	}
123395512ba5SMasatake YAMATO 	return r;
123495512ba5SMasatake YAMATO }
123595512ba5SMasatake YAMATO 
verboseReportCandidate(const char * header,parserCandidate * candidates,unsigned int n_candidates)123695512ba5SMasatake YAMATO static void verboseReportCandidate (const char *header,
123795512ba5SMasatake YAMATO 				    parserCandidate  *candidates,
123895512ba5SMasatake YAMATO 				    unsigned int n_candidates)
123995512ba5SMasatake YAMATO {
1240e5f9cc19SMasatake YAMATO 	unsigned int i;
124195512ba5SMasatake YAMATO 	verbose ("		#%s: %u\n", header, n_candidates);
124295512ba5SMasatake YAMATO 	for (i = 0; i < n_candidates; i++)
124395512ba5SMasatake YAMATO 		verbose ("			%u: %s (%s: \"%s\")\n",
124495512ba5SMasatake YAMATO 			 i,
1245e02be843SMasatake YAMATO 			 LanguageTable[candidates[i].lang].def->name,
124695512ba5SMasatake YAMATO 			 specTypeName [candidates[i].specType],
124795512ba5SMasatake YAMATO 			 candidates[i].spec);
124895512ba5SMasatake YAMATO }
124995512ba5SMasatake YAMATO 
doesCandidatesRequireMemoryStream(const parserCandidate * candidates,int n_candidates)1250ce990805SThomas Braun static bool doesCandidatesRequireMemoryStream(const parserCandidate *candidates,
1251ad63d66dSMasatake YAMATO 						 int n_candidates)
1252ad63d66dSMasatake YAMATO {
1253ad63d66dSMasatake YAMATO 	int i;
1254ad63d66dSMasatake YAMATO 
1255ad63d66dSMasatake YAMATO 	for (i = 0; i < n_candidates; i++)
1256ad63d66dSMasatake YAMATO 		if (doesParserRequireMemoryStream (candidates[i].lang))
1257ce990805SThomas Braun 			return true;
1258ad63d66dSMasatake YAMATO 
1259ce990805SThomas Braun 	return false;
1260ad63d66dSMasatake YAMATO }
1261ad63d66dSMasatake YAMATO 
getSpecLanguageCommon(const char * const spec,struct getLangCtx * glc,unsigned int nominate (const char * const,parserCandidate **),langType * fallback)1262d4c6f1e6SMasatake YAMATO static langType getSpecLanguageCommon (const char *const spec, struct getLangCtx *glc,
1263fbbe6498SMasatake YAMATO 				       unsigned int nominate (const char *const, parserCandidate**),
1264fbbe6498SMasatake YAMATO 				       langType *fallback)
1265d4c6f1e6SMasatake YAMATO {
1266d4c6f1e6SMasatake YAMATO 	langType language;
1267d4c6f1e6SMasatake YAMATO 	parserCandidate  *candidates;
1268d4c6f1e6SMasatake YAMATO 	unsigned int n_candidates;
126995512ba5SMasatake YAMATO 
1270fbbe6498SMasatake YAMATO 	if (fallback)
1271fbbe6498SMasatake YAMATO 		*fallback = LANG_IGNORE;
1272fbbe6498SMasatake YAMATO 
1273d4c6f1e6SMasatake YAMATO 	n_candidates = (*nominate)(spec, &candidates);
127495512ba5SMasatake YAMATO 	verboseReportCandidate ("candidates",
127595512ba5SMasatake YAMATO 				candidates, n_candidates);
1276d4c6f1e6SMasatake YAMATO 
127795512ba5SMasatake YAMATO 	n_candidates = sortAndFilterParserCandidates (candidates, n_candidates);
127895512ba5SMasatake YAMATO 	verboseReportCandidate ("candidates after sorting and filtering",
127995512ba5SMasatake YAMATO 				candidates, n_candidates);
1280672d7311SMasatake YAMATO 
1281d4c6f1e6SMasatake YAMATO 	if (n_candidates == 1)
1282d4c6f1e6SMasatake YAMATO 	{
1283d4c6f1e6SMasatake YAMATO 		language = candidates[0].lang;
1284d4c6f1e6SMasatake YAMATO 	}
1285d4c6f1e6SMasatake YAMATO 	else if (n_candidates > 1)
1286d4c6f1e6SMasatake YAMATO 	{
12878e73dfedSDmitri Tikhonov 		selectLanguage selector = commonSelector(candidates, n_candidates);
1288ce990805SThomas Braun 		bool memStreamRequired = doesCandidatesRequireMemoryStream (candidates,
1289ad63d66dSMasatake YAMATO 									       n_candidates);
1290ad63d66dSMasatake YAMATO 
1291ad63d66dSMasatake YAMATO 		GLC_FOPEN_IF_NECESSARY(glc, fopen_error, memStreamRequired);
12928e73dfedSDmitri Tikhonov 		if (selector) {
12935a3d25e6SMasatake YAMATO 			verbose ("	selector: %p\n", selector);
12944d58dfe8SMasatake YAMATO 			language = pickLanguageBySelection(selector, glc->input, candidates, n_candidates);
12958e73dfedSDmitri Tikhonov 		} else {
12965a3d25e6SMasatake YAMATO 			verbose ("	selector: NONE\n");
129781226553SMasatake YAMATO 		fopen_error:
129838a0a38cSMasatake YAMATO 			language = LANG_IGNORE;
12998e73dfedSDmitri Tikhonov 		}
130038a0a38cSMasatake YAMATO 
13010bc128d2SMasatake YAMATO 		Assert(language != LANG_AUTO);
13020bc128d2SMasatake YAMATO 
1303fbbe6498SMasatake YAMATO 		if (fallback)
1304fbbe6498SMasatake YAMATO 			*fallback = candidates[0].lang;
1305d4c6f1e6SMasatake YAMATO 	}
1306d4c6f1e6SMasatake YAMATO 	else
1307d4c6f1e6SMasatake YAMATO 	{
1308d4c6f1e6SMasatake YAMATO 		language = LANG_IGNORE;
1309d4c6f1e6SMasatake YAMATO 	}
1310d4c6f1e6SMasatake YAMATO 
1311d4c6f1e6SMasatake YAMATO 	eFree(candidates);
1312d4c6f1e6SMasatake YAMATO 	candidates = NULL;
1313d4c6f1e6SMasatake YAMATO 
1314d4c6f1e6SMasatake YAMATO 	return language;
1315d4c6f1e6SMasatake YAMATO }
1316d4c6f1e6SMasatake YAMATO 
getSpecLanguage(const char * const spec,struct getLangCtx * glc,langType * fallback)1317d4c6f1e6SMasatake YAMATO static langType getSpecLanguage (const char *const spec,
1318fbbe6498SMasatake YAMATO                                  struct getLangCtx *glc,
1319fbbe6498SMasatake YAMATO 				 langType *fallback)
1320d4c6f1e6SMasatake YAMATO {
1321fbbe6498SMasatake YAMATO 	return getSpecLanguageCommon(spec, glc, nominateLanguageCandidates,
1322fbbe6498SMasatake YAMATO 				     fallback);
1323d4c6f1e6SMasatake YAMATO }
1324d4c6f1e6SMasatake YAMATO 
getPatternLanguage(const char * const baseName,struct getLangCtx * glc,langType * fallback)1325d4c6f1e6SMasatake YAMATO static langType getPatternLanguage (const char *const baseName,
1326fbbe6498SMasatake YAMATO                                     struct getLangCtx *glc,
1327fbbe6498SMasatake YAMATO 				    langType *fallback)
1328d4c6f1e6SMasatake YAMATO {
1329d4c6f1e6SMasatake YAMATO 	return getSpecLanguageCommon(baseName, glc,
1330fbbe6498SMasatake YAMATO 				     nominateLanguageCandidatesForPattern,
1331fbbe6498SMasatake YAMATO 				     fallback);
1332d4c6f1e6SMasatake YAMATO }
1333d4c6f1e6SMasatake YAMATO 
1334d4c6f1e6SMasatake YAMATO /* This function tries to figure out language contained in a file by
1335d4c6f1e6SMasatake YAMATO  * running a series of tests, trying to find some clues in the file.
1336d4c6f1e6SMasatake YAMATO  */
1337d4c6f1e6SMasatake YAMATO static langType
tasteLanguage(struct getLangCtx * glc,const struct taster * const tasters,int n_tasters,langType * fallback)1338fbbe6498SMasatake YAMATO tasteLanguage (struct getLangCtx *glc, const struct taster *const tasters, int n_tasters,
1339fbbe6498SMasatake YAMATO 	      langType *fallback)
1340d4c6f1e6SMasatake YAMATO {
1341d4c6f1e6SMasatake YAMATO     int i;
1342d4c6f1e6SMasatake YAMATO 
1343fbbe6498SMasatake YAMATO     if (fallback)
1344fbbe6498SMasatake YAMATO 	    *fallback = LANG_IGNORE;
1345d4c6f1e6SMasatake YAMATO     for (i = 0; i < n_tasters; ++i) {
1346d4c6f1e6SMasatake YAMATO         langType language;
1347d4c6f1e6SMasatake YAMATO         vString* spec;
13484f61e7d5SMasatake YAMATO 
1349509a47dbSJiří Techet         mio_rewind(glc->input);
13504f61e7d5SMasatake YAMATO 	spec = tasters[i].taste(glc->input);
13514f61e7d5SMasatake YAMATO 
13524f61e7d5SMasatake YAMATO         if (NULL != spec) {
1353d4c6f1e6SMasatake YAMATO             verbose ("	%s: %s\n", tasters[i].msg, vStringValue (spec));
1354fbbe6498SMasatake YAMATO             language = getSpecLanguage (vStringValue (spec), glc,
1355fbbe6498SMasatake YAMATO 					(fallback && (*fallback == LANG_IGNORE))? fallback: NULL);
1356d4c6f1e6SMasatake YAMATO             vStringDelete (spec);
1357d4c6f1e6SMasatake YAMATO             if (language != LANG_IGNORE)
1358d4c6f1e6SMasatake YAMATO                 return language;
1359d4c6f1e6SMasatake YAMATO         }
1360d4c6f1e6SMasatake YAMATO     }
1361d4c6f1e6SMasatake YAMATO 
1362d4c6f1e6SMasatake YAMATO     return LANG_IGNORE;
1363d4c6f1e6SMasatake YAMATO }
1364d4c6f1e6SMasatake YAMATO 
1365cfac930dSMasatake YAMATO 
1366cfac930dSMasatake YAMATO struct GetLanguageRequest {
1367cfac930dSMasatake YAMATO 	enum { GLR_OPEN, GLR_DISCARD, GLR_REUSE, } type;
1368cfac930dSMasatake YAMATO 	const char *const fileName;
1369cfac930dSMasatake YAMATO 	MIO *mio;
1370ce1f2415SMasatake YAMATO 	time_t mtime;
1371cfac930dSMasatake YAMATO };
1372cfac930dSMasatake YAMATO 
1373d4c6f1e6SMasatake YAMATO static langType
getFileLanguageForRequestInternal(struct GetLanguageRequest * req)1374cfac930dSMasatake YAMATO getFileLanguageForRequestInternal (struct GetLanguageRequest *req)
1375d4c6f1e6SMasatake YAMATO {
1376cfac930dSMasatake YAMATO 	const char *const fileName = req->fileName;
1377d4c6f1e6SMasatake YAMATO     langType language;
1378fbbe6498SMasatake YAMATO 
1379fbbe6498SMasatake YAMATO     /* ctags tries variety ways(HINTS) to choose a proper language
1380fbbe6498SMasatake YAMATO        for given fileName. If multiple candidates are chosen in one of
1381fbbe6498SMasatake YAMATO        the hint, a SELECTOR common between the candidate languages
1382fbbe6498SMasatake YAMATO        is called.
1383fbbe6498SMasatake YAMATO 
1384fbbe6498SMasatake YAMATO        "selection failure" means a selector common between the
1385fbbe6498SMasatake YAMATO        candidates doesn't exist or the common selector returns NULL.
1386fbbe6498SMasatake YAMATO 
1387fbbe6498SMasatake YAMATO        "hint failure" means the hint finds no candidate or
1388fbbe6498SMasatake YAMATO        "selection failure" occurs though the hint finds multiple
1389fbbe6498SMasatake YAMATO        candidates.
1390fbbe6498SMasatake YAMATO 
1391fbbe6498SMasatake YAMATO        If a hint chooses multiple candidates, and selection failure is
1392759d281dSK.Takata        occurred, the hint records one of the candidates as FALLBACK for
1393fbbe6498SMasatake YAMATO        the hint. (The candidates are stored in an array. The first
1394fbbe6498SMasatake YAMATO        element of the array is recorded. However, there is no
1395fbbe6498SMasatake YAMATO        specification about the order of elements in the array.)
1396fbbe6498SMasatake YAMATO 
1397fbbe6498SMasatake YAMATO        If all hints are failed, FALLBACKs of the hints are examined.
1398fbbe6498SMasatake YAMATO        Which fallbacks should be chosen?  `enum hint' defines the order. */
1399fbbe6498SMasatake YAMATO     enum hint {
1400fbbe6498SMasatake YAMATO 	    HINT_INTERP,
1401fbbe6498SMasatake YAMATO 	    HINT_OTHER,
1402fbbe6498SMasatake YAMATO 	    HINT_FILENAME,
1403fbbe6498SMasatake YAMATO 	    HINT_TEMPLATE,
1404fbbe6498SMasatake YAMATO 	    N_HINTS,
1405fbbe6498SMasatake YAMATO     };
1406fbbe6498SMasatake YAMATO     langType fallback[N_HINTS];
1407fbbe6498SMasatake YAMATO     int i;
1408d4c6f1e6SMasatake YAMATO     struct getLangCtx glc = {
1409d4c6f1e6SMasatake YAMATO         .fileName = fileName,
1410cfac930dSMasatake YAMATO         .input    = (req->type == GLR_REUSE)? mio_ref (req->mio): NULL,
1411ce990805SThomas Braun         .err      = false,
1412d4c6f1e6SMasatake YAMATO     };
1413d4c6f1e6SMasatake YAMATO     const char* const baseName = baseFilename (fileName);
1414d4c6f1e6SMasatake YAMATO     char *templateBaseName = NULL;
1415d4c6f1e6SMasatake YAMATO     fileStatus *fstatus = NULL;
1416d4c6f1e6SMasatake YAMATO 
1417fbbe6498SMasatake YAMATO     for (i = 0; i < N_HINTS; i++)
1418fbbe6498SMasatake YAMATO 	fallback [i] = LANG_IGNORE;
1419fbbe6498SMasatake YAMATO 
1420d4c6f1e6SMasatake YAMATO     verbose ("Get file language for %s\n", fileName);
1421d4c6f1e6SMasatake YAMATO 
1422d4c6f1e6SMasatake YAMATO     verbose ("	pattern: %s\n", baseName);
1423fbbe6498SMasatake YAMATO     language = getPatternLanguage (baseName, &glc,
1424fbbe6498SMasatake YAMATO 				   fallback + HINT_FILENAME);
1425d4c6f1e6SMasatake YAMATO     if (language != LANG_IGNORE || glc.err)
1426d4c6f1e6SMasatake YAMATO         goto cleanup;
1427d4c6f1e6SMasatake YAMATO 
1428d4c6f1e6SMasatake YAMATO     {
1429d4c6f1e6SMasatake YAMATO         const char* const tExt = ".in";
1430d4c6f1e6SMasatake YAMATO         templateBaseName = baseFilenameSansExtensionNew (fileName, tExt);
1431d4c6f1e6SMasatake YAMATO         if (templateBaseName)
1432d4c6f1e6SMasatake YAMATO         {
1433d4c6f1e6SMasatake YAMATO             verbose ("	pattern + template(%s): %s\n", tExt, templateBaseName);
1434ce990805SThomas Braun             GLC_FOPEN_IF_NECESSARY(&glc, cleanup, false);
1435509a47dbSJiří Techet             mio_rewind(glc.input);
1436fbbe6498SMasatake YAMATO             language = getPatternLanguage(templateBaseName, &glc,
1437fbbe6498SMasatake YAMATO 					  fallback + HINT_TEMPLATE);
1438d4c6f1e6SMasatake YAMATO             if (language != LANG_IGNORE)
1439d4c6f1e6SMasatake YAMATO                 goto cleanup;
1440d4c6f1e6SMasatake YAMATO         }
1441d4c6f1e6SMasatake YAMATO     }
1442d4c6f1e6SMasatake YAMATO 
14431bd2ff77SMasatake YAMATO 	/* If the input is already opened, we don't have to verify the existence. */
14441bd2ff77SMasatake YAMATO     if (glc.input || ((fstatus = eStat (fileName)) && fstatus->exists))
1445d4c6f1e6SMasatake YAMATO     {
14461bd2ff77SMasatake YAMATO 	    if ((fstatus && fstatus->isExecutable) || Option.guessLanguageEagerly)
1447d4c6f1e6SMasatake YAMATO 	    {
1448ce990805SThomas Braun 		    GLC_FOPEN_IF_NECESSARY (&glc, cleanup, false);
1449fbbe6498SMasatake YAMATO 		    language = tasteLanguage(&glc, eager_tasters, 1,
1450fbbe6498SMasatake YAMATO 					    fallback + HINT_INTERP);
1451d4c6f1e6SMasatake YAMATO 	    }
1452d4c6f1e6SMasatake YAMATO 	    if (language != LANG_IGNORE)
1453d4c6f1e6SMasatake YAMATO 		    goto cleanup;
1454d4c6f1e6SMasatake YAMATO 
1455d4c6f1e6SMasatake YAMATO 	    if (Option.guessLanguageEagerly)
1456d4c6f1e6SMasatake YAMATO 	    {
1457ce990805SThomas Braun 		    GLC_FOPEN_IF_NECESSARY(&glc, cleanup, false);
1458d4c6f1e6SMasatake YAMATO 		    language = tasteLanguage(&glc,
1459d4c6f1e6SMasatake YAMATO 					     eager_tasters + 1,
1460fbbe6498SMasatake YAMATO 					     ARRAY_SIZE(eager_tasters) - 1,
1461fbbe6498SMasatake YAMATO 					     fallback + HINT_OTHER);
1462d4c6f1e6SMasatake YAMATO 	    }
1463d4c6f1e6SMasatake YAMATO     }
1464d4c6f1e6SMasatake YAMATO 
1465d4c6f1e6SMasatake YAMATO 
1466d4c6f1e6SMasatake YAMATO   cleanup:
1467cfac930dSMasatake YAMATO 	if (req->type == GLR_OPEN && glc.input)
1468ce1f2415SMasatake YAMATO 	{
1469cfac930dSMasatake YAMATO 		req->mio = mio_ref (glc.input);
1470ce1f2415SMasatake YAMATO 		if (!fstatus)
1471ce1f2415SMasatake YAMATO 			fstatus = eStat (fileName);
1472ce1f2415SMasatake YAMATO 		if (fstatus)
1473ce1f2415SMasatake YAMATO 			req->mtime = fstatus->mtime;
1474ce1f2415SMasatake YAMATO 	}
1475d4c6f1e6SMasatake YAMATO     GLC_FCLOSE(&glc);
1476d4c6f1e6SMasatake YAMATO     if (fstatus)
1477d4c6f1e6SMasatake YAMATO 	    eStatFree (fstatus);
1478d4c6f1e6SMasatake YAMATO     if (templateBaseName)
1479d4c6f1e6SMasatake YAMATO         eFree (templateBaseName);
1480fbbe6498SMasatake YAMATO 
1481fbbe6498SMasatake YAMATO     for (i = 0;
1482fbbe6498SMasatake YAMATO 	 language == LANG_IGNORE && i < N_HINTS;
1483fbbe6498SMasatake YAMATO 	 i++)
1484fbbe6498SMasatake YAMATO     {
1485fbbe6498SMasatake YAMATO         language = fallback [i];
1486fbbe6498SMasatake YAMATO 	if (language != LANG_IGNORE)
1487fbbe6498SMasatake YAMATO         verbose ("	fallback[hint = %d]: %s\n", i, getLanguageName (language));
1488fbbe6498SMasatake YAMATO     }
1489fbbe6498SMasatake YAMATO 
149082791c20SMasatake YAMATO 	if (language == LANG_IGNORE
1491d8a63e0bSMasatake YAMATO 		&& isLanguageEnabled (LANG_FALLBACK))
149282791c20SMasatake YAMATO 	{
149382791c20SMasatake YAMATO 		language = LANG_FALLBACK;
149482791c20SMasatake YAMATO 		verbose ("	last resort: using \"%s\" parser\n",
149582791c20SMasatake YAMATO 				 getLanguageName (LANG_FALLBACK));
149682791c20SMasatake YAMATO 	}
1497d4c6f1e6SMasatake YAMATO     return language;
1498d4c6f1e6SMasatake YAMATO }
1499d4c6f1e6SMasatake YAMATO 
getFileLanguageForRequest(struct GetLanguageRequest * req)1500cfac930dSMasatake YAMATO static langType getFileLanguageForRequest (struct GetLanguageRequest *req)
1501d4c6f1e6SMasatake YAMATO {
150242b60e7aSMasatake YAMATO 	langType l = Option.language;
150342b60e7aSMasatake YAMATO 
150442b60e7aSMasatake YAMATO 	if (l == LANG_AUTO)
1505cfac930dSMasatake YAMATO 		return getFileLanguageForRequestInternal(req);
150642b60e7aSMasatake YAMATO 	else if (! isLanguageEnabled (l))
150742b60e7aSMasatake YAMATO 	{
150842b60e7aSMasatake YAMATO 		error (FATAL,
15093e7e9e07SMasatake YAMATO 		       "%s parser specified with --language-force is disabled",
151042b60e7aSMasatake YAMATO 		       getLanguageName (l));
151142b60e7aSMasatake YAMATO 		/* For suppressing warnings. */
151242b60e7aSMasatake YAMATO 		return LANG_AUTO;
151342b60e7aSMasatake YAMATO 	}
1514d4c6f1e6SMasatake YAMATO 	else
1515d4c6f1e6SMasatake YAMATO 		return Option.language;
1516d4c6f1e6SMasatake YAMATO }
1517d4c6f1e6SMasatake YAMATO 
getLanguageForFilenameAndContents(const char * const fileName)15185329ae51SMasatake YAMATO extern langType getLanguageForFilenameAndContents (const char *const fileName)
1519e9d4c72cSMasatake YAMATO {
1520cfac930dSMasatake YAMATO 	struct GetLanguageRequest req = {
1521cfac930dSMasatake YAMATO 		.type = GLR_DISCARD,
1522cfac930dSMasatake YAMATO 		.fileName = fileName,
1523ce1f2415SMasatake YAMATO 		.mtime = (time_t)0,
1524cfac930dSMasatake YAMATO 	};
1525cfac930dSMasatake YAMATO 
1526cfac930dSMasatake YAMATO 	return getFileLanguageForRequest (&req);
1527e9d4c72cSMasatake YAMATO }
1528e9d4c72cSMasatake YAMATO 
1529d4c6f1e6SMasatake YAMATO typedef void (*languageCallback)  (langType language, void* user_data);
foreachLanguage(languageCallback callback,void * user_data)1530d4c6f1e6SMasatake YAMATO static void foreachLanguage(languageCallback callback, void *user_data)
1531d4c6f1e6SMasatake YAMATO {
1532d4c6f1e6SMasatake YAMATO 	langType result = LANG_IGNORE;
1533d4c6f1e6SMasatake YAMATO 
1534d4c6f1e6SMasatake YAMATO 	unsigned int i;
1535d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  &&  result == LANG_IGNORE  ;  ++i)
1536d4c6f1e6SMasatake YAMATO 	{
1537e02be843SMasatake YAMATO 		const parserDefinition* const lang = LanguageTable [i].def;
1538d4c6f1e6SMasatake YAMATO 		if (lang->name != NULL)
1539d4c6f1e6SMasatake YAMATO 			callback(i, user_data);
1540d4c6f1e6SMasatake YAMATO 	}
1541d4c6f1e6SMasatake YAMATO }
1542d4c6f1e6SMasatake YAMATO 
printLanguageMap(const langType language,FILE * fp)1543a21d5fcdSMasatake YAMATO static void printLanguageMap (const langType language, FILE *fp)
1544d4c6f1e6SMasatake YAMATO {
1545ce990805SThomas Braun 	bool first = true;
1546d4c6f1e6SMasatake YAMATO 	unsigned int i;
1547efe089d4SMasatake YAMATO 	parserObject *parser = LanguageTable + language;
1548efe089d4SMasatake YAMATO 	stringList* map = parser->currentPatterns;
1549d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1550d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  map != NULL  &&  i < stringListCount (map)  ;  ++i)
1551d4c6f1e6SMasatake YAMATO 	{
1552d4c6f1e6SMasatake YAMATO 		fprintf (fp, "%s(%s)", (first ? "" : " "),
1553d4c6f1e6SMasatake YAMATO 			 vStringValue (stringListItem (map, i)));
1554ce990805SThomas Braun 		first = false;
1555d4c6f1e6SMasatake YAMATO 	}
1556efe089d4SMasatake YAMATO 	map = parser->currentExtensions;
1557d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  map != NULL  &&  i < stringListCount (map)  ;  ++i)
1558d4c6f1e6SMasatake YAMATO 	{
1559d4c6f1e6SMasatake YAMATO 		fprintf (fp, "%s.%s", (first ? "" : " "),
1560d4c6f1e6SMasatake YAMATO 			 vStringValue (stringListItem (map, i)));
1561ce990805SThomas Braun 		first = false;
1562d4c6f1e6SMasatake YAMATO 	}
1563d4c6f1e6SMasatake YAMATO }
1564d4c6f1e6SMasatake YAMATO 
installLanguageMapDefault(const langType language)1565d4c6f1e6SMasatake YAMATO extern void installLanguageMapDefault (const langType language)
1566d4c6f1e6SMasatake YAMATO {
1567efe089d4SMasatake YAMATO 	parserObject* parser;
1568d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1569efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
1570efe089d4SMasatake YAMATO 	if (parser->currentPatterns != NULL)
1571efe089d4SMasatake YAMATO 		stringListDelete (parser->currentPatterns);
1572efe089d4SMasatake YAMATO 	if (parser->currentExtensions != NULL)
1573efe089d4SMasatake YAMATO 		stringListDelete (parser->currentExtensions);
1574d4c6f1e6SMasatake YAMATO 
1575efe089d4SMasatake YAMATO 	if (parser->def->patterns == NULL)
1576efe089d4SMasatake YAMATO 		parser->currentPatterns = stringListNew ();
1577d4c6f1e6SMasatake YAMATO 	else
1578d4c6f1e6SMasatake YAMATO 	{
1579efe089d4SMasatake YAMATO 		parser->currentPatterns =
1580efe089d4SMasatake YAMATO 			stringListNewFromArgv (parser->def->patterns);
1581d4c6f1e6SMasatake YAMATO 	}
1582efe089d4SMasatake YAMATO 	if (parser->def->extensions == NULL)
1583efe089d4SMasatake YAMATO 		parser->currentExtensions = stringListNew ();
1584d4c6f1e6SMasatake YAMATO 	else
1585d4c6f1e6SMasatake YAMATO 	{
1586efe089d4SMasatake YAMATO 		parser->currentExtensions =
1587efe089d4SMasatake YAMATO 			stringListNewFromArgv (parser->def->extensions);
1588d4c6f1e6SMasatake YAMATO 	}
1589d4c6f1e6SMasatake YAMATO 	BEGIN_VERBOSE(vfp);
1590d4c6f1e6SMasatake YAMATO 	{
1591d4c6f1e6SMasatake YAMATO 	printLanguageMap (language, vfp);
1592d4c6f1e6SMasatake YAMATO 	putc ('\n', vfp);
1593d4c6f1e6SMasatake YAMATO 	}
1594d4c6f1e6SMasatake YAMATO 	END_VERBOSE();
1595d4c6f1e6SMasatake YAMATO }
1596d4c6f1e6SMasatake YAMATO 
installLanguageMapDefaults(void)1597d4c6f1e6SMasatake YAMATO extern void installLanguageMapDefaults (void)
1598d4c6f1e6SMasatake YAMATO {
1599d4c6f1e6SMasatake YAMATO 	unsigned int i;
1600d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  ;  ++i)
1601d4c6f1e6SMasatake YAMATO 	{
1602d4c6f1e6SMasatake YAMATO 		verbose ("    %s: ", getLanguageName (i));
1603d4c6f1e6SMasatake YAMATO 		installLanguageMapDefault (i);
1604d4c6f1e6SMasatake YAMATO 	}
1605d4c6f1e6SMasatake YAMATO }
1606d4c6f1e6SMasatake YAMATO 
installLanguageAliasesDefault(const langType language)1607d4c6f1e6SMasatake YAMATO extern void installLanguageAliasesDefault (const langType language)
1608d4c6f1e6SMasatake YAMATO {
1609efe089d4SMasatake YAMATO 	parserObject* parser;
1610d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1611efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
1612efe089d4SMasatake YAMATO 	if (parser->currentAliases != NULL)
1613efe089d4SMasatake YAMATO 		stringListDelete (parser->currentAliases);
1614d4c6f1e6SMasatake YAMATO 
1615efe089d4SMasatake YAMATO 	if (parser->def->aliases == NULL)
1616efe089d4SMasatake YAMATO 		parser->currentAliases = stringListNew ();
1617d4c6f1e6SMasatake YAMATO 	else
1618d4c6f1e6SMasatake YAMATO 	{
1619efe089d4SMasatake YAMATO 		parser->currentAliases =
1620efe089d4SMasatake YAMATO 			stringListNewFromArgv (parser->def->aliases);
1621d4c6f1e6SMasatake YAMATO 	}
1622d4c6f1e6SMasatake YAMATO 	BEGIN_VERBOSE(vfp);
16233de0d210SMasatake YAMATO 	if (parser->currentAliases != NULL)
16243de0d210SMasatake YAMATO 		for (unsigned int i = 0  ;  i < stringListCount (parser->currentAliases)  ;  ++i)
16253de0d210SMasatake YAMATO 			fprintf (vfp, " %s", vStringValue (
16263de0d210SMasatake YAMATO 						 stringListItem (parser->currentAliases, i)));
1627d4c6f1e6SMasatake YAMATO 	putc ('\n', vfp);
1628d4c6f1e6SMasatake YAMATO 	END_VERBOSE();
1629d4c6f1e6SMasatake YAMATO }
16303de0d210SMasatake YAMATO 
installLanguageAliasesDefaults(void)1631d4c6f1e6SMasatake YAMATO extern void installLanguageAliasesDefaults (void)
1632d4c6f1e6SMasatake YAMATO {
1633d4c6f1e6SMasatake YAMATO 	unsigned int i;
1634d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  ;  ++i)
1635d4c6f1e6SMasatake YAMATO 	{
1636d4c6f1e6SMasatake YAMATO 		verbose ("    %s: ", getLanguageName (i));
1637d4c6f1e6SMasatake YAMATO 		installLanguageAliasesDefault (i);
1638d4c6f1e6SMasatake YAMATO 	}
1639d4c6f1e6SMasatake YAMATO }
1640d4c6f1e6SMasatake YAMATO 
clearLanguageMap(const langType language)1641d4c6f1e6SMasatake YAMATO extern void clearLanguageMap (const langType language)
1642d4c6f1e6SMasatake YAMATO {
1643d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1644efe089d4SMasatake YAMATO 	stringListClear ((LanguageTable + language)->currentPatterns);
1645efe089d4SMasatake YAMATO 	stringListClear ((LanguageTable + language)->currentExtensions);
1646d4c6f1e6SMasatake YAMATO }
1647d4c6f1e6SMasatake YAMATO 
clearLanguageAliases(const langType language)1648d4c6f1e6SMasatake YAMATO extern void clearLanguageAliases (const langType language)
1649d4c6f1e6SMasatake YAMATO {
1650d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1651237651d1SMasatake YAMATO 
1652237651d1SMasatake YAMATO 	parserObject* parser = (LanguageTable + language);
1653237651d1SMasatake YAMATO 	if (parser->currentAliases)
1654237651d1SMasatake YAMATO 		stringListClear (parser->currentAliases);
1655d4c6f1e6SMasatake YAMATO }
1656d4c6f1e6SMasatake YAMATO 
removeLanguagePatternMap1(const langType language,const char * const pattern)1657ce990805SThomas Braun static bool removeLanguagePatternMap1(const langType language, const char *const pattern)
16585455a701SMasatake YAMATO {
1659ce990805SThomas Braun 	bool result = false;
1660efe089d4SMasatake YAMATO 	stringList* const ptrn = (LanguageTable + language)->currentPatterns;
1661d815b8c3SMasatake YAMATO 
1662af2ee6f2SMasatake YAMATO 	if (ptrn != NULL && stringListDeleteItemExtension (ptrn, pattern))
16635455a701SMasatake YAMATO 	{
1664d815b8c3SMasatake YAMATO 		verbose (" (removed from %s)", getLanguageName (language));
1665ce990805SThomas Braun 		result = true;
16665455a701SMasatake YAMATO 	}
1667d815b8c3SMasatake YAMATO 	return result;
16685455a701SMasatake YAMATO }
1669d815b8c3SMasatake YAMATO 
removeLanguagePatternMap(const langType language,const char * const pattern)1670ce990805SThomas Braun extern bool removeLanguagePatternMap (const langType language, const char *const pattern)
1671d815b8c3SMasatake YAMATO {
1672ce990805SThomas Braun 	bool result = false;
1673d815b8c3SMasatake YAMATO 
1674d815b8c3SMasatake YAMATO 	if (language == LANG_AUTO)
1675d815b8c3SMasatake YAMATO 	{
1676d815b8c3SMasatake YAMATO 		unsigned int i;
1677d815b8c3SMasatake YAMATO 		for (i = 0  ;  i < LanguageCount  &&  ! result ;  ++i)
1678d815b8c3SMasatake YAMATO 			result = removeLanguagePatternMap1 (i, pattern) || result;
1679d815b8c3SMasatake YAMATO 	}
1680d815b8c3SMasatake YAMATO 	else
1681d815b8c3SMasatake YAMATO 		result = removeLanguagePatternMap1 (language, pattern);
16825455a701SMasatake YAMATO 	return result;
16835455a701SMasatake YAMATO }
16845455a701SMasatake YAMATO 
addLanguagePatternMap(const langType language,const char * ptrn,bool exclusiveInAllLanguages)1685d932931fSMasatake YAMATO extern void addLanguagePatternMap (const langType language, const char* ptrn,
1686ce990805SThomas Braun 				   bool exclusiveInAllLanguages)
1687d4c6f1e6SMasatake YAMATO {
1688d4c6f1e6SMasatake YAMATO 	vString* const str = vStringNewInit (ptrn);
1689efe089d4SMasatake YAMATO 	parserObject* parser;
1690d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1691efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
1692d932931fSMasatake YAMATO 	if (exclusiveInAllLanguages)
1693d932931fSMasatake YAMATO 		removeLanguagePatternMap (LANG_AUTO, ptrn);
1694efe089d4SMasatake YAMATO 	stringListAdd (parser->currentPatterns, str);
1695d4c6f1e6SMasatake YAMATO }
1696d4c6f1e6SMasatake YAMATO 
removeLanguageExtensionMap1(const langType language,const char * const extension)1697ce990805SThomas Braun static bool removeLanguageExtensionMap1 (const langType language, const char *const extension)
1698d4c6f1e6SMasatake YAMATO {
1699ce990805SThomas Braun 	bool result = false;
1700efe089d4SMasatake YAMATO 	stringList* const exts = (LanguageTable + language)->currentExtensions;
1701d815b8c3SMasatake YAMATO 
1702af2ee6f2SMasatake YAMATO 	if (exts != NULL  &&  stringListDeleteItemExtension (exts, extension))
1703d4c6f1e6SMasatake YAMATO 	{
1704d815b8c3SMasatake YAMATO 		verbose (" (removed from %s)", getLanguageName (language));
1705ce990805SThomas Braun 		result = true;
1706d4c6f1e6SMasatake YAMATO 	}
1707d815b8c3SMasatake YAMATO 	return result;
1708d4c6f1e6SMasatake YAMATO }
1709d815b8c3SMasatake YAMATO 
removeLanguageExtensionMap(const langType language,const char * const extension)1710ce990805SThomas Braun extern bool removeLanguageExtensionMap (const langType language, const char *const extension)
1711d815b8c3SMasatake YAMATO {
1712ce990805SThomas Braun 	bool result = false;
1713d815b8c3SMasatake YAMATO 
1714d815b8c3SMasatake YAMATO 	if (language == LANG_AUTO)
1715d815b8c3SMasatake YAMATO 	{
1716d815b8c3SMasatake YAMATO 		unsigned int i;
1717d815b8c3SMasatake YAMATO 		for (i = 0  ;  i < LanguageCount ;  ++i)
1718d815b8c3SMasatake YAMATO 			result = removeLanguageExtensionMap1 (i, extension) || result;
1719d815b8c3SMasatake YAMATO 	}
1720d815b8c3SMasatake YAMATO 	else
1721d815b8c3SMasatake YAMATO 		result = removeLanguageExtensionMap1 (language, extension);
1722d4c6f1e6SMasatake YAMATO 	return result;
1723d4c6f1e6SMasatake YAMATO }
1724d4c6f1e6SMasatake YAMATO 
addLanguageExtensionMap(const langType language,const char * extension,bool exclusiveInAllLanguages)1725d4c6f1e6SMasatake YAMATO extern void addLanguageExtensionMap (
1726d932931fSMasatake YAMATO 		const langType language, const char* extension,
1727ce990805SThomas Braun 		bool exclusiveInAllLanguages)
1728d4c6f1e6SMasatake YAMATO {
1729d4c6f1e6SMasatake YAMATO 	vString* const str = vStringNewInit (extension);
1730d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1731d932931fSMasatake YAMATO 	if (exclusiveInAllLanguages)
1732d932931fSMasatake YAMATO 		removeLanguageExtensionMap (LANG_AUTO, extension);
1733efe089d4SMasatake YAMATO 	stringListAdd ((LanguageTable + language)->currentExtensions, str);
1734d4c6f1e6SMasatake YAMATO }
1735d4c6f1e6SMasatake YAMATO 
addLanguageAlias(const langType language,const char * alias)1736d4c6f1e6SMasatake YAMATO extern void addLanguageAlias (const langType language, const char* alias)
1737d4c6f1e6SMasatake YAMATO {
1738d4c6f1e6SMasatake YAMATO 	vString* const str = vStringNewInit (alias);
1739efe089d4SMasatake YAMATO 	parserObject* parser;
1740d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1741efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
1742efe089d4SMasatake YAMATO 	if (parser->currentAliases == NULL)
1743efe089d4SMasatake YAMATO 		parser->currentAliases = stringListNew ();
1744efe089d4SMasatake YAMATO 	stringListAdd (parser->currentAliases, str);
1745d4c6f1e6SMasatake YAMATO }
1746d4c6f1e6SMasatake YAMATO 
enableLanguage(const langType language,const bool state)1747ce990805SThomas Braun extern void enableLanguage (const langType language, const bool state)
1748d4c6f1e6SMasatake YAMATO {
1749d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1750e02be843SMasatake YAMATO 	LanguageTable [language].def->enabled = state;
1751d4c6f1e6SMasatake YAMATO }
1752d4c6f1e6SMasatake YAMATO 
1753782707aeSMasatake YAMATO #ifdef DO_TRACING
traceLanguage(langType language)1754782707aeSMasatake YAMATO extern void traceLanguage (langType language)
1755782707aeSMasatake YAMATO {
1756782707aeSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1757782707aeSMasatake YAMATO 	LanguageTable [language].def->traced = true;
1758782707aeSMasatake YAMATO }
isLanguageTraced(langType language)1759782707aeSMasatake YAMATO extern bool isLanguageTraced (langType language)
1760782707aeSMasatake YAMATO {
1761782707aeSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1762782707aeSMasatake YAMATO 	return LanguageTable [language].def->traced;
1763782707aeSMasatake YAMATO }
1764782707aeSMasatake YAMATO #endif /* DO_TRACING */
1765782707aeSMasatake YAMATO 
enableLanguages(const bool state)1766ce990805SThomas Braun extern void enableLanguages (const bool state)
1767d4c6f1e6SMasatake YAMATO {
1768d4c6f1e6SMasatake YAMATO 	unsigned int i;
1769d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  ;  ++i)
1770d4c6f1e6SMasatake YAMATO 		enableLanguage (i, state);
1771d4c6f1e6SMasatake YAMATO }
1772d4c6f1e6SMasatake YAMATO 
installFieldDefinition(const langType language)1773b56bd065SMasatake YAMATO static void installFieldDefinition (const langType language)
1774ad1a3891SMasatake YAMATO {
1775fd1f9e69SMasatake YAMATO 	unsigned int i;
1776ad1a3891SMasatake YAMATO 	parserDefinition * parser;
1777ad1a3891SMasatake YAMATO 
1778ad1a3891SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1779e02be843SMasatake YAMATO 	parser = LanguageTable [language].def;
1780ad1a3891SMasatake YAMATO 
1781a739fa5fSMasatake YAMATO 	if (parser->fieldTable != NULL)
1782ad1a3891SMasatake YAMATO 	{
1783a739fa5fSMasatake YAMATO 		for (i = 0; i < parser->fieldCount; i++)
1784a739fa5fSMasatake YAMATO 			defineField (& parser->fieldTable [i], language);
1785ad1a3891SMasatake YAMATO 	}
1786ad1a3891SMasatake YAMATO }
1787ad1a3891SMasatake YAMATO 
installXtagDefinition(const langType language)1788e3712f53SMasatake YAMATO static void installXtagDefinition (const langType language)
17898643c5b5SMasatake YAMATO {
17908643c5b5SMasatake YAMATO 	unsigned int i;
17918643c5b5SMasatake YAMATO 	parserDefinition * parser;
17928643c5b5SMasatake YAMATO 
17938643c5b5SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
1794e02be843SMasatake YAMATO 	parser = LanguageTable [language].def;
17958643c5b5SMasatake YAMATO 
1796a02a9600SMasatake YAMATO 	if (parser->xtagTable != NULL)
17978643c5b5SMasatake YAMATO 	{
1798a02a9600SMasatake YAMATO 		for (i = 0; i < parser->xtagCount; i++)
1799a02a9600SMasatake YAMATO 			defineXtag (& parser->xtagTable [i], language);
18008643c5b5SMasatake YAMATO 	}
18018643c5b5SMasatake YAMATO }
18028643c5b5SMasatake YAMATO 
initializeParserOne(langType lang)18035a26e8b2SMasatake YAMATO static void initializeParserOne (langType lang)
1804d9ff6343SMasatake YAMATO {
1805e61266e4SMasatake YAMATO 	parserObject *const parser = LanguageTable + lang;
1806f35d9939SMasatake YAMATO 
1807d453869fSMasatake YAMATO 	if (parser->initialized)
1808d0471042SMasatake YAMATO 		goto out;
1809d453869fSMasatake YAMATO 
1810e61266e4SMasatake YAMATO 	verbose ("Initialize parser: %s\n", parser->def->name);
1811ce990805SThomas Braun 	parser->initialized = true;
1812d453869fSMasatake YAMATO 
1813f5779afeSMasatake YAMATO 	installKeywordTable (lang);
1814a086aff1SMasatake YAMATO 	installTagXpathTable (lang);
1815b56bd065SMasatake YAMATO 	installFieldDefinition     (lang);
1816e3712f53SMasatake YAMATO 	installXtagDefinition      (lang);
1817f5779afeSMasatake YAMATO 
18182b6707b2SMasatake YAMATO 	/* regex definitions refers xtag definitions.
18192b6707b2SMasatake YAMATO 	   So installing RegexTable must be after installing
18202b6707b2SMasatake YAMATO 	   xtag definitions. */
18212b6707b2SMasatake YAMATO 	installTagRegexTable (lang);
18222b6707b2SMasatake YAMATO 
1823e61266e4SMasatake YAMATO 	if (parser->def->initialize != NULL)
1824e61266e4SMasatake YAMATO 		parser->def->initialize (lang);
18258d8d8e3bSMasatake YAMATO 
1826edc12faeSMasatake YAMATO 	initializeDependencies (parser->def, parser->slaveControlBlock);
18278d8d8e3bSMasatake YAMATO 
1828a3851331SMasatake YAMATO 	Assert (parser->fileKind != NULL);
1829b271b49dSMasatake YAMATO 	Assert (!doesParserUseKind (parser->kindControlBlock, parser->fileKind->letter));
1830d0471042SMasatake YAMATO 
1831d0471042SMasatake YAMATO 	return;
1832d0471042SMasatake YAMATO 
1833d0471042SMasatake YAMATO  out:
1834d0471042SMasatake YAMATO 	/* lazyInitialize() installs findRegexTags() to parser->parser.
1835d0471042SMasatake YAMATO 	   findRegexTags() should be installed to a parser if the parser is
1836d0471042SMasatake YAMATO 	   optlib based(created by --langdef) and has some regex patterns(defined
1837d0471042SMasatake YAMATO 	   with --regex-<LANG>). findRegexTags() makes regex matching work.
1838d0471042SMasatake YAMATO 
1839d0471042SMasatake YAMATO 	   If a parser can be initialized during evaluating options,
1840d0471042SMasatake YAMATO 	   --fields-<LANG>=+{something}, for an example.
1841d0471042SMasatake YAMATO 	   If such option is evaluated first, evaluating --regex-<LANG>=...
1842d0471042SMasatake YAMATO 	   option doesn't cause installing findRegexTags. As the result
1843d0471042SMasatake YAMATO 	   regex matching doesn't work. lazyInitialize was called only
1844d0471042SMasatake YAMATO 	   once when --fields-<LANG>=+{something} was evaluated. In the
1845d0471042SMasatake YAMATO 	   timing ctags had not seen --regex-<LANG>=.... Even though
1846d0471042SMasatake YAMATO 	   ctags saw --regex-<LANG>=.... after initializing, there
1847d0471042SMasatake YAMATO 	   was no chance to install findRegexTags() to parser->parser.
1848d0471042SMasatake YAMATO 
184955cd1033SMasatake YAMATO 	   Following code block gives extra chances to call lazyInitialize)
1850d0471042SMasatake YAMATO 	   which installs findRegexTags() to parser->parser.	 */
1851d0471042SMasatake YAMATO 	if (parser->def->initialize == lazyInitialize)
1852d0471042SMasatake YAMATO 		parser->def->initialize (lang);
1853dc0f490fSMasatake YAMATO }
1854dc0f490fSMasatake YAMATO 
initializeParser(langType lang)18555a26e8b2SMasatake YAMATO extern void initializeParser (langType lang)
18565a26e8b2SMasatake YAMATO {
18575a26e8b2SMasatake YAMATO 	if (lang == LANG_AUTO)
18585a26e8b2SMasatake YAMATO 	{
185946ab94ccSMasatake YAMATO 		unsigned int i;
18605a26e8b2SMasatake YAMATO 		for (i = 0; i < countParsers(); i++)
18615a26e8b2SMasatake YAMATO 			initializeParserOne (i);
18625a26e8b2SMasatake YAMATO 	}
18635a26e8b2SMasatake YAMATO 	else
18645a26e8b2SMasatake YAMATO 		initializeParserOne (lang);
18655a26e8b2SMasatake YAMATO }
1866dc0f490fSMasatake YAMATO 
linkDependenciesAtInitializeParsing(parserDefinition * const parser)186778143775SMasatake YAMATO static void linkDependenciesAtInitializeParsing (parserDefinition *const parser)
186878143775SMasatake YAMATO {
186978143775SMasatake YAMATO 	unsigned int i;
187078143775SMasatake YAMATO 	parserDependency *d;
187178143775SMasatake YAMATO 	langType upper;
1872d86d3772SMasatake YAMATO 	parserDefinition *lowerParser;
1873edc12faeSMasatake YAMATO 	parserObject *upperParser;
187478143775SMasatake YAMATO 
187578143775SMasatake YAMATO 	for (i = 0; i < parser->dependencyCount; i++)
187678143775SMasatake YAMATO 	{
187778143775SMasatake YAMATO 		d = parser->dependencies + i;
1878d86d3772SMasatake YAMATO 
1879d86d3772SMasatake YAMATO 		if (d->type == DEPTYPE_FOREIGNER)
1880d86d3772SMasatake YAMATO 		{
1881d86d3772SMasatake YAMATO 			upper = parser->id;
1882d86d3772SMasatake YAMATO 			langType lower = getNamedLanguage (d->upperParser, 0);
1883d86d3772SMasatake YAMATO 			if (lower == LANG_IGNORE)
1884d86d3772SMasatake YAMATO 				error (FATAL,
1885d86d3772SMasatake YAMATO 					   "Unknown language: \"%s\" as a foreigner for %s",
1886d86d3772SMasatake YAMATO 					   d->upperParser, parser->name);
1887d86d3772SMasatake YAMATO 
1888d86d3772SMasatake YAMATO 			lowerParser = LanguageTable [lower].def;
1889d86d3772SMasatake YAMATO 		}
1890d86d3772SMasatake YAMATO 		else
1891d86d3772SMasatake YAMATO 		{
189278143775SMasatake YAMATO 			upper = getNamedLanguage (d->upperParser, 0);
1893d86d3772SMasatake YAMATO 			lowerParser = parser;
1894d86d3772SMasatake YAMATO 		}
1895d86d3772SMasatake YAMATO 
1896edc12faeSMasatake YAMATO 		upperParser = LanguageTable + upper;
189778143775SMasatake YAMATO 
1898edc12faeSMasatake YAMATO 		linkDependencyAtInitializeParsing (d->type, upperParser->def,
1899edc12faeSMasatake YAMATO 										   upperParser->slaveControlBlock,
19009a5a18e6SMasatake YAMATO 										   upperParser->kindControlBlock,
1901d86d3772SMasatake YAMATO 										   lowerParser,
1902d86d3772SMasatake YAMATO 										   (LanguageTable + lowerParser->id)->kindControlBlock,
19039a5a18e6SMasatake YAMATO 										   d->data);
190478143775SMasatake YAMATO 	}
190578143775SMasatake YAMATO }
190678143775SMasatake YAMATO 
19079f303cbfSMasatake YAMATO /* Used in both builtin and optlib parsers. */
initializeParsingCommon(parserDefinition * def,bool is_builtin)19089f303cbfSMasatake YAMATO static void initializeParsingCommon (parserDefinition *def, bool is_builtin)
19099f303cbfSMasatake YAMATO {
1910edc12faeSMasatake YAMATO 	parserObject *parser;
19119f303cbfSMasatake YAMATO 
19129f303cbfSMasatake YAMATO 	if (is_builtin)
19139f303cbfSMasatake YAMATO 		verbose ("%s%s", LanguageCount > 0 ? ", " : "", def->name);
19149f303cbfSMasatake YAMATO 	else
19159f303cbfSMasatake YAMATO 		verbose ("Add optlib parser: %s\n", def->name);
19169f303cbfSMasatake YAMATO 
19179f303cbfSMasatake YAMATO 	def->id = LanguageCount++;
1918edc12faeSMasatake YAMATO 	parser = LanguageTable + def->id;
1919edc12faeSMasatake YAMATO 	parser->def = def;
19209f303cbfSMasatake YAMATO 
1921f140c7c3SMasatake YAMATO 	hashTablePutItem (LanguageHTable, def->name, def);
1922f140c7c3SMasatake YAMATO 
1923edc12faeSMasatake YAMATO 	parser->fileKind = &defaultFileKind;
1924edc12faeSMasatake YAMATO 
19257bef4da4SMasatake YAMATO 	parser->kindControlBlock  = allocKindControlBlock (def);
1926a641e930SMasatake YAMATO 	parser->slaveControlBlock = allocSlaveControlBlock (def);
1927bce55cc7SMasatake YAMATO 	parser->lregexControlBlock = allocLregexControlBlock (def);
19289f303cbfSMasatake YAMATO }
19299f303cbfSMasatake YAMATO 
initializeParsing(void)1930d4c6f1e6SMasatake YAMATO extern void initializeParsing (void)
1931d4c6f1e6SMasatake YAMATO {
1932d4c6f1e6SMasatake YAMATO 	unsigned int builtInCount;
1933d4c6f1e6SMasatake YAMATO 	unsigned int i;
1934d4c6f1e6SMasatake YAMATO 
1935d4c6f1e6SMasatake YAMATO 	builtInCount = ARRAY_SIZE (BuiltInParsers);
1936e02be843SMasatake YAMATO 	LanguageTable = xMalloc (builtInCount, parserObject);
1937efe089d4SMasatake YAMATO 	memset(LanguageTable, 0, builtInCount * sizeof (parserObject));
1938f02166dcSMasatake YAMATO 	for (i = 0; i < builtInCount; ++i)
1939f02166dcSMasatake YAMATO 	{
1940f02166dcSMasatake YAMATO 		LanguageTable [i].pretendingAsLanguage = LANG_IGNORE;
1941f02166dcSMasatake YAMATO 		LanguageTable [i].pretendedAsLanguage = LANG_IGNORE;
1942f02166dcSMasatake YAMATO 	}
1943d4c6f1e6SMasatake YAMATO 
1944f140c7c3SMasatake YAMATO 	LanguageHTable = hashTableNew (127,
1945f140c7c3SMasatake YAMATO 								   hashCstrcasehash,
1946f140c7c3SMasatake YAMATO 								   hashCstrcaseeq,
1947f140c7c3SMasatake YAMATO 								   NULL,
1948f140c7c3SMasatake YAMATO 								   NULL);
1949f8cb8817SMasatake YAMATO 	DEFAULT_TRASH_BOX(LanguageHTable, hashTableDelete);
1950f140c7c3SMasatake YAMATO 
1951d4c6f1e6SMasatake YAMATO 	verbose ("Installing parsers: ");
1952d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < builtInCount  ;  ++i)
1953d4c6f1e6SMasatake YAMATO 	{
1954d4c6f1e6SMasatake YAMATO 		parserDefinition* const def = (*BuiltInParsers [i]) ();
1955d4c6f1e6SMasatake YAMATO 		if (def != NULL)
1956d4c6f1e6SMasatake YAMATO 		{
19571b788e0dSMasatake YAMATO 			Assert (def->name);
19581b788e0dSMasatake YAMATO 			Assert (def->name[0] != '\0');
19591b788e0dSMasatake YAMATO 			Assert (strcmp (def->name, RSV_LANG_ALL));
19600278c2a1SMasatake YAMATO 			Assert (strpbrk (def->name, "!\"$%&'()*,-./:;<=>?@[\\]^`|~") == NULL);
19611b788e0dSMasatake YAMATO 
19621b788e0dSMasatake YAMATO 			if (def->method & METHOD_NOT_CRAFTED)
1963d4c6f1e6SMasatake YAMATO 				def->parser = findRegexTags;
1964d4c6f1e6SMasatake YAMATO 			else
19651b788e0dSMasatake YAMATO 				/* parser definition must define one and only one parsing routine */
19661b788e0dSMasatake YAMATO 				Assert ((!!def->parser) + (!!def->parser2) == 1);
19671b788e0dSMasatake YAMATO 
19689f303cbfSMasatake YAMATO 			initializeParsingCommon (def, true);
1969d4c6f1e6SMasatake YAMATO 		}
1970d4c6f1e6SMasatake YAMATO 	}
1971d4c6f1e6SMasatake YAMATO 	verbose ("\n");
197278143775SMasatake YAMATO 
197378143775SMasatake YAMATO 	for (i = 0; i < builtInCount  ;  ++i)
1974e02be843SMasatake YAMATO 		linkDependenciesAtInitializeParsing (LanguageTable [i].def);
1975dc0f490fSMasatake YAMATO }
1976dc0f490fSMasatake YAMATO 
freeParserResources(void)1977d4c6f1e6SMasatake YAMATO extern void freeParserResources (void)
1978d4c6f1e6SMasatake YAMATO {
1979d4c6f1e6SMasatake YAMATO 	unsigned int i;
1980d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  ;  ++i)
1981d4c6f1e6SMasatake YAMATO 	{
1982efe089d4SMasatake YAMATO 		parserObject* const parser = LanguageTable + i;
1983d4c6f1e6SMasatake YAMATO 
1984efe089d4SMasatake YAMATO 		if (parser->def->finalize)
1985e61266e4SMasatake YAMATO 			(parser->def->finalize)((langType)i, (bool)parser->initialized);
1986b88a2810SMasatake YAMATO 
1987eb480042SMasatake YAMATO 		uninstallTagXpathTable (i);
1988eb480042SMasatake YAMATO 
1989bce55cc7SMasatake YAMATO 		freeLregexControlBlock (parser->lregexControlBlock);
19907bef4da4SMasatake YAMATO 		freeKindControlBlock (parser->kindControlBlock);
19917bef4da4SMasatake YAMATO 		parser->kindControlBlock = NULL;
19927bef4da4SMasatake YAMATO 
1993edc12faeSMasatake YAMATO 		finalizeDependencies (parser->def, parser->slaveControlBlock);
1994edc12faeSMasatake YAMATO 		freeSlaveControlBlock (parser->slaveControlBlock);
1995edc12faeSMasatake YAMATO 		parser->slaveControlBlock = NULL;
1996b88a2810SMasatake YAMATO 
1997efe089d4SMasatake YAMATO 		freeList (&parser->currentPatterns);
1998efe089d4SMasatake YAMATO 		freeList (&parser->currentExtensions);
1999efe089d4SMasatake YAMATO 		freeList (&parser->currentAliases);
2000d4c6f1e6SMasatake YAMATO 
2001efe089d4SMasatake YAMATO 		eFree (parser->def->name);
2002efe089d4SMasatake YAMATO 		parser->def->name = NULL;
2003efe089d4SMasatake YAMATO 		eFree (parser->def);
2004efe089d4SMasatake YAMATO 		parser->def = NULL;
2005d4c6f1e6SMasatake YAMATO 	}
2006d4c6f1e6SMasatake YAMATO 	if (LanguageTable != NULL)
2007d4c6f1e6SMasatake YAMATO 		eFree (LanguageTable);
2008d4c6f1e6SMasatake YAMATO 	LanguageTable = NULL;
2009d4c6f1e6SMasatake YAMATO 	LanguageCount = 0;
2010d4c6f1e6SMasatake YAMATO }
2011d4c6f1e6SMasatake YAMATO 
doNothing(void)2012d4c6f1e6SMasatake YAMATO static void doNothing (void)
2013d4c6f1e6SMasatake YAMATO {
2014d4c6f1e6SMasatake YAMATO }
2015d4c6f1e6SMasatake YAMATO 
optlibRunBaseParser(void)201611fea497SMasatake YAMATO static void optlibRunBaseParser (void)
201711fea497SMasatake YAMATO {
201811fea497SMasatake YAMATO 	scheduleRunningBaseparser (0);
201911fea497SMasatake YAMATO }
202011fea497SMasatake YAMATO 
optlibIsDedicatedSubparser(parserDefinition * def)202111fea497SMasatake YAMATO static bool optlibIsDedicatedSubparser (parserDefinition* def)
202211fea497SMasatake YAMATO {
202311fea497SMasatake YAMATO 	return (def->dependencies
202411fea497SMasatake YAMATO 			&& (def->dependencies->type == DEPTYPE_SUBPARSER)
202511fea497SMasatake YAMATO 			&& ((subparser *)def->dependencies->data)->direction & SUBPARSER_SUB_RUNS_BASE);
202611fea497SMasatake YAMATO }
202711fea497SMasatake YAMATO 
lazyInitialize(langType language)20285492e375SMasatake YAMATO static void lazyInitialize (langType language)
2029d4c6f1e6SMasatake YAMATO {
203011fea497SMasatake YAMATO 	parserDefinition* def;
2031d4c6f1e6SMasatake YAMATO 
2032d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
203311fea497SMasatake YAMATO 	def = LanguageTable [language].def;
2034d4c6f1e6SMasatake YAMATO 
203511fea497SMasatake YAMATO 	def->parser = doNothing;
2036d4c6f1e6SMasatake YAMATO 
203711fea497SMasatake YAMATO 	if (def->method & METHOD_REGEX)
203811fea497SMasatake YAMATO 	{
203911fea497SMasatake YAMATO 		if (optlibIsDedicatedSubparser (def))
204011fea497SMasatake YAMATO 			def->parser = optlibRunBaseParser;
204111fea497SMasatake YAMATO 		else
204211fea497SMasatake YAMATO 			def->parser = findRegexTags;
204311fea497SMasatake YAMATO 	}
20442fa3c9e1SMasatake YAMATO }
2045d4c6f1e6SMasatake YAMATO 
enableDefaultFileKind(bool state)204664270418SMasatake YAMATO extern void enableDefaultFileKind (bool state)
204764270418SMasatake YAMATO {
204864270418SMasatake YAMATO 	defaultFileKind.enabled = state;
204964270418SMasatake YAMATO }
205064270418SMasatake YAMATO 
2051d4c6f1e6SMasatake YAMATO /*
2052d4c6f1e6SMasatake YAMATO *   Option parsing
2053d4c6f1e6SMasatake YAMATO */
205411fea497SMasatake YAMATO struct preLangDefFlagData
205511fea497SMasatake YAMATO {
205611fea497SMasatake YAMATO 	char *base;
205711fea497SMasatake YAMATO 	subparserRunDirection direction;
2058225f14f2SMasatake YAMATO 	bool autoFQTag;
205911fea497SMasatake YAMATO };
206011fea497SMasatake YAMATO 
pre_lang_def_flag_base_long(const char * const optflag,const char * const param,void * data)2061beb5437bSMasatake YAMATO static void pre_lang_def_flag_base_long (const char* const optflag, const char* const param, void* data)
2062beb5437bSMasatake YAMATO {
206311fea497SMasatake YAMATO 	struct preLangDefFlagData * flag_data = data;
2064beb5437bSMasatake YAMATO 	langType base;
2065beb5437bSMasatake YAMATO 
2066beb5437bSMasatake YAMATO 	if (param[0] == '\0')
2067beb5437bSMasatake YAMATO 	{
2068beb5437bSMasatake YAMATO 		error (WARNING, "No base parser specified for \"%s\" flag of --langdef option", optflag);
2069beb5437bSMasatake YAMATO 		return;
2070beb5437bSMasatake YAMATO 	}
2071beb5437bSMasatake YAMATO 
2072beb5437bSMasatake YAMATO 	base = getNamedLanguage (param, 0);
2073beb5437bSMasatake YAMATO 	if (base == LANG_IGNORE)
2074beb5437bSMasatake YAMATO 	{
2075759d281dSK.Takata 		error (WARNING, "Unknown language(%s) is specified for \"%s\" flag of --langdef option",
2076beb5437bSMasatake YAMATO 			   param, optflag);
2077beb5437bSMasatake YAMATO 		return;
2078beb5437bSMasatake YAMATO 
2079beb5437bSMasatake YAMATO 	}
2080beb5437bSMasatake YAMATO 
2081ee235db8SMasatake YAMATO 	langType cpreproc = getNamedLanguage ("CPreProcessor", 0);
2082ee235db8SMasatake YAMATO 	if (base == cpreproc)
2083ee235db8SMasatake YAMATO 	{
2084ee235db8SMasatake YAMATO 		error (WARNING,
2085ee235db8SMasatake YAMATO 			   "Because of an internal limitation, Making a sub parser based on the CPreProcessor parser is not allowed: %s",
2086ee235db8SMasatake YAMATO 			   param);
2087ee235db8SMasatake YAMATO 		return;
2088ee235db8SMasatake YAMATO 	}
2089ee235db8SMasatake YAMATO 
209011fea497SMasatake YAMATO 	flag_data->base = eStrdup(param);
209111fea497SMasatake YAMATO }
209211fea497SMasatake YAMATO 
209311fea497SMasatake YAMATO #define LANGDEF_FLAG_DEDICATED "dedicated"
209411fea497SMasatake YAMATO #define LANGDEF_FLAG_SHARED    "shared"
209511fea497SMasatake YAMATO #define LANGDEF_FLAG_BIDIR     "bidirectional"
pre_lang_def_flag_direction_long(const char * const optflag,const char * const param CTAGS_ATTR_UNUSED,void * data)2096e4d16241SMasatake YAMATO static void pre_lang_def_flag_direction_long (const char* const optflag, const char* const param CTAGS_ATTR_UNUSED, void* data)
209711fea497SMasatake YAMATO {
209811fea497SMasatake YAMATO 	struct preLangDefFlagData * flag_data = data;
209911fea497SMasatake YAMATO 
210011fea497SMasatake YAMATO 	if (strcmp(optflag, LANGDEF_FLAG_DEDICATED) == 0)
210111fea497SMasatake YAMATO 		flag_data->direction = SUBPARSER_SUB_RUNS_BASE;
210211fea497SMasatake YAMATO 	else if (strcmp(optflag, LANGDEF_FLAG_SHARED) == 0)
210311fea497SMasatake YAMATO 		flag_data->direction = SUBPARSER_BASE_RUNS_SUB;
210411fea497SMasatake YAMATO 	else if (strcmp(optflag, LANGDEF_FLAG_BIDIR) == 0)
210511fea497SMasatake YAMATO 		flag_data->direction = SUBPARSER_BI_DIRECTION;
210611fea497SMasatake YAMATO 	else
210711fea497SMasatake YAMATO 		AssertNotReached ();
2108beb5437bSMasatake YAMATO }
2109beb5437bSMasatake YAMATO 
pre_lang_def_flag_autoFQTag_long(const char * const optflag,const char * const param CTAGS_ATTR_UNUSED,void * data)2110225f14f2SMasatake YAMATO static void pre_lang_def_flag_autoFQTag_long (const char* const optflag,
2111225f14f2SMasatake YAMATO 											  const char* const param CTAGS_ATTR_UNUSED,
2112225f14f2SMasatake YAMATO 											  void* data)
2113225f14f2SMasatake YAMATO {
2114225f14f2SMasatake YAMATO 	struct preLangDefFlagData * flag_data = data;
2115225f14f2SMasatake YAMATO 	flag_data->autoFQTag = true;
2116225f14f2SMasatake YAMATO }
2117225f14f2SMasatake YAMATO 
2118beb5437bSMasatake YAMATO static flagDefinition PreLangDefFlagDef [] = {
2119d8539e07SMasatake YAMATO 	{ '\0',  "base", NULL, pre_lang_def_flag_base_long,
2120d8539e07SMasatake YAMATO 	  "BASEPARSER", "utilize as a base parser"},
2121d8539e07SMasatake YAMATO 	{ '\0',  LANGDEF_FLAG_DEDICATED,  NULL,
2122d8539e07SMasatake YAMATO 	  pre_lang_def_flag_direction_long,
2123d8539e07SMasatake YAMATO 	  NULL, "make the base parser dedicated to this subparser"},
2124d8539e07SMasatake YAMATO 	{ '\0',  LANGDEF_FLAG_SHARED,     NULL,
2125d8539e07SMasatake YAMATO 	  pre_lang_def_flag_direction_long,
2126d8539e07SMasatake YAMATO 	  NULL, "share the base parser with the other subparsers"
2127d8539e07SMasatake YAMATO 	},
2128d8539e07SMasatake YAMATO 	{ '\0',  LANGDEF_FLAG_BIDIR,      NULL,
2129d8539e07SMasatake YAMATO 	  pre_lang_def_flag_direction_long,
2130d8539e07SMasatake YAMATO 	  NULL, "utilize the base parser both 'dedicated' and 'shared' way"
2131d8539e07SMasatake YAMATO 	},
2132225f14f2SMasatake YAMATO 	{ '\0',  "_autoFQTag", NULL, pre_lang_def_flag_autoFQTag_long,
2133225f14f2SMasatake YAMATO 	  NULL, "make full qualified tags automatically based on scope information"},
2134beb5437bSMasatake YAMATO };
2135beb5437bSMasatake YAMATO 
optlibFreeDep(langType lang,bool initialized CTAGS_ATTR_UNUSED)2136431f0b01SMasatake YAMATO static void optlibFreeDep (langType lang, bool initialized CTAGS_ATTR_UNUSED)
2137beb5437bSMasatake YAMATO {
2138beb5437bSMasatake YAMATO 	parserDefinition * pdef = LanguageTable [lang].def;
2139beb5437bSMasatake YAMATO 
2140beb5437bSMasatake YAMATO 	if (pdef->dependencyCount == 1)
2141beb5437bSMasatake YAMATO 	{
2142beb5437bSMasatake YAMATO 		parserDependency *dep = pdef->dependencies;
2143beb5437bSMasatake YAMATO 
2144beb5437bSMasatake YAMATO 		eFree ((char *)dep->upperParser); /* Dirty cast */
2145beb5437bSMasatake YAMATO 		dep->upperParser = NULL;
2146beb5437bSMasatake YAMATO 		eFree (dep->data);
2147beb5437bSMasatake YAMATO 		dep->data = NULL;
2148beb5437bSMasatake YAMATO 		eFree (dep);
2149beb5437bSMasatake YAMATO 		pdef->dependencies = NULL;
2150beb5437bSMasatake YAMATO 	}
2151beb5437bSMasatake YAMATO }
2152beb5437bSMasatake YAMATO 
OptlibParser(const char * name,const char * base,subparserRunDirection direction)215311fea497SMasatake YAMATO static parserDefinition* OptlibParser(const char *name, const char *base,
215411fea497SMasatake YAMATO 									  subparserRunDirection direction)
21559f303cbfSMasatake YAMATO {
21569f303cbfSMasatake YAMATO 	parserDefinition *def;
21579f303cbfSMasatake YAMATO 
21589f303cbfSMasatake YAMATO 	def = parserNew (name);
21599f303cbfSMasatake YAMATO 	def->initialize        = lazyInitialize;
21609f303cbfSMasatake YAMATO 	def->method            = METHOD_NOT_CRAFTED;
2161beb5437bSMasatake YAMATO 	if (base)
2162beb5437bSMasatake YAMATO 	{
2163beb5437bSMasatake YAMATO 		subparser *sub = xCalloc (1, subparser);
2164beb5437bSMasatake YAMATO 		parserDependency *dep = xCalloc (1, parserDependency);
2165beb5437bSMasatake YAMATO 
216611fea497SMasatake YAMATO 		sub->direction = direction;
2167beb5437bSMasatake YAMATO 		dep->type = DEPTYPE_SUBPARSER;
2168beb5437bSMasatake YAMATO 		dep->upperParser = eStrdup (base);
2169beb5437bSMasatake YAMATO 		dep->data = sub;
2170beb5437bSMasatake YAMATO 		def->dependencies = dep;
2171beb5437bSMasatake YAMATO 		def->dependencyCount = 1;
2172beb5437bSMasatake YAMATO 		def->finalize = optlibFreeDep;
2173beb5437bSMasatake YAMATO 	}
21749f303cbfSMasatake YAMATO 
21759f303cbfSMasatake YAMATO 	return def;
21769f303cbfSMasatake YAMATO }
21779f303cbfSMasatake YAMATO 
processLanguageDefineOption(const char * const option,const char * const parameter)2178d4c6f1e6SMasatake YAMATO extern void processLanguageDefineOption (
217911fea497SMasatake YAMATO 		const char *const option, const char *const parameter)
2180d4c6f1e6SMasatake YAMATO {
21816144f58aSMasatake YAMATO 	char *name;
21826144f58aSMasatake YAMATO 	char *flags;
21836144f58aSMasatake YAMATO 	parserDefinition*  def;
21846144f58aSMasatake YAMATO 
21856144f58aSMasatake YAMATO 	flags = strchr (parameter, LONG_FLAGS_OPEN);
21866144f58aSMasatake YAMATO 	if (flags)
21876144f58aSMasatake YAMATO 		name = eStrndup (parameter, flags - parameter);
21886144f58aSMasatake YAMATO 	else
21896144f58aSMasatake YAMATO 		name = eStrdup (parameter);
21906144f58aSMasatake YAMATO 
21912ff65297SMasatake YAMATO 	/* Veirfy that the name of new language is acceptable or not. */
21920278c2a1SMasatake YAMATO 	char *unacceptable;
21932ff65297SMasatake YAMATO 	if (name [0] == '\0')
21942ff65297SMasatake YAMATO 	{
21952ff65297SMasatake YAMATO 		eFree (name);
21962ff65297SMasatake YAMATO 		error (FATAL, "No language specified for \"%s\" option", option);
21972ff65297SMasatake YAMATO 	}
21982ff65297SMasatake YAMATO 	else if (getNamedLanguage (name, 0) != LANG_IGNORE)
21992ce906a2SMasatake YAMATO 	{
22002ce906a2SMasatake YAMATO 		/* name cannot be freed because it is used in the FATAL message. */
22012ce906a2SMasatake YAMATO 		error (FATAL, "Language \"%s\" already defined", name);
22022ce906a2SMasatake YAMATO 	}
22032ff65297SMasatake YAMATO 	else if (strcmp(name, RSV_LANG_ALL) == 0)
22042ff65297SMasatake YAMATO 	{
22052ff65297SMasatake YAMATO 		eFree (name);
22062ff65297SMasatake YAMATO 		error (FATAL, "\"all\" is reserved; don't use it as the name for defining a new language");
22072ff65297SMasatake YAMATO 	}
22080278c2a1SMasatake YAMATO 	else if ((unacceptable = strpbrk (name, "!\"$%&'()*,-./:;<=>?@[\\]^`|~")))
22090278c2a1SMasatake YAMATO 	{
22100278c2a1SMasatake YAMATO 		char c = *unacceptable;
22110278c2a1SMasatake YAMATO 
22120278c2a1SMasatake YAMATO 		/* name cannot be freed because it is used in the FATAL message. */
22130278c2a1SMasatake YAMATO 		/* We accept '_'.
22140278c2a1SMasatake YAMATO 		 * We accept # and + because they are already used in C# parser and C++ parser.
22150278c2a1SMasatake YAMATO 		 * {... is already trimmed at the beginning of this function. */
22160278c2a1SMasatake YAMATO 		if ((c == '`') || (c == '\''))
22170278c2a1SMasatake YAMATO 			error (FATAL, "don't use \"%c\" in a language name (%s)", c, name);
22180278c2a1SMasatake YAMATO 		else
22190278c2a1SMasatake YAMATO 			error (FATAL, "don't use `%c' in a language name (%s)", c, name);
22200278c2a1SMasatake YAMATO 	}
22212ff65297SMasatake YAMATO 
22229f303cbfSMasatake YAMATO 	LanguageTable = xRealloc (LanguageTable, LanguageCount + 1, parserObject);
22239f303cbfSMasatake YAMATO 	memset (LanguageTable + LanguageCount, 0, sizeof(parserObject));
22249f303cbfSMasatake YAMATO 
222511fea497SMasatake YAMATO 	struct preLangDefFlagData data = {
222611fea497SMasatake YAMATO 		.base = NULL,
222711fea497SMasatake YAMATO 		.direction = SUBPARSER_UNKNOWN_DIRECTION,
2228225f14f2SMasatake YAMATO 		.autoFQTag = false,
222911fea497SMasatake YAMATO 	};
223011fea497SMasatake YAMATO 	flagsEval (flags, PreLangDefFlagDef, ARRAY_SIZE (PreLangDefFlagDef), &data);
2231beb5437bSMasatake YAMATO 
223211fea497SMasatake YAMATO 	if (data.base == NULL && data.direction != SUBPARSER_UNKNOWN_DIRECTION)
223311fea497SMasatake YAMATO 		error (WARNING, "Ignore the direction of subparser because \"{base=}\" is not given");
223411fea497SMasatake YAMATO 
223511fea497SMasatake YAMATO 	if (data.base && data.direction == SUBPARSER_UNKNOWN_DIRECTION)
223611fea497SMasatake YAMATO 		data.direction = SUBPARSER_BASE_RUNS_SUB;
223711fea497SMasatake YAMATO 
223811fea497SMasatake YAMATO 	def = OptlibParser (name, data.base, data.direction);
223911fea497SMasatake YAMATO 	if (data.base)
224011fea497SMasatake YAMATO 		eFree (data.base);
2241beb5437bSMasatake YAMATO 
2242225f14f2SMasatake YAMATO 	def->requestAutomaticFQTag = data.autoFQTag;
2243225f14f2SMasatake YAMATO 
22449f303cbfSMasatake YAMATO 	initializeParsingCommon (def, false);
2245beb5437bSMasatake YAMATO 	linkDependenciesAtInitializeParsing (def);
22469f303cbfSMasatake YAMATO 
22479f303cbfSMasatake YAMATO 	LanguageTable [def->id].currentPatterns = stringListNew ();
22489f303cbfSMasatake YAMATO 	LanguageTable [def->id].currentExtensions = stringListNew ();
2249f02166dcSMasatake YAMATO 	LanguageTable [def->id].pretendingAsLanguage = LANG_IGNORE;
2250f02166dcSMasatake YAMATO 	LanguageTable [def->id].pretendedAsLanguage = LANG_IGNORE;
22516144f58aSMasatake YAMATO 
22526144f58aSMasatake YAMATO 	eFree (name);
2253d4c6f1e6SMasatake YAMATO }
2254d4c6f1e6SMasatake YAMATO 
isLanguageKindEnabled(const langType language,int kindIndex)22555c56d939SMasatake YAMATO extern bool isLanguageKindEnabled (const langType language, int kindIndex)
2256ebd6043dSMasatake YAMATO {
22575a475eaeSMasatake YAMATO 	kindDefinition * kdef = getLanguageKind (language, kindIndex);
225853485acaSMasatake YAMATO 	return kdef->enabled;
225953485acaSMasatake YAMATO }
2260ebd6043dSMasatake YAMATO 
isLanguageRoleEnabled(const langType language,int kindIndex,int roleIndex)2261320b1e8bSMasatake YAMATO extern bool isLanguageRoleEnabled (const langType language, int kindIndex, int roleIndex)
2262320b1e8bSMasatake YAMATO {
2263320b1e8bSMasatake YAMATO 	return isRoleEnabled(LanguageTable [language].kindControlBlock,
2264320b1e8bSMasatake YAMATO 						 kindIndex, roleIndex);
2265320b1e8bSMasatake YAMATO }
2266320b1e8bSMasatake YAMATO 
isLanguageKindRefOnly(const langType language,int kindIndex)22679261585aSMasatake YAMATO extern bool isLanguageKindRefOnly (const langType language, int kindIndex)
22689261585aSMasatake YAMATO {
22699261585aSMasatake YAMATO 	kindDefinition * def =  getLanguageKind(language, kindIndex);
22709261585aSMasatake YAMATO 	return def->referenceOnly;
22719261585aSMasatake YAMATO }
22729261585aSMasatake YAMATO 
resetLanguageKinds(const langType language,const bool mode)2273ce990805SThomas Braun static void resetLanguageKinds (const langType language, const bool mode)
2274d4c6f1e6SMasatake YAMATO {
22757f1bb89cSMasatake YAMATO 	const parserObject* parser;
22767f1bb89cSMasatake YAMATO 
2277d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
22787f1bb89cSMasatake YAMATO 	parser = LanguageTable + language;
2279d4c6f1e6SMasatake YAMATO 
2280d4c6f1e6SMasatake YAMATO 	{
2281d4c6f1e6SMasatake YAMATO 		unsigned int i;
22827f1bb89cSMasatake YAMATO 		struct kindControlBlock *kcb = parser->kindControlBlock;
22837f1bb89cSMasatake YAMATO 
22847f1bb89cSMasatake YAMATO 		for (i = 0  ;  i < countKinds (kcb)  ;  ++i)
22857f1bb89cSMasatake YAMATO 		{
22867f1bb89cSMasatake YAMATO 			kindDefinition *kdef = getKind (kcb, i);
22877f1bb89cSMasatake YAMATO 			enableKind (kdef, mode);
22887f1bb89cSMasatake YAMATO 		}
2289d4c6f1e6SMasatake YAMATO 	}
2290d4c6f1e6SMasatake YAMATO }
2291d4c6f1e6SMasatake YAMATO 
enableLanguageKindForLetter(const langType language,const int kind,const bool mode)22924177f5aaSMasatake YAMATO static bool enableLanguageKindForLetter (
2293ce990805SThomas Braun 		const langType language, const int kind, const bool mode)
2294d4c6f1e6SMasatake YAMATO {
2295ce990805SThomas Braun 	bool result = false;
22964177f5aaSMasatake YAMATO 	kindDefinition* const def = getLanguageKindForLetter (language, kind);
229720aac2eeSMasatake YAMATO 	if (def != NULL)
2298d4c6f1e6SMasatake YAMATO 	{
229920aac2eeSMasatake YAMATO 		enableKind (def, mode);
2300ce990805SThomas Braun 		result = true;
2301d4c6f1e6SMasatake YAMATO 	}
2302d4c6f1e6SMasatake YAMATO 	return result;
2303d4c6f1e6SMasatake YAMATO }
2304d4c6f1e6SMasatake YAMATO 
enableLanguageKindForName(const langType language,const char * const name,const bool mode)2305c9dd5111SMasatake YAMATO static bool enableLanguageKindForName (
2306c9dd5111SMasatake YAMATO 	const langType language, const char * const name, const bool mode)
2307b77a0405SMasatake YAMATO {
2308ce990805SThomas Braun 	bool result = false;
2309c9dd5111SMasatake YAMATO 	kindDefinition* const def = getLanguageKindForName (language, name);
231020aac2eeSMasatake YAMATO 	if (def != NULL)
2311b77a0405SMasatake YAMATO 	{
231220aac2eeSMasatake YAMATO 		enableKind (def, mode);
2313ce990805SThomas Braun 		result = true;
2314b77a0405SMasatake YAMATO 	}
2315b77a0405SMasatake YAMATO 	return result;
2316b77a0405SMasatake YAMATO }
2317b77a0405SMasatake YAMATO 
processLangKindDefinition(const langType language,const char * const option,const char * const parameter)2318e112e8abSMasatake YAMATO static void processLangKindDefinition (
2319d4c6f1e6SMasatake YAMATO 		const langType language, const char *const option,
2320d4c6f1e6SMasatake YAMATO 		const char *const parameter)
2321d4c6f1e6SMasatake YAMATO {
2322d4c6f1e6SMasatake YAMATO 	const char *p = parameter;
2323ce990805SThomas Braun 	bool mode = true;
2324d4c6f1e6SMasatake YAMATO 	int c;
2325b77a0405SMasatake YAMATO 	static vString *longName;
2326ce990805SThomas Braun 	bool inLongName = false;
2327b77a0405SMasatake YAMATO 	const char *k;
2328ce990805SThomas Braun 	bool r;
2329d4c6f1e6SMasatake YAMATO 
2330d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
2331d4c6f1e6SMasatake YAMATO 
2332078b9679SMasatake YAMATO 	initializeParser (language);
2333d4c6f1e6SMasatake YAMATO 	if (*p == '*')
2334d4c6f1e6SMasatake YAMATO 	{
2335ce990805SThomas Braun 		resetLanguageKinds (language, true);
2336d4c6f1e6SMasatake YAMATO 		p++;
2337d4c6f1e6SMasatake YAMATO 	}
2338d4c6f1e6SMasatake YAMATO 	else if (*p != '+'  &&  *p != '-')
2339ce990805SThomas Braun 		resetLanguageKinds (language, false);
2340d4c6f1e6SMasatake YAMATO 
234156065e52SMasatake YAMATO 	longName = vStringNewOrClearWithAutoRelease (longName);
2342b77a0405SMasatake YAMATO 
2343b77a0405SMasatake YAMATO 	while ((c = *p++) != '\0')
2344d4c6f1e6SMasatake YAMATO 	{
2345b77a0405SMasatake YAMATO 		switch (c)
2346b77a0405SMasatake YAMATO 		{
2347b77a0405SMasatake YAMATO 		case '+':
2348b77a0405SMasatake YAMATO 			if (inLongName)
2349b77a0405SMasatake YAMATO 				vStringPut (longName, c);
2350b77a0405SMasatake YAMATO 			else
2351ce990805SThomas Braun 				mode = true;
2352b77a0405SMasatake YAMATO 			break;
2353b77a0405SMasatake YAMATO 		case '-':
2354b77a0405SMasatake YAMATO 			if (inLongName)
2355b77a0405SMasatake YAMATO 				vStringPut (longName, c);
2356b77a0405SMasatake YAMATO 			else
2357ce990805SThomas Braun 				mode = false;
2358b77a0405SMasatake YAMATO 			break;
2359b77a0405SMasatake YAMATO 		case '{':
2360b77a0405SMasatake YAMATO 			if (inLongName)
2361b77a0405SMasatake YAMATO 				error(FATAL,
2362b77a0405SMasatake YAMATO 				      "unexpected character in kind specification: \'%c\'",
2363b77a0405SMasatake YAMATO 				      c);
2364ce990805SThomas Braun 			inLongName = true;
2365b77a0405SMasatake YAMATO 			break;
2366b77a0405SMasatake YAMATO 		case '}':
2367b77a0405SMasatake YAMATO 			if (!inLongName)
2368b77a0405SMasatake YAMATO 				error(FATAL,
2369b77a0405SMasatake YAMATO 				      "unexpected character in kind specification: \'%c\'",
2370b77a0405SMasatake YAMATO 				      c);
2371b77a0405SMasatake YAMATO 			k = vStringValue (longName);
2372c9dd5111SMasatake YAMATO 			r = enableLanguageKindForName (language, k, mode);
2373b77a0405SMasatake YAMATO 			if (! r)
2374b77a0405SMasatake YAMATO 				error (WARNING, "Unsupported kind: '%s' for --%s option",
2375b77a0405SMasatake YAMATO 				       k, option);
2376b77a0405SMasatake YAMATO 
2377ce990805SThomas Braun 			inLongName = false;
2378b77a0405SMasatake YAMATO 			vStringClear (longName);
2379b77a0405SMasatake YAMATO 			break;
2380d4c6f1e6SMasatake YAMATO 		default:
2381b77a0405SMasatake YAMATO 			if (inLongName)
2382b77a0405SMasatake YAMATO 				vStringPut (longName, c);
2383b77a0405SMasatake YAMATO 			else
2384b77a0405SMasatake YAMATO 			{
23854177f5aaSMasatake YAMATO 				r = enableLanguageKindForLetter (language, c, mode);
2386b77a0405SMasatake YAMATO 				if (! r)
23871c4543c1SMasatake YAMATO 					error (WARNING, "Unsupported kind: '%c' for --%s option",
2388d4c6f1e6SMasatake YAMATO 					       c, option);
2389b77a0405SMasatake YAMATO 			}
2390d4c6f1e6SMasatake YAMATO 			break;
2391d4c6f1e6SMasatake YAMATO 		}
2392d4c6f1e6SMasatake YAMATO 	}
2393b77a0405SMasatake YAMATO }
2394d4c6f1e6SMasatake YAMATO 
freeKdef(kindDefinition * kdef)23953b7988cfSMasatake YAMATO static void freeKdef (kindDefinition *kdef)
23963b7988cfSMasatake YAMATO {
23973b7988cfSMasatake YAMATO 	eFree (kdef->name);
23983b7988cfSMasatake YAMATO 	eFree (kdef->description);
23993b7988cfSMasatake YAMATO 	eFree (kdef);
24003b7988cfSMasatake YAMATO }
24013b7988cfSMasatake YAMATO 
extractDescriptionAndFlags(const char * input,const char ** flags)2402f741fddfSMasatake YAMATO static char *extractDescriptionAndFlags(const char *input, const char **flags)
2403f741fddfSMasatake YAMATO {
2404f741fddfSMasatake YAMATO 	vString *vdesc = vStringNew();
2405f741fddfSMasatake YAMATO 	bool escaped = false;
2406f741fddfSMasatake YAMATO 
2407f741fddfSMasatake YAMATO 	if (flags)
2408f741fddfSMasatake YAMATO 		*flags = NULL;
2409f741fddfSMasatake YAMATO 
2410f741fddfSMasatake YAMATO 	while (*input != '\0')
2411f741fddfSMasatake YAMATO 	{
2412f741fddfSMasatake YAMATO 		if (escaped)
2413f741fddfSMasatake YAMATO 		{
2414f741fddfSMasatake YAMATO 			vStringPut (vdesc, *input);
2415f741fddfSMasatake YAMATO 			escaped = false;
2416f741fddfSMasatake YAMATO 
2417f741fddfSMasatake YAMATO 		}
2418f741fddfSMasatake YAMATO 		else if (*input == '\\')
2419f741fddfSMasatake YAMATO 			escaped = true;
2420f741fddfSMasatake YAMATO 		else if (*input == LONG_FLAGS_OPEN)
2421f741fddfSMasatake YAMATO 		{
2422f741fddfSMasatake YAMATO 			if (flags)
2423f741fddfSMasatake YAMATO 				*flags = input;
2424f741fddfSMasatake YAMATO 			break;
2425f741fddfSMasatake YAMATO 		}
2426f741fddfSMasatake YAMATO 		else
2427f741fddfSMasatake YAMATO 			vStringPut (vdesc, *input);
2428f741fddfSMasatake YAMATO 		input++;
2429f741fddfSMasatake YAMATO 	}
2430f741fddfSMasatake YAMATO 	return vStringDeleteUnwrap(vdesc);
2431f741fddfSMasatake YAMATO }
2432f741fddfSMasatake YAMATO 
pre_kind_def_flag_refonly_long(const char * const optflag,const char * const param,void * data)2433ba1453a4SMasatake YAMATO static void pre_kind_def_flag_refonly_long (const char* const optflag,
2434ba1453a4SMasatake YAMATO 											const char* const param, void* data)
2435ba1453a4SMasatake YAMATO {
2436ba1453a4SMasatake YAMATO 	kindDefinition *kdef = data;
2437ba1453a4SMasatake YAMATO 	kdef->referenceOnly = true;
2438ba1453a4SMasatake YAMATO }
2439ba1453a4SMasatake YAMATO 
2440ba1453a4SMasatake YAMATO static flagDefinition PreKindDefFlagDef [] = {
2441ba1453a4SMasatake YAMATO 	{ '\0', "_refonly", NULL, pre_kind_def_flag_refonly_long,
2442ba1453a4SMasatake YAMATO 	  NULL, "use this kind reference tags only"},
2443ba1453a4SMasatake YAMATO };
2444ba1453a4SMasatake YAMATO 
processLangDefineKind(const langType language,const char * const option,const char * const parameter)24453b7988cfSMasatake YAMATO static bool processLangDefineKind(const langType language,
24463b7988cfSMasatake YAMATO 								  const char *const option,
24473a6dd371SMasatake YAMATO 								  const char *const parameter)
24483b7988cfSMasatake YAMATO {
24493b7988cfSMasatake YAMATO 	parserObject *parser;
24503b7988cfSMasatake YAMATO 
24513b7988cfSMasatake YAMATO 	kindDefinition *kdef;
2452751c4167SMasatake YAMATO 	char letter;
24533a6dd371SMasatake YAMATO 	const char * p = parameter;
24543b7988cfSMasatake YAMATO 	char *name;
24553b7988cfSMasatake YAMATO 	char *description;
24562854ad6dSMasatake YAMATO 	const char *name_start;
24572854ad6dSMasatake YAMATO 	const char *marker_end;
24582854ad6dSMasatake YAMATO 	size_t name_len;
2459f741fddfSMasatake YAMATO 	const char *flags;
24603b7988cfSMasatake YAMATO 
24613b7988cfSMasatake YAMATO 
24623b7988cfSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
24633b7988cfSMasatake YAMATO 	parser = LanguageTable + language;
24643b7988cfSMasatake YAMATO 
24653b7988cfSMasatake YAMATO 	Assert (p);
24663b7988cfSMasatake YAMATO 
24673b7988cfSMasatake YAMATO 	if (p[0] == '\0')
24683b7988cfSMasatake YAMATO 		error (FATAL, "no kind definition specified in \"--%s\" option", option);
24693b7988cfSMasatake YAMATO 
2470751c4167SMasatake YAMATO 	letter = p[0];
24713b7988cfSMasatake YAMATO 	if (letter == ',')
24723b7988cfSMasatake YAMATO 		error (FATAL, "no kind letter specified in \"--%s\" option", option);
2473751c4167SMasatake YAMATO 	if (/* See #1697. isalnum expects 0~255 as the range of characters. */
2474751c4167SMasatake YAMATO 		!isalpha ((unsigned char)letter)
2475751c4167SMasatake YAMATO 		)
2476e0b5213bSMasatake YAMATO 		error (FATAL, "the kind letter given in \"--%s\" option is not an alphabet", option);
24777e1bd430SMasatake YAMATO 	else if (letter == KIND_FILE_DEFAULT_LETTER)
247847df83bdSMasatake YAMATO 		error (FATAL, "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind",
247947df83bdSMasatake YAMATO 			   KIND_FILE_DEFAULT_LETTER, option, KIND_FILE_DEFAULT_NAME);
24803b7988cfSMasatake YAMATO 	else if (getKindForLetter (parser->kindControlBlock, letter))
24813b7988cfSMasatake YAMATO 	{
24823b7988cfSMasatake YAMATO 		error (WARNING, "the kind for letter `%c' specified in \"--%s\" option is already defined.",
24833b7988cfSMasatake YAMATO 			   letter, option);
24843b7988cfSMasatake YAMATO 		return true;
24853b7988cfSMasatake YAMATO 	}
24863b7988cfSMasatake YAMATO 
24873b7988cfSMasatake YAMATO 	if (p[1] != ',')
24883b7988cfSMasatake YAMATO 		error (FATAL, "wrong kind definition in \"--%s\" option: no comma after letter", option);
24893b7988cfSMasatake YAMATO 
24903b7988cfSMasatake YAMATO 	p += 2;
24913b7988cfSMasatake YAMATO 	if (p[0] == '\0')
24923b7988cfSMasatake YAMATO 		error (FATAL, "no kind name specified in \"--%s\" option", option);
24932854ad6dSMasatake YAMATO 	marker_end = strchr (p, ',');
24942854ad6dSMasatake YAMATO 	if (!marker_end)
24953b7988cfSMasatake YAMATO 		error (FATAL, "no kind description specified in \"--%s\" option", option);
24963b7988cfSMasatake YAMATO 
24972854ad6dSMasatake YAMATO 	name_start = p;
24982854ad6dSMasatake YAMATO 	while (p != marker_end)
24992854ad6dSMasatake YAMATO 	{
25002854ad6dSMasatake YAMATO 		if (p == name_start)
25012854ad6dSMasatake YAMATO 		{
25022854ad6dSMasatake YAMATO 			if (!isalpha(*p))
25032854ad6dSMasatake YAMATO 			{
25042854ad6dSMasatake YAMATO 				char *name_in_msg = eStrndup (name_start, marker_end - name_start);
25052854ad6dSMasatake YAMATO 				error (FATAL,
25062854ad6dSMasatake YAMATO 					   "a kind name doesn't start with an alphabetical character: "
25072854ad6dSMasatake YAMATO 					   "'%s' in \"--%s\" option",
25082854ad6dSMasatake YAMATO 					   name_in_msg, option);
25092854ad6dSMasatake YAMATO 			}
25102854ad6dSMasatake YAMATO 		}
25112854ad6dSMasatake YAMATO 		else
25123b7988cfSMasatake YAMATO 		{
2513a2bda196SMasatake YAMATO 			if (!isalnum (*p))
25142854ad6dSMasatake YAMATO 			{
25152854ad6dSMasatake YAMATO 				char *name_in_msg = eStrndup (name_start, marker_end - name_start);
25162854ad6dSMasatake YAMATO 				error (FATAL,
25172854ad6dSMasatake YAMATO 					   "non-alphanumeric char is used as part of kind name: "
25182854ad6dSMasatake YAMATO 					   "'%s' in \"--%s\" option",
25192854ad6dSMasatake YAMATO 					   name_in_msg, option);
25202854ad6dSMasatake YAMATO 			}
25212854ad6dSMasatake YAMATO 		}
25223b7988cfSMasatake YAMATO 		p++;
25233b7988cfSMasatake YAMATO 	}
25243b7988cfSMasatake YAMATO 
25252854ad6dSMasatake YAMATO 	if (marker_end == name_start)
25263b7988cfSMasatake YAMATO 		error (FATAL, "the kind name in \"--%s\" option is empty", option);
25273b7988cfSMasatake YAMATO 
25282854ad6dSMasatake YAMATO 	name_len = marker_end - name_start;
25292854ad6dSMasatake YAMATO 	if (strncmp (name_start, KIND_FILE_DEFAULT_NAME, name_len) == 0)
25300f8ba855SMasatake YAMATO 		error (FATAL,
25317e1bd430SMasatake YAMATO 			   "the kind name " KIND_FILE_DEFAULT_NAME " in \"--%s\" option is reserved",
25320f8ba855SMasatake YAMATO 			   option);
25330f8ba855SMasatake YAMATO 
25342854ad6dSMasatake YAMATO 	name = eStrndup (name_start, name_len);
25353b7988cfSMasatake YAMATO 	if (getKindForName (parser->kindControlBlock, name))
25363b7988cfSMasatake YAMATO 	{
25373b7988cfSMasatake YAMATO 		error (WARNING, "the kind for name `%s' specified in \"--%s\" option is already defined.",
25383b7988cfSMasatake YAMATO 			   name, option);
25393b7988cfSMasatake YAMATO 		eFree (name);
25403b7988cfSMasatake YAMATO 		return true;
25413b7988cfSMasatake YAMATO 	}
25423b7988cfSMasatake YAMATO 
25433b7988cfSMasatake YAMATO 	p++;
254496b4483eSMasatake YAMATO 	if (p [0] == '\0' || p [0] == LONG_FLAGS_OPEN)
25453b7988cfSMasatake YAMATO 		error (FATAL, "found an empty kind description in \"--%s\" option", option);
254696b4483eSMasatake YAMATO 
2547f741fddfSMasatake YAMATO 	description = extractDescriptionAndFlags (p, &flags);
25483b7988cfSMasatake YAMATO 
25493b7988cfSMasatake YAMATO 	kdef = xCalloc (1, kindDefinition);
25503b7988cfSMasatake YAMATO 	kdef->enabled = true;
25513b7988cfSMasatake YAMATO 	kdef->letter = letter;
25523b7988cfSMasatake YAMATO 	kdef->name = name;
25533b7988cfSMasatake YAMATO 	kdef->description = description;
255496b4483eSMasatake YAMATO 	if (flags)
2555ba1453a4SMasatake YAMATO 		flagsEval (flags, PreKindDefFlagDef, ARRAY_SIZE (PreKindDefFlagDef), kdef);
25563b7988cfSMasatake YAMATO 
25573b7988cfSMasatake YAMATO 	defineKind (parser->kindControlBlock, kdef, freeKdef);
25583b7988cfSMasatake YAMATO 	return true;
25593b7988cfSMasatake YAMATO }
25603b7988cfSMasatake YAMATO 
freeRdef(roleDefinition * rdef)25617adc9db2SMasatake YAMATO static void freeRdef (roleDefinition *rdef)
25627adc9db2SMasatake YAMATO {
25637adc9db2SMasatake YAMATO 	eFree (rdef->name);
25647adc9db2SMasatake YAMATO 	eFree (rdef->description);
25657adc9db2SMasatake YAMATO 	eFree (rdef);
25667adc9db2SMasatake YAMATO }
25677adc9db2SMasatake YAMATO 
processLangDefineRole(const langType language,const char * const kindSpec,const char * const option,const char * const parameter)25687adc9db2SMasatake YAMATO static bool processLangDefineRole(const langType language,
256997d2a121SMasatake YAMATO 								  const char *const kindSpec,
25707adc9db2SMasatake YAMATO 								  const char *const option,
25713a6dd371SMasatake YAMATO 								  const char *const parameter)
25727adc9db2SMasatake YAMATO {
25737adc9db2SMasatake YAMATO 	parserObject *parser;
25747adc9db2SMasatake YAMATO 
25757adc9db2SMasatake YAMATO 	kindDefinition *kdef;
25767adc9db2SMasatake YAMATO 	roleDefinition *rdef;
25777adc9db2SMasatake YAMATO 	char *name;
25787adc9db2SMasatake YAMATO 	char *description;
25797adc9db2SMasatake YAMATO 
25807adc9db2SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
258197d2a121SMasatake YAMATO 	Assert (parameter);
258297d2a121SMasatake YAMATO 
25837adc9db2SMasatake YAMATO 	parser = LanguageTable + language;
25847adc9db2SMasatake YAMATO 
258597d2a121SMasatake YAMATO 	if (*kindSpec == '{')
258697d2a121SMasatake YAMATO 	{
258797d2a121SMasatake YAMATO 		const char *end = strchr (kindSpec, '}');
258897d2a121SMasatake YAMATO 		if (end == NULL)
258997d2a121SMasatake YAMATO 			error (FATAL, "no '}' representing the end of kind name in --%s option: %s",
259097d2a121SMasatake YAMATO 				   option, kindSpec);
259197d2a121SMasatake YAMATO 		if (*(end + 1) != '\0')
259297d2a121SMasatake YAMATO 			error (FATAL, "garbage after the kind specification %s in --%s option",
259397d2a121SMasatake YAMATO 				   kindSpec, option);
259497d2a121SMasatake YAMATO 		char *kindName = eStrndup (kindSpec + 1, end - (kindSpec + 1));
259597d2a121SMasatake YAMATO 		if (strcmp (kindName, KIND_FILE_DEFAULT_NAME) == 0)
259697d2a121SMasatake YAMATO 			error (FATAL, "don't define a role for %c/%s kind; it has no role: --%s",
259797d2a121SMasatake YAMATO 				   KIND_FILE_DEFAULT_LETTER, KIND_FILE_DEFAULT_NAME,
259897d2a121SMasatake YAMATO 				   option);
259997d2a121SMasatake YAMATO 		kdef = getKindForName (parser->kindControlBlock, kindName);
260097d2a121SMasatake YAMATO 		if (kdef == NULL)
260197d2a121SMasatake YAMATO 			error (FATAL, "the kind for name `%s' specified in \"--%s\" option is not defined.",
260297d2a121SMasatake YAMATO 				   kindName, option);
260397d2a121SMasatake YAMATO 		eFree (kindName);
260497d2a121SMasatake YAMATO 	}
260597d2a121SMasatake YAMATO 	else
260697d2a121SMasatake YAMATO 	{
260797d2a121SMasatake YAMATO 		char kletter = *kindSpec;
2608751c4167SMasatake YAMATO 		if (!isalnum ((unsigned char)kletter))
2609bb61d62dSMasatake YAMATO 			error (FATAL, "the kind letter given in \"--%s\" option is not an alphabet or a number", option);
26107e1bd430SMasatake YAMATO 		else if (kletter == KIND_FILE_DEFAULT_LETTER)
261197d2a121SMasatake YAMATO 			error (FATAL, "the kind letter `%c' in \"--%s\" option is reserved for \"%s\" kind, and no role can be attached to it",
261297d2a121SMasatake YAMATO 				   KIND_FILE_DEFAULT_LETTER, option, KIND_FILE_DEFAULT_NAME);
261397d2a121SMasatake YAMATO 		else if (*(kindSpec + 1) != '\0')
261497d2a121SMasatake YAMATO 			error (FATAL, "more than one letters are specified as a kind spec in \"--%s\" option: use `{' and `}' for specifying a kind name",
261597d2a121SMasatake YAMATO 				   option);
26167adc9db2SMasatake YAMATO 
26177adc9db2SMasatake YAMATO 		kdef = getKindForLetter (parser->kindControlBlock, kletter);
26187adc9db2SMasatake YAMATO 		if (kdef == NULL)
26197adc9db2SMasatake YAMATO 		{
262097d2a121SMasatake YAMATO 			error (FATAL, "the kind for letter `%c' specified in \"--%s\" option is not defined.",
262197d2a121SMasatake YAMATO 				   *kindSpec, option);
26227adc9db2SMasatake YAMATO 			return true;
26237adc9db2SMasatake YAMATO 		}
262497d2a121SMasatake YAMATO 	}
26257adc9db2SMasatake YAMATO 
262697d2a121SMasatake YAMATO 	const char * p = parameter;
262797d2a121SMasatake YAMATO 	const char *tmp_end = strchr (p, ',');
26287adc9db2SMasatake YAMATO 	if (!tmp_end)
26297adc9db2SMasatake YAMATO 		error (FATAL, "no role description specified in \"--%s\" option", option);
26307adc9db2SMasatake YAMATO 
263197d2a121SMasatake YAMATO 	const char * tmp_start = p;
26327adc9db2SMasatake YAMATO 	while (p != tmp_end)
26337adc9db2SMasatake YAMATO 	{
26347adc9db2SMasatake YAMATO 		if (!isalnum (*p))
2635af6edb60SMasatake YAMATO 			error (FATAL, "unacceptable char as part of role name in \"--%s\" option: %c",
2636af6edb60SMasatake YAMATO 				   option, *p);
26377adc9db2SMasatake YAMATO 		p++;
26387adc9db2SMasatake YAMATO 	}
26397adc9db2SMasatake YAMATO 
26407adc9db2SMasatake YAMATO 	if (tmp_end == tmp_start)
26417adc9db2SMasatake YAMATO 		error (FATAL, "the role name in \"--%s\" option is empty", option);
26427adc9db2SMasatake YAMATO 
26437adc9db2SMasatake YAMATO 	name = eStrndup (tmp_start, tmp_end - tmp_start);
26447adc9db2SMasatake YAMATO 	if (getRoleForName (parser->kindControlBlock, kdef->id, name))
26457adc9db2SMasatake YAMATO 	{
26467adc9db2SMasatake YAMATO 		error (WARNING, "the role for name `%s' specified in \"--%s\" option is already defined.",
26477adc9db2SMasatake YAMATO 			   name, option);
26487adc9db2SMasatake YAMATO 		eFree (name);
26497adc9db2SMasatake YAMATO 		return true;
26507adc9db2SMasatake YAMATO 	}
26517adc9db2SMasatake YAMATO 
26527adc9db2SMasatake YAMATO 	p++;
26537adc9db2SMasatake YAMATO 	if (p [0] == '\0' || p [0] == LONG_FLAGS_OPEN)
26547adc9db2SMasatake YAMATO 		error (FATAL, "found an empty role description in \"--%s\" option", option);
26557adc9db2SMasatake YAMATO 
265697d2a121SMasatake YAMATO 	const char *flags;
26577adc9db2SMasatake YAMATO 	description = extractDescriptionAndFlags (p, &flags);
26587adc9db2SMasatake YAMATO 
26597adc9db2SMasatake YAMATO 	rdef = xCalloc (1, roleDefinition);
26607adc9db2SMasatake YAMATO 	rdef->enabled = true;
26617adc9db2SMasatake YAMATO 	rdef->name = name;
26627adc9db2SMasatake YAMATO 	rdef->description = description;
26637adc9db2SMasatake YAMATO 
26647adc9db2SMasatake YAMATO 	if (flags)
26657adc9db2SMasatake YAMATO 		flagsEval (flags, NULL, 0, rdef);
26667adc9db2SMasatake YAMATO 
26677adc9db2SMasatake YAMATO 	defineRole (parser->kindControlBlock, kdef->id, rdef, freeRdef);
26687adc9db2SMasatake YAMATO 
26697adc9db2SMasatake YAMATO 	return true;
26707adc9db2SMasatake YAMATO }
26717adc9db2SMasatake YAMATO 
processKinddefOption(const char * const option,const char * const parameter)267218dab48bSMasatake YAMATO extern bool processKinddefOption (const char *const option, const char * const parameter)
26733b7988cfSMasatake YAMATO {
26743b7988cfSMasatake YAMATO 	langType language;
26753b7988cfSMasatake YAMATO 
26763b7988cfSMasatake YAMATO 	language = getLanguageComponentInOption (option, "kinddef-");
26773b7988cfSMasatake YAMATO 	if (language == LANG_IGNORE)
26783b7988cfSMasatake YAMATO 		return false;
26793b7988cfSMasatake YAMATO 
26803b7988cfSMasatake YAMATO 	return processLangDefineKind (language, option, parameter);
26813b7988cfSMasatake YAMATO }
26823b7988cfSMasatake YAMATO 
processRoledefOption(const char * const option,const char * const parameter)26837adc9db2SMasatake YAMATO extern bool processRoledefOption (const char *const option, const char * const parameter)
26847adc9db2SMasatake YAMATO {
268597d2a121SMasatake YAMATO #define PREFIX "_roledef-"
268697d2a121SMasatake YAMATO #define PREFIX_LEN strlen(PREFIX)
26877adc9db2SMasatake YAMATO 
268897d2a121SMasatake YAMATO 	langType language = getLanguageComponentInOption (option, PREFIX);
26897adc9db2SMasatake YAMATO 	if (language == LANG_IGNORE)
26907adc9db2SMasatake YAMATO 		return false;
26917adc9db2SMasatake YAMATO 
269297d2a121SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
269397d2a121SMasatake YAMATO 	const char* kindSpec = option + PREFIX_LEN + strlen (getLanguageName (language));
269497d2a121SMasatake YAMATO 	if (*kindSpec == '\0')
269597d2a121SMasatake YAMATO 		error (FATAL, "no kind is specifined in \"--%s=%s\"", option, parameter);
269697d2a121SMasatake YAMATO 	if (*kindSpec != '.')
269797d2a121SMasatake YAMATO 		error (FATAL, "no delimiter (.) where a kindspec starts is found in \"--%s\": %c",
269897d2a121SMasatake YAMATO 			   option, *kindSpec);
269997d2a121SMasatake YAMATO 	kindSpec++;
270097d2a121SMasatake YAMATO 
270197d2a121SMasatake YAMATO 	return processLangDefineRole (language, kindSpec, option, parameter);
270297d2a121SMasatake YAMATO #undef PREFIX
270397d2a121SMasatake YAMATO #undef PREFIX_LEN
27047adc9db2SMasatake YAMATO }
27057adc9db2SMasatake YAMATO 
2706e112e8abSMasatake YAMATO struct langKindDefinitionStruct {
2707d4c6f1e6SMasatake YAMATO 	const char *const option;
2708d4c6f1e6SMasatake YAMATO 	const char *const parameter;
2709d4c6f1e6SMasatake YAMATO };
processLangKindDefinitionEach(langType lang,void * user_data)2710e112e8abSMasatake YAMATO static void processLangKindDefinitionEach(
2711d4c6f1e6SMasatake YAMATO 	langType lang, void* user_data)
2712d4c6f1e6SMasatake YAMATO {
2713e112e8abSMasatake YAMATO 	struct langKindDefinitionStruct *arg = user_data;
2714e112e8abSMasatake YAMATO 	processLangKindDefinition (lang, arg->option, arg->parameter);
2715d4c6f1e6SMasatake YAMATO }
2716d4c6f1e6SMasatake YAMATO 
parameterEnablingAllOrFileKind(const char * const option,const char * const parameter,bool following_plus_or_minus_op)27177edb8484SMasatake YAMATO static bool parameterEnablingAllOrFileKind (const char *const option,
27187edb8484SMasatake YAMATO 											const char *const parameter,
27197edb8484SMasatake YAMATO 											bool following_plus_or_minus_op)
27207edb8484SMasatake YAMATO {
27217edb8484SMasatake YAMATO 	size_t file_long_flag_len = strlen(KIND_FILE_DEFAULT_NAME);
27227edb8484SMasatake YAMATO 
27237edb8484SMasatake YAMATO 	switch (parameter[0])
27247edb8484SMasatake YAMATO 	{
27257edb8484SMasatake YAMATO 	/* Though only '*' is documented as an acceptable kind spec for
27267edb8484SMasatake YAMATO 	 * --kinds-all option in our man page, we accept '\0' here because
27277edb8484SMasatake YAMATO 	 * it will be useful for testing purpose. */
27287edb8484SMasatake YAMATO 	case '\0':
27297edb8484SMasatake YAMATO 		if (following_plus_or_minus_op)
27307edb8484SMasatake YAMATO 			error(FATAL, "no kind specification after + (or -) in --%s option",
27317edb8484SMasatake YAMATO 				  option);
27327edb8484SMasatake YAMATO 		else
27337edb8484SMasatake YAMATO 			return true;
27347edb8484SMasatake YAMATO 	case '+':
27357edb8484SMasatake YAMATO 	case '-':
27367edb8484SMasatake YAMATO 		if (following_plus_or_minus_op)
27377edb8484SMasatake YAMATO 			error(FATAL, "don't repeat + (nor -) in --%s option",
27387edb8484SMasatake YAMATO 				  option);
27397edb8484SMasatake YAMATO 		else
27407edb8484SMasatake YAMATO 			return parameterEnablingAllOrFileKind (option, parameter + 1, true);
27417edb8484SMasatake YAMATO 	case KIND_WILDCARD_LETTER:
27427edb8484SMasatake YAMATO 		if (following_plus_or_minus_op)
27437edb8484SMasatake YAMATO 			error(FATAL, "don't use '*' after + (nor -) in --%s option",
27447edb8484SMasatake YAMATO 				  option);
27457edb8484SMasatake YAMATO 		else
27467edb8484SMasatake YAMATO 			return parameterEnablingAllOrFileKind (option, parameter + 1, false);
27477edb8484SMasatake YAMATO 	case KIND_FILE_DEFAULT_LETTER:
27487edb8484SMasatake YAMATO 		return parameterEnablingAllOrFileKind (option, parameter + 1, false);
27497edb8484SMasatake YAMATO 	case '{':
27507edb8484SMasatake YAMATO 		if (strncmp (parameter + 1, KIND_FILE_DEFAULT_NAME, file_long_flag_len) == 0
27517edb8484SMasatake YAMATO 			&& parameter [1 + file_long_flag_len] == '}')
27527edb8484SMasatake YAMATO 			return parameterEnablingAllOrFileKind (option,
27537edb8484SMasatake YAMATO 												   parameter + 1 + file_long_flag_len + 1,
27547edb8484SMasatake YAMATO 												   false);
27557edb8484SMasatake YAMATO 		break;
27567edb8484SMasatake YAMATO 	}
27577edb8484SMasatake YAMATO 	return false;
27587edb8484SMasatake YAMATO }
27597edb8484SMasatake YAMATO 
processKindsOption(const char * const option,const char * const parameter)276018dab48bSMasatake YAMATO extern bool processKindsOption (
2761d4c6f1e6SMasatake YAMATO 		const char *const option, const char *const parameter)
2762d4c6f1e6SMasatake YAMATO {
276343586520SMasatake YAMATO #define PREFIX "kinds-"
276443586520SMasatake YAMATO #define PREFIX_LEN strlen(PREFIX)
2765d4c6f1e6SMasatake YAMATO 
2766ce990805SThomas Braun 	bool handled = false;
2767e112e8abSMasatake YAMATO 	struct langKindDefinitionStruct arg = {
2768d4c6f1e6SMasatake YAMATO 		.option = option,
2769d4c6f1e6SMasatake YAMATO 		.parameter = parameter,
2770d4c6f1e6SMasatake YAMATO 	};
277143586520SMasatake YAMATO 	langType language;
2772d4c6f1e6SMasatake YAMATO 
277343586520SMasatake YAMATO 	const char* const dash = strchr (option, '-');
277443586520SMasatake YAMATO 	if (dash != NULL  &&
277543586520SMasatake YAMATO 		(strcmp (dash + 1, "kinds") == 0  ||  strcmp (dash + 1, "types") == 0))
277643586520SMasatake YAMATO 	{
277743586520SMasatake YAMATO 		size_t len = dash - option;
2778a7c5f3b5SMasatake YAMATO 		char *langName = eStrndup (option, len);
277943586520SMasatake YAMATO 
2780a7c5f3b5SMasatake YAMATO 		if ((len == 3) && (strcmp (langName, RSV_LANG_ALL) == 0))
27811295de21SMasatake YAMATO 		{
2782a7c5f3b5SMasatake YAMATO 			error (WARNING,
2783a7c5f3b5SMasatake YAMATO 				   "\"--%s\" option is obsolete; use \"--kinds-%s\" instead",
2784a7c5f3b5SMasatake YAMATO 				   option, langName);
27857edb8484SMasatake YAMATO 			if (!parameterEnablingAllOrFileKind (option, parameter, false))
27867edb8484SMasatake YAMATO 				error (FATAL, "only '*', 'F', \"{file}\" or their combination is acceptable as kind letter for --%s", option);
2787e112e8abSMasatake YAMATO 			foreachLanguage(processLangKindDefinitionEach, &arg);
27881295de21SMasatake YAMATO 		}
2789d4c6f1e6SMasatake YAMATO 		else
2790d4c6f1e6SMasatake YAMATO 		{
2791a7c5f3b5SMasatake YAMATO 			language = getNamedLanguage (langName, 0);
2792d4c6f1e6SMasatake YAMATO 			if (language == LANG_IGNORE)
27937d35e3d4SMasatake YAMATO 				error (WARNING, "Unknown language \"%s\" in \"%s\" option", langName, option);
2794d4c6f1e6SMasatake YAMATO 			else
2795e112e8abSMasatake YAMATO 				processLangKindDefinition (language, option, parameter);
2796d4c6f1e6SMasatake YAMATO 		}
2797a7c5f3b5SMasatake YAMATO 		eFree (langName);
2798ce990805SThomas Braun 		handled = true;
2799d4c6f1e6SMasatake YAMATO 	}
280043586520SMasatake YAMATO 	else if ( strncmp (option, PREFIX, PREFIX_LEN) == 0 )
280143586520SMasatake YAMATO 	{
280243586520SMasatake YAMATO 		const char* lang;
280343586520SMasatake YAMATO 
280443586520SMasatake YAMATO 		lang = option + PREFIX_LEN;
2805a1f18f64SMasatake YAMATO 		if (lang[0] == '\0')
280643586520SMasatake YAMATO 			error (WARNING, "No language given in \"%s\" option", option);
2807a1f18f64SMasatake YAMATO 		else if (strcmp (lang, RSV_LANG_ALL) == 0)
28081295de21SMasatake YAMATO 		{
28097edb8484SMasatake YAMATO 			if (!parameterEnablingAllOrFileKind (option, parameter, false))
28107edb8484SMasatake YAMATO 				error (FATAL, "only '*', 'F', \"{file}\" or their combination is acceptable as kind letter for --%s", option);
2811e112e8abSMasatake YAMATO 			foreachLanguage(processLangKindDefinitionEach, &arg);
28121295de21SMasatake YAMATO 		}
281343586520SMasatake YAMATO 		else
281443586520SMasatake YAMATO 		{
28155a55f03bSMasatake YAMATO 			language = getNamedLanguage (lang, 0);
281643586520SMasatake YAMATO 			if (language == LANG_IGNORE)
281743586520SMasatake YAMATO 				error (WARNING, "Unknown language \"%s\" in \"%s\" option", lang, option);
281843586520SMasatake YAMATO 			else
2819e112e8abSMasatake YAMATO 				processLangKindDefinition (language, option, parameter);
28201d4e02b7SMasatake YAMATO 		}
2821ce990805SThomas Braun 		handled = true;
282243586520SMasatake YAMATO 	}
2823d4c6f1e6SMasatake YAMATO 	return handled;
282443586520SMasatake YAMATO #undef PREFIX
282543586520SMasatake YAMATO #undef PREFIX_LEN
2826d4c6f1e6SMasatake YAMATO }
2827d4c6f1e6SMasatake YAMATO 
2828d2842001SMasatake YAMATO /*
2829d2842001SMasatake YAMATO  * The argument specification for --roles-<LANG>:<KIND>= option
2830d2842001SMasatake YAMATO  * =====================================================================
2831d2842001SMasatake YAMATO  *
2832d2842001SMasatake YAMATO  * --roles-all.*=
2833d2842001SMasatake YAMATO  * --roles-all=
2834d2842001SMasatake YAMATO  * => Disable all roles of all kinds in all languages.
2835d2842001SMasatake YAMATO  *
2836d2842001SMasatake YAMATO  * --roles-all.*='*'
2837d2842001SMasatake YAMATO  * --roles-all='*'
2838d2842001SMasatake YAMATO  * => Enable all roles of all kinds in all languages.
2839d2842001SMasatake YAMATO  *
2840d2842001SMasatake YAMATO  * --roles-<LANG>.*=
2841d2842001SMasatake YAMATO  * --roles-<LANG>=
2842d2842001SMasatake YAMATO  * => Disable all roles of all kinds.
2843d2842001SMasatake YAMATO  *
2844d2842001SMasatake YAMATO  * --roles-<LANG>.*=*
2845d2842001SMasatake YAMATO  * --roles-<LANG>=*
2846d2842001SMasatake YAMATO  * => Enable all roles of all kinds.
2847d2842001SMasatake YAMATO  *
2848d2842001SMasatake YAMATO  * --roles-<LANG>.{kind}=
2849d2842001SMasatake YAMATO  * --roles-<LANG>.k=
2850d2842001SMasatake YAMATO  * => Disable all roles of the kind specified with a letter.
2851d2842001SMasatake YAMATO  *
2852d2842001SMasatake YAMATO  * --roles-<LANG>.{kind}=*
2853d2842001SMasatake YAMATO  * --roles-<LANG>.k=*
2854d2842001SMasatake YAMATO  * => Enable all roles of the kind specified with a letter.
2855d2842001SMasatake YAMATO  *
2856d2842001SMasatake YAMATO  * --roles-<LANG>.{kind}=[+|-]{role}
2857d2842001SMasatake YAMATO  * --roles-<LANG>.k=[+|-]{role}
2858d2842001SMasatake YAMATO  * => Enable/disable the role of the kind specified with a letter.
2859d2842001SMasatake YAMATO  *
2860d2842001SMasatake YAMATO  *
2861d2842001SMasatake YAMATO  * Examples of combination
2862d2842001SMasatake YAMATO  * ---------------------------------------------------------------------
2863d2842001SMasatake YAMATO  *
2864d2842001SMasatake YAMATO  * --roles-<LANG>.k0=+{role0}-{role1}{role2}
2865d2842001SMasatake YAMATO  * --roles-<LANG>.{kind1}=+{role0}-{role1}{role2}
2866d2842001SMasatake YAMATO  *
2867d2842001SMasatake YAMATO  *
286857a18729SMasatake YAMATO  * How --roledef should be change to align --roles-<LANG> notation
2869d2842001SMasatake YAMATO  * ---------------------------------------------------------------------
2870d2842001SMasatake YAMATO  *
2871d2842001SMasatake YAMATO  * --_roledef-<LANG>.k=role,description
2872d2842001SMasatake YAMATO  * --_roledef-<LANG>.{kind}=role,description
2873d2842001SMasatake YAMATO  *
2874d2842001SMasatake YAMATO  * The notation was
2875d2842001SMasatake YAMATO  *  --_roledef-<LANG>=k.role,description
2876d2842001SMasatake YAMATO  *
2877d2842001SMasatake YAMATO  *
287857a18729SMasatake YAMATO  * How --param should be change to align --roles-<LANG> notation
2879d2842001SMasatake YAMATO  * ---------------------------------------------------------------------
2880d2842001SMasatake YAMATO  *
28818114f7b3SMasatake YAMATO  * --param-<LANG>.name=argument
2882d2842001SMasatake YAMATO  *
28834c5decb0SMasatake YAMATO  * The notation was
28848114f7b3SMasatake YAMATO  * --param-<LANG>:name=argument
2885d2842001SMasatake YAMATO  *
2886d2842001SMasatake YAMATO  *
288757a18729SMasatake YAMATO  * How --paramdef should be to align --roles-<LANG> notation
2888d2842001SMasatake YAMATO  * ---------------------------------------------------------------------
2889d2842001SMasatake YAMATO  *
2890d2842001SMasatake YAMATO  * --_paramdef-<LANG>.name=[ default (desription) ]
2891d2842001SMasatake YAMATO  *
2892d2842001SMasatake YAMATO  *
2893d2842001SMasatake YAMATO  * Discussion: which shoule we use . or : ?
2894d2842001SMasatake YAMATO  * ---------------------------------------------------------------------
2895d2842001SMasatake YAMATO  *
2896d2842001SMasatake YAMATO  * `.' is better because `:' implies fields.
2897d2842001SMasatake YAMATO  *
2898d2842001SMasatake YAMATO  */
2899d2842001SMasatake YAMATO struct langKindRoleDefinitionStruct {
2900d2842001SMasatake YAMATO 	int kindIndex;
2901d2842001SMasatake YAMATO 	const char *const option;
2902d2842001SMasatake YAMATO 	const char *const parameter;
2903d2842001SMasatake YAMATO };
2904d2842001SMasatake YAMATO 
2905d2842001SMasatake YAMATO typedef void (*kindCallback)  (langType language, int kindIndex, void* user_data);
foreachKind(langType language,kindCallback callback,void * user_data)2906d2842001SMasatake YAMATO static void foreachKind(langType language, kindCallback callback, void *user_data)
2907d2842001SMasatake YAMATO {
2908d2842001SMasatake YAMATO 	unsigned int c = countLanguageKinds (language);
2909d2842001SMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
2910d2842001SMasatake YAMATO 		callback (language, (int)i, user_data);
2911d2842001SMasatake YAMATO }
2912d2842001SMasatake YAMATO 
resetKindRoles(const langType language,int kindIndex,const bool mode)2913d2842001SMasatake YAMATO static void resetKindRoles (const langType language, int kindIndex, const bool mode)
2914d2842001SMasatake YAMATO {
2915d2842001SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
2916d2842001SMasatake YAMATO 	unsigned int c = countLanguageRoles (language, kindIndex);
2917d2842001SMasatake YAMATO 
2918d2842001SMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
2919d2842001SMasatake YAMATO 	{
2920d2842001SMasatake YAMATO 		roleDefinition* rdef = getLanguageRole (language, kindIndex, (int)i);
2921d2842001SMasatake YAMATO 		enableRole (rdef, mode);
2922d2842001SMasatake YAMATO 	}
2923d2842001SMasatake YAMATO }
2924d2842001SMasatake YAMATO 
resetKindRolesAsCallback(const langType language,int kindIndex,void * user_data)2925d2842001SMasatake YAMATO static void resetKindRolesAsCallback (const langType language, int kindIndex, void *user_data)
2926d2842001SMasatake YAMATO {
2927d2842001SMasatake YAMATO 	bool mode = (bool)user_data;
2928d2842001SMasatake YAMATO 	resetKindRoles (language, kindIndex, mode);
2929d2842001SMasatake YAMATO }
2930d2842001SMasatake YAMATO 
processLangKindRoleDefinition(const langType language,const int kindIndex,const char * const option,const char * const parameter)2931d2842001SMasatake YAMATO static void processLangKindRoleDefinition (
2932d2842001SMasatake YAMATO 		const langType language, const int kindIndex, const char *const option,
2933d2842001SMasatake YAMATO 		const char *const parameter)
2934d2842001SMasatake YAMATO {
2935d2842001SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
2936d2842001SMasatake YAMATO 	Assert (kindIndex != KIND_GHOST_INDEX);
2937d2842001SMasatake YAMATO 	initializeParser (language);
2938d2842001SMasatake YAMATO 
2939d2842001SMasatake YAMATO 	const char *p = parameter;
2940d2842001SMasatake YAMATO 	bool mode = true;
2941d2842001SMasatake YAMATO 
2942d2842001SMasatake YAMATO 	if (*p == '\0')
2943d2842001SMasatake YAMATO 	{
2944d2842001SMasatake YAMATO 		resetKindRoles (language, kindIndex, false);
2945d2842001SMasatake YAMATO 		return;
2946d2842001SMasatake YAMATO 	}
2947d2842001SMasatake YAMATO 	else if (*p != '+' && *p != '-' )
2948d2842001SMasatake YAMATO 		resetKindRoles (language, kindIndex, false);
2949d2842001SMasatake YAMATO 
2950d2842001SMasatake YAMATO 	while (*p != '\0')
2951d2842001SMasatake YAMATO 	{
2952d2842001SMasatake YAMATO 		if (*p == '+')
2953d2842001SMasatake YAMATO 		{
2954d2842001SMasatake YAMATO 			mode = true;
2955d2842001SMasatake YAMATO 			p++;
2956d2842001SMasatake YAMATO 		}
2957d2842001SMasatake YAMATO 		else if (*p == '-')
2958d2842001SMasatake YAMATO 		{
2959d2842001SMasatake YAMATO 			mode = false;
2960d2842001SMasatake YAMATO 			p++;
2961d2842001SMasatake YAMATO 		}
2962d2842001SMasatake YAMATO 		else if (*p == '{')
2963d2842001SMasatake YAMATO 		{
2964d2842001SMasatake YAMATO 			p++;
2965d2842001SMasatake YAMATO 			char *q = strchr (p, '}');
2966d2842001SMasatake YAMATO 			if (!q)
2967d2842001SMasatake YAMATO 
2968d2842001SMasatake YAMATO 				error (FATAL, "no '}' representing the end of role name in --%s option: %s",
2969d2842001SMasatake YAMATO 					   option, p);
2970d2842001SMasatake YAMATO 			if (p == q)
2971d2842001SMasatake YAMATO 				error (FATAL, "empty role for the kind letter: %c",
2972d2842001SMasatake YAMATO 					   getLanguageKind (language, kindIndex)->letter);
2973d2842001SMasatake YAMATO 
2974d2842001SMasatake YAMATO 			char *rname = eStrndup (p,  q - p);
2975d2842001SMasatake YAMATO 			roleDefinition *rdef = getLanguageRoleForName (language, kindIndex, rname);
2976d2842001SMasatake YAMATO 			if (!rdef)
2977d2842001SMasatake YAMATO 				error (WARNING, "no such role: %s of %c kind in language %s",
2978d2842001SMasatake YAMATO 					   rname, getLanguageKind (language, kindIndex)->letter,
2979d2842001SMasatake YAMATO 					   getLanguageName (language));
2980d2842001SMasatake YAMATO 			else
2981d2842001SMasatake YAMATO 				enableRole (rdef, mode);
2982d2842001SMasatake YAMATO 			eFree (rname);
2983d2842001SMasatake YAMATO 			p = q + 1;
2984d2842001SMasatake YAMATO 		}
2985d2842001SMasatake YAMATO 		else if (*p == '*')
2986d2842001SMasatake YAMATO 		{
2987d2842001SMasatake YAMATO 			resetKindRoles (language, kindIndex, true);
2988d2842001SMasatake YAMATO 			p++;
2989d2842001SMasatake YAMATO 		}
2990d2842001SMasatake YAMATO 		else
2991d2842001SMasatake YAMATO 			error (FATAL, "unexpected character %c in --%s=%s option",
2992d2842001SMasatake YAMATO 				   *p, option, parameter);
2993d2842001SMasatake YAMATO 	}
2994d2842001SMasatake YAMATO }
2995d2842001SMasatake YAMATO 
processLangKindRoleDefinitionEach(langType language,void * user_data)2996d2842001SMasatake YAMATO static void processLangKindRoleDefinitionEach (langType language, void* user_data)
2997d2842001SMasatake YAMATO {
2998d2842001SMasatake YAMATO 	struct langKindRoleDefinitionStruct *arg = user_data;
2999d2842001SMasatake YAMATO 
3000d2842001SMasatake YAMATO 	if (arg->kindIndex == KIND_GHOST_INDEX)
3001d2842001SMasatake YAMATO 	{
3002d2842001SMasatake YAMATO 		initializeParser (language);
3003d2842001SMasatake YAMATO 		foreachKind (language, resetKindRolesAsCallback,
3004d2842001SMasatake YAMATO 					 ((*(arg->parameter) == '*')? (void *)true: (void *)false));
3005d2842001SMasatake YAMATO 	}
3006d2842001SMasatake YAMATO 	else
3007d2842001SMasatake YAMATO 		processLangKindRoleDefinition (language, arg->kindIndex,
3008d2842001SMasatake YAMATO 									   arg->option, arg->parameter);
3009d2842001SMasatake YAMATO }
3010d2842001SMasatake YAMATO 
processRolesOption(const char * const option,const char * const parameter)3011d2842001SMasatake YAMATO extern bool processRolesOption (const char *const option, const char *const parameter)
3012d2842001SMasatake YAMATO {
3013d2842001SMasatake YAMATO #define PREFIX "roles-"
3014d2842001SMasatake YAMATO #define PREFIX_LEN strlen(PREFIX)
3015d2842001SMasatake YAMATO 
3016d2842001SMasatake YAMATO 	if ( strncmp (option, PREFIX, PREFIX_LEN) != 0 )
3017d2842001SMasatake YAMATO 		return false;
3018d2842001SMasatake YAMATO 
3019d2842001SMasatake YAMATO 	const char* lang = option + PREFIX_LEN;
3020d2842001SMasatake YAMATO 	if (lang[0] == '\0')
3021d2842001SMasatake YAMATO 	{
3022d2842001SMasatake YAMATO 		error (WARNING, "no language given in \"%s\" option", option);
3023d2842001SMasatake YAMATO 		return true;
3024d2842001SMasatake YAMATO 	}
3025d2842001SMasatake YAMATO 
3026d2842001SMasatake YAMATO 	/*
3027d2842001SMasatake YAMATO 	 * --roles-all.*=
3028d2842001SMasatake YAMATO 	 * --roles-all=
3029d2842001SMasatake YAMATO 	 * => Disable all roles of all kinds in all languages.
3030d2842001SMasatake YAMATO 	 *
3031d2842001SMasatake YAMATO 	 * --roles-all.*='*'
3032d2842001SMasatake YAMATO 	 * --roles-all='*'
3033d2842001SMasatake YAMATO 	 * => Enable all roles of all kinds in all languages.
3034d2842001SMasatake YAMATO 	 */
3035d2842001SMasatake YAMATO 	if (strncmp (lang, RSV_LANG_ALL, strlen(RSV_LANG_ALL)) == 0)
3036d2842001SMasatake YAMATO 	{
3037d2842001SMasatake YAMATO 		if (lang [strlen (RSV_LANG_ALL)] == '\0'
3038d2842001SMasatake YAMATO 			|| (strcmp (lang + strlen (RSV_LANG_ALL), ".*") == 0))
3039d2842001SMasatake YAMATO 		{
3040d2842001SMasatake YAMATO 			if (*parameter == '\0'
3041d2842001SMasatake YAMATO 				|| strcmp(parameter, "*") == 0)
3042d2842001SMasatake YAMATO 			{
3043d2842001SMasatake YAMATO 				struct langKindRoleDefinitionStruct arg = {
3044d2842001SMasatake YAMATO 					.kindIndex = KIND_GHOST_INDEX,
3045d2842001SMasatake YAMATO 					.option = option,
3046d2842001SMasatake YAMATO 					.parameter = parameter,
3047d2842001SMasatake YAMATO 				};
3048d2842001SMasatake YAMATO 				foreachLanguage (processLangKindRoleDefinitionEach, &arg);
3049d2842001SMasatake YAMATO 				return true;
3050d2842001SMasatake YAMATO 			}
3051d2842001SMasatake YAMATO 			else
3052d2842001SMasatake YAMATO 				error (FATAL, "only '*' or '' (empty string) is acceptable as an argument for --%s: %s",
3053d2842001SMasatake YAMATO 					   option,
3054d2842001SMasatake YAMATO 					   parameter);
3055d2842001SMasatake YAMATO 		}
3056d2842001SMasatake YAMATO 		else if (lang [strlen(RSV_LANG_ALL)] == '.')
3057d2842001SMasatake YAMATO 			error (FATAL, "only '*' or '' (empty string) is acceptable as a kind spec for --%sall: --%s",
3058d2842001SMasatake YAMATO 				   PREFIX,
3059d2842001SMasatake YAMATO 				   option);
3060d2842001SMasatake YAMATO 	}
3061d2842001SMasatake YAMATO 
3062d2842001SMasatake YAMATO 	/* Decide the language. */
3063d2842001SMasatake YAMATO 	langType language;
3064d2842001SMasatake YAMATO 	const char *dot = strchr (lang, '.');
3065d2842001SMasatake YAMATO 	if (dot)
3066d2842001SMasatake YAMATO 		language = getNamedLanguage (lang, dot - lang);
3067d2842001SMasatake YAMATO 	else
3068d2842001SMasatake YAMATO 		language = getNamedLanguage (lang, 0);
3069d2842001SMasatake YAMATO 
3070d2842001SMasatake YAMATO 	if (language == LANG_IGNORE)
3071d2842001SMasatake YAMATO 	{
3072d2842001SMasatake YAMATO 		char *lang0 = dot? eStrndup (lang, dot - lang): NULL;
3073d2842001SMasatake YAMATO 		error (WARNING, "unknown language \"%s\" in --%s option",
3074d2842001SMasatake YAMATO 			   (lang0? lang0: lang), option);
3075d2842001SMasatake YAMATO 		if (lang0)
3076d2842001SMasatake YAMATO 			eFree (lang0);
3077d2842001SMasatake YAMATO 		return true;
3078d2842001SMasatake YAMATO 	}
3079d2842001SMasatake YAMATO 
3080d2842001SMasatake YAMATO 	/*
3081d2842001SMasatake YAMATO 	 * --roles-<LANG>.*=
3082d2842001SMasatake YAMATO 	 * --roles-<LANG>=
3083d2842001SMasatake YAMATO 	 * => Disable all roles of all kinds.
3084d2842001SMasatake YAMATO 	 *
3085d2842001SMasatake YAMATO 	 * --roles-<LANG>.*=*
3086d2842001SMasatake YAMATO 	 * --roles-<LANG>=*
3087d2842001SMasatake YAMATO 	 * => Enable all roles of all kinds.
3088d2842001SMasatake YAMATO 	 */
3089d2842001SMasatake YAMATO 	if (dot == NULL || (strcmp (dot, ".*") == 0))
3090d2842001SMasatake YAMATO 	{
3091d2842001SMasatake YAMATO 		if (*parameter == '\0'
3092d2842001SMasatake YAMATO 			|| strcmp(parameter, "*") == 0)
3093d2842001SMasatake YAMATO 		{
3094d2842001SMasatake YAMATO 			foreachKind (language, resetKindRolesAsCallback,
3095d2842001SMasatake YAMATO 						 ((*parameter == '*')? (void*)true: (void*)false));
3096d2842001SMasatake YAMATO 			return true;
3097d2842001SMasatake YAMATO 		}
3098d2842001SMasatake YAMATO 		else
3099d2842001SMasatake YAMATO 			error (FATAL, "only '*' or '' (empty string) is acceptable as an argument for --%s: %s",
3100d2842001SMasatake YAMATO 				   option,
3101d2842001SMasatake YAMATO 				   parameter);
3102d2842001SMasatake YAMATO 	}
3103d2842001SMasatake YAMATO 
3104d2842001SMasatake YAMATO 	/* Decide the kind of the language. */
3105d2842001SMasatake YAMATO 	parserObject *parser = LanguageTable + language;
3106d2842001SMasatake YAMATO 	int kindIndex = KIND_GHOST_INDEX;
3107d2842001SMasatake YAMATO 	const char *kind = dot + 1;
3108d2842001SMasatake YAMATO 	if (*kind == '{')
3109d2842001SMasatake YAMATO 	{
3110d2842001SMasatake YAMATO 		const char *name_end = strchr (kind, '}');
3111d2842001SMasatake YAMATO 		if (name_end == NULL)
3112d2842001SMasatake YAMATO 			error (FATAL, "no '}' representing the end of kind name in --%s option: %s",
3113d2842001SMasatake YAMATO 				   option, kind);
3114d2842001SMasatake YAMATO 		char *kindName = eStrndup (kind + 1, name_end - (kind + 1));
3115d2842001SMasatake YAMATO 		if (strcmp (kindName, KIND_FILE_DEFAULT_NAME) == 0)
3116d2842001SMasatake YAMATO 		{
311747df83bdSMasatake YAMATO 			error (WARNING, "don't enable/disable a role in %c/%s kind; it has no role: --%s",
311847df83bdSMasatake YAMATO 				   KIND_FILE_DEFAULT_LETTER, KIND_FILE_DEFAULT_NAME,
3119d2842001SMasatake YAMATO 				   option);
3120d2842001SMasatake YAMATO 			return true;
3121d2842001SMasatake YAMATO 		}
3122d2842001SMasatake YAMATO 		kindIndex = getKindIndexForName (parser->kindControlBlock, kindName);
3123d2842001SMasatake YAMATO 		if (kindIndex == KIND_GHOST_INDEX)
3124d2842001SMasatake YAMATO 		{
3125d2842001SMasatake YAMATO 			eFree (kindName);
3126d2842001SMasatake YAMATO 			error (WARNING, "no such kind name as specified in --%s option", option);
3127d2842001SMasatake YAMATO 			return true;
3128d2842001SMasatake YAMATO 		}
3129d2842001SMasatake YAMATO 		if (*(name_end + 1) != '\0')
3130d2842001SMasatake YAMATO 			error (FATAL, "garbage after the kind specification {%s} in --%s option",
3131d2842001SMasatake YAMATO 				   kindName, option);
3132d2842001SMasatake YAMATO 		eFree (kindName);
3133d2842001SMasatake YAMATO 	}
3134d2842001SMasatake YAMATO 	else if (isalpha ((unsigned char)*kind))
3135d2842001SMasatake YAMATO 	{
3136d2842001SMasatake YAMATO 		if (*kind == KIND_FILE_DEFAULT_LETTER)
3137d2842001SMasatake YAMATO 		{
313847df83bdSMasatake YAMATO 			error (WARNING, "don't enable/disable a role in %c/%s kind; it has no role: --%s",
313947df83bdSMasatake YAMATO 				   KIND_FILE_DEFAULT_LETTER, KIND_FILE_DEFAULT_NAME,
3140d2842001SMasatake YAMATO 				   option);
3141d2842001SMasatake YAMATO 			return true;
3142d2842001SMasatake YAMATO 		}
3143d2842001SMasatake YAMATO 		kindIndex = getKindIndexForLetter (parser->kindControlBlock, *kind);
3144d2842001SMasatake YAMATO 		if (kindIndex == KIND_GHOST_INDEX)
3145d2842001SMasatake YAMATO 		{
3146d2842001SMasatake YAMATO 			error (WARNING, "no such kind letter as specified in --%s option", option);
3147d2842001SMasatake YAMATO 			return true;
3148d2842001SMasatake YAMATO 		}
3149d2842001SMasatake YAMATO 		if (*(kind + 1) != '\0')
3150d2842001SMasatake YAMATO 			error (FATAL, "garbage after the kind specification '%c' in --%s option",
3151d2842001SMasatake YAMATO 				   *kind, option);
3152d2842001SMasatake YAMATO 	}
3153d2842001SMasatake YAMATO 	else
3154d2842001SMasatake YAMATO 		error (FATAL, "'%c', unexpected character in --%s", *kind, option);
3155d2842001SMasatake YAMATO 
3156d2842001SMasatake YAMATO 
3157d2842001SMasatake YAMATO 	/*
3158d2842001SMasatake YAMATO 	 * --roles-<LANG>.{kind}=
3159d2842001SMasatake YAMATO 	 * --roles-<LANG>.k=
3160d2842001SMasatake YAMATO 	 * => Disable all roles of the kind specified with a letter.
3161d2842001SMasatake YAMATO 	 *
3162d2842001SMasatake YAMATO 	 * --roles-<LANG>.{kind}=*
3163d2842001SMasatake YAMATO 	 * --roles-<LANG>.k=*
3164d2842001SMasatake YAMATO 	 * => Enable all roles of the kind specified with a letter.
3165d2842001SMasatake YAMATO 	 *
3166d2842001SMasatake YAMATO 	 * --roles-<LANG>.{kind}=[+|-|]{role}
3167d2842001SMasatake YAMATO 	 * --roles-<LANG>.k=[+|-|]{role}
3168d2842001SMasatake YAMATO 	 * => Enable/disable the role of the kind specified with a letter.
3169d2842001SMasatake YAMATO 	 */
3170d2842001SMasatake YAMATO 	processLangKindRoleDefinition (language, kindIndex, option, parameter);
3171d2842001SMasatake YAMATO 
3172d2842001SMasatake YAMATO 	return true;
3173d2842001SMasatake YAMATO #undef PREFIX
3174d2842001SMasatake YAMATO #undef PREFIX_LEN
3175d2842001SMasatake YAMATO }
3176d2842001SMasatake YAMATO 
printLanguageRoles(const langType language,const char * kindspecs,bool withListHeader,bool machinable,FILE * fp)31776348dd8fSMasatake YAMATO extern void printLanguageRoles (const langType language, const char* kindspecs,
3178489f37b8SMasatake YAMATO 								bool withListHeader, bool machinable, FILE *fp)
3179575c9c6cSMasatake YAMATO {
3180489f37b8SMasatake YAMATO 	struct colprintTable *table = roleColprintTableNew();
3181489f37b8SMasatake YAMATO 	parserObject *parser;
3182575c9c6cSMasatake YAMATO 
3183489f37b8SMasatake YAMATO 	initializeParser (language);
3184471cbca7SMasatake YAMATO 
3185575c9c6cSMasatake YAMATO 	if (language == LANG_AUTO)
3186575c9c6cSMasatake YAMATO 	{
3187489f37b8SMasatake YAMATO 		for (unsigned int i = 0  ;  i < LanguageCount  ;  ++i)
3188489f37b8SMasatake YAMATO 		{
3189489f37b8SMasatake YAMATO 			if (!isLanguageVisible (i))
3190489f37b8SMasatake YAMATO 				continue;
3191489f37b8SMasatake YAMATO 
3192489f37b8SMasatake YAMATO 			parser = LanguageTable + i;
31936348dd8fSMasatake YAMATO 			roleColprintAddRoles (table, parser->kindControlBlock, kindspecs);
3194489f37b8SMasatake YAMATO 		}
3195575c9c6cSMasatake YAMATO 	}
3196575c9c6cSMasatake YAMATO 	else
3197489f37b8SMasatake YAMATO 	{
3198489f37b8SMasatake YAMATO 		parser = LanguageTable + language;
31996348dd8fSMasatake YAMATO 		roleColprintAddRoles (table, parser->kindControlBlock, kindspecs);
3200489f37b8SMasatake YAMATO 	}
3201575c9c6cSMasatake YAMATO 
3202489f37b8SMasatake YAMATO 	roleColprintTablePrint (table, (language != LANG_AUTO),
3203489f37b8SMasatake YAMATO 							withListHeader, machinable, fp);
3204489f37b8SMasatake YAMATO 	colprintTableDelete (table);
3205575c9c6cSMasatake YAMATO }
3206575c9c6cSMasatake YAMATO 
printKinds(langType language,bool indent,struct colprintTable * table)32079601d44cSMasatake YAMATO static void printKinds (langType language, bool indent,
32089601d44cSMasatake YAMATO 						struct colprintTable * table)
3209d4c6f1e6SMasatake YAMATO {
3210384186fcSMasatake YAMATO 	const parserObject *parser;
3211384186fcSMasatake YAMATO 	struct kindControlBlock *kcb;
3212d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3213078b9679SMasatake YAMATO 
3214078b9679SMasatake YAMATO 	initializeParser (language);
3215384186fcSMasatake YAMATO 	parser = LanguageTable + language;
3216384186fcSMasatake YAMATO 	kcb = parser->kindControlBlock;
3217384186fcSMasatake YAMATO 
32189601d44cSMasatake YAMATO 	if (table)
32199601d44cSMasatake YAMATO 		kindColprintAddLanguageLines (table, kcb);
32209601d44cSMasatake YAMATO 	else
322121d6a459SMasatake YAMATO 	{
32229601d44cSMasatake YAMATO 		for (unsigned int i = 0  ;  i < countKinds(kcb)  ;  ++i)
32239601d44cSMasatake YAMATO 			printKind (getKind(kcb, i), indent);
322421d6a459SMasatake YAMATO 	}
3225d4c6f1e6SMasatake YAMATO }
3226d4c6f1e6SMasatake YAMATO 
printLanguageKinds(const langType language,bool allKindFields,bool withListHeader,bool machinable,FILE * fp)3227a2dce47aSMasatake YAMATO extern void printLanguageKinds (const langType language, bool allKindFields,
3228a2dce47aSMasatake YAMATO 								bool withListHeader, bool machinable, FILE *fp)
3229d4c6f1e6SMasatake YAMATO {
32309601d44cSMasatake YAMATO 	struct colprintTable * table = NULL;
32319601d44cSMasatake YAMATO 
32329601d44cSMasatake YAMATO 	if (allKindFields)
32339601d44cSMasatake YAMATO 		table = kindColprintTableNew ();
32349601d44cSMasatake YAMATO 
3235d4c6f1e6SMasatake YAMATO 	if (language == LANG_AUTO)
3236d4c6f1e6SMasatake YAMATO 	{
32379601d44cSMasatake YAMATO 		for (unsigned int i = 0  ;  i < LanguageCount  ;  ++i)
3238d4c6f1e6SMasatake YAMATO 		{
3239e02be843SMasatake YAMATO 			const parserDefinition* const lang = LanguageTable [i].def;
324021d6a459SMasatake YAMATO 
3241632163c2SMasatake YAMATO 			if (lang->invisible)
3242632163c2SMasatake YAMATO 				continue;
3243632163c2SMasatake YAMATO 
32449601d44cSMasatake YAMATO 			if (!table)
3245362fa008SMasatake YAMATO 				printf ("%s%s\n", lang->name, isLanguageEnabled (i) ? "" : " [disabled]");
32469601d44cSMasatake YAMATO 			printKinds (i, true, table);
3247d4c6f1e6SMasatake YAMATO 		}
3248d4c6f1e6SMasatake YAMATO 	}
3249d4c6f1e6SMasatake YAMATO 	else
32509601d44cSMasatake YAMATO 		printKinds (language, false, table);
3251908570b8SMasatake YAMATO 
32529601d44cSMasatake YAMATO 	if (allKindFields)
32539601d44cSMasatake YAMATO 	{
32549601d44cSMasatake YAMATO 		kindColprintTablePrint(table, (language == LANG_AUTO)? 0: 1,
3255a2dce47aSMasatake YAMATO 							   withListHeader, machinable, fp);
32569601d44cSMasatake YAMATO 		colprintTableDelete (table);
3257d4c6f1e6SMasatake YAMATO 	}
3258908570b8SMasatake YAMATO }
3259d4c6f1e6SMasatake YAMATO 
printParameters(struct colprintTable * table,langType language)3260813a10c0SMasatake YAMATO static void printParameters (struct colprintTable *table, langType language)
32613671b1d2SMasatake YAMATO {
32623671b1d2SMasatake YAMATO 	const parserDefinition* lang;
32633671b1d2SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
32643671b1d2SMasatake YAMATO 
32653671b1d2SMasatake YAMATO 	initializeParser (language);
3266e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
32673671b1d2SMasatake YAMATO 	if (lang->parameterHandlerTable != NULL)
32683671b1d2SMasatake YAMATO 	{
3269813a10c0SMasatake YAMATO 		for (unsigned int i = 0; i < lang->parameterHandlerCount; ++i)
3270813a10c0SMasatake YAMATO 			paramColprintAddParameter(table, language, lang->parameterHandlerTable + i);
3271813a10c0SMasatake YAMATO 	}
32723671b1d2SMasatake YAMATO 
3273813a10c0SMasatake YAMATO }
3274813a10c0SMasatake YAMATO 
printLanguageParameters(const langType language,bool withListHeader,bool machinable,FILE * fp)3275813a10c0SMasatake YAMATO extern void printLanguageParameters (const langType language,
3276813a10c0SMasatake YAMATO 									 bool withListHeader, bool machinable, FILE *fp)
32773671b1d2SMasatake YAMATO {
3278813a10c0SMasatake YAMATO 	struct colprintTable *table =  paramColprintTableNew();
32793671b1d2SMasatake YAMATO 
32803671b1d2SMasatake YAMATO 	if (language == LANG_AUTO)
32813671b1d2SMasatake YAMATO 	{
3282813a10c0SMasatake YAMATO 		for (unsigned int i = 0; i < LanguageCount ; ++i)
32833671b1d2SMasatake YAMATO 		{
3284e02be843SMasatake YAMATO 			const parserDefinition* const lang = LanguageTable [i].def;
32853671b1d2SMasatake YAMATO 
32863671b1d2SMasatake YAMATO 			if (lang->invisible)
32873671b1d2SMasatake YAMATO 				continue;
3288813a10c0SMasatake YAMATO 
3289813a10c0SMasatake YAMATO 			printParameters (table, i);
32903671b1d2SMasatake YAMATO 		}
32913671b1d2SMasatake YAMATO 	}
32923671b1d2SMasatake YAMATO 	else
3293813a10c0SMasatake YAMATO 		printParameters (table, language);
32943671b1d2SMasatake YAMATO 
3295813a10c0SMasatake YAMATO 	paramColprintTablePrint (table, (language != LANG_AUTO),
3296813a10c0SMasatake YAMATO 							 withListHeader, machinable, fp);
3297813a10c0SMasatake YAMATO 	colprintTableDelete (table);
32983671b1d2SMasatake YAMATO }
32993671b1d2SMasatake YAMATO 
processLangAliasOption(const langType language,const char * const parameter)3300322bc4faSMasatake YAMATO static void processLangAliasOption (const langType language,
3301d4c6f1e6SMasatake YAMATO 				    const char *const parameter)
3302d4c6f1e6SMasatake YAMATO {
3303d4c6f1e6SMasatake YAMATO 	const char* alias;
3304efe089d4SMasatake YAMATO 	const parserObject * parser;
3305d4c6f1e6SMasatake YAMATO 
3306d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3307efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
3308d4c6f1e6SMasatake YAMATO 
3309f3f2d137SMasatake YAMATO 	if (parameter[0] == '\0')
3310f3f2d137SMasatake YAMATO 	{
3311f3f2d137SMasatake YAMATO 		clearLanguageAliases (language);
3312aed717c1SMasatake YAMATO 		verbose ("clear aliases for %s\n", parser->def->name);
3313aed717c1SMasatake YAMATO 	}
3314aed717c1SMasatake YAMATO 	else if (strcmp (parameter, RSV_LANGMAP_DEFAULT) == 0)
3315aed717c1SMasatake YAMATO 	{
3316aed717c1SMasatake YAMATO 		installLanguageAliasesDefault (language);
3317aed717c1SMasatake YAMATO 		verbose ("reset aliases for %s\n", parser->def->name);
3318f3f2d137SMasatake YAMATO 	}
3319f3f2d137SMasatake YAMATO 	else if (parameter[0] == '+')
3320d4c6f1e6SMasatake YAMATO 	{
3321d4c6f1e6SMasatake YAMATO 		alias = parameter + 1;
3322d4c6f1e6SMasatake YAMATO 		addLanguageAlias(language, alias);
3323aed717c1SMasatake YAMATO 		verbose ("add an alias %s to %s\n", alias, parser->def->name);
3324d4c6f1e6SMasatake YAMATO 	}
3325d4c6f1e6SMasatake YAMATO 	else if (parameter[0] == '-')
3326d4c6f1e6SMasatake YAMATO 	{
3327efe089d4SMasatake YAMATO 		if (parser->currentAliases)
3328d4c6f1e6SMasatake YAMATO 		{
3329d4c6f1e6SMasatake YAMATO 			alias = parameter + 1;
3330efe089d4SMasatake YAMATO 			if (stringListDeleteItemExtension (parser->currentAliases, alias))
3331d4c6f1e6SMasatake YAMATO 			{
3332aed717c1SMasatake YAMATO 				verbose ("remove an alias %s from %s\n", alias, parser->def->name);
3333d4c6f1e6SMasatake YAMATO 			}
3334d4c6f1e6SMasatake YAMATO 		}
3335d4c6f1e6SMasatake YAMATO 	}
3336d4c6f1e6SMasatake YAMATO 	else
3337d4c6f1e6SMasatake YAMATO 	{
3338d4c6f1e6SMasatake YAMATO 		alias = parameter;
3339d4c6f1e6SMasatake YAMATO 		clearLanguageAliases (language);
3340d4c6f1e6SMasatake YAMATO 		addLanguageAlias(language, alias);
3341efe089d4SMasatake YAMATO 		verbose ("set alias %s to %s\n", alias, parser->def->name);
3342d4c6f1e6SMasatake YAMATO 	}
3343d4c6f1e6SMasatake YAMATO 
3344d4c6f1e6SMasatake YAMATO }
3345d4c6f1e6SMasatake YAMATO 
processAliasOption(const char * const option,const char * const parameter)3346ce990805SThomas Braun extern bool processAliasOption (
3347d4c6f1e6SMasatake YAMATO 		const char *const option, const char *const parameter)
3348d4c6f1e6SMasatake YAMATO {
3349d4c6f1e6SMasatake YAMATO 	langType language;
3350d4c6f1e6SMasatake YAMATO 
3351a18efdb7SMasatake YAMATO 	Assert (parameter);
3352a18efdb7SMasatake YAMATO 
3353a18efdb7SMasatake YAMATO #define PREFIX "alias-"
3354a18efdb7SMasatake YAMATO 	if (strcmp (option, "alias-" RSV_LANG_ALL) == 0)
3355a18efdb7SMasatake YAMATO 	{
3356a18efdb7SMasatake YAMATO 		if ((parameter[0] == '\0')
3357a18efdb7SMasatake YAMATO 			|| (strcmp (parameter, RSV_LANGMAP_DEFAULT) == 0))
3358a18efdb7SMasatake YAMATO 		{
3359a18efdb7SMasatake YAMATO 			for (unsigned int i = 0; i < LanguageCount; i++)
3360a18efdb7SMasatake YAMATO 			{
3361a18efdb7SMasatake YAMATO 				clearLanguageAliases (i);
3362a18efdb7SMasatake YAMATO 				verbose ("clear aliases for %s\n", getLanguageName(i));
3363a18efdb7SMasatake YAMATO 			}
3364a18efdb7SMasatake YAMATO 
3365a18efdb7SMasatake YAMATO 			if (parameter[0] != '\0')
3366a18efdb7SMasatake YAMATO 			{
3367a18efdb7SMasatake YAMATO 				verbose ("  Installing default language aliases:\n");
3368a18efdb7SMasatake YAMATO 				installLanguageAliasesDefaults ();
3369a18efdb7SMasatake YAMATO 			}
3370a18efdb7SMasatake YAMATO 		}
3371a18efdb7SMasatake YAMATO 		else
3372a18efdb7SMasatake YAMATO 		{
3373a18efdb7SMasatake YAMATO 			error (WARNING, "Use \"%s\" option for reset (\"default\") or clearing (\"\")", option);
3374a18efdb7SMasatake YAMATO 			return false;
3375a18efdb7SMasatake YAMATO 		}
3376a18efdb7SMasatake YAMATO 		return true;
3377a18efdb7SMasatake YAMATO 	}
3378a18efdb7SMasatake YAMATO 
3379d4ee22f1SMasatake YAMATO 	language = getLanguageComponentInOption (option, "alias-");
3380d4c6f1e6SMasatake YAMATO 	if (language == LANG_IGNORE)
3381ce990805SThomas Braun 		return false;
3382a18efdb7SMasatake YAMATO #undef PREFIX
3383d4c6f1e6SMasatake YAMATO 
3384322bc4faSMasatake YAMATO 	processLangAliasOption (language, parameter);
3385ce990805SThomas Braun 	return true;
3386d4c6f1e6SMasatake YAMATO }
3387d4c6f1e6SMasatake YAMATO 
printMaps(const langType language,langmapType type)338859204b36SMasatake YAMATO static void printMaps (const langType language, langmapType type)
3389d4c6f1e6SMasatake YAMATO {
3390efe089d4SMasatake YAMATO 	const parserObject* parser;
3391d4c6f1e6SMasatake YAMATO 	unsigned int i;
3392e57a5ca2SMasatake YAMATO 
3393efe089d4SMasatake YAMATO 	parser = LanguageTable + language;
3394efe089d4SMasatake YAMATO 	printf ("%-8s", parser->def->name);
3395efe089d4SMasatake YAMATO 	if (parser->currentPatterns != NULL && (type & LMAP_PATTERN))
3396efe089d4SMasatake YAMATO 		for (i = 0  ;  i < stringListCount (parser->currentPatterns)  ;  ++i)
3397d4c6f1e6SMasatake YAMATO 			printf (" %s", vStringValue (
3398efe089d4SMasatake YAMATO 						stringListItem (parser->currentPatterns, i)));
3399922d4048SMasatake YAMATO 	if (parser->currentExtensions != NULL && (type & LMAP_EXTENSION))
3400922d4048SMasatake YAMATO 		for (i = 0  ;  i < stringListCount (parser->currentExtensions)  ;  ++i)
3401922d4048SMasatake YAMATO 			printf (" *.%s", vStringValue (
3402922d4048SMasatake YAMATO 						stringListItem (parser->currentExtensions, i)));
3403d4c6f1e6SMasatake YAMATO 	putchar ('\n');
3404d4c6f1e6SMasatake YAMATO }
3405d4c6f1e6SMasatake YAMATO 
mapColprintTableNew(langmapType type)3406e57a5ca2SMasatake YAMATO static struct colprintTable *mapColprintTableNew (langmapType type)
3407d4c6f1e6SMasatake YAMATO {
3408e57a5ca2SMasatake YAMATO 	if ((type & LMAP_ALL) == LMAP_ALL)
3409e57a5ca2SMasatake YAMATO 		return colprintTableNew ("L:LANGUAGE", "L:TYPE", "L:MAP", NULL);
3410e57a5ca2SMasatake YAMATO 	else if (type & LMAP_PATTERN)
3411e57a5ca2SMasatake YAMATO 		return colprintTableNew ("L:LANGUAGE", "L:PATTERN", NULL);
3412e57a5ca2SMasatake YAMATO 	else if (type & LMAP_EXTENSION)
3413e57a5ca2SMasatake YAMATO 		return colprintTableNew ("L:LANGUAGE", "L:EXTENSION", NULL);
3414e57a5ca2SMasatake YAMATO 	else
3415e57a5ca2SMasatake YAMATO 	{
3416e57a5ca2SMasatake YAMATO 		AssertNotReached ();
3417e57a5ca2SMasatake YAMATO 		return NULL;
3418e57a5ca2SMasatake YAMATO 	}
3419d4c6f1e6SMasatake YAMATO }
3420d4c6f1e6SMasatake YAMATO 
mapColprintAddLanguage(struct colprintTable * table,langmapType type,const parserObject * parser)3421e57a5ca2SMasatake YAMATO static void mapColprintAddLanguage (struct colprintTable * table,
3422e57a5ca2SMasatake YAMATO 									langmapType type,
3423e57a5ca2SMasatake YAMATO 									const parserObject* parser)
3424d4c6f1e6SMasatake YAMATO {
3425e57a5ca2SMasatake YAMATO 	struct colprintLine * line;
3426e57a5ca2SMasatake YAMATO 	unsigned int count;
3427e57a5ca2SMasatake YAMATO 	unsigned int i;
3428e57a5ca2SMasatake YAMATO 
3429e57a5ca2SMasatake YAMATO 	if ((type & LMAP_PATTERN) && (0 < (count = stringListCount (parser->currentPatterns))))
3430e57a5ca2SMasatake YAMATO 	{
3431e57a5ca2SMasatake YAMATO 		for (i = 0; i < count; i++)
3432e57a5ca2SMasatake YAMATO 		{
3433e57a5ca2SMasatake YAMATO 			line = colprintTableGetNewLine (table);
3434e57a5ca2SMasatake YAMATO 			vString *pattern = stringListItem (parser->currentPatterns, i);
3435e57a5ca2SMasatake YAMATO 
3436e57a5ca2SMasatake YAMATO 			colprintLineAppendColumnCString (line, parser->def->name);
3437e57a5ca2SMasatake YAMATO 			if (type & LMAP_EXTENSION)
3438e57a5ca2SMasatake YAMATO 				colprintLineAppendColumnCString (line, "pattern");
3439e57a5ca2SMasatake YAMATO 			colprintLineAppendColumnVString (line, pattern);
3440e57a5ca2SMasatake YAMATO 		}
3441e57a5ca2SMasatake YAMATO 	}
3442e57a5ca2SMasatake YAMATO 
3443e57a5ca2SMasatake YAMATO 	if ((type & LMAP_EXTENSION) && (0 < (count = stringListCount (parser->currentExtensions))))
3444e57a5ca2SMasatake YAMATO 	{
3445e57a5ca2SMasatake YAMATO 		for (i = 0; i < count; i++)
3446e57a5ca2SMasatake YAMATO 		{
3447e57a5ca2SMasatake YAMATO 			line = colprintTableGetNewLine (table);
3448e57a5ca2SMasatake YAMATO 			vString *extension = stringListItem (parser->currentExtensions, i);
3449e57a5ca2SMasatake YAMATO 
3450e57a5ca2SMasatake YAMATO 			colprintLineAppendColumnCString (line, parser->def->name);
3451e57a5ca2SMasatake YAMATO 			if (type & LMAP_PATTERN)
3452e57a5ca2SMasatake YAMATO 				colprintLineAppendColumnCString (line, "extension");
3453e57a5ca2SMasatake YAMATO 			colprintLineAppendColumnVString (line, extension);
3454e57a5ca2SMasatake YAMATO 		}
3455e57a5ca2SMasatake YAMATO 	}
3456e57a5ca2SMasatake YAMATO }
3457e57a5ca2SMasatake YAMATO 
printLanguageMaps(const langType language,langmapType type,bool withListHeader,bool machinable,FILE * fp)3458e57a5ca2SMasatake YAMATO extern void printLanguageMaps (const langType language, langmapType type,
3459e57a5ca2SMasatake YAMATO 							   bool withListHeader, bool machinable, FILE *fp)
3460e57a5ca2SMasatake YAMATO {
3461e57a5ca2SMasatake YAMATO 	/* DON'T SORT THE LIST
3462e57a5ca2SMasatake YAMATO 
3463e57a5ca2SMasatake YAMATO 	   The order of listing should be equal to the order of matching
3464e57a5ca2SMasatake YAMATO 	   for the parser selection. */
3465e57a5ca2SMasatake YAMATO 
3466e57a5ca2SMasatake YAMATO 	struct colprintTable * table = NULL;
3467e57a5ca2SMasatake YAMATO 	if (type & LMAP_TABLE_OUTPUT)
3468e57a5ca2SMasatake YAMATO 		table = mapColprintTableNew(type);
3469e57a5ca2SMasatake YAMATO 
3470d4c6f1e6SMasatake YAMATO 	if (language == LANG_AUTO)
3471d4c6f1e6SMasatake YAMATO 	{
3472e57a5ca2SMasatake YAMATO 		for (unsigned int i = 0  ;  i < LanguageCount  ;  ++i)
3473e57a5ca2SMasatake YAMATO 		{
3474e57a5ca2SMasatake YAMATO 			if (!isLanguageVisible (i))
3475e57a5ca2SMasatake YAMATO 				continue;
3476e57a5ca2SMasatake YAMATO 
3477e57a5ca2SMasatake YAMATO 			if (type & LMAP_TABLE_OUTPUT)
3478e57a5ca2SMasatake YAMATO 			{
3479e57a5ca2SMasatake YAMATO 				const parserObject* parser = LanguageTable + i;
3480e57a5ca2SMasatake YAMATO 
3481e57a5ca2SMasatake YAMATO 				mapColprintAddLanguage (table, type, parser);
3482e57a5ca2SMasatake YAMATO 			}
3483e57a5ca2SMasatake YAMATO 			else
348459204b36SMasatake YAMATO 				printMaps (i, type);
3485d4c6f1e6SMasatake YAMATO 		}
3486e57a5ca2SMasatake YAMATO 	}
3487e57a5ca2SMasatake YAMATO 	else
3488e57a5ca2SMasatake YAMATO 	{
3489e57a5ca2SMasatake YAMATO 		Assert (0 <= language  &&  language < (int) LanguageCount);
3490e57a5ca2SMasatake YAMATO 
3491e57a5ca2SMasatake YAMATO 		if (type & LMAP_TABLE_OUTPUT)
3492e57a5ca2SMasatake YAMATO 		{
3493e57a5ca2SMasatake YAMATO 			const parserObject* parser = LanguageTable + language;
3494e57a5ca2SMasatake YAMATO 
3495e57a5ca2SMasatake YAMATO 			mapColprintAddLanguage (table, type, parser);
3496e57a5ca2SMasatake YAMATO 		}
3497d4c6f1e6SMasatake YAMATO 		else
349859204b36SMasatake YAMATO 			printMaps (language, type);
3499d4c6f1e6SMasatake YAMATO 	}
3500d4c6f1e6SMasatake YAMATO 
3501e57a5ca2SMasatake YAMATO 
3502e57a5ca2SMasatake YAMATO 	if (type & LMAP_TABLE_OUTPUT)
3503d4c6f1e6SMasatake YAMATO 	{
3504e57a5ca2SMasatake YAMATO 		colprintTablePrint (table, (language == LANG_AUTO)? 0: 1,
3505e57a5ca2SMasatake YAMATO 							withListHeader, machinable, fp);
3506e57a5ca2SMasatake YAMATO 		colprintTableDelete (table);
3507e57a5ca2SMasatake YAMATO 	}
3508e57a5ca2SMasatake YAMATO }
3509e57a5ca2SMasatake YAMATO 
aliasColprintTableNew(void)351045425726SMasatake YAMATO static struct colprintTable *aliasColprintTableNew (void)
3511d4c6f1e6SMasatake YAMATO {
351245425726SMasatake YAMATO 	return colprintTableNew ("L:LANGUAGE", "L:ALIAS", NULL);
351345425726SMasatake YAMATO }
351445425726SMasatake YAMATO 
aliasColprintAddLanguage(struct colprintTable * table,const parserObject * parser)351545425726SMasatake YAMATO static void aliasColprintAddLanguage (struct colprintTable * table,
351645425726SMasatake YAMATO 									  const parserObject* parser)
351745425726SMasatake YAMATO {
351845425726SMasatake YAMATO 	unsigned int count;
351945425726SMasatake YAMATO 
352045425726SMasatake YAMATO 	if (parser->currentAliases && (0 < (count = stringListCount (parser->currentAliases))))
352145425726SMasatake YAMATO 	{
352245425726SMasatake YAMATO 		for (unsigned int i = 0; i < count; i++)
352345425726SMasatake YAMATO 		{
352445425726SMasatake YAMATO 			struct colprintLine * line = colprintTableGetNewLine (table);
352545425726SMasatake YAMATO 			vString *alias = stringListItem (parser->currentAliases, i);;
352645425726SMasatake YAMATO 
352745425726SMasatake YAMATO 			colprintLineAppendColumnCString (line, parser->def->name);
352845425726SMasatake YAMATO 			colprintLineAppendColumnVString (line, alias);
352945425726SMasatake YAMATO 		}
353045425726SMasatake YAMATO 	}
353145425726SMasatake YAMATO }
353245425726SMasatake YAMATO 
printLanguageAliases(const langType language,bool withListHeader,bool machinable,FILE * fp)353345425726SMasatake YAMATO extern void printLanguageAliases (const langType language,
353445425726SMasatake YAMATO 								  bool withListHeader, bool machinable, FILE *fp)
353545425726SMasatake YAMATO {
353645425726SMasatake YAMATO 	/* DON'T SORT THE LIST
353745425726SMasatake YAMATO 
353845425726SMasatake YAMATO 	   The order of listing should be equal to the order of matching
353945425726SMasatake YAMATO 	   for the parser selection. */
354045425726SMasatake YAMATO 
354145425726SMasatake YAMATO 	struct colprintTable * table = aliasColprintTableNew();
354245425726SMasatake YAMATO 	const parserObject* parser;
354345425726SMasatake YAMATO 
3544d4c6f1e6SMasatake YAMATO 	if (language == LANG_AUTO)
3545d4c6f1e6SMasatake YAMATO 	{
354645425726SMasatake YAMATO 		for (unsigned int i = 0; i < LanguageCount; ++i)
354745425726SMasatake YAMATO 		{
354845425726SMasatake YAMATO 			parser = LanguageTable + i;
354945425726SMasatake YAMATO 			if (parser->def->invisible)
355045425726SMasatake YAMATO 				continue;
355145425726SMasatake YAMATO 
355245425726SMasatake YAMATO 			aliasColprintAddLanguage (table, parser);
355345425726SMasatake YAMATO 		}
3554d4c6f1e6SMasatake YAMATO 	}
3555d4c6f1e6SMasatake YAMATO 	else
3556d4c6f1e6SMasatake YAMATO 	{
3557d4c6f1e6SMasatake YAMATO 		Assert (0 <= language  &&  language < (int) LanguageCount);
355845425726SMasatake YAMATO 		parser = LanguageTable + language;
355945425726SMasatake YAMATO 		aliasColprintAddLanguage (table, parser);
3560d4c6f1e6SMasatake YAMATO 	}
356145425726SMasatake YAMATO 
356245425726SMasatake YAMATO 	colprintTablePrint (table, (language == LANG_AUTO)? 0: 1,
356345425726SMasatake YAMATO 						withListHeader, machinable, fp);
356445425726SMasatake YAMATO 	colprintTableDelete (table);
3565d4c6f1e6SMasatake YAMATO }
3566d4c6f1e6SMasatake YAMATO 
printLanguage(const langType language,parserDefinition ** ltable)3567f10da43aSMasatake YAMATO static void printLanguage (const langType language, parserDefinition** ltable)
3568d4c6f1e6SMasatake YAMATO {
3569d4c6f1e6SMasatake YAMATO 	const parserDefinition* lang;
3570d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3571f10da43aSMasatake YAMATO 	lang = ltable [language];
3572a7fc12e5SMasatake YAMATO 
3573a7fc12e5SMasatake YAMATO 	if (lang->invisible)
3574a7fc12e5SMasatake YAMATO 		return;
3575a7fc12e5SMasatake YAMATO 
3576f10da43aSMasatake YAMATO 	printf ("%s%s\n", lang->name, isLanguageEnabled (lang->id) ? "" : " [disabled]");
3577f10da43aSMasatake YAMATO }
3578f10da43aSMasatake YAMATO 
printLanguageList(void)3579d4c6f1e6SMasatake YAMATO extern void printLanguageList (void)
3580d4c6f1e6SMasatake YAMATO {
3581d4c6f1e6SMasatake YAMATO 	unsigned int i;
3582f10da43aSMasatake YAMATO 	parserDefinition **ltable;
3583f10da43aSMasatake YAMATO 
3584f10da43aSMasatake YAMATO 	ltable = xMalloc (LanguageCount, parserDefinition*);
3585e02be843SMasatake YAMATO 	for (i = 0 ; i < LanguageCount ; ++i)
3586e02be843SMasatake YAMATO 		ltable[i] = LanguageTable[i].def;
3587f10da43aSMasatake YAMATO 	qsort (ltable, LanguageCount, sizeof (parserDefinition*), compareParsersByName);
3588f10da43aSMasatake YAMATO 
3589d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < LanguageCount  ;  ++i)
3590f10da43aSMasatake YAMATO 		printLanguage (i, ltable);
3591f10da43aSMasatake YAMATO 
3592f10da43aSMasatake YAMATO 	eFree (ltable);
3593d4c6f1e6SMasatake YAMATO }
3594d4c6f1e6SMasatake YAMATO 
xtagDefinitionDestroy(xtagDefinition * xdef)3595ac99a095SMasatake YAMATO static void xtagDefinitionDestroy (xtagDefinition *xdef)
3596ac99a095SMasatake YAMATO {
3597ac99a095SMasatake YAMATO 	eFree ((void *)xdef->name);
3598ac99a095SMasatake YAMATO 	eFree ((void *)xdef->description);
3599ac99a095SMasatake YAMATO 	eFree (xdef);
3600ac99a095SMasatake YAMATO }
3601ac99a095SMasatake YAMATO 
processLangDefineExtra(const langType language,const char * const option,const char * const parameter)3602f687ebcfSMasatake YAMATO static bool processLangDefineExtra (const langType language,
3603f687ebcfSMasatake YAMATO 									const char *const option,
36043a6dd371SMasatake YAMATO 									const char *const parameter)
3605f687ebcfSMasatake YAMATO {
3606f687ebcfSMasatake YAMATO 	xtagDefinition *xdef;
36073a6dd371SMasatake YAMATO 	const char * p = parameter;
360876d85274SMasatake YAMATO 	const char *name_end;
3609f687ebcfSMasatake YAMATO 	const char *desc;
361076d85274SMasatake YAMATO 	const char *flags;
3611f687ebcfSMasatake YAMATO 
3612f687ebcfSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3613f687ebcfSMasatake YAMATO 	Assert (p);
3614f687ebcfSMasatake YAMATO 
3615f687ebcfSMasatake YAMATO 	if (p[0] == '\0')
3616f687ebcfSMasatake YAMATO 		error (FATAL, "no extra definition specified in \"--%s\" option", option);
3617f687ebcfSMasatake YAMATO 
361876d85274SMasatake YAMATO 	name_end = strchr (p, ',');
361976d85274SMasatake YAMATO 	if (!name_end)
3620f687ebcfSMasatake YAMATO 		error (FATAL, "no extra description specified in \"--%s\" option", option);
362176d85274SMasatake YAMATO 	else if (name_end == p)
3622f687ebcfSMasatake YAMATO 		error (FATAL, "the extra name in \"--%s\" option is empty", option);
3623f687ebcfSMasatake YAMATO 
362476d85274SMasatake YAMATO 	for (; p < name_end; p++)
3625f687ebcfSMasatake YAMATO 	{
3626f687ebcfSMasatake YAMATO 		if (!isalnum (*p))
3627f687ebcfSMasatake YAMATO 			error (FATAL, "unacceptable char as part of extra name in \"--%s\" option",
3628f687ebcfSMasatake YAMATO 				   option);
3629f687ebcfSMasatake YAMATO 	}
3630f687ebcfSMasatake YAMATO 
363176d85274SMasatake YAMATO 	p++;
363276d85274SMasatake YAMATO 	if (p [0] == '\0' || p [0] == LONG_FLAGS_OPEN)
363376d85274SMasatake YAMATO 		error (FATAL, "extra description in \"--%s\" option is empty", option);
363476d85274SMasatake YAMATO 
363576d85274SMasatake YAMATO 	desc = extractDescriptionAndFlags (p, &flags);
363676d85274SMasatake YAMATO 
3637f687ebcfSMasatake YAMATO 	xdef = xCalloc (1, xtagDefinition);
3638f687ebcfSMasatake YAMATO 	xdef->enabled = false;
3639f687ebcfSMasatake YAMATO 	xdef->letter = NUL_XTAG_LETTER;
36403a6dd371SMasatake YAMATO 	xdef->name = eStrndup (parameter, name_end - parameter);
364176d85274SMasatake YAMATO 	xdef->description = desc;
3642f687ebcfSMasatake YAMATO 	xdef->isEnabled = NULL;
3643ac99a095SMasatake YAMATO 	DEFAULT_TRASH_BOX(xdef, xtagDefinitionDestroy);
3644f687ebcfSMasatake YAMATO 
364576d85274SMasatake YAMATO 	if (flags)
364676d85274SMasatake YAMATO 		flagsEval (flags, NULL, 0, xdef);
364776d85274SMasatake YAMATO 
3648f687ebcfSMasatake YAMATO 	defineXtag (xdef, language);
3649f687ebcfSMasatake YAMATO 
3650f687ebcfSMasatake YAMATO 	return true;
3651f687ebcfSMasatake YAMATO }
3652f687ebcfSMasatake YAMATO 
processExtradefOption(const char * const option,const char * const parameter)3653f687ebcfSMasatake YAMATO extern bool processExtradefOption (const char *const option, const char *const parameter)
3654f687ebcfSMasatake YAMATO {
3655f687ebcfSMasatake YAMATO 	langType language;
3656f687ebcfSMasatake YAMATO 
36572d422213SMasatake YAMATO 	language = getLanguageComponentInOption (option, "_" "extradef-");
3658f687ebcfSMasatake YAMATO 	if (language == LANG_IGNORE)
3659f687ebcfSMasatake YAMATO 		return false;
3660f687ebcfSMasatake YAMATO 
3661f687ebcfSMasatake YAMATO 	return processLangDefineExtra (language, option, parameter);
3662f687ebcfSMasatake YAMATO }
3663f687ebcfSMasatake YAMATO 
fieldDefinitionDestroy(fieldDefinition * fdef)36645fd045b3SMasatake YAMATO static void fieldDefinitionDestroy (fieldDefinition *fdef)
36655fd045b3SMasatake YAMATO {
36665fd045b3SMasatake YAMATO 	eFree ((void *)fdef->description);
36675fd045b3SMasatake YAMATO 	eFree ((void *)fdef->name);
36685fd045b3SMasatake YAMATO 	eFree (fdef);
36695fd045b3SMasatake YAMATO }
36705fd045b3SMasatake YAMATO 
processLangDefineField(const langType language,const char * const option,const char * const parameter)36715fd045b3SMasatake YAMATO static bool processLangDefineField (const langType language,
36725fd045b3SMasatake YAMATO 									const char *const option,
36735fd045b3SMasatake YAMATO 									const char *const parameter)
36745fd045b3SMasatake YAMATO {
36755fd045b3SMasatake YAMATO 	fieldDefinition *fdef;
36765fd045b3SMasatake YAMATO 	const char * p = parameter;
36773c7e951eSMasatake YAMATO 	const char *name_end;
36785fd045b3SMasatake YAMATO 	const char *desc;
36793c7e951eSMasatake YAMATO 	const char *flags;
36805fd045b3SMasatake YAMATO 
36815fd045b3SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
36825fd045b3SMasatake YAMATO 	Assert (p);
36835fd045b3SMasatake YAMATO 
36845fd045b3SMasatake YAMATO 	if (p[0] == '\0')
36855fd045b3SMasatake YAMATO 		error (FATAL, "no field definition specified in \"--%s\" option", option);
36865fd045b3SMasatake YAMATO 
36873c7e951eSMasatake YAMATO 	name_end = strchr (p, ',');
36883c7e951eSMasatake YAMATO 	if (!name_end)
36895fd045b3SMasatake YAMATO 		error (FATAL, "no field description specified in \"--%s\" option", option);
36903c7e951eSMasatake YAMATO 	else if (name_end == p)
36915fd045b3SMasatake YAMATO 		error (FATAL, "the field name in \"--%s\" option is empty", option);
36925fd045b3SMasatake YAMATO 
36933c7e951eSMasatake YAMATO 	for (; p < name_end; p++)
36945fd045b3SMasatake YAMATO 	{
3695ae599e0fSMasatake YAMATO 		if (!isalpha (*p))
36965fd045b3SMasatake YAMATO 			error (FATAL, "unacceptable char as part of field name in \"--%s\" option",
36975fd045b3SMasatake YAMATO 				   option);
36985fd045b3SMasatake YAMATO 	}
36995fd045b3SMasatake YAMATO 
37003c7e951eSMasatake YAMATO 	p++;
37013c7e951eSMasatake YAMATO 	if (p [0] == '\0' || p [0] == LONG_FLAGS_OPEN)
37025fd045b3SMasatake YAMATO 		error (FATAL, "field description in \"--%s\" option is empty", option);
37035fd045b3SMasatake YAMATO 
37043c7e951eSMasatake YAMATO 	desc = extractDescriptionAndFlags (p, &flags);
37053c7e951eSMasatake YAMATO 
37065fd045b3SMasatake YAMATO 	fdef = xCalloc (1, fieldDefinition);
37075fd045b3SMasatake YAMATO 	fdef->enabled = false;
37085fd045b3SMasatake YAMATO 	fdef->letter = NUL_FIELD_LETTER;
37093c7e951eSMasatake YAMATO 	fdef->name = eStrndup(parameter, name_end - parameter);
37103c7e951eSMasatake YAMATO 	fdef->description = desc;
37115fd045b3SMasatake YAMATO 	fdef->isValueAvailable = NULL;
3712fba3677cSMasatake YAMATO 	fdef->getValueObject = NULL;
3713fba3677cSMasatake YAMATO 	fdef->getterValueType = NULL;
3714fba3677cSMasatake YAMATO 	fdef->setValueObject = NULL;
3715fba3677cSMasatake YAMATO 	fdef->setterValueType = NULL;
3716fba3677cSMasatake YAMATO 	fdef->checkValueForSetter = NULL;
37175fd045b3SMasatake YAMATO 	fdef->dataType = FIELDTYPE_STRING; /* TODO */
37185fd045b3SMasatake YAMATO 	fdef->ftype = FIELD_UNKNOWN;
37195fd045b3SMasatake YAMATO 	DEFAULT_TRASH_BOX(fdef, fieldDefinitionDestroy);
37205fd045b3SMasatake YAMATO 
37213c7e951eSMasatake YAMATO 	if (flags)
37223c7e951eSMasatake YAMATO 		flagsEval (flags, NULL, 0, fdef);
37233c7e951eSMasatake YAMATO 
37245fd045b3SMasatake YAMATO 	defineField (fdef, language);
37255fd045b3SMasatake YAMATO 
37265fd045b3SMasatake YAMATO 	return true;
37275fd045b3SMasatake YAMATO }
37285fd045b3SMasatake YAMATO 
processFielddefOption(const char * const option,const char * const parameter)37295fd045b3SMasatake YAMATO extern bool processFielddefOption (const char *const option, const char *const parameter)
37305fd045b3SMasatake YAMATO {
37315fd045b3SMasatake YAMATO 	langType language;
37325fd045b3SMasatake YAMATO 
37335fd045b3SMasatake YAMATO 	language = getLanguageComponentInOption (option, "_fielddef-");
37345fd045b3SMasatake YAMATO 	if (language == LANG_IGNORE)
37355fd045b3SMasatake YAMATO 		return false;
37365fd045b3SMasatake YAMATO 
37375fd045b3SMasatake YAMATO 	return processLangDefineField (language, option, parameter);
37385fd045b3SMasatake YAMATO }
3739f687ebcfSMasatake YAMATO 
3740d4c6f1e6SMasatake YAMATO /*
3741d4c6f1e6SMasatake YAMATO *   File parsing
3742d4c6f1e6SMasatake YAMATO */
3743d4c6f1e6SMasatake YAMATO 
createTagsForFile(const langType language,const unsigned int passCount)3744e5b7a250SMasatake YAMATO static rescanReason createTagsForFile (const langType language,
3745bc1a5e1bSMasatake YAMATO 				       const unsigned int passCount)
3746d4c6f1e6SMasatake YAMATO {
3747e02be843SMasatake YAMATO 	parserDefinition *const lang = LanguageTable [language].def;
3748bc1a5e1bSMasatake YAMATO 	rescanReason rescan = RESCAN_NONE;
3749bc1a5e1bSMasatake YAMATO 
3750bc1a5e1bSMasatake YAMATO 	resetInputFile (language);
37518d8d8e3bSMasatake YAMATO 
37528d8d8e3bSMasatake YAMATO 	Assert (lang->parser || lang->parser2);
3753d4c6f1e6SMasatake YAMATO 
3754a53e10d8SMasatake YAMATO 	notifyInputStart ();
3755a53e10d8SMasatake YAMATO 
3756d4c6f1e6SMasatake YAMATO 	if (lang->parser != NULL)
3757d4c6f1e6SMasatake YAMATO 		lang->parser ();
3758d4c6f1e6SMasatake YAMATO 	else if (lang->parser2 != NULL)
3759d4c6f1e6SMasatake YAMATO 		rescan = lang->parser2 (passCount);
3760d4c6f1e6SMasatake YAMATO 
3761a53e10d8SMasatake YAMATO 	notifyInputEnd ();
3762a53e10d8SMasatake YAMATO 
3763d4c6f1e6SMasatake YAMATO 	return rescan;
3764d4c6f1e6SMasatake YAMATO }
3765d4c6f1e6SMasatake YAMATO 
notifyLanguageRegexInputStart(langType language)37662db4cedcSMasatake YAMATO extern void notifyLanguageRegexInputStart (langType language)
37672db4cedcSMasatake YAMATO {
3768d86d3772SMasatake YAMATO 	parserObject *pobj = LanguageTable + language;
3769d86d3772SMasatake YAMATO 	parserDefinition *pdef = pobj->def;
3770d86d3772SMasatake YAMATO 
3771d86d3772SMasatake YAMATO 	notifyRegexInputStart(pobj->lregexControlBlock);
3772d86d3772SMasatake YAMATO 	for (unsigned int i = 0; i < pdef->dependencyCount; i++)
3773d86d3772SMasatake YAMATO 	{
3774d86d3772SMasatake YAMATO 		parserDependency *d = pdef->dependencies + i;
3775d86d3772SMasatake YAMATO 		if (d->type != DEPTYPE_FOREIGNER)
3776d86d3772SMasatake YAMATO 			continue;
3777d86d3772SMasatake YAMATO 		langType foreigner = getNamedLanguage (d->upperParser, 0);
3778d86d3772SMasatake YAMATO 		if (foreigner == LANG_IGNORE)
3779d86d3772SMasatake YAMATO 			continue;
3780d86d3772SMasatake YAMATO 
3781d86d3772SMasatake YAMATO 		notifyLanguageRegexInputStart (foreigner);
3782d86d3772SMasatake YAMATO 	}
37832db4cedcSMasatake YAMATO }
37842db4cedcSMasatake YAMATO 
notifyLanguageRegexInputEnd(langType language)37852db4cedcSMasatake YAMATO extern void notifyLanguageRegexInputEnd (langType language)
37862db4cedcSMasatake YAMATO {
3787d86d3772SMasatake YAMATO 	parserObject *pobj = LanguageTable + language;
3788d86d3772SMasatake YAMATO 	parserDefinition *pdef = pobj->def;
3789d86d3772SMasatake YAMATO 
3790d86d3772SMasatake YAMATO 	for (unsigned int i = 0; i < pdef->dependencyCount; i++)
3791d86d3772SMasatake YAMATO 	{
3792d86d3772SMasatake YAMATO 		parserDependency *d = pdef->dependencies + i;
3793d86d3772SMasatake YAMATO 		if (d->type != DEPTYPE_FOREIGNER)
3794d86d3772SMasatake YAMATO 			continue;
3795d86d3772SMasatake YAMATO 		langType foreigner = getNamedLanguage (d->upperParser, 0);
3796d86d3772SMasatake YAMATO 		if (foreigner == LANG_IGNORE)
3797d86d3772SMasatake YAMATO 			continue;
3798d86d3772SMasatake YAMATO 
3799d86d3772SMasatake YAMATO 		notifyLanguageRegexInputEnd (foreigner);
3800d86d3772SMasatake YAMATO 	}
38012db4cedcSMasatake YAMATO 	notifyRegexInputEnd((LanguageTable + language)->lregexControlBlock);
38022db4cedcSMasatake YAMATO }
38032db4cedcSMasatake YAMATO 
parserCorkFlags(parserDefinition * parser)38046b1a862eSMasatake YAMATO static unsigned int parserCorkFlags (parserDefinition *parser)
3805bbd7ded8SMasatake YAMATO {
3806bbd7ded8SMasatake YAMATO 	subparser *tmp;
38076b1a862eSMasatake YAMATO 	unsigned int r = 0;
3808bbd7ded8SMasatake YAMATO 
38096b1a862eSMasatake YAMATO 	r |= parser->useCork;
3810bbd7ded8SMasatake YAMATO 
3811c25346c2SMasatake YAMATO 	if (doesLanguageExpectCorkInRegex (parser->id)
3812298e3c61SMasatake YAMATO 	    || parser->requestAutomaticFQTag)
38136b1a862eSMasatake YAMATO 		r |= CORK_QUEUE;
3814298e3c61SMasatake YAMATO 
3815bbd7ded8SMasatake YAMATO 	pushLanguage (parser->id);
381611358a9dSMasatake YAMATO 	foreachSubparser(tmp, true)
3817bbd7ded8SMasatake YAMATO 	{
3818edc12faeSMasatake YAMATO 		langType t = getSubparserLanguage (tmp);
38196b1a862eSMasatake YAMATO 		r |= parserCorkFlags (LanguageTable[t].def);
3820bbd7ded8SMasatake YAMATO 	}
3821bbd7ded8SMasatake YAMATO 	popLanguage ();
3822bbd7ded8SMasatake YAMATO 	return r;
3823bbd7ded8SMasatake YAMATO }
3824bbd7ded8SMasatake YAMATO 
setupLanguageSubparsersInUse(const langType language)38256a8f21eaSMasatake YAMATO static void setupLanguageSubparsersInUse (const langType language)
38266a8f21eaSMasatake YAMATO {
38276a8f21eaSMasatake YAMATO 	subparser *tmp;
38286a8f21eaSMasatake YAMATO 
38296a8f21eaSMasatake YAMATO 	setupSubparsersInUse ((LanguageTable + language)->slaveControlBlock);
383011358a9dSMasatake YAMATO 	foreachSubparser(tmp, true)
38316a8f21eaSMasatake YAMATO 	{
38326a8f21eaSMasatake YAMATO 		langType t = getSubparserLanguage (tmp);
38336a8f21eaSMasatake YAMATO 		enterSubparser (tmp);
38346a8f21eaSMasatake YAMATO 		setupLanguageSubparsersInUse(t);
38356a8f21eaSMasatake YAMATO 		leaveSubparser ();
38366a8f21eaSMasatake YAMATO 	}
38376a8f21eaSMasatake YAMATO }
38386a8f21eaSMasatake YAMATO 
teardownLanguageSubparsersInUse(const langType language)38396a8f21eaSMasatake YAMATO static subparser* teardownLanguageSubparsersInUse (const langType language)
38406a8f21eaSMasatake YAMATO {
38416a8f21eaSMasatake YAMATO 	subparser *tmp;
38426a8f21eaSMasatake YAMATO 
384311358a9dSMasatake YAMATO 	foreachSubparser(tmp, true)
38446a8f21eaSMasatake YAMATO 	{
38456a8f21eaSMasatake YAMATO 		langType t = getSubparserLanguage (tmp);
38466a8f21eaSMasatake YAMATO 		enterSubparser (tmp);
38476a8f21eaSMasatake YAMATO 		teardownLanguageSubparsersInUse(t);
38486a8f21eaSMasatake YAMATO 		leaveSubparser ();
38496a8f21eaSMasatake YAMATO 	}
38506a8f21eaSMasatake YAMATO 	return teardownSubparsersInUse ((LanguageTable + language)->slaveControlBlock);
38516a8f21eaSMasatake YAMATO }
38526a8f21eaSMasatake YAMATO 
initializeParserStats(parserObject * parser)3853a9c91f4dSMasatake YAMATO static void	initializeParserStats (parserObject *parser)
3854a9c91f4dSMasatake YAMATO {
3855a9c91f4dSMasatake YAMATO 	if (Option.printTotals > 1 && parser->used == 0 && parser->def->initStats)
3856a9c91f4dSMasatake YAMATO 		parser->def->initStats (parser->def->id);
3857a9c91f4dSMasatake YAMATO 	parser->used = 1;
3858a9c91f4dSMasatake YAMATO }
3859a9c91f4dSMasatake YAMATO 
printParserStatisticsIfUsed(langType language)3860a9c91f4dSMasatake YAMATO extern void printParserStatisticsIfUsed (langType language)
3861a9c91f4dSMasatake YAMATO {
3862a9c91f4dSMasatake YAMATO 	parserObject *parser = &(LanguageTable [language]);
3863a9c91f4dSMasatake YAMATO 
3864d4318624SMasatake YAMATO 	if (parser->used)
3865d4318624SMasatake YAMATO 	{
3866d4318624SMasatake YAMATO 		if (parser->def->printStats)
3867a9c91f4dSMasatake YAMATO 		{
3868a9c91f4dSMasatake YAMATO 			fprintf(stderr, "\nSTATISTICS of %s\n", getLanguageName (language));
3869a9c91f4dSMasatake YAMATO 			fputs("==============================================\n", stderr);
3870a9c91f4dSMasatake YAMATO 			parser->def->printStats (language);
3871a9c91f4dSMasatake YAMATO 		}
3872d4318624SMasatake YAMATO 		printLanguageMultitableStatistics (language);
3873d4318624SMasatake YAMATO 	}
3874a9c91f4dSMasatake YAMATO }
3875a9c91f4dSMasatake YAMATO 
createTagsWithFallback1(const langType language,langType * exclusive_subparser)387609b4041bSMasatake YAMATO static bool createTagsWithFallback1 (const langType language,
387709b4041bSMasatake YAMATO 									 langType *exclusive_subparser)
3878d4c6f1e6SMasatake YAMATO {
3879ce990805SThomas Braun 	bool tagFileResized = false;
3880c1f939f9SMasatake YAMATO 	unsigned long numTags	= numTagsAdded ();
3881509a47dbSJiří Techet 	MIOPos tagfpos;
38824fa68e36SMasatake YAMATO 	int lastPromise = getLastPromise ();
3883d4c6f1e6SMasatake YAMATO 	unsigned int passCount = 0;
3884d4c6f1e6SMasatake YAMATO 	rescanReason whyRescan;
388597a77b13SMasatake YAMATO 	parserObject *parser;
38866b1a862eSMasatake YAMATO 	unsigned int corkFlags;
38876b1a862eSMasatake YAMATO 	bool useCork = false;
3888d4c6f1e6SMasatake YAMATO 
3889bc1a5e1bSMasatake YAMATO 	initializeParser (language);
389097a77b13SMasatake YAMATO 	parser = &(LanguageTable [language]);
3891a53e10d8SMasatake YAMATO 
38926a8f21eaSMasatake YAMATO 	setupLanguageSubparsersInUse (language);
3893a53e10d8SMasatake YAMATO 
38946b1a862eSMasatake YAMATO 	corkFlags = parserCorkFlags (parser->def);
38956b1a862eSMasatake YAMATO 	useCork = corkFlags & CORK_QUEUE;
3896bbd7ded8SMasatake YAMATO 	if (useCork)
38976b1a862eSMasatake YAMATO 		corkTagFile(corkFlags);
3898e5b7a250SMasatake YAMATO 
38995d526d9eSMasatake YAMATO 	if (isXtagEnabled (XTAG_PSEUDO_TAGS))
3900bc1a5e1bSMasatake YAMATO 		addParserPseudoTags (language);
3901a9c91f4dSMasatake YAMATO 	initializeParserStats (parser);
3902c1f939f9SMasatake YAMATO 	tagFilePosition (&tagfpos);
3903bc1a5e1bSMasatake YAMATO 
3904b90904baSMasatake YAMATO 	anonResetMaybe (parser);
39053c91b1eaSMasatake YAMATO 
3906d4c6f1e6SMasatake YAMATO 	while ( ( whyRescan =
3907e5b7a250SMasatake YAMATO 		  createTagsForFile (language, ++passCount) )
3908d4c6f1e6SMasatake YAMATO 		!= RESCAN_NONE)
3909d4c6f1e6SMasatake YAMATO 	{
3910bbd7ded8SMasatake YAMATO 		if (useCork)
3911e5b7a250SMasatake YAMATO 		{
3912e5b7a250SMasatake YAMATO 			uncorkTagFile();
39136b1a862eSMasatake YAMATO 			corkTagFile(corkFlags);
3914e5b7a250SMasatake YAMATO 		}
3915e5b7a250SMasatake YAMATO 
3916e5b7a250SMasatake YAMATO 
3917d4c6f1e6SMasatake YAMATO 		if (whyRescan == RESCAN_FAILED)
3918d4c6f1e6SMasatake YAMATO 		{
3919d4c6f1e6SMasatake YAMATO 			/*  Restore prior state of tag file.
3920d4c6f1e6SMasatake YAMATO 			*/
39214a3ba775SMasatake YAMATO 			setTagFilePosition (&tagfpos, true);
3922c1f939f9SMasatake YAMATO 			setNumTagsAdded (numTags);
392367d1f12fSJiří Techet 			writerRescanFailed (numTags);
3924ce990805SThomas Braun 			tagFileResized = true;
39254fa68e36SMasatake YAMATO 			breakPromisesAfter(lastPromise);
3926d4c6f1e6SMasatake YAMATO 		}
3927d4c6f1e6SMasatake YAMATO 		else if (whyRescan == RESCAN_APPEND)
3928d4c6f1e6SMasatake YAMATO 		{
3929c1f939f9SMasatake YAMATO 			tagFilePosition (&tagfpos);
3930c1f939f9SMasatake YAMATO 			numTags = numTagsAdded ();
39314fa68e36SMasatake YAMATO 			lastPromise = getLastPromise ();
3932d4c6f1e6SMasatake YAMATO 		}
3933d4c6f1e6SMasatake YAMATO 	}
3934bc1a5e1bSMasatake YAMATO 
39354e0c6ed6SMasatake YAMATO 	/* Force filling allLines buffer and kick the multiline regex parser */
3936b177b3faSMasatake YAMATO 	if (hasLanguageMultilineRegexPatterns (language))
39374e0c6ed6SMasatake YAMATO 		while (readLineFromInputFile () != NULL)
39384e0c6ed6SMasatake YAMATO 			; /* Do nothing */
39394e0c6ed6SMasatake YAMATO 
3940bbd7ded8SMasatake YAMATO 	if (useCork)
3941e5b7a250SMasatake YAMATO 		uncorkTagFile();
3942e5b7a250SMasatake YAMATO 
394309b4041bSMasatake YAMATO 	{
39446a8f21eaSMasatake YAMATO 		subparser *s = teardownLanguageSubparsersInUse (language);
394509b4041bSMasatake YAMATO 		if (exclusive_subparser && s)
394609b4041bSMasatake YAMATO 			*exclusive_subparser = getSubparserLanguage (s);
394709b4041bSMasatake YAMATO 	}
3948a53e10d8SMasatake YAMATO 
3949e5b7a250SMasatake YAMATO 	return tagFileResized;
3950e5b7a250SMasatake YAMATO }
3951e5b7a250SMasatake YAMATO 
runParserInNarrowedInputStream(const langType language,unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,unsigned long sourceLineOffset,int promise)3952ce990805SThomas Braun extern bool runParserInNarrowedInputStream (const langType language,
3953ef722b09SMasatake YAMATO 					       unsigned long startLine, long startCharOffset,
3954ef722b09SMasatake YAMATO 					       unsigned long endLine, long endCharOffset,
395511e58e48SMasatake YAMATO 					       unsigned long sourceLineOffset,
395611e58e48SMasatake YAMATO 					       int promise)
39574fa68e36SMasatake YAMATO {
3958ce990805SThomas Braun 	bool tagFileResized;
3959af389e57SMasatake YAMATO 
3960af389e57SMasatake YAMATO 	verbose ("runParserInNarrowedInputStream: %s; "
3961af389e57SMasatake YAMATO 			 "file: %s, "
3962c3f1785fSMasatake YAMATO 			 "start(line: %lu, offset: %ld, srcline: %lu)"
3963af389e57SMasatake YAMATO 			 " - "
3964c3f1785fSMasatake YAMATO 			 "end(line: %lu, offset: %ld)\n",
3965af389e57SMasatake YAMATO 			 getLanguageName (language),
3966af389e57SMasatake YAMATO 			 getInputFileName (),
3967af389e57SMasatake YAMATO 			 startLine, startCharOffset, sourceLineOffset,
3968af389e57SMasatake YAMATO 			 endLine, endCharOffset);
3969af389e57SMasatake YAMATO 
39704d1713c7SMasatake YAMATO 	pushNarrowedInputStream (
39719128cdbaSMasatake YAMATO 				 doesParserRequireMemoryStream (language),
39724fa68e36SMasatake YAMATO 				 startLine, startCharOffset,
39734fa68e36SMasatake YAMATO 				 endLine, endCharOffset,
397411e58e48SMasatake YAMATO 				 sourceLineOffset,
397511e58e48SMasatake YAMATO 				 promise);
397609b4041bSMasatake YAMATO 	tagFileResized = createTagsWithFallback1 (language, NULL);
39774fa68e36SMasatake YAMATO 	popNarrowedInputStream  ();
39784fa68e36SMasatake YAMATO 	return tagFileResized;
39794fa68e36SMasatake YAMATO 
39804fa68e36SMasatake YAMATO }
39814fa68e36SMasatake YAMATO 
createTagsWithFallback(const char * const fileName,const langType language,MIO * mio,time_t mtime,bool * failureInOpenning)3982ce990805SThomas Braun static bool createTagsWithFallback (
3983e5b7a250SMasatake YAMATO 	const char *const fileName, const langType language,
3984ce1f2415SMasatake YAMATO 	MIO *mio, time_t mtime, bool *failureInOpenning)
3985e5b7a250SMasatake YAMATO {
398609b4041bSMasatake YAMATO 	langType exclusive_subparser = LANG_IGNORE;
3987ce990805SThomas Braun 	bool tagFileResized = false;
3988e5b7a250SMasatake YAMATO 
3989e5b7a250SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
3990e5b7a250SMasatake YAMATO 
3991ce1f2415SMasatake YAMATO 	if (!openInputFile (fileName, language, mio, mtime))
39928ae1a1ffSMasatake YAMATO 	{
39938ae1a1ffSMasatake YAMATO 		*failureInOpenning = true;
3994ce990805SThomas Braun 		return false;
39958ae1a1ffSMasatake YAMATO 	}
39968ae1a1ffSMasatake YAMATO 	*failureInOpenning = false;
3997e5b7a250SMasatake YAMATO 
399809b4041bSMasatake YAMATO 	tagFileResized = createTagsWithFallback1 (language,
399909b4041bSMasatake YAMATO 											  &exclusive_subparser);
4000ce990805SThomas Braun 	tagFileResized = forcePromises()? true: tagFileResized;
4001e5b7a250SMasatake YAMATO 
400209b4041bSMasatake YAMATO 	pushLanguage ((exclusive_subparser == LANG_IGNORE)
400309b4041bSMasatake YAMATO 				  ? language
400409b4041bSMasatake YAMATO 				  : exclusive_subparser);
4005e5b7a250SMasatake YAMATO 	makeFileTag (fileName);
40064dfa41deSMasatake YAMATO 	popLanguage ();
4007bc1a5e1bSMasatake YAMATO 	closeInputFile ();
4008bc1a5e1bSMasatake YAMATO 
4009d4c6f1e6SMasatake YAMATO 	return tagFileResized;
4010d4c6f1e6SMasatake YAMATO }
4011d4c6f1e6SMasatake YAMATO 
printGuessedParser(const char * const fileName,langType language)4012d4c6f1e6SMasatake YAMATO static void printGuessedParser (const char* const fileName, langType language)
4013d4c6f1e6SMasatake YAMATO {
4014d4c6f1e6SMasatake YAMATO 	const char *parserName;
4015d4c6f1e6SMasatake YAMATO 
4016d4c6f1e6SMasatake YAMATO 	if (language == LANG_IGNORE)
4017d4c6f1e6SMasatake YAMATO 	{
4018ce990805SThomas Braun 		Option.printLanguage = ((int)true) + 1;
4019db2bf481SMasatake YAMATO 		parserName = RSV_NONE;
4020d4c6f1e6SMasatake YAMATO 	}
4021d4c6f1e6SMasatake YAMATO 	else
4022f02166dcSMasatake YAMATO 	{
4023f02166dcSMasatake YAMATO 		parserName = getLanguageName (language);
4024f02166dcSMasatake YAMATO 	}
4025d4c6f1e6SMasatake YAMATO 
4026d4c6f1e6SMasatake YAMATO 	printf("%s: %s\n", fileName, parserName);
4027d4c6f1e6SMasatake YAMATO }
4028d4c6f1e6SMasatake YAMATO 
40292acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
40302acdcfa1SYasuhiro Matsumoto static char **EncodingMap;
40312acdcfa1SYasuhiro Matsumoto static unsigned int EncodingMapMax;
40322acdcfa1SYasuhiro Matsumoto 
addLanguageEncoding(const langType language,const char * const encoding)40332acdcfa1SYasuhiro Matsumoto static void addLanguageEncoding (const langType language,
40342acdcfa1SYasuhiro Matsumoto 									const char *const encoding)
40352acdcfa1SYasuhiro Matsumoto {
40362acdcfa1SYasuhiro Matsumoto 	if (language > EncodingMapMax || EncodingMapMax == 0)
40372acdcfa1SYasuhiro Matsumoto 	{
40382acdcfa1SYasuhiro Matsumoto 		int i;
40392acdcfa1SYasuhiro Matsumoto 		int istart = (EncodingMapMax == 0)? 0: EncodingMapMax + 1;
40402acdcfa1SYasuhiro Matsumoto 		EncodingMap = xRealloc (EncodingMap, (language + 1), char*);
40412acdcfa1SYasuhiro Matsumoto 		for (i = istart;  i <= language  ;  ++i)
40422acdcfa1SYasuhiro Matsumoto 		{
40432acdcfa1SYasuhiro Matsumoto 			EncodingMap [i] = NULL;
40442acdcfa1SYasuhiro Matsumoto 		}
40452acdcfa1SYasuhiro Matsumoto 		EncodingMapMax = language;
40462acdcfa1SYasuhiro Matsumoto 	}
40472acdcfa1SYasuhiro Matsumoto 	if (EncodingMap [language])
40482acdcfa1SYasuhiro Matsumoto 		eFree (EncodingMap [language]);
40492acdcfa1SYasuhiro Matsumoto 	EncodingMap [language] = eStrdup(encoding);
40502acdcfa1SYasuhiro Matsumoto 	if (!Option.outputEncoding)
40512acdcfa1SYasuhiro Matsumoto 		Option.outputEncoding = eStrdup("UTF-8");
40522acdcfa1SYasuhiro Matsumoto }
40532acdcfa1SYasuhiro Matsumoto 
processLanguageEncodingOption(const char * const option,const char * const parameter)4054ce990805SThomas Braun extern bool processLanguageEncodingOption (const char *const option, const char *const parameter)
40552acdcfa1SYasuhiro Matsumoto {
40562acdcfa1SYasuhiro Matsumoto 	langType language;
40572acdcfa1SYasuhiro Matsumoto 
40582acdcfa1SYasuhiro Matsumoto 	language = getLanguageComponentInOption (option, "input-encoding-");
40592acdcfa1SYasuhiro Matsumoto 	if (language == LANG_IGNORE)
4060ce990805SThomas Braun 		return false;
40612acdcfa1SYasuhiro Matsumoto 
40622acdcfa1SYasuhiro Matsumoto 	addLanguageEncoding (language, parameter);
4063ce990805SThomas Braun 	return true;
40642acdcfa1SYasuhiro Matsumoto }
40652acdcfa1SYasuhiro Matsumoto 
freeEncodingResources(void)40662acdcfa1SYasuhiro Matsumoto extern void freeEncodingResources (void)
40672acdcfa1SYasuhiro Matsumoto {
40682acdcfa1SYasuhiro Matsumoto 	if (EncodingMap)
40692acdcfa1SYasuhiro Matsumoto 	{
407046ab94ccSMasatake YAMATO 		unsigned int i;
40712acdcfa1SYasuhiro Matsumoto 		for (i = 0  ;  i <= EncodingMapMax  ; ++i)
40722acdcfa1SYasuhiro Matsumoto 		{
40732acdcfa1SYasuhiro Matsumoto 			if (EncodingMap [i])
40742acdcfa1SYasuhiro Matsumoto 				eFree (EncodingMap [i]);
40752acdcfa1SYasuhiro Matsumoto 		}
4076a32a50f1SMasatake YAMATO 		eFree (EncodingMap);
40772acdcfa1SYasuhiro Matsumoto 	}
40782acdcfa1SYasuhiro Matsumoto 	if (Option.inputEncoding)
40792acdcfa1SYasuhiro Matsumoto 		eFree (Option.inputEncoding);
40802acdcfa1SYasuhiro Matsumoto 	if (Option.outputEncoding)
40812acdcfa1SYasuhiro Matsumoto 		eFree (Option.outputEncoding);
40822acdcfa1SYasuhiro Matsumoto }
4083bde9f60aSColomban Wendling 
getLanguageEncoding(const langType language)4084bde9f60aSColomban Wendling extern const char *getLanguageEncoding (const langType language)
4085bde9f60aSColomban Wendling {
4086bde9f60aSColomban Wendling 	if (EncodingMap && language <= EncodingMapMax && EncodingMap [language])
4087bde9f60aSColomban Wendling 		return EncodingMap[language];
4088bde9f60aSColomban Wendling 	else
4089bde9f60aSColomban Wendling 		return Option.inputEncoding;
4090bde9f60aSColomban Wendling }
40912acdcfa1SYasuhiro Matsumoto #endif
40922acdcfa1SYasuhiro Matsumoto 
addParserPseudoTags(langType language)4093ce8d2e8fSMasatake YAMATO static void addParserPseudoTags (langType language)
4094ce8d2e8fSMasatake YAMATO {
40958df191b2SMasatake YAMATO 	parserObject *parser = LanguageTable + language;
40968df191b2SMasatake YAMATO 	if (!parser->pseudoTagPrinted)
4097ce8d2e8fSMasatake YAMATO 	{
4098ef573be0SMasatake YAMATO 		for (int i = 0; i < PTAG_COUNT; i++)
4099ef573be0SMasatake YAMATO 		{
4100ef573be0SMasatake YAMATO 			if (isPtagParserSpecific (i))
4101ef573be0SMasatake YAMATO 				makePtagIfEnabled (i, language, parser);
4102ef573be0SMasatake YAMATO 		}
41038df191b2SMasatake YAMATO 		parser->pseudoTagPrinted = 1;
4104ce8d2e8fSMasatake YAMATO 	}
4105ce8d2e8fSMasatake YAMATO }
4106ce8d2e8fSMasatake YAMATO 
doesParserRequireMemoryStream(const langType language)4107ce990805SThomas Braun extern bool doesParserRequireMemoryStream (const langType language)
410831cb4225SMasatake YAMATO {
410931cb4225SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4110e02be843SMasatake YAMATO 	parserDefinition *const lang = LanguageTable [language].def;
411146ab94ccSMasatake YAMATO 	unsigned int i;
411231cb4225SMasatake YAMATO 
4113b19a98c8SMasatake YAMATO 	if (lang->tagXpathTableCount > 0
4114e535639cSMasatake YAMATO 		|| lang->useMemoryStreamInput)
4115b19a98c8SMasatake YAMATO 	{
4116b19a98c8SMasatake YAMATO 		verbose ("%s requires a memory stream for input\n", lang->name);
4117288cd67dSMasatake YAMATO 		return true;
4118b19a98c8SMasatake YAMATO 	}
4119288cd67dSMasatake YAMATO 
41207d7040f4SMasatake YAMATO 	for (i = 0; i < lang->dependencyCount; i++)
41217d7040f4SMasatake YAMATO 	{
41227d7040f4SMasatake YAMATO 		parserDependency *d = lang->dependencies + i;
41237d7040f4SMasatake YAMATO 		if (d->type == DEPTYPE_SUBPARSER &&
41247d7040f4SMasatake YAMATO 			((subparser *)(d->data))->direction & SUBPARSER_SUB_RUNS_BASE)
41257d7040f4SMasatake YAMATO 		{
41267d7040f4SMasatake YAMATO 			langType baseParser;
41277d7040f4SMasatake YAMATO 			baseParser = getNamedLanguage (d->upperParser, 0);
41287d7040f4SMasatake YAMATO 			if (doesParserRequireMemoryStream(baseParser))
41297d7040f4SMasatake YAMATO 			{
41307d7040f4SMasatake YAMATO 				verbose ("%s/%s requires a memory stream for input\n", lang->name,
41317d7040f4SMasatake YAMATO 						 LanguageTable[baseParser].def->name);
41327d7040f4SMasatake YAMATO 				return true;
41337d7040f4SMasatake YAMATO 			}
41347d7040f4SMasatake YAMATO 		}
41357d7040f4SMasatake YAMATO 	}
41367d7040f4SMasatake YAMATO 
4137288cd67dSMasatake YAMATO 	return false;
413831cb4225SMasatake YAMATO }
413931cb4225SMasatake YAMATO 
parseFile(const char * const fileName)4140ce990805SThomas Braun extern bool parseFile (const char *const fileName)
4141d4c6f1e6SMasatake YAMATO {
4142d33423e3SSzymon Tomasz Stefanek 	TRACE_ENTER_TEXT("Parsing file %s",fileName);
4143eda0f17cSMasatake YAMATO 	bool bRet = parseFileWithMio (fileName, NULL, NULL);
4144d33423e3SSzymon Tomasz Stefanek 	TRACE_LEAVE();
4145d33423e3SSzymon Tomasz Stefanek 	return bRet;
4146f9f37517SAman Gupta }
4147f9f37517SAman Gupta 
parseMio(const char * const fileName,langType language,MIO * mio,time_t mtime,bool useSourceFileTagPath,void * clientData)4148ce1f2415SMasatake YAMATO static bool parseMio (const char *const fileName, langType language, MIO* mio, time_t mtime, bool useSourceFileTagPath,
4149eda0f17cSMasatake YAMATO 					  void *clientData)
4150eda0f17cSMasatake YAMATO {
4151eda0f17cSMasatake YAMATO 	bool tagFileResized = false;
41528ae1a1ffSMasatake YAMATO 	bool failureInOpenning = false;
4153eda0f17cSMasatake YAMATO 
4154eda0f17cSMasatake YAMATO 	setupWriter (clientData);
4155eda0f17cSMasatake YAMATO 
4156eda0f17cSMasatake YAMATO 	setupAnon ();
4157eda0f17cSMasatake YAMATO 
4158eda0f17cSMasatake YAMATO 	initParserTrashBox ();
4159eda0f17cSMasatake YAMATO 
4160ce1f2415SMasatake YAMATO 	tagFileResized = createTagsWithFallback (fileName, language, mio, mtime, &failureInOpenning);
4161eda0f17cSMasatake YAMATO 
4162eda0f17cSMasatake YAMATO 	finiParserTrashBox ();
4163eda0f17cSMasatake YAMATO 
4164eda0f17cSMasatake YAMATO 	teardownAnon ();
4165eda0f17cSMasatake YAMATO 
41668ae1a1ffSMasatake YAMATO 	if (useSourceFileTagPath && (!failureInOpenning))
4167eda0f17cSMasatake YAMATO 		return teardownWriter (getSourceFileTagPath())? true: tagFileResized;
4168eda0f17cSMasatake YAMATO 	else
4169eda0f17cSMasatake YAMATO 		return teardownWriter(fileName);
4170eda0f17cSMasatake YAMATO }
4171eda0f17cSMasatake YAMATO 
parseFileWithMio(const char * const fileName,MIO * mio,void * clientData)4172eda0f17cSMasatake YAMATO extern bool parseFileWithMio (const char *const fileName, MIO *mio,
4173eda0f17cSMasatake YAMATO 							  void *clientData)
4174f9f37517SAman Gupta {
4175ce990805SThomas Braun 	bool tagFileResized = false;
417642b60e7aSMasatake YAMATO 	langType language;
4177cfac930dSMasatake YAMATO 	struct GetLanguageRequest req = {
4178cfac930dSMasatake YAMATO 		.type = mio? GLR_REUSE: GLR_OPEN,
4179cfac930dSMasatake YAMATO 		.fileName = fileName,
4180cfac930dSMasatake YAMATO 		.mio = mio,
4181cfac930dSMasatake YAMATO 	};
4182ce1f2415SMasatake YAMATO 	memset (&req.mtime, 0, sizeof (req.mtime));
418342b60e7aSMasatake YAMATO 
4184cfac930dSMasatake YAMATO 	language = getFileLanguageForRequest (&req);
4185d4c6f1e6SMasatake YAMATO 	Assert (language != LANG_AUTO);
4186d4c6f1e6SMasatake YAMATO 
4187d4c6f1e6SMasatake YAMATO 	if (Option.printLanguage)
4188d4c6f1e6SMasatake YAMATO 	{
4189d4c6f1e6SMasatake YAMATO 		printGuessedParser (fileName, language);
4190d4c6f1e6SMasatake YAMATO 		return tagFileResized;
4191d4c6f1e6SMasatake YAMATO 	}
4192d4c6f1e6SMasatake YAMATO 
4193d4c6f1e6SMasatake YAMATO 	if (language == LANG_IGNORE)
4194f8bd0fa2SMasatake YAMATO 		verbose ("ignoring %s (unknown language/language disabled)\n",
4195f8bd0fa2SMasatake YAMATO 			 fileName);
4196d4c6f1e6SMasatake YAMATO 	else
4197d4c6f1e6SMasatake YAMATO 	{
41983e7e9e07SMasatake YAMATO 		Assert(isLanguageEnabled (language));
41993e7e9e07SMasatake YAMATO 
42002050d074SAman Gupta 		if (Option.filter && ! Option.interactive)
4201d4c6f1e6SMasatake YAMATO 			openTagFile ();
42022acdcfa1SYasuhiro Matsumoto 
42032acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
42047d6be565SMasatake YAMATO 		/* TODO: checkUTF8BOM can be used to update the encodings. */
4205bde9f60aSColomban Wendling 		openConverter (getLanguageEncoding (language), Option.outputEncoding);
42062acdcfa1SYasuhiro Matsumoto #endif
4207ce1f2415SMasatake YAMATO 		tagFileResized = parseMio (fileName, language, req.mio, req.mtime, true, clientData);
42082050d074SAman Gupta 		if (Option.filter && ! Option.interactive)
4209d4c6f1e6SMasatake YAMATO 			closeTagFile (tagFileResized);
4210d4c6f1e6SMasatake YAMATO 		addTotals (1, 0L, 0L);
4211d4c6f1e6SMasatake YAMATO 
42122acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
42132acdcfa1SYasuhiro Matsumoto 		closeConverter ();
42142acdcfa1SYasuhiro Matsumoto #endif
4215d4c6f1e6SMasatake YAMATO 	}
4216e9d4c72cSMasatake YAMATO 
4217cfac930dSMasatake YAMATO 	if (req.type == GLR_OPEN && req.mio)
4218b978efd6SMasatake YAMATO 		mio_unref (req.mio);
4219d33423e3SSzymon Tomasz Stefanek 
4220d4c6f1e6SMasatake YAMATO 	return tagFileResized;
4221d4c6f1e6SMasatake YAMATO }
4222d4c6f1e6SMasatake YAMATO 
parseRawBuffer(const char * fileName,unsigned char * buffer,size_t bufferSize,const langType language,void * clientData)4223eda0f17cSMasatake YAMATO extern bool parseRawBuffer(const char *fileName, unsigned char *buffer,
4224eda0f17cSMasatake YAMATO 			 size_t bufferSize, const langType language, void *clientData)
4225eda0f17cSMasatake YAMATO {
4226eda0f17cSMasatake YAMATO 	MIO *mio = NULL;
4227eda0f17cSMasatake YAMATO 	bool r;
4228eda0f17cSMasatake YAMATO 
4229eda0f17cSMasatake YAMATO 	if (buffer)
4230eda0f17cSMasatake YAMATO 		mio = mio_new_memory (buffer, bufferSize, NULL, NULL);
4231eda0f17cSMasatake YAMATO 
4232ce1f2415SMasatake YAMATO 	r = parseMio (fileName, language, mio, (time_t)0, false, clientData);
4233eda0f17cSMasatake YAMATO 
4234eda0f17cSMasatake YAMATO 	if (buffer)
4235eda0f17cSMasatake YAMATO 		mio_unref (mio);
4236eda0f17cSMasatake YAMATO 
4237eda0f17cSMasatake YAMATO 	return r;
4238eda0f17cSMasatake YAMATO }
4239eda0f17cSMasatake YAMATO 
matchLanguageMultilineRegexCommon(const langType language,bool (* func)(struct lregexControlBlock *,const vString * const),const vString * const allLines)424041e0b4f8SMasatake YAMATO static void matchLanguageMultilineRegexCommon (const langType language,
424141e0b4f8SMasatake YAMATO 											   bool (* func) (struct lregexControlBlock *, const vString* const),
424241e0b4f8SMasatake YAMATO 											   const vString* const allLines)
424353dda59eSMasatake YAMATO {
4244b177b3faSMasatake YAMATO 	subparser *tmp;
4245b177b3faSMasatake YAMATO 
424641e0b4f8SMasatake YAMATO 	func ((LanguageTable + language)->lregexControlBlock, allLines);
424711358a9dSMasatake YAMATO 	foreachSubparser(tmp, true)
4248b177b3faSMasatake YAMATO 	{
4249b177b3faSMasatake YAMATO 		langType t = getSubparserLanguage (tmp);
4250b177b3faSMasatake YAMATO 		enterSubparser (tmp);
425141e0b4f8SMasatake YAMATO 		matchLanguageMultilineRegexCommon (t, func, allLines);
4252b177b3faSMasatake YAMATO 		leaveSubparser ();
4253b177b3faSMasatake YAMATO 	}
4254b177b3faSMasatake YAMATO }
4255b177b3faSMasatake YAMATO 
matchLanguageMultilineRegex(const langType language,const vString * const allLines)425641e0b4f8SMasatake YAMATO extern void matchLanguageMultilineRegex (const langType language,
425741e0b4f8SMasatake YAMATO 										 const vString* const allLines)
425841e0b4f8SMasatake YAMATO {
425941e0b4f8SMasatake YAMATO 	matchLanguageMultilineRegexCommon(language, matchMultilineRegex, allLines);
426041e0b4f8SMasatake YAMATO }
426141e0b4f8SMasatake YAMATO 
matchLanguageMultitableRegex(const langType language,const vString * const allLines)426241e0b4f8SMasatake YAMATO extern void matchLanguageMultitableRegex (const langType language,
426341e0b4f8SMasatake YAMATO 										  const vString* const allLines)
426441e0b4f8SMasatake YAMATO {
426541e0b4f8SMasatake YAMATO 	matchLanguageMultilineRegexCommon(language, matchMultitableRegex, allLines);
426641e0b4f8SMasatake YAMATO }
426741e0b4f8SMasatake YAMATO 
processLanguageMultitableExtendingOption(langType language,const char * const parameter)4268bf809d1aSMasatake YAMATO extern void processLanguageMultitableExtendingOption (langType language, const char *const parameter)
4269bf809d1aSMasatake YAMATO {
4270bf809d1aSMasatake YAMATO 	const char* src;
4271bf809d1aSMasatake YAMATO 	char* dist;
4272bf809d1aSMasatake YAMATO 	const char *tmp;
4273bf809d1aSMasatake YAMATO 
4274bf809d1aSMasatake YAMATO 	tmp = strchr(parameter, '+');
4275bf809d1aSMasatake YAMATO 
4276bf809d1aSMasatake YAMATO 	if (!tmp)
4277bf809d1aSMasatake YAMATO 		error (FATAL, "no separator(+) found: %s", parameter);
4278bf809d1aSMasatake YAMATO 
4279bf809d1aSMasatake YAMATO 	if (tmp == parameter)
4280bf809d1aSMasatake YAMATO 		error (FATAL, "the name of source table is empty in table extending: %s", parameter);
4281bf809d1aSMasatake YAMATO 
4282bf809d1aSMasatake YAMATO 	src = tmp + 1;
4283bf809d1aSMasatake YAMATO 	if (!*src)
4284bf809d1aSMasatake YAMATO 		error (FATAL, "the name of dist table is empty in table extending: %s", parameter);
4285bf809d1aSMasatake YAMATO 
4286bf809d1aSMasatake YAMATO 	dist = eStrndup(parameter, tmp  - parameter);
4287bf809d1aSMasatake YAMATO 	extendRegexTable(((LanguageTable + language)->lregexControlBlock), src, dist);
4288bf809d1aSMasatake YAMATO 	eFree (dist);
4289bf809d1aSMasatake YAMATO }
4290bf809d1aSMasatake YAMATO 
lregexQueryParserAndSubparsers(const langType language,bool (* predicate)(struct lregexControlBlock *))4291018165e6Sjannick0 static bool lregexQueryParserAndSubparsers (const langType language, bool (* predicate) (struct lregexControlBlock *))
4292b177b3faSMasatake YAMATO {
4293b177b3faSMasatake YAMATO 	bool r;
4294b177b3faSMasatake YAMATO 	subparser *tmp;
4295b177b3faSMasatake YAMATO 
4296b177b3faSMasatake YAMATO 	r = predicate ((LanguageTable + language)->lregexControlBlock);
4297b177b3faSMasatake YAMATO 	if (!r)
4298b177b3faSMasatake YAMATO 	{
429911358a9dSMasatake YAMATO 		foreachSubparser(tmp, true)
4300b177b3faSMasatake YAMATO 		{
4301b177b3faSMasatake YAMATO 			langType t = getSubparserLanguage (tmp);
4302b177b3faSMasatake YAMATO 			enterSubparser (tmp);
4303018165e6Sjannick0 			r = lregexQueryParserAndSubparsers (t, predicate);
4304b177b3faSMasatake YAMATO 			leaveSubparser ();
4305b177b3faSMasatake YAMATO 
4306b177b3faSMasatake YAMATO 			if (r)
4307b177b3faSMasatake YAMATO 				break;
4308b177b3faSMasatake YAMATO 		}
4309b177b3faSMasatake YAMATO 	}
4310b177b3faSMasatake YAMATO 
4311b177b3faSMasatake YAMATO 	return r;
431253dda59eSMasatake YAMATO }
431353dda59eSMasatake YAMATO 
hasLanguageMultilineRegexPatterns(const langType language)431453dda59eSMasatake YAMATO extern bool hasLanguageMultilineRegexPatterns (const langType language)
431553dda59eSMasatake YAMATO {
4316018165e6Sjannick0 	return lregexQueryParserAndSubparsers (language, regexNeedsMultilineBuffer);
431753dda59eSMasatake YAMATO }
431853dda59eSMasatake YAMATO 
4319b177b3faSMasatake YAMATO 
addLanguageCallbackRegex(const langType language,const char * const regex,const char * const flags,const regexCallback callback,bool * disabled,void * userData)432053dda59eSMasatake YAMATO extern void addLanguageCallbackRegex (const langType language, const char *const regex, const char *const flags,
432153dda59eSMasatake YAMATO 									  const regexCallback callback, bool *disabled, void *userData)
432253dda59eSMasatake YAMATO {
432353dda59eSMasatake YAMATO 	addCallbackRegex ((LanguageTable +language)->lregexControlBlock, regex, flags, callback, disabled, userData);
432453dda59eSMasatake YAMATO }
432553dda59eSMasatake YAMATO 
doesLanguageExpectCorkInRegex(const langType language)4326c25346c2SMasatake YAMATO extern bool doesLanguageExpectCorkInRegex (const langType language)
432753dda59eSMasatake YAMATO {
4328cb4dd5c3SMasatake YAMATO 	bool hasScopeAction;
4329cb4dd5c3SMasatake YAMATO 
4330cb4dd5c3SMasatake YAMATO 	pushLanguage (language);
4331c25346c2SMasatake YAMATO 	hasScopeAction = lregexQueryParserAndSubparsers (language, doesExpectCorkInRegex);
4332cb4dd5c3SMasatake YAMATO 	popLanguage ();
4333cb4dd5c3SMasatake YAMATO 
4334cb4dd5c3SMasatake YAMATO 	return hasScopeAction;
433553dda59eSMasatake YAMATO }
433653dda59eSMasatake YAMATO 
matchLanguageRegex(const langType language,const vString * const line)433730edf066SMasatake YAMATO extern void matchLanguageRegex (const langType language, const vString* const line)
433853dda59eSMasatake YAMATO {
433918193ebfSMasatake YAMATO 	subparser *tmp;
434018193ebfSMasatake YAMATO 
434130edf066SMasatake YAMATO 	matchRegex ((LanguageTable + language)->lregexControlBlock, line);
434211358a9dSMasatake YAMATO 	foreachSubparser(tmp, true)
434318193ebfSMasatake YAMATO 	{
434418193ebfSMasatake YAMATO 		langType t = getSubparserLanguage (tmp);
434518193ebfSMasatake YAMATO 		enterSubparser (tmp);
434618193ebfSMasatake YAMATO 		matchLanguageRegex (t, line);
434718193ebfSMasatake YAMATO 		leaveSubparser ();
434818193ebfSMasatake YAMATO 	}
434953dda59eSMasatake YAMATO }
435053dda59eSMasatake YAMATO 
processLanguageRegexOption(langType language,enum regexParserType regptype,const char * const parameter)4351056b32e1SMasatake YAMATO extern bool processLanguageRegexOption (langType language,
43521b9c3aecSMasatake YAMATO 										enum regexParserType regptype,
4353056b32e1SMasatake YAMATO 										const char *const parameter)
4354056b32e1SMasatake YAMATO {
4355641e337aSMasatake YAMATO 	processTagRegexOption ((LanguageTable +language)->lregexControlBlock,
43561b9c3aecSMasatake YAMATO 						   regptype, parameter);
4357056b32e1SMasatake YAMATO 
4358056b32e1SMasatake YAMATO 	return true;
4359056b32e1SMasatake YAMATO }
4360056b32e1SMasatake YAMATO 
processTabledefOption(const char * const option,const char * const parameter)4361e0e33135SMasatake YAMATO extern bool processTabledefOption (const char *const option, const char *const parameter)
4362e0e33135SMasatake YAMATO {
4363e0e33135SMasatake YAMATO 	langType language;
4364e0e33135SMasatake YAMATO 
4365e0e33135SMasatake YAMATO 	language = getLanguageComponentInOption (option, "_tabledef-");
4366e0e33135SMasatake YAMATO 	if (language == LANG_IGNORE)
4367e0e33135SMasatake YAMATO 		return false;
4368e0e33135SMasatake YAMATO 
4369e0e33135SMasatake YAMATO 	if (parameter == NULL || parameter[0] == '\0')
4370e0e33135SMasatake YAMATO 		error (FATAL, "A parameter is needed after \"%s\" option", option);
4371e0e33135SMasatake YAMATO 
4372e0e33135SMasatake YAMATO 	addRegexTable((LanguageTable +language)->lregexControlBlock, parameter);
4373e0e33135SMasatake YAMATO 	return true;
4374e0e33135SMasatake YAMATO }
4375e0e33135SMasatake YAMATO 
useRegexMethod(const langType language)4376d4c6f1e6SMasatake YAMATO extern void useRegexMethod (const langType language)
4377d4c6f1e6SMasatake YAMATO {
4378d4c6f1e6SMasatake YAMATO 	parserDefinition* lang;
4379d4c6f1e6SMasatake YAMATO 
4380d4c6f1e6SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4381e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4382d4c6f1e6SMasatake YAMATO 	lang->method |= METHOD_REGEX;
4383d4c6f1e6SMasatake YAMATO }
4384d4c6f1e6SMasatake YAMATO 
useXpathMethod(const langType language)43852082dbbfSColomban Wendling static void useXpathMethod (const langType language)
4386a086aff1SMasatake YAMATO {
4387a086aff1SMasatake YAMATO 	parserDefinition* lang;
4388a086aff1SMasatake YAMATO 
4389a086aff1SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4390e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4391a086aff1SMasatake YAMATO 	lang->method |= METHOD_XPATH;
4392a086aff1SMasatake YAMATO }
4393a086aff1SMasatake YAMATO 
installTagRegexTable(const langType language)4394d453869fSMasatake YAMATO static void installTagRegexTable (const langType language)
4395dc0f490fSMasatake YAMATO {
4396056b32e1SMasatake YAMATO 	parserObject* parser;
4397dc0f490fSMasatake YAMATO 	parserDefinition* lang;
4398dc0f490fSMasatake YAMATO 	unsigned int i;
4399dc0f490fSMasatake YAMATO 
4400dc0f490fSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4401056b32e1SMasatake YAMATO 	parser = LanguageTable + language;
4402056b32e1SMasatake YAMATO 	lang = parser->def;
4403dc0f490fSMasatake YAMATO 
4404dc0f490fSMasatake YAMATO 
4405d453869fSMasatake YAMATO 	if (lang->tagRegexTable != NULL)
44066578b12dSMasatake YAMATO 	{
4407965b7025SMasatake YAMATO 		/* ctags_cli_main() calls initRegexOptscript ().
4408965b7025SMasatake YAMATO 		 * However, mini-geany deasn't call ctags_cli_main().
4409965b7025SMasatake YAMATO 		 * So we call initRegexOptscript () here.
4410965b7025SMasatake YAMATO 		 */
4411965b7025SMasatake YAMATO 		initRegexOptscript ();
4412965b7025SMasatake YAMATO 
4413dc0f490fSMasatake YAMATO 	    for (i = 0; i < lang->tagRegexCount; ++i)
4414641e337aSMasatake YAMATO 		{
4415641e337aSMasatake YAMATO 			if (lang->tagRegexTable [i].mline)
4416641e337aSMasatake YAMATO 				addTagMultiLineRegex (parser->lregexControlBlock,
4417641e337aSMasatake YAMATO 									  lang->tagRegexTable [i].regex,
4418641e337aSMasatake YAMATO 									  lang->tagRegexTable [i].name,
4419641e337aSMasatake YAMATO 									  lang->tagRegexTable [i].kinds,
4420641e337aSMasatake YAMATO 									  lang->tagRegexTable [i].flags,
4421641e337aSMasatake YAMATO 									  (lang->tagRegexTable [i].disabled));
4422641e337aSMasatake YAMATO 			else
4423056b32e1SMasatake YAMATO 				addTagRegex (parser->lregexControlBlock,
4424dc0f490fSMasatake YAMATO 							 lang->tagRegexTable [i].regex,
4425dc0f490fSMasatake YAMATO 							 lang->tagRegexTable [i].name,
4426dc0f490fSMasatake YAMATO 							 lang->tagRegexTable [i].kinds,
44272a738f47SMasatake YAMATO 							 lang->tagRegexTable [i].flags,
44282a738f47SMasatake YAMATO 							 (lang->tagRegexTable [i].disabled));
44296578b12dSMasatake YAMATO 		}
4430dc0f490fSMasatake YAMATO 	}
4431641e337aSMasatake YAMATO }
4432dc0f490fSMasatake YAMATO 
installKeywordTable(const langType language)4433d453869fSMasatake YAMATO static void installKeywordTable (const langType language)
4434c379c5d2SMasatake YAMATO {
4435c379c5d2SMasatake YAMATO 	parserDefinition* lang;
4436c379c5d2SMasatake YAMATO 	unsigned int i;
4437c379c5d2SMasatake YAMATO 
4438c379c5d2SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4439e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4440c379c5d2SMasatake YAMATO 
4441d453869fSMasatake YAMATO 	if (lang->keywordTable != NULL)
444273ba730fSMasatake YAMATO 	{
4443c379c5d2SMasatake YAMATO 		for (i = 0; i < lang->keywordCount; ++i)
4444c379c5d2SMasatake YAMATO 			addKeyword (lang->keywordTable [i].name,
4445c379c5d2SMasatake YAMATO 				    language,
4446c379c5d2SMasatake YAMATO 				    lang->keywordTable [i].id);
444773ba730fSMasatake YAMATO 	}
4448c379c5d2SMasatake YAMATO }
4449e7283d01SMasatake YAMATO 
installTagXpathTable(const langType language)4450d453869fSMasatake YAMATO static void installTagXpathTable (const langType language)
4451a086aff1SMasatake YAMATO {
4452a086aff1SMasatake YAMATO 	parserDefinition* lang;
4453a086aff1SMasatake YAMATO 	unsigned int i, j;
4454a086aff1SMasatake YAMATO 
4455a086aff1SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4456e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4457a086aff1SMasatake YAMATO 
4458d453869fSMasatake YAMATO 	if (lang->tagXpathTableTable != NULL)
4459a086aff1SMasatake YAMATO 	{
4460a086aff1SMasatake YAMATO 		for (i = 0; i < lang->tagXpathTableCount; ++i)
4461a086aff1SMasatake YAMATO 			for (j = 0; j < lang->tagXpathTableTable[i].count; ++j)
4462a086aff1SMasatake YAMATO 				addTagXpath (language, lang->tagXpathTableTable[i].table + j);
4463fe9cf7d1SMasatake YAMATO 		useXpathMethod (language);
4464a086aff1SMasatake YAMATO 	}
4465a086aff1SMasatake YAMATO }
4466a086aff1SMasatake YAMATO 
uninstallTagXpathTable(const langType language)4467eb480042SMasatake YAMATO static void uninstallTagXpathTable (const langType language)
4468eb480042SMasatake YAMATO {
4469eb480042SMasatake YAMATO 	parserDefinition* lang;
4470eb480042SMasatake YAMATO 	unsigned int i, j;
4471eb480042SMasatake YAMATO 
4472eb480042SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4473eb480042SMasatake YAMATO 	lang = LanguageTable [language].def;
4474eb480042SMasatake YAMATO 
4475eb480042SMasatake YAMATO 	if (lang->tagXpathTableTable != NULL)
4476eb480042SMasatake YAMATO 	{
4477eb480042SMasatake YAMATO 		for (i = 0; i < lang->tagXpathTableCount; ++i)
4478eb480042SMasatake YAMATO 			for (j = 0; j < lang->tagXpathTableTable[i].count; ++j)
4479eb480042SMasatake YAMATO 				removeTagXpath (language, lang->tagXpathTableTable[i].table + j);
4480eb480042SMasatake YAMATO 	}
4481eb480042SMasatake YAMATO }
4482eb480042SMasatake YAMATO 
getXpathTableTable(const langType language,unsigned int nth)44830fde73e0SMasatake YAMATO const tagXpathTableTable *getXpathTableTable (const langType language, unsigned int nth)
44840fde73e0SMasatake YAMATO {
44850fde73e0SMasatake YAMATO 	parserDefinition* lang;
44860fde73e0SMasatake YAMATO 
44870fde73e0SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
44880fde73e0SMasatake YAMATO 	lang = LanguageTable [language].def;
44890fde73e0SMasatake YAMATO 
44900fde73e0SMasatake YAMATO 	Assert (nth < lang->tagXpathTableCount);
44910fde73e0SMasatake YAMATO 	return lang->tagXpathTableTable + nth;
44920fde73e0SMasatake YAMATO }
44930fde73e0SMasatake YAMATO 
getXpathFileSpecCount(const langType language)4494d5e6de9cSMasatake YAMATO extern unsigned int getXpathFileSpecCount (const langType language)
4495d5e6de9cSMasatake YAMATO {
4496d5e6de9cSMasatake YAMATO 	parserDefinition* lang;
4497d5e6de9cSMasatake YAMATO 
4498d5e6de9cSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4499e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4500d5e6de9cSMasatake YAMATO 
4501d5e6de9cSMasatake YAMATO 	return lang->xpathFileSpecCount;
4502d5e6de9cSMasatake YAMATO }
4503d5e6de9cSMasatake YAMATO 
getXpathFileSpec(const langType language,unsigned int nth)4504d5e6de9cSMasatake YAMATO extern xpathFileSpec* getXpathFileSpec (const langType language, unsigned int nth)
4505d5e6de9cSMasatake YAMATO {
4506d5e6de9cSMasatake YAMATO 	parserDefinition* lang;
4507d5e6de9cSMasatake YAMATO 
4508d5e6de9cSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4509e02be843SMasatake YAMATO 	lang = LanguageTable [language].def;
4510d5e6de9cSMasatake YAMATO 
4511d5e6de9cSMasatake YAMATO 	Assert (nth < lang->xpathFileSpecCount);
4512d5e6de9cSMasatake YAMATO 	return lang->xpathFileSpecs + nth;
4513d5e6de9cSMasatake YAMATO }
4514d5e6de9cSMasatake YAMATO 
makeKindSeparatorsPseudoTags(const langType language,const ptagDesc * pdesc)4515ce990805SThomas Braun extern bool makeKindSeparatorsPseudoTags (const langType language,
4516c645eb4cSMasatake YAMATO 					     const ptagDesc *pdesc)
4517ce8d2e8fSMasatake YAMATO {
45185510af75SMasatake YAMATO 	parserObject* parser;
4519ce8d2e8fSMasatake YAMATO 	parserDefinition* lang;
45205510af75SMasatake YAMATO 	struct kindControlBlock *kcb;
45215510af75SMasatake YAMATO 	kindDefinition *kind;
4522ce8d2e8fSMasatake YAMATO 	unsigned int kindCount;
4523e5f9cc19SMasatake YAMATO 	unsigned int i, j;
4524ce8d2e8fSMasatake YAMATO 
4525ce990805SThomas Braun 	bool r = false;
4526ab9fd29dSMasatake YAMATO 
4527ce8d2e8fSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
45285510af75SMasatake YAMATO 	parser = LanguageTable + language;
45295510af75SMasatake YAMATO 	lang = parser->def;
45305510af75SMasatake YAMATO 	kcb = parser->kindControlBlock;
45315510af75SMasatake YAMATO 	kindCount = countKinds(kcb);
4532ce8d2e8fSMasatake YAMATO 
45335510af75SMasatake YAMATO 	if (kindCount == 0)
4534ab9fd29dSMasatake YAMATO 		return r;
4535ce8d2e8fSMasatake YAMATO 
453602cadfe0SMasatake YAMATO 	vString *sepval = vStringNew();
4537ce8d2e8fSMasatake YAMATO 	for (i = 0; i < kindCount; ++i)
4538ce8d2e8fSMasatake YAMATO 	{
45395510af75SMasatake YAMATO 		kind = getKind (kcb, i);
45405510af75SMasatake YAMATO 		for (j = 0; j < kind->separatorCount; ++j)
4541ce8d2e8fSMasatake YAMATO 		{
45422ea43882SMasatake YAMATO 			char name[3] = {[1] = '\0', [2] = '\0'};
4543e112e8abSMasatake YAMATO 			const kindDefinition *upperKind;
4544ce8d2e8fSMasatake YAMATO 			const scopeSeparator *sep;
4545ce8d2e8fSMasatake YAMATO 
45465510af75SMasatake YAMATO 			sep = kind->separators + j;
4547ce8d2e8fSMasatake YAMATO 
4548f92e6bf2SMasatake YAMATO 			if (sep->parentKindIndex == KIND_WILDCARD_INDEX)
4549e9e86f51SMasatake YAMATO 			{
45502ea43882SMasatake YAMATO 				name[0] = KIND_WILDCARD_LETTER;
45512ea43882SMasatake YAMATO 				name[1] = kind->letter;
4552e9e86f51SMasatake YAMATO 			}
4553f92e6bf2SMasatake YAMATO 			else if (sep->parentKindIndex == KIND_GHOST_INDEX)
4554e9e86f51SMasatake YAMATO 			{
4555e9e86f51SMasatake YAMATO 				/* This is root separator: no upper item is here. */
45562ea43882SMasatake YAMATO 				name[0] = kind->letter;
4557e9e86f51SMasatake YAMATO 			}
4558ce8d2e8fSMasatake YAMATO 			else
4559ce8d2e8fSMasatake YAMATO 			{
4560f92e6bf2SMasatake YAMATO 				upperKind = getLanguageKind (language,
4561f92e6bf2SMasatake YAMATO 							    sep->parentKindIndex);
4562ce8d2e8fSMasatake YAMATO 				if (!upperKind)
4563ce8d2e8fSMasatake YAMATO 					continue;
4564ce8d2e8fSMasatake YAMATO 
45652ea43882SMasatake YAMATO 				name[0] = upperKind->letter;
45662ea43882SMasatake YAMATO 				name[1] = kind->letter;
4567e9e86f51SMasatake YAMATO 			}
4568e9e86f51SMasatake YAMATO 
4569ce8d2e8fSMasatake YAMATO 
4570ce8d2e8fSMasatake YAMATO 			vStringClear (sepval);
4571ce8d2e8fSMasatake YAMATO 			vStringCatSWithEscaping (sepval, sep->separator);
4572ce8d2e8fSMasatake YAMATO 
4573ab9fd29dSMasatake YAMATO 			r = writePseudoTag (pdesc, vStringValue (sepval),
4574ab9fd29dSMasatake YAMATO 					    name, lang->name) || r;
4575ce8d2e8fSMasatake YAMATO 		}
4576ce8d2e8fSMasatake YAMATO 	}
457702cadfe0SMasatake YAMATO 	vStringDelete (sepval);
4578ab9fd29dSMasatake YAMATO 
4579ab9fd29dSMasatake YAMATO 	return r;
4580ce8d2e8fSMasatake YAMATO }
4581ce8d2e8fSMasatake YAMATO 
4582e362e918SMasatake YAMATO struct makeKindDescriptionPseudoTagData {
4583e362e918SMasatake YAMATO 	const char* langName;
4584c645eb4cSMasatake YAMATO 	const ptagDesc *pdesc;
4585ce990805SThomas Braun 	bool written;
4586e362e918SMasatake YAMATO };
4587e362e918SMasatake YAMATO 
makeKindDescriptionPseudoTag(kindDefinition * kind,void * user_data)4588e112e8abSMasatake YAMATO static bool makeKindDescriptionPseudoTag (kindDefinition *kind,
4589e362e918SMasatake YAMATO 					     void *user_data)
4590e362e918SMasatake YAMATO {
4591e362e918SMasatake YAMATO 	struct makeKindDescriptionPseudoTagData *data = user_data;
4592e362e918SMasatake YAMATO 	vString *letter_and_name;
4593e362e918SMasatake YAMATO 	vString *description;
45942b2809eaSMasatake YAMATO 	const char *d;
4595e362e918SMasatake YAMATO 
4596e362e918SMasatake YAMATO 	letter_and_name = vStringNew ();
4597e362e918SMasatake YAMATO 	description = vStringNew ();
4598e362e918SMasatake YAMATO 
4599e362e918SMasatake YAMATO 	vStringPut (letter_and_name, kind -> letter);
4600e362e918SMasatake YAMATO 	vStringPut (letter_and_name, ',');
4601e362e918SMasatake YAMATO 	vStringCatS (letter_and_name, kind -> name);
4602e362e918SMasatake YAMATO 
46032b2809eaSMasatake YAMATO 	d = kind->description? kind->description: kind->name;
46042b2809eaSMasatake YAMATO 	vStringCatSWithEscapingAsPattern (description, d);
4605ab9fd29dSMasatake YAMATO 	data->written |=  writePseudoTag (data->pdesc, vStringValue (letter_and_name),
4606e362e918SMasatake YAMATO 					  vStringValue (description),
4607e362e918SMasatake YAMATO 					  data->langName);
4608e362e918SMasatake YAMATO 
4609e362e918SMasatake YAMATO 	vStringDelete (description);
4610e362e918SMasatake YAMATO 	vStringDelete (letter_and_name);
4611e362e918SMasatake YAMATO 
4612ce990805SThomas Braun 	return false;
4613e362e918SMasatake YAMATO }
4614e362e918SMasatake YAMATO 
makeRoleDescriptionPseudoTag(kindDefinition * kind,roleDefinition * role,void * user_data)4615cea85fadSMasatake YAMATO static bool makeRoleDescriptionPseudoTag (kindDefinition *kind,
4616cea85fadSMasatake YAMATO 										  roleDefinition *role,
4617cea85fadSMasatake YAMATO 										  void *user_data)
4618cea85fadSMasatake YAMATO {
4619cea85fadSMasatake YAMATO 	struct makeKindDescriptionPseudoTagData *data = user_data;
4620cea85fadSMasatake YAMATO 
4621cea85fadSMasatake YAMATO 	vString *parser_and_kind_name = vStringNewInit (data->langName);
4622cea85fadSMasatake YAMATO 	vStringCatS (parser_and_kind_name, PSEUDO_TAG_SEPARATOR);
4623cea85fadSMasatake YAMATO 	vStringCatS (parser_and_kind_name, kind->name);
4624cea85fadSMasatake YAMATO 
4625cea85fadSMasatake YAMATO 	vString *description = vStringNew ();
4626cea85fadSMasatake YAMATO 	const char *d = role->description? role->description: role->name;
4627cea85fadSMasatake YAMATO 	vStringCatSWithEscapingAsPattern (description, d);
4628cea85fadSMasatake YAMATO 
4629cea85fadSMasatake YAMATO 	data->written |=  writePseudoTag (data->pdesc, role->name,
4630cea85fadSMasatake YAMATO 									  vStringValue (description),
4631cea85fadSMasatake YAMATO 									  vStringValue (parser_and_kind_name));
4632cea85fadSMasatake YAMATO 
4633cea85fadSMasatake YAMATO 	vStringDelete (description);
4634cea85fadSMasatake YAMATO 	vStringDelete (parser_and_kind_name);
4635cea85fadSMasatake YAMATO 
4636cea85fadSMasatake YAMATO 	return false;
4637cea85fadSMasatake YAMATO }
4638cea85fadSMasatake YAMATO 
makeKindDescriptionsPseudoTags(const langType language,const ptagDesc * pdesc)4639ce990805SThomas Braun extern bool makeKindDescriptionsPseudoTags (const langType language,
4640c645eb4cSMasatake YAMATO 					    const ptagDesc *pdesc)
4641e362e918SMasatake YAMATO {
46427b543634SMasatake YAMATO 	parserObject *parser;
46437b543634SMasatake YAMATO 	struct kindControlBlock *kcb;
4644e362e918SMasatake YAMATO 	parserDefinition* lang;
46457b543634SMasatake YAMATO 	kindDefinition *kind;
4646e362e918SMasatake YAMATO 	unsigned int kindCount, i;
4647e362e918SMasatake YAMATO 	struct makeKindDescriptionPseudoTagData data;
4648e362e918SMasatake YAMATO 
4649e362e918SMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
46507b543634SMasatake YAMATO 	parser = LanguageTable + language;
46517b543634SMasatake YAMATO 	kcb = parser->kindControlBlock;
46527b543634SMasatake YAMATO 	lang = parser->def;
46537b543634SMasatake YAMATO 
46547b543634SMasatake YAMATO 	kindCount = countKinds(kcb);
4655e362e918SMasatake YAMATO 
4656e362e918SMasatake YAMATO 	data.langName = lang->name;
4657e362e918SMasatake YAMATO 	data.pdesc = pdesc;
4658ce990805SThomas Braun 	data.written = false;
4659e362e918SMasatake YAMATO 
4660e362e918SMasatake YAMATO 	for (i = 0; i < kindCount; ++i)
46617b543634SMasatake YAMATO 	{
4662fd0af0cfSMasatake YAMATO 		if (!isLanguageKindEnabled (language, i))
4663fd0af0cfSMasatake YAMATO 			continue;
4664fd0af0cfSMasatake YAMATO 
46657b543634SMasatake YAMATO 		kind = getKind (kcb, i);
46667b543634SMasatake YAMATO 		makeKindDescriptionPseudoTag (kind, &data);
46677b543634SMasatake YAMATO 	}
4668e362e918SMasatake YAMATO 
4669ab9fd29dSMasatake YAMATO 	return data.written;
4670e362e918SMasatake YAMATO }
4671e362e918SMasatake YAMATO 
makeFieldDescriptionPseudoTag(const langType language,fieldType f,const ptagDesc * pdesc)46729ab0e076SMasatake YAMATO static bool makeFieldDescriptionPseudoTag (const langType language,
46739ab0e076SMasatake YAMATO 										   fieldType f,
46749ab0e076SMasatake YAMATO 										   const ptagDesc *pdesc)
46759ab0e076SMasatake YAMATO {
46769ab0e076SMasatake YAMATO 	vString *description;
46779ab0e076SMasatake YAMATO 	const char *name = getFieldName (f);
46789ab0e076SMasatake YAMATO 
46799ab0e076SMasatake YAMATO 	if (name == NULL || name [0] == '\0')
46809ab0e076SMasatake YAMATO 		return false;
46819ab0e076SMasatake YAMATO 
46829ab0e076SMasatake YAMATO 	description = vStringNew ();
46839ab0e076SMasatake YAMATO 	vStringCatSWithEscapingAsPattern (description,
46849ab0e076SMasatake YAMATO 									  getFieldDescription (f));
46859ab0e076SMasatake YAMATO 
46869ab0e076SMasatake YAMATO 	bool r = writePseudoTag (pdesc, name,
46879ab0e076SMasatake YAMATO 							 vStringValue (description),
46889ab0e076SMasatake YAMATO 							 language == LANG_IGNORE? NULL: getLanguageName (language));
46899ab0e076SMasatake YAMATO 
46909ab0e076SMasatake YAMATO 	vStringDelete (description);
46919ab0e076SMasatake YAMATO 	return r;
46929ab0e076SMasatake YAMATO }
46939ab0e076SMasatake YAMATO 
makeFieldDescriptionsPseudoTags(const langType language,const ptagDesc * pdesc)46949ab0e076SMasatake YAMATO extern bool makeFieldDescriptionsPseudoTags (const langType language,
46959ab0e076SMasatake YAMATO 											 const ptagDesc *pdesc)
46969ab0e076SMasatake YAMATO {
46979ab0e076SMasatake YAMATO 	bool written = false;
46989ab0e076SMasatake YAMATO 	for (int i = 0; i < countFields (); i++)
46999ab0e076SMasatake YAMATO 	{
47009ab0e076SMasatake YAMATO 		if (getFieldOwner (i) == language
47019ab0e076SMasatake YAMATO 			&& isFieldEnabled (i))
47029ab0e076SMasatake YAMATO 		{
47039ab0e076SMasatake YAMATO 			if (makeFieldDescriptionPseudoTag (language, i, pdesc))
47049ab0e076SMasatake YAMATO 				written = true;
47059ab0e076SMasatake YAMATO 		}
47069ab0e076SMasatake YAMATO 	}
47079ab0e076SMasatake YAMATO 	return written;
47089ab0e076SMasatake YAMATO }
47099ab0e076SMasatake YAMATO 
makeExtraDescriptionPseudoTag(const langType language,xtagType x,const ptagDesc * pdesc)4710726cac0cSMasatake YAMATO static bool makeExtraDescriptionPseudoTag (const langType language,
4711726cac0cSMasatake YAMATO 										   xtagType x,
4712726cac0cSMasatake YAMATO 										   const ptagDesc *pdesc)
4713726cac0cSMasatake YAMATO {
4714726cac0cSMasatake YAMATO 	vString *description;
4715726cac0cSMasatake YAMATO 	const char *name = getXtagName (x);
4716726cac0cSMasatake YAMATO 
4717726cac0cSMasatake YAMATO 	if (name == NULL || name [0] == '\0')
4718726cac0cSMasatake YAMATO 		return false;
4719726cac0cSMasatake YAMATO 
4720726cac0cSMasatake YAMATO 	description = vStringNew ();
4721726cac0cSMasatake YAMATO 	vStringCatSWithEscapingAsPattern (description,
4722726cac0cSMasatake YAMATO 									  getXtagDescription (x));
4723726cac0cSMasatake YAMATO 
4724726cac0cSMasatake YAMATO 	bool r = writePseudoTag (pdesc, name,
4725726cac0cSMasatake YAMATO 							 vStringValue (description),
4726726cac0cSMasatake YAMATO 							 language == LANG_IGNORE? NULL: getLanguageName (language));
4727726cac0cSMasatake YAMATO 
4728726cac0cSMasatake YAMATO 	vStringDelete (description);
4729726cac0cSMasatake YAMATO 	return r;
4730726cac0cSMasatake YAMATO }
4731726cac0cSMasatake YAMATO 
makeExtraDescriptionsPseudoTags(const langType language,const ptagDesc * pdesc)4732726cac0cSMasatake YAMATO extern bool makeExtraDescriptionsPseudoTags (const langType language,
4733726cac0cSMasatake YAMATO 											 const ptagDesc *pdesc)
4734726cac0cSMasatake YAMATO {
4735726cac0cSMasatake YAMATO 	bool written = false;
4736726cac0cSMasatake YAMATO 	for (int i = 0; i < countXtags (); i++)
4737726cac0cSMasatake YAMATO 	{
4738726cac0cSMasatake YAMATO 		if (getXtagOwner (i) == language
4739726cac0cSMasatake YAMATO 			&& isXtagEnabled (i))
4740726cac0cSMasatake YAMATO 		{
4741726cac0cSMasatake YAMATO 			if (makeExtraDescriptionPseudoTag (language, i, pdesc))
4742726cac0cSMasatake YAMATO 				written = true;
4743726cac0cSMasatake YAMATO 		}
4744726cac0cSMasatake YAMATO 	}
4745726cac0cSMasatake YAMATO 	return written;
4746726cac0cSMasatake YAMATO }
4747726cac0cSMasatake YAMATO 
makeRoleDescriptionsPseudoTags(const langType language,const ptagDesc * pdesc)4748cea85fadSMasatake YAMATO extern bool makeRoleDescriptionsPseudoTags (const langType language,
4749cea85fadSMasatake YAMATO 											const ptagDesc *pdesc)
4750cea85fadSMasatake YAMATO {
4751cea85fadSMasatake YAMATO 	parserObject *parser;
4752cea85fadSMasatake YAMATO 	struct kindControlBlock *kcb;
4753cea85fadSMasatake YAMATO 	parserDefinition* lang;
4754cea85fadSMasatake YAMATO 	kindDefinition *kind;
4755cea85fadSMasatake YAMATO 	struct makeKindDescriptionPseudoTagData data;
4756cea85fadSMasatake YAMATO 
4757cea85fadSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
4758cea85fadSMasatake YAMATO 	parser = LanguageTable + language;
4759cea85fadSMasatake YAMATO 	kcb = parser->kindControlBlock;
4760cea85fadSMasatake YAMATO 	lang = parser->def;
4761cea85fadSMasatake YAMATO 
4762cea85fadSMasatake YAMATO 	unsigned int kindCount = countKinds(kcb);
4763cea85fadSMasatake YAMATO 
4764cea85fadSMasatake YAMATO 	data.langName = lang->name;
4765cea85fadSMasatake YAMATO 	data.pdesc = pdesc;
4766cea85fadSMasatake YAMATO 	data.written = false;
4767cea85fadSMasatake YAMATO 
4768cea85fadSMasatake YAMATO 	for (unsigned int i = 0; i < kindCount; ++i)
4769cea85fadSMasatake YAMATO 	{
4770cea85fadSMasatake YAMATO 		if (!isLanguageKindEnabled (language, i))
4771cea85fadSMasatake YAMATO 			continue;
4772cea85fadSMasatake YAMATO 
4773cea85fadSMasatake YAMATO 		kind = getKind (kcb, i);
4774cea85fadSMasatake YAMATO 
4775cea85fadSMasatake YAMATO 		unsigned int roleCount = countRoles (kcb, i);
4776cea85fadSMasatake YAMATO 		for (unsigned int j = 0; j < roleCount; ++j)
4777cea85fadSMasatake YAMATO 		{
4778cea85fadSMasatake YAMATO 			if (isRoleEnabled (kcb, i, j))
4779cea85fadSMasatake YAMATO 			{
4780cea85fadSMasatake YAMATO 				roleDefinition *role = getRole (kcb, i, j);
4781cea85fadSMasatake YAMATO 				makeRoleDescriptionPseudoTag (kind, role, &data);
4782cea85fadSMasatake YAMATO 			}
4783cea85fadSMasatake YAMATO 		}
4784cea85fadSMasatake YAMATO 	}
4785cea85fadSMasatake YAMATO 
4786cea85fadSMasatake YAMATO 	return data.written;
4787cea85fadSMasatake YAMATO }
4788cea85fadSMasatake YAMATO 
4789e7283d01SMasatake YAMATO /*
4790d1437c58SMasatake YAMATO *   Copyright (c) 2016, Szymon Tomasz Stefanek
4791d1437c58SMasatake YAMATO *
4792d1437c58SMasatake YAMATO *   This source code is released for free distribution under the terms of the
4793d1437c58SMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
4794d1437c58SMasatake YAMATO *
4795d1437c58SMasatake YAMATO *   Anonymous name generator
4796d1437c58SMasatake YAMATO */
479787b7bfceSMasatake YAMATO static ptrArray *parsersUsedInCurrentInput;
4798d1437c58SMasatake YAMATO 
setupAnon(void)479987b7bfceSMasatake YAMATO static void setupAnon (void)
4800d1437c58SMasatake YAMATO {
48013c91b1eaSMasatake YAMATO 	parsersUsedInCurrentInput = ptrArrayNew (NULL);
48023c91b1eaSMasatake YAMATO }
48033c91b1eaSMasatake YAMATO 
teardownAnon(void)480487b7bfceSMasatake YAMATO static void teardownAnon (void)
480587b7bfceSMasatake YAMATO {
480687b7bfceSMasatake YAMATO 	ptrArrayDelete (parsersUsedInCurrentInput);
480787b7bfceSMasatake YAMATO }
480887b7bfceSMasatake YAMATO 
anonResetMaybe(parserObject * parser)480997a77b13SMasatake YAMATO static void anonResetMaybe (parserObject *parser)
48103c91b1eaSMasatake YAMATO {
481197a77b13SMasatake YAMATO 	if (ptrArrayHas (parsersUsedInCurrentInput, parser))
48123c91b1eaSMasatake YAMATO 		return;
48133c91b1eaSMasatake YAMATO 
481497a77b13SMasatake YAMATO 	parser -> anonymousIdentiferId = 0;
481597a77b13SMasatake YAMATO 	ptrArrayAdd (parsersUsedInCurrentInput, parser);
4816d1437c58SMasatake YAMATO }
4817d1437c58SMasatake YAMATO 
anonHash(const unsigned char * str)4818d1437c58SMasatake YAMATO static unsigned int anonHash(const unsigned char *str)
4819d1437c58SMasatake YAMATO {
4820d1437c58SMasatake YAMATO 	unsigned int hash = 5381;
4821d1437c58SMasatake YAMATO 	int c;
4822d1437c58SMasatake YAMATO 
4823d1437c58SMasatake YAMATO 	while((c = *str++))
4824d1437c58SMasatake YAMATO 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
4825d1437c58SMasatake YAMATO 
4826d1437c58SMasatake YAMATO 	return hash ;
4827d1437c58SMasatake YAMATO }
4828d1437c58SMasatake YAMATO 
anonHashString(const char * filename,char buf[9])48292b15528aSMasatake YAMATO extern void anonHashString (const char *filename, char buf[9])
48302b15528aSMasatake YAMATO {
48312b15528aSMasatake YAMATO 	sprintf(buf, "%08x", anonHash((const unsigned char *)filename));
48322b15528aSMasatake YAMATO }
48332b15528aSMasatake YAMATO 
48342b15528aSMasatake YAMATO 
anonConcat(vString * buffer,int kind)4835a13d8d73SMasatake YAMATO extern void anonConcat (vString *buffer, int kind)
4836a13d8d73SMasatake YAMATO {
4837a13d8d73SMasatake YAMATO 	anonGenerate (buffer, NULL, kind);
4838a13d8d73SMasatake YAMATO }
4839a13d8d73SMasatake YAMATO 
anonGenerate(vString * buffer,const char * prefix,int kind)4840d1437c58SMasatake YAMATO extern void anonGenerate (vString *buffer, const char *prefix, int kind)
4841d1437c58SMasatake YAMATO {
484297a77b13SMasatake YAMATO 	parserObject* parser = LanguageTable + getInputLanguage ();
484397a77b13SMasatake YAMATO 	parser -> anonymousIdentiferId ++;
4844d1437c58SMasatake YAMATO 
4845d1437c58SMasatake YAMATO 	char szNum[32];
48462b15528aSMasatake YAMATO 	char buf [9];
4847d1437c58SMasatake YAMATO 
4848a13d8d73SMasatake YAMATO 	if (prefix)
4849d1437c58SMasatake YAMATO 		vStringCopyS(buffer, prefix);
4850d1437c58SMasatake YAMATO 
48512b15528aSMasatake YAMATO 	anonHashString (getInputFileName(), buf);
48522b15528aSMasatake YAMATO 	sprintf(szNum,"%s%02x%02x",buf,parser -> anonymousIdentiferId, kind);
4853d1437c58SMasatake YAMATO 	vStringCatS(buffer,szNum);
4854d1437c58SMasatake YAMATO }
4855d1437c58SMasatake YAMATO 
anonGenerateNew(const char * prefix,int kind)485622f2e7c1SMasatake YAMATO extern vString *anonGenerateNew (const char *prefix, int kind)
485722f2e7c1SMasatake YAMATO {
485822f2e7c1SMasatake YAMATO 	vString *buffer = vStringNew ();
485922f2e7c1SMasatake YAMATO 
486022f2e7c1SMasatake YAMATO 	anonGenerate (buffer, prefix, kind);
486122f2e7c1SMasatake YAMATO 	return buffer;
486222f2e7c1SMasatake YAMATO }
486322f2e7c1SMasatake YAMATO 
48644d6cdcecSMasatake YAMATO 
applyParameter(const langType language,const char * name,const char * args)48654d6cdcecSMasatake YAMATO extern void applyParameter (const langType language, const char *name, const char *args)
48664d6cdcecSMasatake YAMATO {
48674d6cdcecSMasatake YAMATO 	parserDefinition* parser;
48684d6cdcecSMasatake YAMATO 
48694d6cdcecSMasatake YAMATO 
48704d6cdcecSMasatake YAMATO 	Assert (0 <= language  &&  language < (int) LanguageCount);
48714d6cdcecSMasatake YAMATO 
48724d6cdcecSMasatake YAMATO 	initializeParserOne (language);
4873e02be843SMasatake YAMATO 	parser = LanguageTable [language].def;
48744d6cdcecSMasatake YAMATO 
48754d6cdcecSMasatake YAMATO 	if (parser->parameterHandlerTable)
48764d6cdcecSMasatake YAMATO 	{
48774d6cdcecSMasatake YAMATO 		unsigned int i;
48784d6cdcecSMasatake YAMATO 
48794d6cdcecSMasatake YAMATO 		for (i = 0; i < parser->parameterHandlerCount; i++)
48804d6cdcecSMasatake YAMATO 		{
48814d6cdcecSMasatake YAMATO 			if (strcmp (parser->parameterHandlerTable [i].name, name) == 0)
48824d6cdcecSMasatake YAMATO 			{
48834d6cdcecSMasatake YAMATO 				parser->parameterHandlerTable [i].handleParameter (language, name, args);
48844d6cdcecSMasatake YAMATO 				return;
48854d6cdcecSMasatake YAMATO 			}
48864d6cdcecSMasatake YAMATO 		}
48874d6cdcecSMasatake YAMATO 	}
48884d6cdcecSMasatake YAMATO 
48894d6cdcecSMasatake YAMATO 	error (FATAL, "no such parameter in %s: %s", parser->name, name);
48904d6cdcecSMasatake YAMATO }
48914d6cdcecSMasatake YAMATO 
getNextSubparser(subparser * last,bool includingNoneCraftedParser)489211358a9dSMasatake YAMATO extern subparser *getNextSubparser(subparser *last,
489311358a9dSMasatake YAMATO 								   bool includingNoneCraftedParser)
4894a53e10d8SMasatake YAMATO {
4895a53e10d8SMasatake YAMATO 	langType lang = getInputLanguage ();
4896faa60990SMasatake YAMATO 	parserObject *parser = LanguageTable + lang;
489791ee7ae2SMasatake YAMATO 	subparser *r;
489891ee7ae2SMasatake YAMATO 	langType t;
4899a53e10d8SMasatake YAMATO 
4900a53e10d8SMasatake YAMATO 	if (last == NULL)
4901edc12faeSMasatake YAMATO 		r = getFirstSubparser(parser->slaveControlBlock);
4902a53e10d8SMasatake YAMATO 	else
490391ee7ae2SMasatake YAMATO 		r = last->next;
490491ee7ae2SMasatake YAMATO 
490591ee7ae2SMasatake YAMATO 	if (r == NULL)
490691ee7ae2SMasatake YAMATO 		return r;
490791ee7ae2SMasatake YAMATO 
490891ee7ae2SMasatake YAMATO 	t = getSubparserLanguage(r);
490911358a9dSMasatake YAMATO 	if (isLanguageEnabled (t) &&
491011358a9dSMasatake YAMATO 		(includingNoneCraftedParser
49111593689dSMasatake YAMATO 		 || ((((LanguageTable + t)->def->method) & METHOD_NOT_CRAFTED) == 0)))
491291ee7ae2SMasatake YAMATO 		return r;
491391ee7ae2SMasatake YAMATO 	else
491411358a9dSMasatake YAMATO 		return getNextSubparser (r, includingNoneCraftedParser);
4915a53e10d8SMasatake YAMATO }
4916a53e10d8SMasatake YAMATO 
getNextSlaveParser(slaveParser * last)4917c9ab038cSMasatake YAMATO extern slaveParser *getNextSlaveParser(slaveParser *last)
4918c9ab038cSMasatake YAMATO {
4919c9ab038cSMasatake YAMATO 	langType lang = getInputLanguage ();
4920c9ab038cSMasatake YAMATO 	parserObject *parser = LanguageTable + lang;
4921c9ab038cSMasatake YAMATO 	slaveParser *r;
4922c9ab038cSMasatake YAMATO 
4923c9ab038cSMasatake YAMATO 	if (last == NULL)
4924c9ab038cSMasatake YAMATO 		r = getFirstSlaveParser(parser->slaveControlBlock);
4925c9ab038cSMasatake YAMATO 	else
4926c9ab038cSMasatake YAMATO 		r = last->next;
4927c9ab038cSMasatake YAMATO 
4928c9ab038cSMasatake YAMATO 	return r;
4929c9ab038cSMasatake YAMATO }
4930c9ab038cSMasatake YAMATO 
scheduleRunningBaseparser(int dependencyIndex)4931a53e10d8SMasatake YAMATO extern void scheduleRunningBaseparser (int dependencyIndex)
4932a53e10d8SMasatake YAMATO {
4933a53e10d8SMasatake YAMATO 	langType current = getInputLanguage ();
4934e02be843SMasatake YAMATO 	parserDefinition *current_parser = LanguageTable [current].def;
4935a53e10d8SMasatake YAMATO 	parserDependency *dep = NULL;
4936a53e10d8SMasatake YAMATO 
4937a53e10d8SMasatake YAMATO 	if (dependencyIndex == RUN_DEFAULT_SUBPARSERS)
4938a53e10d8SMasatake YAMATO 	{
493946ab94ccSMasatake YAMATO 		for (unsigned int i = 0; i < current_parser->dependencyCount; ++i)
4940a53e10d8SMasatake YAMATO 			if (current_parser->dependencies[i].type == DEPTYPE_SUBPARSER)
4941a53e10d8SMasatake YAMATO 			{
4942a53e10d8SMasatake YAMATO 				dep = current_parser->dependencies + i;
4943a53e10d8SMasatake YAMATO 				break;
4944a53e10d8SMasatake YAMATO 			}
4945a53e10d8SMasatake YAMATO 	}
4946a53e10d8SMasatake YAMATO 	else
4947a53e10d8SMasatake YAMATO 		dep = current_parser->dependencies + dependencyIndex;
4948a53e10d8SMasatake YAMATO 
4949a53e10d8SMasatake YAMATO 	if (dep == NULL)
4950a53e10d8SMasatake YAMATO 		return;
4951a53e10d8SMasatake YAMATO 
4952a53e10d8SMasatake YAMATO 	const char *base_name = dep->upperParser;
4953a53e10d8SMasatake YAMATO 	langType base = getNamedLanguage (base_name, 0);
4954a5489f2eSMasatake YAMATO 	parserObject *base_parser = LanguageTable + base;
4955a53e10d8SMasatake YAMATO 
4956a53e10d8SMasatake YAMATO 	if (dependencyIndex == RUN_DEFAULT_SUBPARSERS)
4957edc12faeSMasatake YAMATO 		useDefaultSubparsers(base_parser->slaveControlBlock);
4958a53e10d8SMasatake YAMATO 	else
4959edc12faeSMasatake YAMATO 		useSpecifiedSubparser (base_parser->slaveControlBlock,
4960edc12faeSMasatake YAMATO 							   dep->data);
4961a53e10d8SMasatake YAMATO 
4962f91acbe7SMasatake YAMATO 	if (!isLanguageEnabled (base))
4963f91acbe7SMasatake YAMATO 	{
4964f91acbe7SMasatake YAMATO 		enableLanguage (base, true);
4965f91acbe7SMasatake YAMATO 		base_parser->dontEmit = true;
4966a5489f2eSMasatake YAMATO 		verbose ("force enable \"%s\" as base parser\n", base_parser->def->name);
4967f91acbe7SMasatake YAMATO 	}
4968f91acbe7SMasatake YAMATO 
4969a53e10d8SMasatake YAMATO 	{
4970a53e10d8SMasatake YAMATO 		subparser *tmp;
4971a53e10d8SMasatake YAMATO 
4972a53e10d8SMasatake YAMATO 		verbose ("scheduleRunningBaseparser %s with subparsers: ", base_name);
4973a53e10d8SMasatake YAMATO 		pushLanguage (base);
497411358a9dSMasatake YAMATO 		foreachSubparser(tmp, true)
4975b2ee2118SMasatake YAMATO 		{
4976b2ee2118SMasatake YAMATO 			langType t = getSubparserLanguage (tmp);
4977b2ee2118SMasatake YAMATO 			verbose ("%s ", getLanguageName (t));
4978b2ee2118SMasatake YAMATO 		}
4979a53e10d8SMasatake YAMATO 		popLanguage ();
4980a53e10d8SMasatake YAMATO 		verbose ("\n");
4981a53e10d8SMasatake YAMATO 	}
4982a53e10d8SMasatake YAMATO 
4983a53e10d8SMasatake YAMATO 
4984a53e10d8SMasatake YAMATO 	makePromise(base_name, THIN_STREAM_SPEC);
4985a53e10d8SMasatake YAMATO }
4986a53e10d8SMasatake YAMATO 
isParserMarkedNoEmission(void)4987f91acbe7SMasatake YAMATO extern bool isParserMarkedNoEmission (void)
4988f91acbe7SMasatake YAMATO {
4989f91acbe7SMasatake YAMATO 	langType lang = getInputLanguage();
4990a5489f2eSMasatake YAMATO 	parserObject *parser = LanguageTable + lang;
4991f91acbe7SMasatake YAMATO 
4992f91acbe7SMasatake YAMATO 	return parser->dontEmit;
4993f91acbe7SMasatake YAMATO }
4994f91acbe7SMasatake YAMATO 
4995a53e10d8SMasatake YAMATO 
getSubparserRunningBaseparser(void)4996a53e10d8SMasatake YAMATO extern subparser* getSubparserRunningBaseparser (void)
4997a53e10d8SMasatake YAMATO {
4998a53e10d8SMasatake YAMATO 	langType current = getInputLanguage ();
4999faa60990SMasatake YAMATO 	parserObject *current_parser = LanguageTable + current;
5000edc12faeSMasatake YAMATO 	subparser *s = getFirstSubparser (current_parser->slaveControlBlock);
5001a53e10d8SMasatake YAMATO 
5002a53e10d8SMasatake YAMATO 	if (s && s->schedulingBaseparserExplicitly)
5003a53e10d8SMasatake YAMATO 		return s;
5004a53e10d8SMasatake YAMATO 	else
5005a53e10d8SMasatake YAMATO 		return NULL;
5006a53e10d8SMasatake YAMATO }
5007a53e10d8SMasatake YAMATO 
printLanguageSubparsers(const langType language,bool withListHeader,bool machinable,FILE * fp)5008406a9384SMasatake YAMATO extern void printLanguageSubparsers (const langType language,
5009406a9384SMasatake YAMATO 									 bool withListHeader, bool machinable, FILE *fp)
5010410a34d6SMasatake YAMATO {
5011410a34d6SMasatake YAMATO 	for (int i = 0; i < (int) LanguageCount; i++)
5012410a34d6SMasatake YAMATO 		initializeParserOne (i);
5013410a34d6SMasatake YAMATO 
5014406a9384SMasatake YAMATO 	struct colprintTable * table = subparserColprintTableNew();
5015406a9384SMasatake YAMATO 	parserObject *parser;
5016410a34d6SMasatake YAMATO 
5017410a34d6SMasatake YAMATO 	if (language == LANG_AUTO)
5018410a34d6SMasatake YAMATO 	{
5019410a34d6SMasatake YAMATO 		for (int i = 0; i < (int) LanguageCount; i++)
5020406a9384SMasatake YAMATO 		{
5021406a9384SMasatake YAMATO 			parser = LanguageTable + i;
5022406a9384SMasatake YAMATO 			if (parser->def->invisible)
5023406a9384SMasatake YAMATO 				continue;
5024406a9384SMasatake YAMATO 
5025406a9384SMasatake YAMATO 			subparserColprintAddSubparsers (table,
5026406a9384SMasatake YAMATO 											parser->slaveControlBlock);
5027406a9384SMasatake YAMATO 		}
5028410a34d6SMasatake YAMATO 	}
5029410a34d6SMasatake YAMATO 	else
5030406a9384SMasatake YAMATO 	{
5031406a9384SMasatake YAMATO 		parser = (LanguageTable + language);
5032406a9384SMasatake YAMATO 		subparserColprintAddSubparsers (table,
5033406a9384SMasatake YAMATO 										parser->slaveControlBlock);
5034406a9384SMasatake YAMATO 	}
5035406a9384SMasatake YAMATO 
5036406a9384SMasatake YAMATO 	subparserColprintTablePrint (table,
5037406a9384SMasatake YAMATO 								 withListHeader, machinable,
5038406a9384SMasatake YAMATO 								 fp);
5039406a9384SMasatake YAMATO 	colprintTableDelete (table);
5040410a34d6SMasatake YAMATO }
5041410a34d6SMasatake YAMATO 
printLangdefFlags(bool withListHeader,bool machinable,FILE * fp)5042d8539e07SMasatake YAMATO extern void printLangdefFlags (bool withListHeader, bool machinable, FILE *fp)
5043d8539e07SMasatake YAMATO {
5044d8539e07SMasatake YAMATO 	struct colprintTable * table;
5045d8539e07SMasatake YAMATO 
5046d8539e07SMasatake YAMATO 	table = flagsColprintTableNew ();
5047d8539e07SMasatake YAMATO 
5048d8539e07SMasatake YAMATO 	flagsColprintAddDefinitions (table, PreLangDefFlagDef, ARRAY_SIZE (PreLangDefFlagDef));
5049d8539e07SMasatake YAMATO 
5050d8539e07SMasatake YAMATO 	flagsColprintTablePrint (table, withListHeader, machinable, fp);
5051d8539e07SMasatake YAMATO 	colprintTableDelete(table);
5052d8539e07SMasatake YAMATO }
5053d8539e07SMasatake YAMATO 
printKinddefFlags(bool withListHeader,bool machinable,FILE * fp)5054e5d40a50SMasatake YAMATO extern void printKinddefFlags (bool withListHeader, bool machinable, FILE *fp)
5055e5d40a50SMasatake YAMATO {
5056e5d40a50SMasatake YAMATO 	struct colprintTable * table;
5057e5d40a50SMasatake YAMATO 
5058e5d40a50SMasatake YAMATO 	table = flagsColprintTableNew ();
5059e5d40a50SMasatake YAMATO 
5060e5d40a50SMasatake YAMATO 	flagsColprintAddDefinitions (table, PreKindDefFlagDef, ARRAY_SIZE (PreKindDefFlagDef));
5061e5d40a50SMasatake YAMATO 
5062e5d40a50SMasatake YAMATO 	flagsColprintTablePrint (table, withListHeader, machinable, fp);
5063e5d40a50SMasatake YAMATO 	colprintTableDelete(table);
5064e5d40a50SMasatake YAMATO }
5065e5d40a50SMasatake YAMATO 
printLanguageMultitableStatistics(langType language)5066d4318624SMasatake YAMATO extern void printLanguageMultitableStatistics (langType language)
50671e923193SMasatake YAMATO {
50681e923193SMasatake YAMATO 	parserObject* const parser = LanguageTable + language;
5069d4318624SMasatake YAMATO 	printMultitableStatistics (parser->lregexControlBlock);
50701e923193SMasatake YAMATO }
50711e923193SMasatake YAMATO 
addLanguageRegexTable(const langType language,const char * name)507289c588f7SMasatake YAMATO extern void addLanguageRegexTable (const langType language, const char *name)
507389c588f7SMasatake YAMATO {
507489c588f7SMasatake YAMATO 	parserObject* const parser = LanguageTable + language;
507589c588f7SMasatake YAMATO 	addRegexTable (parser->lregexControlBlock, name);
507689c588f7SMasatake YAMATO }
507789c588f7SMasatake YAMATO 
addLanguageTagMultiTableRegex(const langType language,const char * const table_name,const char * const regex,const char * const name,const char * const kinds,const char * const flags,bool * disabled)507889c588f7SMasatake YAMATO extern void addLanguageTagMultiTableRegex(const langType language,
507989c588f7SMasatake YAMATO 										  const char* const table_name,
508089c588f7SMasatake YAMATO 										  const char* const regex,
508189c588f7SMasatake YAMATO 										  const char* const name, const char* const kinds, const char* const flags,
508289c588f7SMasatake YAMATO 										  bool *disabled)
508389c588f7SMasatake YAMATO {
508489c588f7SMasatake YAMATO 	parserObject* const parser = LanguageTable + language;
508589c588f7SMasatake YAMATO 	addTagMultiTableRegex (parser->lregexControlBlock, table_name, regex,
508689c588f7SMasatake YAMATO 						   name, kinds, flags, disabled);
508789c588f7SMasatake YAMATO }
508889c588f7SMasatake YAMATO 
addLanguageOptscriptToHook(langType language,enum scriptHook hook,const char * const src)5089b6124a60SMasatake YAMATO extern void addLanguageOptscriptToHook (langType language, enum scriptHook hook, const char *const src)
50905c872341SMasatake YAMATO {
5091b6124a60SMasatake YAMATO 	addOptscriptToHook (LanguageTable [language].lregexControlBlock, hook, src);
50921409a195SMasatake YAMATO }
50931409a195SMasatake YAMATO 
processHookOption(const char * const option,const char * const parameter,const char * prefix,enum scriptHook hook)50941409a195SMasatake YAMATO static bool processHookOption (const char *const option, const char *const parameter, const char *prefix,
5095b6124a60SMasatake YAMATO 							   enum scriptHook hook)
50961409a195SMasatake YAMATO {
50971409a195SMasatake YAMATO 	langType language = getLanguageComponentInOption (option, prefix);
50985c872341SMasatake YAMATO 	if (language == LANG_IGNORE)
50995c872341SMasatake YAMATO 		return false;
51005c872341SMasatake YAMATO 
51015c872341SMasatake YAMATO 	if (parameter == NULL || parameter[0] == '\0')
51025c872341SMasatake YAMATO 		error (FATAL, "A parameter is needed after \"%s\" option", option);
51035c872341SMasatake YAMATO 
51045c872341SMasatake YAMATO 	const char * code = flagsEval (parameter, NULL, 0, NULL);
51055c872341SMasatake YAMATO 	if (code == NULL)
51065c872341SMasatake YAMATO 		error (FATAL, "Cannot recognized a code block surrounded by `{{' and `}}' after \"%s\" option", option);
5107b6124a60SMasatake YAMATO 	addLanguageOptscriptToHook (language, hook, code);
51085c872341SMasatake YAMATO 
51095c872341SMasatake YAMATO 	return true;
51105c872341SMasatake YAMATO }
51115c872341SMasatake YAMATO 
processPreludeOption(const char * const option,const char * const parameter)51121409a195SMasatake YAMATO extern bool processPreludeOption (const char *const option, const char *const parameter)
51131409a195SMasatake YAMATO {
5114b6124a60SMasatake YAMATO 	return processHookOption (option, parameter, "_prelude-", SCRIPT_HOOK_PRELUDE);
51151409a195SMasatake YAMATO }
51161409a195SMasatake YAMATO 
processSequelOption(const char * const option,const char * const parameter)51171409a195SMasatake YAMATO extern bool processSequelOption (const char *const option, const char *const parameter)
51181409a195SMasatake YAMATO {
5119b6124a60SMasatake YAMATO 	return processHookOption (option, parameter, "_sequel-", SCRIPT_HOOK_SEQUEL);
51201409a195SMasatake YAMATO }
51211409a195SMasatake YAMATO 
processPretendOption(const char * const option,const char * const parameter)5122f02166dcSMasatake YAMATO extern bool processPretendOption (const char *const option, const char *const parameter)
5123f02166dcSMasatake YAMATO {
5124f02166dcSMasatake YAMATO 	langType new_language, old_language;
5125f02166dcSMasatake YAMATO 
5126f02166dcSMasatake YAMATO #define pretendOptionPrefix "_pretend-"
5127f02166dcSMasatake YAMATO 	new_language = getLanguageComponentInOptionFull (option, pretendOptionPrefix, true);
5128f02166dcSMasatake YAMATO 	if (new_language == LANG_IGNORE)
5129f02166dcSMasatake YAMATO 		return false;
5130f02166dcSMasatake YAMATO 
5131f02166dcSMasatake YAMATO 	if (parameter == NULL || parameter[0] == '\0')
5132f02166dcSMasatake YAMATO 		error (FATAL, "A parameter is needed after \"%s\" option", option);
5133f02166dcSMasatake YAMATO 
51349a391711SMasatake YAMATO 	old_language = getNamedLanguageFull (parameter, 0, true, false);
5135f02166dcSMasatake YAMATO 	if (old_language == LANG_IGNORE)
5136f02166dcSMasatake YAMATO 		error (FATAL, "Unknown language \"%s\" in option \"--%s=%s\"",
5137f02166dcSMasatake YAMATO 			   parameter, option, parameter);
5138f02166dcSMasatake YAMATO 
5139f02166dcSMasatake YAMATO 	if (LanguageTable [new_language].pretendingAsLanguage != LANG_IGNORE)
5140f02166dcSMasatake YAMATO 	{
5141f02166dcSMasatake YAMATO 		error (FATAL, "%s parser pretends as %s already\n",
5142f02166dcSMasatake YAMATO 			   getLanguageNameFull (new_language, true),
5143f02166dcSMasatake YAMATO 			   getLanguageNameFull (LanguageTable [new_language].pretendingAsLanguage, true));
5144f02166dcSMasatake YAMATO 	}
5145f02166dcSMasatake YAMATO 	if (LanguageTable [old_language].pretendedAsLanguage != LANG_IGNORE)
5146f02166dcSMasatake YAMATO 	{
5147f02166dcSMasatake YAMATO 		error (FATAL, "%s parser is pretended as %s already\n",
5148f02166dcSMasatake YAMATO 			   getLanguageNameFull (old_language, true),
5149f02166dcSMasatake YAMATO 			   getLanguageNameFull (LanguageTable [old_language].pretendedAsLanguage, true));
5150f02166dcSMasatake YAMATO 	}
5151f02166dcSMasatake YAMATO 
5152f02166dcSMasatake YAMATO 	verbose ("%s pretends %s\n",
5153f02166dcSMasatake YAMATO 			 getLanguageNameFull (new_language, true),
5154f02166dcSMasatake YAMATO 			 getLanguageNameFull (old_language, true));
5155f02166dcSMasatake YAMATO 
5156f02166dcSMasatake YAMATO 	LanguageTable [new_language].pretendingAsLanguage = old_language;
5157f02166dcSMasatake YAMATO 	LanguageTable [old_language].pretendedAsLanguage  = new_language;
5158f02166dcSMasatake YAMATO 
5159f02166dcSMasatake YAMATO 	verbose ("force enabling %s\n",
5160f02166dcSMasatake YAMATO 			 getLanguageNameFull (new_language, true));
5161f02166dcSMasatake YAMATO 	enableLanguage (new_language, true);
5162f02166dcSMasatake YAMATO 
5163351239a8SMasanari Iida 	verbose ("force disabling %s\n",
5164f02166dcSMasatake YAMATO 			 getLanguageNameFull (old_language, true));
5165f02166dcSMasatake YAMATO 	enableLanguage (old_language, false);
5166f02166dcSMasatake YAMATO 
5167f02166dcSMasatake YAMATO 	return true;
5168f02166dcSMasatake YAMATO }
5169f02166dcSMasatake YAMATO 
getLanguageCorkUsage(langType lang)5170a64816f9SMasatake YAMATO extern unsigned int getLanguageCorkUsage (langType lang)
5171a64816f9SMasatake YAMATO {
5172a64816f9SMasatake YAMATO 	parserObject* const parser = LanguageTable + lang;
5173a64816f9SMasatake YAMATO 	return parserCorkFlags (parser->def);
5174a64816f9SMasatake YAMATO }
5175a64816f9SMasatake YAMATO 
5176d1437c58SMasatake YAMATO /*
517782791c20SMasatake YAMATO  * The universal fallback parser.
517882791c20SMasatake YAMATO  * If any parser doesn't handle the input, this parser is
517982791c20SMasatake YAMATO  * used for the input when --languages=+Unknown is given.
518082791c20SMasatake YAMATO  * writer-etags enables this parser implicitly.
518182791c20SMasatake YAMATO  */
FallbackParser(void)518282791c20SMasatake YAMATO static parserDefinition *FallbackParser (void)
518382791c20SMasatake YAMATO {
518482791c20SMasatake YAMATO 	parserDefinition *const def = parserNew ("Unknown");
518582791c20SMasatake YAMATO 	def->extensions = NULL;
518682791c20SMasatake YAMATO 	def->kindTable = NULL;
518782791c20SMasatake YAMATO 	def->kindCount = 0;
518882791c20SMasatake YAMATO 
518982791c20SMasatake YAMATO 	/* A user can extend this parser with --regex-Unknown=...
519082791c20SMasatake YAMATO 	 * or --langdef=MyParser{base=Unknown}.
519182791c20SMasatake YAMATO 	 *
519282791c20SMasatake YAMATO 	 * TODO: if following conditions are met, dontFindTags()
519382791c20SMasatake YAMATO 	 * defined below can be used.
519482791c20SMasatake YAMATO 	 * - any regex pattern is not defined,
519582791c20SMasatake YAMATO 	 * - any sub parser is not defined, and
519682791c20SMasatake YAMATO 	 * - end: field is not enabled.
519782791c20SMasatake YAMATO 	 */
519882791c20SMasatake YAMATO 	def->parser = findRegexTags;
519982791c20SMasatake YAMATO 	def->enabled = 0;
520082791c20SMasatake YAMATO 	def->method = METHOD_REGEX;
520182791c20SMasatake YAMATO 	return def;
520282791c20SMasatake YAMATO }
520382791c20SMasatake YAMATO 
520482791c20SMasatake YAMATO /*
5205b9636b4dSMasatake YAMATO  * A dummy parser for printing pseudo tags in xref output
5206b9636b4dSMasatake YAMATO  */
dontFindTags(void)5207b9636b4dSMasatake YAMATO static void dontFindTags (void)
5208b9636b4dSMasatake YAMATO {
5209b9636b4dSMasatake YAMATO }
5210b9636b4dSMasatake YAMATO 
5211b9636b4dSMasatake YAMATO static kindDefinition CtagsKinds[] = {
5212b9636b4dSMasatake YAMATO 	{true, 'p', "ptag", "pseudo tags"},
5213b9636b4dSMasatake YAMATO };
5214b9636b4dSMasatake YAMATO 
CTagsParser(void)5215b9636b4dSMasatake YAMATO static parserDefinition *CTagsParser (void)
5216b9636b4dSMasatake YAMATO {
5217b9636b4dSMasatake YAMATO 	parserDefinition *const def = parserNew ("UniversalCtags");
5218b9636b4dSMasatake YAMATO 	def->extensions = NULL;
5219b9636b4dSMasatake YAMATO 	def->kindTable = CtagsKinds;
5220b9636b4dSMasatake YAMATO 	def->kindCount = ARRAY_SIZE(CtagsKinds);
5221b9636b4dSMasatake YAMATO 	def->parser = dontFindTags;
5222b9636b4dSMasatake YAMATO 	def->invisible = true;
5223b9636b4dSMasatake YAMATO 	return def;
5224b9636b4dSMasatake YAMATO }
5225b9636b4dSMasatake YAMATO 
5226b9636b4dSMasatake YAMATO /*
5227e7283d01SMasatake YAMATO  * A parser for CTagsSelfTest (CTST)
5228e7283d01SMasatake YAMATO  */
5229d3ee68cdSMasatake YAMATO #define SELF_TEST_PARSER "CTagsSelfTest"
523034826b73SMasatake YAMATO #if defined(DEBUG) && defined(HAVE_SECCOMP)
5231539991e1SMasatake YAMATO extern void getppid(void);
5232539991e1SMasatake YAMATO #endif
5233d3ee68cdSMasatake YAMATO 
5234a9c91f4dSMasatake YAMATO static bool CTST_GatherStats;
5235a9c91f4dSMasatake YAMATO static int CTST_num_handled_char;
5236a9c91f4dSMasatake YAMATO 
5237e7283d01SMasatake YAMATO typedef enum {
5238e7283d01SMasatake YAMATO 	K_BROKEN,
52397aeeb638SMasatake YAMATO 	K_NO_LETTER,
52407aeeb638SMasatake YAMATO 	K_NO_LONG_NAME,
5241d3ee68cdSMasatake YAMATO 	K_NOTHING_SPECIAL,
5242d3ee68cdSMasatake YAMATO 	K_GUEST_BEGINNING,
5243d3ee68cdSMasatake YAMATO 	K_GUEST_END,
524434826b73SMasatake YAMATO #if defined(DEBUG) && defined(HAVE_SECCOMP)
5245539991e1SMasatake YAMATO 	K_CALL_GETPPID,
5246539991e1SMasatake YAMATO #endif
5247bac26e10SMasatake YAMATO 	K_DISABLED,
5248bac26e10SMasatake YAMATO 	K_ENABLED,
5249f7ce3343SMasatake YAMATO 	K_ROLES,
5250f7ce3343SMasatake YAMATO 	K_ROLES_DISABLED,
52517b08b440SMasatake YAMATO 	K_FIELD_TESTING,
525256175ec1SMasatake YAMATO 	K_TRIGGER_NOTICE,
5253e7283d01SMasatake YAMATO 	KIND_COUNT
5254e7283d01SMasatake YAMATO } CTST_Kind;
5255e7283d01SMasatake YAMATO 
5256a31f61c4SMasatake YAMATO typedef enum {
5257a31f61c4SMasatake YAMATO 	R_BROKEN_REF,
5258a31f61c4SMasatake YAMATO } CTST_BrokenRole;
5259a31f61c4SMasatake YAMATO 
526013457258SMasatake YAMATO static roleDefinition CTST_BrokenRoles [] = {
5261ce990805SThomas Braun 	{true, "broken", "broken" },
5262a31f61c4SMasatake YAMATO };
5263a31f61c4SMasatake YAMATO 
5264bac26e10SMasatake YAMATO typedef enum {
5265bac26e10SMasatake YAMATO 	R_DISABLED_KIND_DISABLED_ROLE,
5266bac26e10SMasatake YAMATO 	R_DISABLED_KIND_ENABLED_ROLE,
5267bac26e10SMasatake YAMATO } CTST_DisabledKindRole;
5268bac26e10SMasatake YAMATO 
526913457258SMasatake YAMATO static roleDefinition CTST_DisabledKindRoles [] = {
5270351239a8SMasanari Iida 	{ false, "disabled", "disabled role attached to disabled kind" },
5271bac26e10SMasatake YAMATO 	{ true,  "enabled",  "enabled role attached to disabled kind"  },
5272bac26e10SMasatake YAMATO };
5273bac26e10SMasatake YAMATO 
5274bac26e10SMasatake YAMATO typedef enum {
5275bac26e10SMasatake YAMATO 	R_ENABLED_KIND_DISABLED_ROLE,
5276bac26e10SMasatake YAMATO 	R_ENABLED_KIND_ENABLED_ROLE,
5277bac26e10SMasatake YAMATO } CTST_EnabledKindRole;
5278bac26e10SMasatake YAMATO 
527913457258SMasatake YAMATO static roleDefinition CTST_EnabledKindRoles [] = {
5280351239a8SMasanari Iida 	{ false, "disabled", "disabled role attached to enabled kind" },
5281bac26e10SMasatake YAMATO 	{ true,  "enabled",  "enabled role attached to enabled kind"  },
5282bac26e10SMasatake YAMATO };
5283bac26e10SMasatake YAMATO 
5284f7ce3343SMasatake YAMATO typedef enum {
5285f7ce3343SMasatake YAMATO 	R_ROLES_KIND_A_ROLE,
5286f7ce3343SMasatake YAMATO 	R_ROLES_KIND_B_ROLE,
5287f7ce3343SMasatake YAMATO 	R_ROLES_KIND_C_ROLE,
5288f7ce3343SMasatake YAMATO 	R_ROLES_KIND_D_ROLE,
5289f7ce3343SMasatake YAMATO } CTST_RolesKindRole;
5290f7ce3343SMasatake YAMATO 
529113457258SMasatake YAMATO static roleDefinition CTST_RolesKindRoles [] = {
5292f7ce3343SMasatake YAMATO 	{ true,  "a", "A role" },
5293f7ce3343SMasatake YAMATO 	{ true,  "b", "B role" },
5294f7ce3343SMasatake YAMATO 	{ false, "c", "C role" },
5295f7ce3343SMasatake YAMATO 	{ true,  "d", "D role"  },
5296f7ce3343SMasatake YAMATO };
5297f7ce3343SMasatake YAMATO 
5298f7ce3343SMasatake YAMATO typedef enum {
5299f7ce3343SMasatake YAMATO 	R_ROLES_DISABLED_KIND_A_ROLE,
5300f7ce3343SMasatake YAMATO 	R_ROLES_DISABLED_KIND_B_ROLE,
5301f7ce3343SMasatake YAMATO } CTST_RolesDisableKindRole;
5302f7ce3343SMasatake YAMATO 
5303f7ce3343SMasatake YAMATO 
530413457258SMasatake YAMATO static roleDefinition CTST_RolesDisabledKindRoles [] = {
5305f7ce3343SMasatake YAMATO 	{ true,  "A", "A role" },
5306f7ce3343SMasatake YAMATO 	{ true,  "B", "B role" },
5307f7ce3343SMasatake YAMATO };
5308f7ce3343SMasatake YAMATO 
5309e112e8abSMasatake YAMATO static kindDefinition CTST_Kinds[KIND_COUNT] = {
53108c4e6d88SMasatake YAMATO 	/* `a' is reserved for kinddef testing */
5311ce990805SThomas Braun 	{true, 'b', "broken tag", "name with unwanted characters",
5312ce990805SThomas Braun 	 .referenceOnly = false, ATTACH_ROLES (CTST_BrokenRoles) },
53137e1bd430SMasatake YAMATO 	{true, KIND_NULL_LETTER, "no letter", "kind with no letter"
53147aeeb638SMasatake YAMATO 	 /* use '@' when testing. */
53157aeeb638SMasatake YAMATO 	},
53167aeeb638SMasatake YAMATO 	{true, 'L', NULL, "kind with no long name" },
5317d3ee68cdSMasatake YAMATO 	{true, 'N', "nothingSpecial", "emit a normal tag" },
5318d3ee68cdSMasatake YAMATO 	{true, 'B', NULL, "beginning of an area for a guest" },
5319d3ee68cdSMasatake YAMATO 	{true, 'E', NULL, "end of an area for a guest" },
532034826b73SMasatake YAMATO #if defined(DEBUG) && defined(HAVE_SECCOMP)
5321539991e1SMasatake YAMATO 	{true, 'P', "callGetPPid", "trigger calling getppid(2) that seccomp sandbox disallows"},
5322539991e1SMasatake YAMATO #endif
5323bac26e10SMasatake YAMATO 	{false,'d', "disabled", "a kind disabled by default",
5324bac26e10SMasatake YAMATO 	 .referenceOnly = false, ATTACH_ROLES (CTST_DisabledKindRoles)},
5325bac26e10SMasatake YAMATO 	{true, 'e', "enabled", "a kind enabled by default",
5326bac26e10SMasatake YAMATO 	 .referenceOnly = false, ATTACH_ROLES (CTST_EnabledKindRoles)},
5327f7ce3343SMasatake YAMATO 	{true, 'r', "roles", "emit a tag with multi roles",
5328f7ce3343SMasatake YAMATO 	 .referenceOnly = true, ATTACH_ROLES (CTST_RolesKindRoles)},
5329f7ce3343SMasatake YAMATO 	{false, 'R', "rolesDisabled", "emit a tag with multi roles(disabled by default)",
5330f7ce3343SMasatake YAMATO 	 .referenceOnly = true, ATTACH_ROLES (CTST_RolesDisabledKindRoles)},
53317b08b440SMasatake YAMATO 	{true,  'f', "fieldMaker", "tag for testing field:" },
533256175ec1SMasatake YAMATO 	{true,  'n', "triggerNotice", "trigger notice output"},
53337b08b440SMasatake YAMATO };
53347b08b440SMasatake YAMATO 
53357b08b440SMasatake YAMATO typedef enum {
53367b08b440SMasatake YAMATO 	F_BOOLEAN_FIELD,
53377b08b440SMasatake YAMATO 	F_BOOLEAN_AND_STRING_FIELD,
53387b08b440SMasatake YAMATO 	COUNT_FIELD
53397b08b440SMasatake YAMATO } CTSTField;
53407b08b440SMasatake YAMATO 
53417b08b440SMasatake YAMATO static fieldDefinition CTSTFields[COUNT_FIELD] = {
53427b08b440SMasatake YAMATO 	{ .name = "bField",
53437b08b440SMasatake YAMATO 	  .description = "field for testing boolean type",
53447b08b440SMasatake YAMATO 	  .dataType = FIELDTYPE_BOOL,
53457b08b440SMasatake YAMATO 	  .enabled = true,
53467b08b440SMasatake YAMATO 	},
53477b08b440SMasatake YAMATO 	{ .name = "sbField",
53487b08b440SMasatake YAMATO 	  .description = "field for testing string|boolean type",
53497b08b440SMasatake YAMATO 	  .dataType = FIELDTYPE_STRING|FIELDTYPE_BOOL,
53507b08b440SMasatake YAMATO 	  .enabled = true,
53517b08b440SMasatake YAMATO 	},
5352e7283d01SMasatake YAMATO };
5353e7283d01SMasatake YAMATO 
createCTSTTags(void)5354e7283d01SMasatake YAMATO static void createCTSTTags (void)
5355e7283d01SMasatake YAMATO {
5356e7283d01SMasatake YAMATO 	int i;
5357e7283d01SMasatake YAMATO 	const unsigned char *line;
5358e7283d01SMasatake YAMATO 	tagEntryInfo e;
5359e7283d01SMasatake YAMATO 
5360d3ee68cdSMasatake YAMATO 	unsigned long lb = 0;
5361d3ee68cdSMasatake YAMATO 	unsigned long le = 0;
5362d3ee68cdSMasatake YAMATO 
5363bac26e10SMasatake YAMATO 	int found_enabled_disabled[2] = {0, 0};
5364bac26e10SMasatake YAMATO 
5365e97e7d4aSMasatake YAMATO 	TRACE_ENTER_TEXT("Parsing starts");
5366e97e7d4aSMasatake YAMATO 
53671b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
5368e7283d01SMasatake YAMATO 	{
5369e7283d01SMasatake YAMATO 		int c = line[0];
5370e7283d01SMasatake YAMATO 
5371e7283d01SMasatake YAMATO 		for (i = 0; i < KIND_COUNT; i++)
53727aeeb638SMasatake YAMATO 			if ((c == CTST_Kinds[i].letter && i != K_NO_LETTER)
53737aeeb638SMasatake YAMATO 				|| (c == '@' && i == K_NO_LETTER))
5374e7283d01SMasatake YAMATO 			{
5375a9c91f4dSMasatake YAMATO 				if (CTST_GatherStats)
5376a9c91f4dSMasatake YAMATO 					CTST_num_handled_char++;
5377a9c91f4dSMasatake YAMATO 
5378e7283d01SMasatake YAMATO 				switch (i)
5379e7283d01SMasatake YAMATO 				{
5380e7283d01SMasatake YAMATO 					case K_BROKEN:
538116a2541cSMasatake YAMATO 						initTagEntry (&e, "one\nof\rbroken\tname", i);
5382f92e6bf2SMasatake YAMATO 						e.extensionFields.scopeKindIndex = K_BROKEN;
5383f63d8d2cSMasatake YAMATO 						e.extensionFields.scopeName = "\\Broken\tContext";
5384e7283d01SMasatake YAMATO 						makeTagEntry (&e);
53850647c2a9SMasatake YAMATO 						initTagEntry (&e, "only\nnewline", i);
53860647c2a9SMasatake YAMATO 						makeTagEntry (&e);
53870647c2a9SMasatake YAMATO 						initTagEntry (&e, "only\ttab", i);
53880647c2a9SMasatake YAMATO 						makeTagEntry (&e);
53890647c2a9SMasatake YAMATO 						initTagEntry (&e, "newline-in-scope", i);
53900647c2a9SMasatake YAMATO 						e.extensionFields.scopeKindIndex = K_BROKEN;
53910647c2a9SMasatake YAMATO 						e.extensionFields.scopeName = "parent\nscope";
53920647c2a9SMasatake YAMATO 						makeTagEntry (&e);
53930647c2a9SMasatake YAMATO 						initTagEntry (&e, "tab-in-scope", i);
53940647c2a9SMasatake YAMATO 						e.extensionFields.scopeKindIndex = K_BROKEN;
53950647c2a9SMasatake YAMATO 						e.extensionFields.scopeName = "parent\tscope";
53960647c2a9SMasatake YAMATO 						makeTagEntry (&e);
5397e7283d01SMasatake YAMATO 						break;
53987aeeb638SMasatake YAMATO 					case K_NO_LETTER:
539916a2541cSMasatake YAMATO 						initTagEntry (&e, "abnormal kindDefinition testing (no letter)", i);
54007aeeb638SMasatake YAMATO 						makeTagEntry (&e);
54017aeeb638SMasatake YAMATO 						break;
54027aeeb638SMasatake YAMATO 					case K_NO_LONG_NAME:
540316a2541cSMasatake YAMATO 						initTagEntry (&e, "abnormal kindDefinition testing (no long name)", i);
54047aeeb638SMasatake YAMATO 						makeTagEntry (&e);
54057aeeb638SMasatake YAMATO 						break;
5406d3ee68cdSMasatake YAMATO 					case K_NOTHING_SPECIAL:
5407d3ee68cdSMasatake YAMATO 						if (!lb)
5408d3ee68cdSMasatake YAMATO 						{
540916a2541cSMasatake YAMATO 							initTagEntry (&e, "NOTHING_SPECIAL", i);
5410d3ee68cdSMasatake YAMATO 							makeTagEntry (&e);
5411d3ee68cdSMasatake YAMATO 						}
5412d3ee68cdSMasatake YAMATO 						break;
5413d3ee68cdSMasatake YAMATO 					case K_GUEST_BEGINNING:
5414d3ee68cdSMasatake YAMATO 						lb = getInputLineNumber ();
5415d3ee68cdSMasatake YAMATO 						break;
5416d3ee68cdSMasatake YAMATO 					case K_GUEST_END:
5417d3ee68cdSMasatake YAMATO 						le = getInputLineNumber ();
5418d3ee68cdSMasatake YAMATO 						makePromise (SELF_TEST_PARSER, lb + 1, 0, le, 0, lb + 1);
5419d3ee68cdSMasatake YAMATO 						break;
542034826b73SMasatake YAMATO #if defined(DEBUG) && defined(HAVE_SECCOMP)
5421539991e1SMasatake YAMATO 				    case K_CALL_GETPPID:
5422539991e1SMasatake YAMATO 						getppid();
5423539991e1SMasatake YAMATO 						break;
5424539991e1SMasatake YAMATO #endif
5425bac26e10SMasatake YAMATO 				    case K_DISABLED:
5426bac26e10SMasatake YAMATO 				    case K_ENABLED:
5427bac26e10SMasatake YAMATO 						{
5428bac26e10SMasatake YAMATO 							int role;
5429bac26e10SMasatake YAMATO 							char *name;
5430bac26e10SMasatake YAMATO 							if (found_enabled_disabled[i == K_DISABLED]++ == 0)
5431bac26e10SMasatake YAMATO 							{
543224b256e3SMasatake YAMATO 								role = ROLE_DEFINITION_INDEX;
5433bac26e10SMasatake YAMATO 								name = (i == K_DISABLED)
5434bac26e10SMasatake YAMATO 									? "disable-kind-no-role"
5435bac26e10SMasatake YAMATO 									: "enabled-kind-no-role";
5436bac26e10SMasatake YAMATO 							}
5437bac26e10SMasatake YAMATO 							else if (found_enabled_disabled[i == K_DISABLED]++ == 1)
5438bac26e10SMasatake YAMATO 							{
5439bac26e10SMasatake YAMATO 								role = (i == K_DISABLED)
5440bac26e10SMasatake YAMATO 									? R_DISABLED_KIND_DISABLED_ROLE
5441bac26e10SMasatake YAMATO 									: R_ENABLED_KIND_DISABLED_ROLE;
5442bac26e10SMasatake YAMATO 								name = (i == K_DISABLED)
5443bac26e10SMasatake YAMATO 									? "disable-kind-disabled-role"
5444bac26e10SMasatake YAMATO 									: "enabled-kind-disabled-role";
5445bac26e10SMasatake YAMATO 							}
5446bac26e10SMasatake YAMATO 							else
5447bac26e10SMasatake YAMATO 							{
5448bac26e10SMasatake YAMATO 								role = (i == K_DISABLED)
5449bac26e10SMasatake YAMATO 									? R_DISABLED_KIND_ENABLED_ROLE
5450bac26e10SMasatake YAMATO 									: R_ENABLED_KIND_ENABLED_ROLE;
5451bac26e10SMasatake YAMATO 								name = (i == K_DISABLED)
5452bac26e10SMasatake YAMATO 									? "disable-kind-enabled-role"
5453bac26e10SMasatake YAMATO 									: "enabled-kind-enabled-role";
5454bac26e10SMasatake YAMATO 							}
5455bac26e10SMasatake YAMATO 							initRefTagEntry (&e, name, i, role);
5456bac26e10SMasatake YAMATO 							makeTagEntry (&e);
5457bac26e10SMasatake YAMATO 							break;
5458bac26e10SMasatake YAMATO 						}
5459f7ce3343SMasatake YAMATO 					case K_ROLES:
5460f7ce3343SMasatake YAMATO 					{
5461f7ce3343SMasatake YAMATO 						char *name = "multiRolesTarget";
5462f7ce3343SMasatake YAMATO 						int qindex;
5463f7ce3343SMasatake YAMATO 						tagEntryInfo *qe;
5464f7ce3343SMasatake YAMATO 
5465f7ce3343SMasatake YAMATO 						initTagEntry (&e, name, i);
5466f7ce3343SMasatake YAMATO 						assignRole(&e, R_ROLES_KIND_A_ROLE);
5467f7ce3343SMasatake YAMATO 						assignRole(&e, R_ROLES_KIND_C_ROLE);
5468f7ce3343SMasatake YAMATO 						assignRole(&e, R_ROLES_KIND_D_ROLE);
5469f7ce3343SMasatake YAMATO 						qindex = makeTagEntry (&e);
5470f7ce3343SMasatake YAMATO 						qe = getEntryInCorkQueue (qindex);
54713671ad72SMasatake YAMATO 						if (qe)
5472f7ce3343SMasatake YAMATO 							assignRole(qe, R_ROLES_KIND_B_ROLE);
5473f7ce3343SMasatake YAMATO 						break;
5474f7ce3343SMasatake YAMATO 					}
5475f7ce3343SMasatake YAMATO 					case K_ROLES_DISABLED:
5476f7ce3343SMasatake YAMATO 					{
5477f7ce3343SMasatake YAMATO 						char *name = "multiRolesDisabledTarget";
5478f7ce3343SMasatake YAMATO 
5479f7ce3343SMasatake YAMATO 						initRefTagEntry (&e, name, i, R_ROLES_DISABLED_KIND_A_ROLE);
5480f7ce3343SMasatake YAMATO 						makeTagEntry (&e);
5481f7ce3343SMasatake YAMATO 						initRefTagEntry (&e, name, i, R_ROLES_DISABLED_KIND_B_ROLE);
5482f7ce3343SMasatake YAMATO 						makeTagEntry (&e);
5483f7ce3343SMasatake YAMATO 						break;
5484f7ce3343SMasatake YAMATO 					}
54857b08b440SMasatake YAMATO 					case K_FIELD_TESTING:
54867b08b440SMasatake YAMATO 					{
54877b08b440SMasatake YAMATO 						char c = 'a';
54887b08b440SMasatake YAMATO 						char name []= {'\0', 't', 'a', 'g', '\0' };
54897b08b440SMasatake YAMATO 
54907b08b440SMasatake YAMATO 						name [0] = c++;
54917b08b440SMasatake YAMATO 						initTagEntry (&e, name, i);
54927b08b440SMasatake YAMATO 						attachParserField (&e, false,
54937b08b440SMasatake YAMATO 										   CTSTFields[F_BOOLEAN_FIELD].ftype, "");
54947b08b440SMasatake YAMATO 						makeTagEntry (&e);
54957b08b440SMasatake YAMATO 
54967b08b440SMasatake YAMATO 						name [0] = c++;
54977b08b440SMasatake YAMATO 						initTagEntry (&e, name, i);
54987b08b440SMasatake YAMATO 						makeTagEntry (&e);
54997b08b440SMasatake YAMATO 
55007b08b440SMasatake YAMATO 						name [0] = c++;
55017b08b440SMasatake YAMATO 						initTagEntry (&e, name, i);
55027b08b440SMasatake YAMATO 						attachParserField (&e, false,
55037b08b440SMasatake YAMATO 										   CTSTFields[F_BOOLEAN_AND_STRING_FIELD].ftype, "val");
55047b08b440SMasatake YAMATO 						makeTagEntry (&e);
55057b08b440SMasatake YAMATO 
55067b08b440SMasatake YAMATO 						name [0] = c++;
55077b08b440SMasatake YAMATO 						initTagEntry (&e, name, i);
55087b08b440SMasatake YAMATO 						attachParserField (&e, false,
55097b08b440SMasatake YAMATO 										   CTSTFields[F_BOOLEAN_AND_STRING_FIELD].ftype, "");
55107b08b440SMasatake YAMATO 						makeTagEntry (&e);
55117b08b440SMasatake YAMATO 
55127b08b440SMasatake YAMATO 						break;
55137b08b440SMasatake YAMATO 					}
551456175ec1SMasatake YAMATO 					case K_TRIGGER_NOTICE:
551556175ec1SMasatake YAMATO 						notice ("notice output for testing: %s", CTST_Kinds [i].name);
551656175ec1SMasatake YAMATO 						break;
5517e7283d01SMasatake YAMATO 				}
5518e7283d01SMasatake YAMATO 			}
5519e7283d01SMasatake YAMATO 	}
5520e97e7d4aSMasatake YAMATO 
5521e97e7d4aSMasatake YAMATO 	TRACE_LEAVE();
5522e7283d01SMasatake YAMATO }
5523e7283d01SMasatake YAMATO 
initStatsCTST(langType lang CTAGS_ATTR_UNUSED)5524a9c91f4dSMasatake YAMATO static void initStatsCTST (langType lang CTAGS_ATTR_UNUSED)
5525a9c91f4dSMasatake YAMATO {
5526a9c91f4dSMasatake YAMATO 	CTST_GatherStats = true;
5527a9c91f4dSMasatake YAMATO }
5528a9c91f4dSMasatake YAMATO 
printStatsCTST(langType lang CTAGS_ATTR_UNUSED)5529a9c91f4dSMasatake YAMATO static void printStatsCTST (langType lang CTAGS_ATTR_UNUSED)
5530a9c91f4dSMasatake YAMATO {
5531a9c91f4dSMasatake YAMATO 	fprintf (stderr, "The number of handled chars: %d\n",
5532a9c91f4dSMasatake YAMATO 			 CTST_num_handled_char);
5533a9c91f4dSMasatake YAMATO }
5534a9c91f4dSMasatake YAMATO 
CTagsSelfTestParser(void)55350435a2b5SMasatake YAMATO static parserDefinition *CTagsSelfTestParser (void)
5536e7283d01SMasatake YAMATO {
5537e7283d01SMasatake YAMATO 	static const char *const extensions[] = { NULL };
5538d3ee68cdSMasatake YAMATO 	parserDefinition *const def = parserNew (SELF_TEST_PARSER);
5539e7283d01SMasatake YAMATO 	def->extensions = extensions;
554009ae690fSMasatake YAMATO 	def->kindTable = CTST_Kinds;
5541e7283d01SMasatake YAMATO 	def->kindCount = KIND_COUNT;
5542e7283d01SMasatake YAMATO 	def->parser = createCTSTTags;
5543ce990805SThomas Braun 	def->invisible = true;
55446342bbd5SMasatake YAMATO 	def->useMemoryStreamInput = true;
55456b1a862eSMasatake YAMATO 	def->useCork = CORK_QUEUE;
5546a9c91f4dSMasatake YAMATO 	def->initStats = initStatsCTST;
5547a9c91f4dSMasatake YAMATO 	def->printStats = printStatsCTST;
55487b08b440SMasatake YAMATO 	def->fieldTable = CTSTFields;
55497b08b440SMasatake YAMATO 	def->fieldCount = ARRAY_SIZE (CTSTFields);
55507b08b440SMasatake YAMATO 
5551e7283d01SMasatake YAMATO 	return def;
5552e7283d01SMasatake YAMATO }
5553