2 * Copyright (c) 2000-2002, Darren Hiebert
3 * Copyright (c) 2009-2011, Enrico Tröger
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License version 2 or (at your option) any later version.
8 * This module contains functions for generating tags for NSIS scripts
9 * (https://en.wikipedia.org/wiki/Nullsoft_Scriptable_Install_System).
17 #include "general.h" /* must always come first */
46 static roleDefinition NsisScriptRoles
[] = {
47 { true, "included", "included with !include" },
50 static kindDefinition NsisKinds
[] = {
51 { true, 's', "section", "sections"},
52 { true, 'f', "function", "functions"},
53 { true, 'v', "variable", "variables"},
54 { true, 'd', "definition", "definitions"},
55 { true, 'm', "macro", "macros"},
56 { true, 'S', "sectionGroup", "section groups"},
57 { false, 'p', "macroparam", "macro parameters"},
58 { true, 'l', "langstr", "language strings"},
59 { true, 'i', "script", "NSIS scripts",
60 .referenceOnly
= true, ATTACH_ROLES(NsisScriptRoles
)},
67 static fieldDefinition NsisFields
[] = {
69 .description
= "language identifier specified in (License)LangString commands",
74 * FUNCTION DEFINITIONS
77 static const unsigned char* skipWhitespace (const unsigned char* cp
)
79 while (isspace ((int) *cp
))
84 static const unsigned char* skipFlags (const unsigned char* cp
)
89 while (! isspace ((int) *cp
))
91 while (isspace ((int) *cp
))
97 static int makeSimpleTagWithScope(vString
*name
, int kindIndex
, int parentCorkIndex
)
100 initTagEntry (&e
, vStringValue (name
), kindIndex
);
101 e
.extensionFields
.scopeIndex
= parentCorkIndex
;
102 return makeTagEntry (&e
);
105 #define lineStartingWith(CP,EXPECTED,EOL) \
106 (strncasecmp ((const char*) CP, EXPECTED, strlen(EXPECTED)) == 0 \
107 && (EOL ? (isspace ((int) CP [strlen(EXPECTED)]) || CP [strlen(EXPECTED)] == '\0') \
108 : isspace ((int) CP [strlen(EXPECTED)])))
110 #define fillName(NAME,CP,CONDITION) \
113 vStringPut ((NAME), (int) *(CP)); \
118 static const unsigned char* parseSection (const unsigned char* cp
, vString
*name
,
119 int kindIndex
, int scopeIndex
, int *corkIndex
)
121 cp
= skipWhitespace (cp
);
123 cp
= skipWhitespace (cp
);
126 *corkIndex
= CORK_NIL
;
128 if (strpbrk((const char *)cp
, "'`\""))
130 const unsigned char terminator
= *cp
;
133 if (*cp
== terminator
)
136 * See https://nsis.sourceforge.io/Docs/Chapter4.html#sectionsettext
139 (kindIndex
== K_SECTION
141 : "AnonymousSectionGroup"),
145 else if (*cp
== '\0')
152 vStringPut (name
, (int) *cp
);
159 * Ignore `"' in `$\"' as the terminator of quotation.
161 if (*cp
== '$' && in_escape
== 0)
163 else if (*cp
== '\\' && in_escape
== 1)
165 else if (*cp
== terminator
&& in_escape
== 2)
167 * This `"' is not a terminator of quotation;
168 * set in_escape to 3.
174 if ((in_escape
!= 3) && *cp
== terminator
)
185 while (isalnum ((int) *cp
)
186 || *cp
== '_' || *cp
== '-' || *cp
== '.' || *cp
== '!'
187 || *cp
== '$' || *cp
== '{' || *cp
== '}' || *cp
== '(' || *cp
== ')')
189 vStringPut (name
, (int) *cp
);
193 int r
= makeSimpleTagWithScope (name
, kindIndex
, scopeIndex
);
196 if (vStringLength (name
) > 0)
199 * Try to capture section_index_output.
202 cp
= skipWhitespace (cp
);
204 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_'));
206 if (vStringLength (name
) > 0)
208 makeSimpleTag (name
, K_DEFINITION
);
215 static const unsigned char* parseLangString (const unsigned char* cp
, vString
*name
)
217 cp
= skipWhitespace (cp
);
219 /* `^' is not explained in the nsis reference manual. However, it is used
222 * https://github.com/vim/vim/blob/3dabd718f4b2d8e09de9e2ec73832620b91c2f79/nsis/lang/english.nsi
224 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_' || *cp
== '^'));
226 if (vStringLength (name
) > 0)
228 int r
= makeSimpleTag (name
, K_LANGSTR
);
233 cp
= skipWhitespace (cp
);
234 fillName (name
, cp
, ((*cp
!= '\0') && (!isspace ((int) *cp
))));
235 if (vStringLength (name
) > 0)
237 attachParserFieldToCorkEntry (r
, NsisFields
[F_LANGID
].ftype
,
238 vStringValue (name
));
246 static void findNsisTags (void)
248 int sectionGroupIndex
= CORK_NIL
;
249 vString
*name
= vStringNew ();
250 const unsigned char *line
;
252 while ((line
= readLineFromInputFile ()) != NULL
)
254 const unsigned char* cp
= line
;
256 while (isspace (*cp
))
259 if (*cp
== '#' || *cp
== ';')
263 if (lineStartingWith (cp
, "function", false))
266 cp
= skipWhitespace (cp
);
269 (isalnum ((int) *cp
) || *cp
== '_' || *cp
== '-' || *cp
== '.' || *cp
== '!'));
271 makeSimpleTag (name
, K_FUNCTION
);
275 else if (lineStartingWith (cp
, "var", false))
278 cp
= skipWhitespace (cp
);
281 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_'));
283 makeSimpleTag (name
, K_VARIABLE
);
287 else if (lineStartingWith (cp
, "sectiongroup", false))
290 cp
= parseSection (cp
, name
, K_SECTION_GROUP
, CORK_NIL
, §ionGroupIndex
);
292 else if (lineStartingWith (cp
, "sectiongroupend", true))
295 sectionGroupIndex
= CORK_NIL
;
298 else if (lineStartingWith (cp
, "section", false))
301 cp
= parseSection (cp
, name
, K_SECTION
, sectionGroupIndex
, NULL
);
304 else if (lineStartingWith (cp
, "langstring", false))
307 cp
= parseLangString (cp
, name
);
309 /* LicenseLangString */
310 else if (lineStartingWith (cp
, "licenselangstring", false))
313 cp
= parseLangString (cp
, name
);
316 else if (lineStartingWith (cp
, "!define", false))
319 cp
= skipWhitespace (cp
);
322 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_'));
324 makeSimpleTag (name
, K_DEFINITION
);
328 else if (lineStartingWith (cp
, "!macro", false))
331 cp
= skipWhitespace (cp
);
334 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_'));
336 int index
= makeSimpleTag (name
, K_MACRO
);
337 if (vStringLength (name
) > 0)
342 cp
= skipWhitespace (cp
);
343 fillName (name
, cp
, (isalnum ((int) *cp
) || *cp
== '_'));
344 if (vStringLength (name
) == 0)
346 makeSimpleTagWithScope (name
, K_MACRO_PARAM
, index
);
351 else if (lineStartingWith (cp
, "!include", false))
355 /* !include [/NONFATAL] [/CHARSET=ACP|OEM|CP#|UTF8|UTF16LE|UTF16BE] file */
356 cp
= skipWhitespace (cp
);
360 cp
= skipWhitespace (cp
);
364 cp
= skipWhitespace (cp
);
366 fillName (name
, cp
, (*cp
!= '\0' && *cp
!= ';' && *cp
!= '#'));
367 vStringStripTrailing (name
);
369 if (vStringLength (name
) > 0)
371 makeSimpleRefTag (name
, K_SCRIPT
, NSIS_SCRIPT_INCLUDED
);
374 /* TODO: capture !addincludedir */
377 vStringDelete (name
);
380 extern parserDefinition
* NsisParser (void)
382 static const char *const extensions
[] = {
385 parserDefinition
* def
= parserNew ("NSIS");
386 def
->kindTable
= NsisKinds
;
387 def
->kindCount
= ARRAY_SIZE (NsisKinds
);
388 def
->extensions
= extensions
;
389 def
->fieldTable
= NsisFields
;
390 def
->fieldCount
= ARRAY_SIZE (NsisFields
);
391 def
->parser
= findNsisTags
;
392 def
->useCork
= CORK_QUEUE
;