xref: /Universal-ctags/parsers/nsis.c (revision 6b1a862e526d5017f9f212a321f59d67c859d521)
19d8ec15eSJiří Techet /*
29d8ec15eSJiří Techet *   Copyright (c) 2000-2002, Darren Hiebert
39d8ec15eSJiří Techet *   Copyright (c) 2009-2011, Enrico Tröger
49d8ec15eSJiří Techet *
59d8ec15eSJiří Techet *   This source code is released for free distribution under the terms of the
671fa62beSMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
79d8ec15eSJiří Techet *
89d8ec15eSJiří Techet *   This module contains functions for generating tags for NSIS scripts
99d8ec15eSJiří Techet *   (https://en.wikipedia.org/wiki/Nullsoft_Scriptable_Install_System).
109d8ec15eSJiří Techet *
119d8ec15eSJiří Techet *   Based on sh.c.
129d8ec15eSJiří Techet */
139d8ec15eSJiří Techet 
149d8ec15eSJiří Techet /*
159d8ec15eSJiří Techet *   INCLUDE FILES
169d8ec15eSJiří Techet */
179d8ec15eSJiří Techet #include "general.h"	/* must always come first */
189d8ec15eSJiří Techet 
199d8ec15eSJiří Techet #include <string.h>
209d8ec15eSJiří Techet 
219d1f0cb7SMasatake YAMATO #include "entry.h"
229d8ec15eSJiří Techet #include "parse.h"
239d8ec15eSJiří Techet #include "read.h"
249d8ec15eSJiří Techet #include "vstring.h"
259d8ec15eSJiří Techet #include "routines.h"
269d8ec15eSJiří Techet 
279d8ec15eSJiří Techet /*
289d8ec15eSJiří Techet *   DATA DEFINITIONS
299d8ec15eSJiří Techet */
309d8ec15eSJiří Techet typedef enum {
319d8ec15eSJiří Techet 	K_SECTION,
329d8ec15eSJiří Techet 	K_FUNCTION,
3383771e9dSMasatake YAMATO 	K_VARIABLE,
3483771e9dSMasatake YAMATO 	K_DEFINITION,
35c75fc088SMasatake YAMATO 	K_MACRO,
36279fa60eSMasatake YAMATO 	K_SECTION_GROUP,
37965e8f2dSMasatake YAMATO 	K_MACRO_PARAM,
38594fea13SMasatake YAMATO 	K_LANGSTR,
398693338dSMasatake YAMATO 	K_SCRIPT,
409d8ec15eSJiří Techet } NsisKind;
419d8ec15eSJiří Techet 
428693338dSMasatake YAMATO typedef enum {
438693338dSMasatake YAMATO 	NSIS_SCRIPT_INCLUDED,
448693338dSMasatake YAMATO } nsisScriptRole;
458693338dSMasatake YAMATO 
468693338dSMasatake YAMATO static roleDefinition NsisScriptRoles [] = {
478693338dSMasatake YAMATO 	{ true, "included",  "included with !include" },
488693338dSMasatake YAMATO };
498693338dSMasatake YAMATO 
509d8ec15eSJiří Techet static kindDefinition NsisKinds [] = {
519d8ec15eSJiří Techet 	{ true, 's', "section", "sections"},
529d8ec15eSJiří Techet 	{ true, 'f', "function", "functions"},
5383771e9dSMasatake YAMATO 	{ true, 'v', "variable", "variables"},
5483771e9dSMasatake YAMATO 	{ true, 'd', "definition", "definitions"},
55c75fc088SMasatake YAMATO 	{ true, 'm', "macro", "macros"},
56279fa60eSMasatake YAMATO 	{ true, 'S', "sectionGroup", "section groups"},
57965e8f2dSMasatake YAMATO 	{ false, 'p', "macroparam", "macro parameters"},
58594fea13SMasatake YAMATO 	{ true, 'l', "langstr", "language strings"},
598693338dSMasatake YAMATO 	{ true, 'i', "script", "NSIS scripts",
608693338dSMasatake YAMATO 	  .referenceOnly = true, ATTACH_ROLES(NsisScriptRoles)},
61594fea13SMasatake YAMATO };
62594fea13SMasatake YAMATO 
63594fea13SMasatake YAMATO typedef enum {
64594fea13SMasatake YAMATO 	F_LANGID,
65594fea13SMasatake YAMATO } nsisField;
66594fea13SMasatake YAMATO 
67594fea13SMasatake YAMATO static fieldDefinition NsisFields[] = {
68594fea13SMasatake YAMATO 	{ .name = "langid",
69594fea13SMasatake YAMATO 	  .description = "language identifier specified in (License)LangString commands",
70594fea13SMasatake YAMATO 	  .enabled = true },
719d8ec15eSJiří Techet };
729d8ec15eSJiří Techet 
739d8ec15eSJiří Techet /*
749d8ec15eSJiří Techet *   FUNCTION DEFINITIONS
759d8ec15eSJiří Techet */
769d8ec15eSJiří Techet 
skipWhitespace(const unsigned char * cp)77a15add00SMasatake YAMATO static const unsigned char* skipWhitespace (const unsigned char* cp)
78a15add00SMasatake YAMATO {
79a15add00SMasatake YAMATO 	while (isspace ((int) *cp))
80a15add00SMasatake YAMATO 		++cp;
81a15add00SMasatake YAMATO 	return cp;
82a15add00SMasatake YAMATO }
83a15add00SMasatake YAMATO 
skipFlags(const unsigned char * cp)84a15add00SMasatake YAMATO static const unsigned char* skipFlags (const unsigned char* cp)
85a15add00SMasatake YAMATO {
86a15add00SMasatake YAMATO 	while (*cp == '/')
87a15add00SMasatake YAMATO 	{
88a15add00SMasatake YAMATO 		++cp;
89a15add00SMasatake YAMATO 		while (! isspace ((int) *cp))
90a15add00SMasatake YAMATO 			++cp;
91a15add00SMasatake YAMATO 		while (isspace ((int) *cp))
92a15add00SMasatake YAMATO 			++cp;
93a15add00SMasatake YAMATO 	}
94a15add00SMasatake YAMATO 	return cp;
95a15add00SMasatake YAMATO }
96a15add00SMasatake YAMATO 
makeSimpleTagWithScope(vString * name,int kindIndex,int parentCorkIndex)979d1f0cb7SMasatake YAMATO static int makeSimpleTagWithScope(vString *name, int kindIndex, int parentCorkIndex)
989d1f0cb7SMasatake YAMATO {
999d1f0cb7SMasatake YAMATO 	tagEntryInfo e;
1009d1f0cb7SMasatake YAMATO 	initTagEntry (&e, vStringValue (name), kindIndex);
1019d1f0cb7SMasatake YAMATO 	e.extensionFields.scopeIndex = parentCorkIndex;
1029d1f0cb7SMasatake YAMATO 	return makeTagEntry (&e);
1039d1f0cb7SMasatake YAMATO }
1049d1f0cb7SMasatake YAMATO 
1059d1f0cb7SMasatake YAMATO #define lineStartingWith(CP,EXPECTED,EOL)								\
106c7668dcdSMasatake YAMATO 	(strncasecmp ((const char*) CP, EXPECTED, strlen(EXPECTED)) == 0	\
1079d1f0cb7SMasatake YAMATO 		&& (EOL ? (isspace ((int) CP [strlen(EXPECTED)]) || CP [strlen(EXPECTED)] == '\0') \
1089d1f0cb7SMasatake YAMATO 			: isspace ((int) CP [strlen(EXPECTED)])))
109c7668dcdSMasatake YAMATO 
1101a620a0cSMasatake YAMATO #define fillName(NAME,CP,CONDITION)				\
1111a620a0cSMasatake YAMATO 	while (CONDITION)							\
1121a620a0cSMasatake YAMATO 	{											\
1131a620a0cSMasatake YAMATO 		vStringPut ((NAME), (int) *(CP));		\
1141a620a0cSMasatake YAMATO 		++(CP);									\
1151a620a0cSMasatake YAMATO 	}											\
1161a620a0cSMasatake YAMATO 	do {} while (0)
1171a620a0cSMasatake YAMATO 
parseSection(const unsigned char * cp,vString * name,int kindIndex,int scopeIndex,int * corkIndex)118279fa60eSMasatake YAMATO static const unsigned char* parseSection (const unsigned char* cp, vString *name,
1199d1f0cb7SMasatake YAMATO 										  int kindIndex, int scopeIndex, int *corkIndex)
120c7650be9SMasatake YAMATO {
121c7650be9SMasatake YAMATO 	cp = skipWhitespace (cp);
122c7650be9SMasatake YAMATO 	cp = skipFlags (cp);
12383270f81SMasatake YAMATO 	cp = skipWhitespace (cp);
12483270f81SMasatake YAMATO 
12583270f81SMasatake YAMATO 	if (corkIndex)
12683270f81SMasatake YAMATO 		*corkIndex = CORK_NIL;
12783270f81SMasatake YAMATO 
1281c72c94fSMasatake YAMATO 	if (strpbrk((const char *)cp, "'`\""))
129c7650be9SMasatake YAMATO 	{
1301c72c94fSMasatake YAMATO 		const unsigned char terminator = *cp;
1311c72c94fSMasatake YAMATO 
13283270f81SMasatake YAMATO 		cp++;
1331c72c94fSMasatake YAMATO 		if (*cp == terminator)
13483270f81SMasatake YAMATO 		{
13583270f81SMasatake YAMATO 			/* An empty section.
13683270f81SMasatake YAMATO 			 * See https://nsis.sourceforge.io/Docs/Chapter4.html#sectionsettext
13783270f81SMasatake YAMATO 			 */
13883270f81SMasatake YAMATO 			anonGenerate (name,
13983270f81SMasatake YAMATO 						  (kindIndex == K_SECTION
14083270f81SMasatake YAMATO 						   ? "AnonymousSection"
14183270f81SMasatake YAMATO 						   : "AnonymousSectionGroup"),
14283270f81SMasatake YAMATO 						  kindIndex);
14383270f81SMasatake YAMATO 			cp++;
14483270f81SMasatake YAMATO 		}
14583270f81SMasatake YAMATO 		else if (*cp == '\0')
14683270f81SMasatake YAMATO 			return cp;
14783270f81SMasatake YAMATO 		else
14883270f81SMasatake YAMATO 		{
149d0b42663SMasatake YAMATO 			int in_escape = 0;
15083270f81SMasatake YAMATO 			do
15183270f81SMasatake YAMATO 			{
15283270f81SMasatake YAMATO 				vStringPut (name, (int) *cp);
15383270f81SMasatake YAMATO 				++cp;
15483270f81SMasatake YAMATO 
15583270f81SMasatake YAMATO 				if (*cp == '\0')
15683270f81SMasatake YAMATO 					break;
15783270f81SMasatake YAMATO 
158d0b42663SMasatake YAMATO 				/*
159d0b42663SMasatake YAMATO 				 * Ignore `"' in `$\"' as the terminator of quotation.
160d0b42663SMasatake YAMATO 				 */
161d0b42663SMasatake YAMATO 				if (*cp == '$' && in_escape == 0)
162d0b42663SMasatake YAMATO 					in_escape++;
163d0b42663SMasatake YAMATO 				else if (*cp == '\\' && in_escape == 1)
164d0b42663SMasatake YAMATO 					in_escape++;
1651c72c94fSMasatake YAMATO 				else if (*cp == terminator && in_escape == 2)
166d0b42663SMasatake YAMATO 					/*
167d0b42663SMasatake YAMATO 					 * This `"' is not a terminator of quotation;
168d0b42663SMasatake YAMATO 					 * set in_escape to 3.
169d0b42663SMasatake YAMATO 					 */
170d0b42663SMasatake YAMATO 					in_escape++;
171d0b42663SMasatake YAMATO 				else
172d0b42663SMasatake YAMATO 					in_escape = 0;
173d0b42663SMasatake YAMATO 
1741c72c94fSMasatake YAMATO 				if ((in_escape != 3) && *cp == terminator)
175c7650be9SMasatake YAMATO 				{
176c7650be9SMasatake YAMATO 					++cp;
177c7650be9SMasatake YAMATO 					break;
178c7650be9SMasatake YAMATO 				}
17983270f81SMasatake YAMATO 			}
18083270f81SMasatake YAMATO 			while (1);
18183270f81SMasatake YAMATO 		}
18283270f81SMasatake YAMATO 	}
183c7650be9SMasatake YAMATO 	else
184c7650be9SMasatake YAMATO 	{
18583270f81SMasatake YAMATO 		while (isalnum ((int) *cp)
18683270f81SMasatake YAMATO 			   || *cp == '_' || *cp == '-' || *cp == '.' || *cp == '!'
18783270f81SMasatake YAMATO 			   || *cp == '$' || *cp == '{' || *cp == '}' || *cp == '(' || *cp == ')')
18883270f81SMasatake YAMATO 		{
189c7650be9SMasatake YAMATO 			vStringPut (name, (int) *cp);
190c7650be9SMasatake YAMATO 			++cp;
191c7650be9SMasatake YAMATO 		}
19283270f81SMasatake YAMATO 	}
1939d1f0cb7SMasatake YAMATO 	int r = makeSimpleTagWithScope (name, kindIndex, scopeIndex);
1949d1f0cb7SMasatake YAMATO 	if (corkIndex)
1959d1f0cb7SMasatake YAMATO 		*corkIndex = r;
196c7650be9SMasatake YAMATO 	if (vStringLength (name) > 0)
197c7650be9SMasatake YAMATO 	{
198c7650be9SMasatake YAMATO 		/*
199c7650be9SMasatake YAMATO 		 * Try to capture section_index_output.
200c7650be9SMasatake YAMATO 		 */
201c7650be9SMasatake YAMATO 		vStringClear (name);
202c7650be9SMasatake YAMATO 		cp = skipWhitespace (cp);
203c7650be9SMasatake YAMATO 
204c7650be9SMasatake YAMATO 		fillName (name, cp, (isalnum ((int) *cp) || *cp == '_'));
205c7650be9SMasatake YAMATO 
206c7650be9SMasatake YAMATO 		if (vStringLength (name) > 0)
207c7650be9SMasatake YAMATO 		{
208c7650be9SMasatake YAMATO 			makeSimpleTag (name, K_DEFINITION);
209c7650be9SMasatake YAMATO 			vStringClear (name);
210c7650be9SMasatake YAMATO 		}
211c7650be9SMasatake YAMATO 	}
212c7650be9SMasatake YAMATO 	return cp;
213c7650be9SMasatake YAMATO }
214c7650be9SMasatake YAMATO 
parseLangString(const unsigned char * cp,vString * name)215594fea13SMasatake YAMATO static const unsigned char* parseLangString (const unsigned char* cp, vString *name)
216594fea13SMasatake YAMATO {
217594fea13SMasatake YAMATO 	cp = skipWhitespace (cp);
218594fea13SMasatake YAMATO 
21990a136cfSK.Takata 	/* `^' is not explained in the nsis reference manual. However, it is used
220594fea13SMasatake YAMATO 	 * in gvim.
221594fea13SMasatake YAMATO 	 * e.g.
222594fea13SMasatake YAMATO 	 * https://github.com/vim/vim/blob/3dabd718f4b2d8e09de9e2ec73832620b91c2f79/nsis/lang/english.nsi
223594fea13SMasatake YAMATO 	 */
224594fea13SMasatake YAMATO 	fillName (name, cp, (isalnum ((int) *cp) || *cp == '_' || *cp == '^'));
225594fea13SMasatake YAMATO 
226594fea13SMasatake YAMATO 	if (vStringLength (name) > 0)
227594fea13SMasatake YAMATO 	{
228594fea13SMasatake YAMATO 		int r = makeSimpleTag (name, K_LANGSTR);
229594fea13SMasatake YAMATO 		if (r == CORK_NIL)
230594fea13SMasatake YAMATO 			goto out;
231594fea13SMasatake YAMATO 		vStringClear (name);
232594fea13SMasatake YAMATO 
233594fea13SMasatake YAMATO 		cp = skipWhitespace (cp);
234594fea13SMasatake YAMATO 		fillName (name, cp, ((*cp != '\0') && (!isspace ((int) *cp))));
235594fea13SMasatake YAMATO 		if (vStringLength (name) > 0)
236594fea13SMasatake YAMATO 		{
237594fea13SMasatake YAMATO 			attachParserFieldToCorkEntry (r, NsisFields[F_LANGID].ftype,
238594fea13SMasatake YAMATO 										  vStringValue (name));
239594fea13SMasatake YAMATO 			vStringClear (name);
240594fea13SMasatake YAMATO 		}
241594fea13SMasatake YAMATO 	}
242594fea13SMasatake YAMATO  out:
243594fea13SMasatake YAMATO 	return cp;
244594fea13SMasatake YAMATO }
245594fea13SMasatake YAMATO 
findNsisTags(void)2469d8ec15eSJiří Techet static void findNsisTags (void)
2479d8ec15eSJiří Techet {
2489d1f0cb7SMasatake YAMATO 	int sectionGroupIndex = CORK_NIL;
2499d8ec15eSJiří Techet 	vString *name = vStringNew ();
2509d8ec15eSJiří Techet 	const unsigned char *line;
2519d8ec15eSJiří Techet 
2529d8ec15eSJiří Techet 	while ((line = readLineFromInputFile ()) != NULL)
2539d8ec15eSJiří Techet 	{
2549d8ec15eSJiří Techet 		const unsigned char* cp = line;
2559d8ec15eSJiří Techet 
2569d8ec15eSJiří Techet 		while (isspace (*cp))
2579d8ec15eSJiří Techet 			cp++;
2589d8ec15eSJiří Techet 
2599d8ec15eSJiří Techet 		if (*cp == '#' || *cp == ';')
2609d8ec15eSJiří Techet 			continue;
2619d8ec15eSJiří Techet 
2629d8ec15eSJiří Techet 		/* functions */
2639d1f0cb7SMasatake YAMATO 		if (lineStartingWith (cp, "function", false))
2649d8ec15eSJiří Techet 		{
2659d8ec15eSJiří Techet 			cp += 8;
266a15add00SMasatake YAMATO 			cp = skipWhitespace (cp);
2671a620a0cSMasatake YAMATO 
2681a620a0cSMasatake YAMATO 			fillName (name, cp,
2691a620a0cSMasatake YAMATO 					  (isalnum ((int) *cp) || *cp == '_' || *cp == '-' || *cp == '.' || *cp == '!'));
2701a620a0cSMasatake YAMATO 
2719d8ec15eSJiří Techet 			makeSimpleTag (name, K_FUNCTION);
2729d8ec15eSJiří Techet 			vStringClear (name);
2739d8ec15eSJiří Techet 		}
2749d8ec15eSJiří Techet 		/* variables */
2759d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "var", false))
2769d8ec15eSJiří Techet 		{
2779d8ec15eSJiří Techet 			cp += 3;
278a15add00SMasatake YAMATO 			cp = skipWhitespace (cp);
279a15add00SMasatake YAMATO 			cp = skipFlags (cp);
280a15add00SMasatake YAMATO 
2811a620a0cSMasatake YAMATO 			fillName (name, cp, (isalnum ((int) *cp) || *cp == '_'));
2821a620a0cSMasatake YAMATO 
2839d8ec15eSJiří Techet 			makeSimpleTag (name, K_VARIABLE);
2849d8ec15eSJiří Techet 			vStringClear (name);
2859d8ec15eSJiří Techet 		}
286279fa60eSMasatake YAMATO 		/* section groups */
2879d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "sectiongroup", false))
288279fa60eSMasatake YAMATO 		{
289279fa60eSMasatake YAMATO 			cp += 12;
2909d1f0cb7SMasatake YAMATO 			cp = parseSection (cp, name, K_SECTION_GROUP, CORK_NIL, &sectionGroupIndex);
2919d1f0cb7SMasatake YAMATO 		}
2929d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "sectiongroupend", true))
2939d1f0cb7SMasatake YAMATO 		{
2949d1f0cb7SMasatake YAMATO 			cp += 15;
2959d1f0cb7SMasatake YAMATO 			sectionGroupIndex = CORK_NIL;
296279fa60eSMasatake YAMATO 		}
2979d8ec15eSJiří Techet 		/* sections */
2989d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "section", false))
2999d8ec15eSJiří Techet 		{
3009d8ec15eSJiří Techet 			cp += 7;
3019d1f0cb7SMasatake YAMATO 			cp = parseSection (cp, name, K_SECTION, sectionGroupIndex, NULL);
3029d8ec15eSJiří Techet 		}
303594fea13SMasatake YAMATO 		/* LangString */
304594fea13SMasatake YAMATO 		else if (lineStartingWith (cp, "langstring", false))
305594fea13SMasatake YAMATO 		{
306594fea13SMasatake YAMATO 			cp += 10;
307594fea13SMasatake YAMATO 			cp = parseLangString (cp, name);
308594fea13SMasatake YAMATO 		}
309594fea13SMasatake YAMATO 		/* LicenseLangString */
310594fea13SMasatake YAMATO 		else if (lineStartingWith (cp, "licenselangstring", false))
311594fea13SMasatake YAMATO 		{
312594fea13SMasatake YAMATO 			cp += 17;
313594fea13SMasatake YAMATO 			cp = parseLangString (cp, name);
314594fea13SMasatake YAMATO 		}
315568fd7d7SMasatake YAMATO 		/* definitions */
3169d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "!define", false))
317568fd7d7SMasatake YAMATO 		{
318568fd7d7SMasatake YAMATO 			cp += 7;
319568fd7d7SMasatake YAMATO 			cp = skipWhitespace (cp);
320568fd7d7SMasatake YAMATO 			cp = skipFlags (cp);
321568fd7d7SMasatake YAMATO 
322568fd7d7SMasatake YAMATO 			fillName (name, cp, (isalnum ((int) *cp) || *cp == '_'));
323568fd7d7SMasatake YAMATO 
324568fd7d7SMasatake YAMATO 			makeSimpleTag (name, K_DEFINITION);
325568fd7d7SMasatake YAMATO 			vStringClear (name);
326568fd7d7SMasatake YAMATO 		}
327c75fc088SMasatake YAMATO 		/* macro */
3289d1f0cb7SMasatake YAMATO 		else if (lineStartingWith (cp, "!macro", false))
329c75fc088SMasatake YAMATO 		{
330c75fc088SMasatake YAMATO 			cp += 6;
331c75fc088SMasatake YAMATO 			cp = skipWhitespace (cp);
332c75fc088SMasatake YAMATO 			cp = skipFlags (cp);
333c75fc088SMasatake YAMATO 
334c75fc088SMasatake YAMATO 			fillName (name, cp, (isalnum ((int) *cp) || *cp == '_'));
335c75fc088SMasatake YAMATO 
336965e8f2dSMasatake YAMATO 			int index = makeSimpleTag (name, K_MACRO);
337965e8f2dSMasatake YAMATO 			if (vStringLength (name) > 0)
338965e8f2dSMasatake YAMATO 			{
339965e8f2dSMasatake YAMATO 				while (1)
340965e8f2dSMasatake YAMATO 				{
341c75fc088SMasatake YAMATO 					vStringClear (name);
342965e8f2dSMasatake YAMATO 					cp = skipWhitespace (cp);
343965e8f2dSMasatake YAMATO 					fillName (name, cp, (isalnum ((int) *cp) || *cp == '_'));
344965e8f2dSMasatake YAMATO 					if (vStringLength (name) == 0)
345965e8f2dSMasatake YAMATO 						break;
346965e8f2dSMasatake YAMATO 					makeSimpleTagWithScope (name, K_MACRO_PARAM, index);
347965e8f2dSMasatake YAMATO 				}
348965e8f2dSMasatake YAMATO 			}
349c75fc088SMasatake YAMATO 		}
3508693338dSMasatake YAMATO 		/* include */
3518693338dSMasatake YAMATO 		else if (lineStartingWith (cp, "!include", false))
3528693338dSMasatake YAMATO 		{
3538693338dSMasatake YAMATO 			cp += 8;
3548693338dSMasatake YAMATO 
3558693338dSMasatake YAMATO 			/* !include [/NONFATAL] [/CHARSET=ACP|OEM|CP#|UTF8|UTF16LE|UTF16BE] file */
3568693338dSMasatake YAMATO 			cp = skipWhitespace (cp);
3578693338dSMasatake YAMATO 
3588693338dSMasatake YAMATO 			/* /NONFATAL */
3598693338dSMasatake YAMATO 			cp = skipFlags (cp);
3608693338dSMasatake YAMATO 			cp = skipWhitespace (cp);
3618693338dSMasatake YAMATO 
3628693338dSMasatake YAMATO 			/* /CHARSET */
3638693338dSMasatake YAMATO 			cp = skipFlags (cp);
3648693338dSMasatake YAMATO 			cp = skipWhitespace (cp);
3658693338dSMasatake YAMATO 
3668693338dSMasatake YAMATO 			fillName (name, cp, (*cp != '\0' && *cp != ';' && *cp != '#'));
3678693338dSMasatake YAMATO 			vStringStripTrailing (name);
3688693338dSMasatake YAMATO 
3698693338dSMasatake YAMATO 			if (vStringLength (name) > 0)
3708693338dSMasatake YAMATO 			{
3718693338dSMasatake YAMATO 				makeSimpleRefTag (name, K_SCRIPT, NSIS_SCRIPT_INCLUDED);
3728693338dSMasatake YAMATO 				vStringClear (name);
3738693338dSMasatake YAMATO 			}
374a1aa3c2bSK.Takata 			/* TODO: capture !addincludedir */
3758693338dSMasatake YAMATO 		}
3769d8ec15eSJiří Techet 	}
3779d8ec15eSJiří Techet 	vStringDelete (name);
3789d8ec15eSJiří Techet }
3799d8ec15eSJiří Techet 
NsisParser(void)3809d8ec15eSJiří Techet extern parserDefinition* NsisParser (void)
3819d8ec15eSJiří Techet {
3829d8ec15eSJiří Techet 	static const char *const extensions [] = {
3839d8ec15eSJiří Techet 		"nsi", "nsh", NULL
3849d8ec15eSJiří Techet 	};
3859d8ec15eSJiří Techet 	parserDefinition* def = parserNew ("NSIS");
3869d8ec15eSJiří Techet 	def->kindTable  = NsisKinds;
3879d8ec15eSJiří Techet 	def->kindCount  = ARRAY_SIZE (NsisKinds);
3889d8ec15eSJiří Techet 	def->extensions = extensions;
389594fea13SMasatake YAMATO 	def->fieldTable = NsisFields;
390594fea13SMasatake YAMATO 	def->fieldCount = ARRAY_SIZE (NsisFields);
3919d8ec15eSJiří Techet 	def->parser     = findNsisTags;
392*6b1a862eSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
3939d8ec15eSJiří Techet 	return def;
3949d8ec15eSJiří Techet }
395