Small update of German translation
[geany-mirror.git] / ctags / parsers / make.c
blob8f3180495f584ffa93fea4efca7f9d40334ee6b4
1 /*
2 * Copyright (c) 2000-2005, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for generating tags for makefiles.
8 */
11 * INCLUDE FILES
13 #include "general.h" /* must always come first */
15 #include <string.h>
16 #include <ctype.h>
18 #include "make.h"
20 #include "kind.h"
21 #include "parse.h"
22 #include "read.h"
23 #include "routines.h"
24 #include "strlist.h"
25 #include "vstring.h"
26 #include "xtag.h"
30 * DATA DEFINITIONS
32 typedef enum {
33 K_MACRO, K_TARGET, K_INCLUDE,
34 } makeKind;
36 typedef enum {
37 R_INCLUDE_GENERIC,
38 R_INCLUDE_OPTIONAL,
39 } makeMakefileRole;
41 static roleDefinition MakeMakefileRoles [] = {
42 { true, "included", "included" },
43 { true, "optional", "optionally included"},
46 static kindDefinition MakeKinds [] = {
47 { true, 'm', "macro", "macros"},
48 { true, 't', "target", "targets"},
49 { true, 'I', "makefile", "makefiles",
50 .referenceOnly = true, ATTACH_ROLES(MakeMakefileRoles)},
55 * FUNCTION DEFINITIONS
58 static int nextChar (void)
60 int c = getcFromInputFile ();
61 if (c == '\\')
63 c = getcFromInputFile ();
64 if (c == '\n')
65 c = nextChar ();
67 return c;
70 static void skipLine (void)
72 int c;
74 c = nextChar ();
75 while (c != EOF && c != '\n');
76 if (c == '\n')
77 ungetcToInputFile (c);
80 static int skipToNonWhite (int c)
82 while (c != '\n' && isspace (c))
83 c = nextChar ();
84 return c;
87 static bool isIdentifier (int c)
89 return (bool)(c != '\0' && (isalnum (c) || strchr (".-_/$(){}%", c) != NULL));
92 static bool isSpecialTarget (vString *const name)
94 size_t i = 0;
95 /* All special targets begin with '.'. */
96 if (vStringLength (name) < 1 || vStringChar (name, i++) != '.') {
97 return false;
99 while (i < vStringLength (name)) {
100 char ch = vStringChar (name, i++);
101 if (ch != '_' && !isupper (ch))
103 return false;
106 return true;
109 static void makeSimpleMakeTag (vString *const name, makeKind kind)
111 if (!isLanguageEnabled (getInputLanguage ()))
112 return;
114 makeSimpleTag (name, kind);
117 static void makeSimpleMakeRefTag (const vString* const name, const int kind,
118 int roleIndex)
120 if (!isLanguageEnabled (getInputLanguage ()))
121 return;
123 makeSimpleRefTag (name, kind, roleIndex);
126 static void newTarget (vString *const name)
128 /* Ignore GNU Make's "special targets". */
129 if (isSpecialTarget (name))
131 return;
133 makeSimpleMakeTag (name, K_TARGET);
136 static void newMacro (vString *const name, bool with_define_directive, bool appending)
138 subparser *s;
140 if (!appending)
141 makeSimpleMakeTag (name, K_MACRO);
143 foreachSubparser(s, false)
145 makeSubparser *m = (makeSubparser *)s;
146 enterSubparser(s);
147 if (m->newMacroNotify)
148 m->newMacroNotify (m, vStringValue(name), with_define_directive, appending);
149 leaveSubparser();
153 static void valueFound (vString *const name)
155 subparser *s;
156 foreachSubparser(s, false)
158 makeSubparser *m = (makeSubparser *)s;
159 enterSubparser(s);
160 if (m->valueNotify)
161 m->valueNotify (m, vStringValue (name));
162 leaveSubparser();
166 static void directiveFound (vString *const name)
168 subparser *s;
169 foreachSubparser (s, false)
171 makeSubparser *m = (makeSubparser *)s;
172 enterSubparser(s);
173 if (m->directiveNotify)
174 m->directiveNotify (m, vStringValue (name));
175 leaveSubparser();
179 static void newInclude (vString *const name, bool optional)
181 makeSimpleMakeRefTag (name, K_INCLUDE,
182 optional? R_INCLUDE_OPTIONAL: R_INCLUDE_GENERIC);
185 static bool isAcceptableAsInclude (vString *const name)
187 if (strcmp (vStringValue (name), "$") == 0)
188 return false;
189 return true;
192 static void readIdentifier (const int first, vString *const id)
194 int depth = 0;
195 int c = first;
196 vStringClear (id);
197 while (isIdentifier (c) || (depth > 0 && c != EOF && c != '\n'))
199 if (c == '(' || c == '{')
200 depth++;
201 else if (depth > 0 && (c == ')' || c == '}'))
202 depth--;
203 vStringPut (id, c);
204 c = nextChar ();
206 ungetcToInputFile (c);
209 static void findMakeTags (void)
211 stringList *identifiers = stringListNew ();
212 bool newline = true;
213 bool in_define = false;
214 bool in_value = false;
215 bool in_rule = false;
216 bool variable_possible = true;
217 bool appending = false;
218 int c;
219 subparser *sub;
221 sub = getSubparserRunningBaseparser();
222 if (sub)
223 chooseExclusiveSubparser (sub, NULL);
225 while ((c = nextChar ()) != EOF)
227 if (newline)
229 if (in_rule)
231 if (c == '\t' || (c = skipToNonWhite (c)) == '#')
233 skipLine (); /* skip rule or comment */
234 c = nextChar ();
236 else if (c != '\n')
237 in_rule = false;
239 else if (in_value)
240 in_value = false;
242 stringListClear (identifiers);
243 variable_possible = (bool)(!in_rule);
244 newline = false;
246 if (c == '\n')
247 newline = true;
248 else if (isspace (c))
249 continue;
250 else if (c == '#')
251 skipLine ();
252 else if (variable_possible && c == '?')
254 c = nextChar ();
255 ungetcToInputFile (c);
256 variable_possible = (c == '=');
258 else if (variable_possible && c == '+')
260 c = nextChar ();
261 ungetcToInputFile (c);
262 variable_possible = (c == '=');
263 appending = true;
265 else if ((! in_value) && variable_possible && c == ':' &&
266 stringListCount (identifiers) > 0)
268 c = nextChar ();
269 ungetcToInputFile (c);
270 if (c != '=')
272 unsigned int i;
273 for (i = 0; i < stringListCount (identifiers); i++)
274 newTarget (stringListItem (identifiers, i));
275 stringListClear (identifiers);
276 in_rule = true;
279 else if (variable_possible && c == '=' &&
280 stringListCount (identifiers) == 1)
282 newMacro (stringListItem (identifiers, 0), false, appending);
284 in_value = true;
285 in_rule = false;
286 appending = false;
288 else if (variable_possible && isIdentifier (c))
290 vString *name = vStringNew ();
291 readIdentifier (c, name);
292 stringListAdd (identifiers, name);
294 if (in_value)
295 valueFound(name);
297 if (stringListCount (identifiers) == 1)
299 if (in_define && ! strcmp (vStringValue (name), "endef"))
300 in_define = false;
301 else if (in_define)
302 skipLine ();
303 else if (! strcmp (vStringValue (name), "define"))
305 in_define = true;
306 c = skipToNonWhite (nextChar ());
307 vStringClear (name);
308 /* all remaining characters on the line are the name -- even spaces */
309 while (c != EOF && c != '\n')
311 vStringPut (name, c);
312 c = nextChar ();
314 if (c == '\n')
315 ungetcToInputFile (c);
316 vStringStripTrailing (name);
318 newMacro (name, true, false);
320 else if (! strcmp (vStringValue (name), "export"))
321 stringListClear (identifiers);
322 else if (! strcmp (vStringValue (name), "include")
323 || ! strcmp (vStringValue (name), "sinclude")
324 || ! strcmp (vStringValue (name), "-include"))
326 bool optional = (vStringValue (name)[0] == 'i')? false: true;
327 while (1)
329 c = skipToNonWhite (nextChar ());
330 readIdentifier (c, name);
331 vStringStripTrailing (name);
332 if (isAcceptableAsInclude(name))
333 newInclude (name, optional);
335 /* non-space characters after readIdentifier() may
336 * be rejected by the function:
337 * e.g.
338 * include $*
340 * Here, remove such characters from input stream.
343 c = nextChar ();
344 while (c != EOF && c != '\n' && (!isspace (c)));
345 if (c == '\n')
346 ungetcToInputFile (c);
348 if (c == EOF || c == '\n')
349 break;
352 else
353 directiveFound (name);
356 else
357 variable_possible = false;
360 stringListDelete (identifiers);
364 extern parserDefinition* MakefileParser (void)
366 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
367 static const char *const extensions [] = { "mak", "mk", NULL };
368 static const char *const aliases [] = {
369 /* the mode name in emacs */
370 "makefile",
371 NULL };
372 parserDefinition* const def = parserNew ("Make");
373 def->kindTable = MakeKinds;
374 def->kindCount = ARRAY_SIZE (MakeKinds);
375 def->patterns = patterns;
376 def->extensions = extensions;
377 def->aliases = aliases;
378 def->parser = findMakeTags;
379 return def;