xref: /Universal-ctags/parsers/iniconf.c (revision 3671ad7255885a0c8f6ff4979d80c70f201ea411)
1dc3daa67SMasatake YAMATO /*
2dc3daa67SMasatake YAMATO *
3dc3daa67SMasatake YAMATO *   Copyright (c) 2000-2001, Darren Hiebert
4dc3daa67SMasatake YAMATO *
5dc3daa67SMasatake YAMATO *   This source code is released for free distribution under the terms of the
6dc3daa67SMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
7dc3daa67SMasatake YAMATO *
8dc3daa67SMasatake YAMATO *   This module contains functions for generating tags for ini/config files.
9dc3daa67SMasatake YAMATO */
10dc3daa67SMasatake YAMATO 
11dc3daa67SMasatake YAMATO /*
12dc3daa67SMasatake YAMATO  *  This is based on geany's conf.c:
13dc3daa67SMasatake YAMATO  * --------------------------------
14dc3daa67SMasatake YAMATO  * commit 3af538fa65f8b17897259080db8144b1edc43470
15dc3daa67SMasatake YAMATO  * Author: Enrico Tröger <enrico.troeger@uvena.de>
16dc3daa67SMasatake YAMATO  * Date:   Sun Nov 27 20:39:57 2005 +0000
17dc3daa67SMasatake YAMATO  *
18dc3daa67SMasatake YAMATO  * added tag support for filetype Conf
19dc3daa67SMasatake YAMATO  *
20dc3daa67SMasatake YAMATO  *
21dc3daa67SMasatake YAMATO  * git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@15 ea778897-0a13-0410-b9d1-a72fbfd435f5
22dc3daa67SMasatake YAMATO  *
23dc3daa67SMasatake YAMATO  */
24dc3daa67SMasatake YAMATO 
25dc3daa67SMasatake YAMATO #include "general.h"  /* must always come first */
26dc3daa67SMasatake YAMATO 
2714781660SMasatake YAMATO #include "entry.h"
28dc3daa67SMasatake YAMATO #include "htable.h"
2987214e15SMasatake YAMATO #include "iniconf.h"
30dc3daa67SMasatake YAMATO #include "parse.h"
31dc3daa67SMasatake YAMATO #include "read.h"
32ed9b023fSMasatake YAMATO #include "subparser.h"
33dc3daa67SMasatake YAMATO #include "vstring.h"
34dc3daa67SMasatake YAMATO 
isIdentifier(int c)35ce990805SThomas Braun static bool isIdentifier (int c)
36dc3daa67SMasatake YAMATO {
37dc3daa67SMasatake YAMATO     /* allow whitespace within keys and sections */
38ce990805SThomas Braun     return (bool)(isalnum (c) || isspace (c) ||  c == '_');
39dc3daa67SMasatake YAMATO }
40dc3daa67SMasatake YAMATO 
isValue(int c)41ce990805SThomas Braun static bool isValue (int c)
42dc3daa67SMasatake YAMATO {
43dc3daa67SMasatake YAMATO 	return (c != '\0');
44dc3daa67SMasatake YAMATO }
45dc3daa67SMasatake YAMATO 
maySwitchLanguage(const char * section,const char * key,const char * value)46ed9b023fSMasatake YAMATO static iniconfSubparser *maySwitchLanguage (const char *section, const char *key, const char *value)
47dc3daa67SMasatake YAMATO {
48ed9b023fSMasatake YAMATO 	iniconfSubparser *iniconf_subparser = NULL;
49ed9b023fSMasatake YAMATO 	subparser *sub;
50ed9b023fSMasatake YAMATO 
5111358a9dSMasatake YAMATO 	foreachSubparser (sub, false)
52ed9b023fSMasatake YAMATO 	{
53ed9b023fSMasatake YAMATO 		iniconfSubparser *s = (iniconfSubparser *)sub;
54ed9b023fSMasatake YAMATO 		if ((sub->direction & SUBPARSER_BASE_RUNS_SUB)
55ed9b023fSMasatake YAMATO 			&& s->probeLanguage)
56ed9b023fSMasatake YAMATO 		{
57ed9b023fSMasatake YAMATO 			bool r;
58ed9b023fSMasatake YAMATO 
593abcac5dSMasatake YAMATO 			enterSubparser ((subparser *)s);
60ed9b023fSMasatake YAMATO 			r = s->probeLanguage(section, key, value);
61ed9b023fSMasatake YAMATO 			leaveSubparser ();
62ed9b023fSMasatake YAMATO 			if (r)
63ed9b023fSMasatake YAMATO 			{
64ed9b023fSMasatake YAMATO 				iniconf_subparser = s;
65ed9b023fSMasatake YAMATO 				chooseExclusiveSubparser (sub, NULL);
66ed9b023fSMasatake YAMATO 				break;
67ed9b023fSMasatake YAMATO 			}
68ed9b023fSMasatake YAMATO 		}
69dc3daa67SMasatake YAMATO 	}
70dc3daa67SMasatake YAMATO 
71ed9b023fSMasatake YAMATO 	return iniconf_subparser;
72ed9b023fSMasatake YAMATO }
73dc3daa67SMasatake YAMATO 
74ed9b023fSMasatake YAMATO typedef enum {
75ed9b023fSMasatake YAMATO 	K_SECTION,
76ed9b023fSMasatake YAMATO 	K_KEY,
77ed9b023fSMasatake YAMATO } makeKind;
78dc3daa67SMasatake YAMATO 
79e112e8abSMasatake YAMATO static kindDefinition IniconfKinds [] = {
80ed9b023fSMasatake YAMATO 	{ true, 's', "section",  "sections"},
81ed9b023fSMasatake YAMATO 	{ true, 'k', "key",      "keys"},
82dc3daa67SMasatake YAMATO };
83dc3daa67SMasatake YAMATO 
makeIniconfTagMaybe(const char * section,const char * key,const char * value CTAGS_ATTR_UNUSED,int * index)84e4d16241SMasatake YAMATO static void makeIniconfTagMaybe (const char *section, const char *key, const char *value CTAGS_ATTR_UNUSED, int *index)
85dc3daa67SMasatake YAMATO {
86ed9b023fSMasatake YAMATO 	tagEntryInfo e;
87dc3daa67SMasatake YAMATO 
88ed9b023fSMasatake YAMATO 	if (!isLanguageEnabled (getInputLanguage ()))
89dc3daa67SMasatake YAMATO 		return;
90dc3daa67SMasatake YAMATO 
91ed9b023fSMasatake YAMATO 	if (key)
92ed9b023fSMasatake YAMATO 	{
9316a2541cSMasatake YAMATO 		initTagEntry (&e, key, K_KEY);
94ed9b023fSMasatake YAMATO 		e.extensionFields.scopeIndex = *index;
95ed9b023fSMasatake YAMATO 		makeTagEntry (&e);
96ed9b023fSMasatake YAMATO 	}
97ed9b023fSMasatake YAMATO 	else
98ed9b023fSMasatake YAMATO 	{
99*3671ad72SMasatake YAMATO 		tagEntryInfo *last = getEntryInCorkQueue (*index);
100ed9b023fSMasatake YAMATO 		if (last)
101ed9b023fSMasatake YAMATO 			last->extensionFields.endLine = getInputLineNumber ();
102dc3daa67SMasatake YAMATO 
10316a2541cSMasatake YAMATO 		initTagEntry (&e, section, K_SECTION);
104ed9b023fSMasatake YAMATO 		*index = makeTagEntry (&e);
105dc3daa67SMasatake YAMATO 	}
106dc3daa67SMasatake YAMATO }
107dc3daa67SMasatake YAMATO 
findIniconfTags(void)108ed9b023fSMasatake YAMATO static void findIniconfTags (void)
109dc3daa67SMasatake YAMATO {
110ed9b023fSMasatake YAMATO 	const unsigned char *line;
111dc3daa67SMasatake YAMATO 	vString *val   = vStringNew ();
112dc3daa67SMasatake YAMATO 	vString *name  = vStringNew ();
113dc3daa67SMasatake YAMATO 	vString *scope = vStringNew ();
114ed9b023fSMasatake YAMATO 	iniconfSubparser *sub;
115ed9b023fSMasatake YAMATO 	int sectionCorkIndex = CORK_NIL;
116dc3daa67SMasatake YAMATO 
117dc3daa67SMasatake YAMATO 
118ed9b023fSMasatake YAMATO 	sub = (iniconfSubparser *)getSubparserRunningBaseparser();
119ed9b023fSMasatake YAMATO 	if (sub)
120ed9b023fSMasatake YAMATO 		chooseExclusiveSubparser ((subparser *)sub, NULL);
121dc3daa67SMasatake YAMATO 
122dc3daa67SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
123dc3daa67SMasatake YAMATO 	{
124dc3daa67SMasatake YAMATO 		const unsigned char* cp = line;
125ce990805SThomas Braun 		bool possible = true;
126dc3daa67SMasatake YAMATO 
127c1faa6e5SMasatake YAMATO 		if (isspace ((int) *cp) || *cp == '#' || *cp == ';' || *cp == '\0'
128c1faa6e5SMasatake YAMATO 		    || (*cp == '/' && *(cp+1) == '/'))
129dc3daa67SMasatake YAMATO 			continue;
130dc3daa67SMasatake YAMATO 
131dc3daa67SMasatake YAMATO 		/* look for a section */
132c1faa6e5SMasatake YAMATO 		if (*cp == '[')
133dc3daa67SMasatake YAMATO 		{
134dc3daa67SMasatake YAMATO 			++cp;
135dc3daa67SMasatake YAMATO 			while (*cp != '\0' && *cp != ']')
136dc3daa67SMasatake YAMATO 			{
137dc3daa67SMasatake YAMATO 				vStringPut (name, (int) *cp);
138dc3daa67SMasatake YAMATO 				++cp;
139dc3daa67SMasatake YAMATO 			}
140dc3daa67SMasatake YAMATO 
141ed9b023fSMasatake YAMATO 			makeIniconfTagMaybe (vStringValue (name), NULL, NULL,
142dc3daa67SMasatake YAMATO 								 &sectionCorkIndex);
143dc3daa67SMasatake YAMATO 
144ed9b023fSMasatake YAMATO 
145ed9b023fSMasatake YAMATO 			if (!sub)
146ed9b023fSMasatake YAMATO 				sub = maySwitchLanguage (vStringValue (name), NULL, NULL);
147ed9b023fSMasatake YAMATO 
148ed9b023fSMasatake YAMATO 			if (sub)
149dc3daa67SMasatake YAMATO 			{
1503abcac5dSMasatake YAMATO 				enterSubparser((subparser *)sub);
151ed9b023fSMasatake YAMATO 				sub->newDataNotify (sub, vStringValue (name), NULL, NULL);
152ed9b023fSMasatake YAMATO 				leaveSubparser ();
153dc3daa67SMasatake YAMATO 			}
154dc3daa67SMasatake YAMATO 
155dc3daa67SMasatake YAMATO 			vStringCopy (scope, name);
156dc3daa67SMasatake YAMATO 			vStringClear (name);
157dc3daa67SMasatake YAMATO 			continue;
158dc3daa67SMasatake YAMATO 		}
159dc3daa67SMasatake YAMATO 
160dc3daa67SMasatake YAMATO 		while (*cp != '\0')
161dc3daa67SMasatake YAMATO 		{
162dc3daa67SMasatake YAMATO 			/*  We look for any sequence of identifier characters following a white space */
163dc3daa67SMasatake YAMATO 			if (possible && isIdentifier ((int) *cp))
164dc3daa67SMasatake YAMATO 			{
165dc3daa67SMasatake YAMATO 				while (isIdentifier ((int) *cp))
166dc3daa67SMasatake YAMATO 				{
167dc3daa67SMasatake YAMATO 					vStringPut (name, (int) *cp);
168dc3daa67SMasatake YAMATO 					++cp;
169dc3daa67SMasatake YAMATO 				}
170dc3daa67SMasatake YAMATO 				vStringStripTrailing (name);
171dc3daa67SMasatake YAMATO 				while (isspace ((int) *cp))
172dc3daa67SMasatake YAMATO 					++cp;
173dc3daa67SMasatake YAMATO 				if (*cp == '=' || *cp == ':')
174dc3daa67SMasatake YAMATO 				{
175dc3daa67SMasatake YAMATO 
176dc3daa67SMasatake YAMATO 					cp++;
177dc3daa67SMasatake YAMATO 					while (isspace ((int) *cp))
178dc3daa67SMasatake YAMATO 						++cp;
179dc3daa67SMasatake YAMATO 					while (isValue ((int) *cp))
180dc3daa67SMasatake YAMATO 					{
181dc3daa67SMasatake YAMATO 						vStringPut (val, (int) *cp);
182dc3daa67SMasatake YAMATO 						++cp;
183dc3daa67SMasatake YAMATO 					}
184dc3daa67SMasatake YAMATO 					vStringStripTrailing (val);
185dc3daa67SMasatake YAMATO 
186ed9b023fSMasatake YAMATO 					makeIniconfTagMaybe ((vStringLength (scope) > 0)
187dc3daa67SMasatake YAMATO 										 ? vStringValue (scope)
188dc3daa67SMasatake YAMATO 										 : NULL,
189dc3daa67SMasatake YAMATO 										 vStringValue (name),
190dc3daa67SMasatake YAMATO 										 vStringValue (val),
191dc3daa67SMasatake YAMATO 										 &sectionCorkIndex);
192ed9b023fSMasatake YAMATO 					if (!sub)
193ed9b023fSMasatake YAMATO 						sub = maySwitchLanguage ((vStringLength (scope) > 0)
194dc3daa67SMasatake YAMATO 												 ? vStringValue (scope)
195dc3daa67SMasatake YAMATO 												 : NULL,
196dc3daa67SMasatake YAMATO 												 vStringValue (name),
197dc3daa67SMasatake YAMATO 												 vStringValue (val));
198ed9b023fSMasatake YAMATO 					if (sub)
199dc3daa67SMasatake YAMATO 					{
2003abcac5dSMasatake YAMATO 						enterSubparser ((subparser *)sub);
201ed9b023fSMasatake YAMATO 						sub->newDataNotify (sub,
202ed9b023fSMasatake YAMATO 											(vStringLength (scope) > 0)
203dc3daa67SMasatake YAMATO 											? vStringValue (scope)
204dc3daa67SMasatake YAMATO 											: NULL,
205dc3daa67SMasatake YAMATO 											vStringValue (name),
206ed9b023fSMasatake YAMATO 											vStringValue (val));
207ed9b023fSMasatake YAMATO 						leaveSubparser ();
208ed9b023fSMasatake YAMATO 					}
209dc3daa67SMasatake YAMATO 					vStringClear (val);
210dc3daa67SMasatake YAMATO 				}
211dc3daa67SMasatake YAMATO 				vStringClear (name);
212dc3daa67SMasatake YAMATO 			}
213dc3daa67SMasatake YAMATO 			else
214dc3daa67SMasatake YAMATO 				possible = !!(isspace ((int) *cp));
215dc3daa67SMasatake YAMATO 
216dc3daa67SMasatake YAMATO 			if (*cp != '\0')
217dc3daa67SMasatake YAMATO 				++cp;
218dc3daa67SMasatake YAMATO 		}
219dc3daa67SMasatake YAMATO 	}
220dc3daa67SMasatake YAMATO 
221dc3daa67SMasatake YAMATO 	vStringDelete (name);
222dc3daa67SMasatake YAMATO 	vStringDelete (scope);
223dc3daa67SMasatake YAMATO 	vStringDelete (val);
224dc3daa67SMasatake YAMATO }
225dc3daa67SMasatake YAMATO 
IniconfParser(void)226dc3daa67SMasatake YAMATO extern parserDefinition* IniconfParser (void)
227dc3daa67SMasatake YAMATO {
228dc3daa67SMasatake YAMATO 	static const char *const extensions [] = { "ini", "conf", NULL };
229dc3daa67SMasatake YAMATO 	parserDefinition* const def = parserNew ("Iniconf");
230dc3daa67SMasatake YAMATO 
23109ae690fSMasatake YAMATO 	def->kindTable      = IniconfKinds;
232dc3daa67SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (IniconfKinds);
233dc3daa67SMasatake YAMATO 	def->extensions = extensions;
234dc3daa67SMasatake YAMATO 	def->parser     = findIniconfTags;
2356b1a862eSMasatake YAMATO 	def->useCork   = CORK_QUEUE;
236dc3daa67SMasatake YAMATO 
237dc3daa67SMasatake YAMATO 	return def;
238dc3daa67SMasatake YAMATO }
239