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, §ionGroupIndex);
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