Make parser includes closer to uctags and sync parser license header
[geany-mirror.git] / ctags / parsers / make.c
blobfcf4d86c46c6c1773bea21a6e9ea4fe8f5900e67
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 <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
19 #include "options.h"
20 #include "parse.h"
21 #include "read.h"
22 #include "routines.h"
23 #include "vstring.h"
24 #include "xtag.h"
27 * DATA DEFINITIONS
29 typedef enum {
30 K_MACRO, K_TARGET
31 } shKind;
33 static kindOption MakeKinds [] = {
34 { TRUE, 'm', "macro", "macros"},
35 { TRUE, 't', "target", "targets"}
39 * FUNCTION DEFINITIONS
42 static int nextChar (void)
44 int c = fileGetc ();
45 if (c == '\\')
47 c = fileGetc ();
48 if (c == '\n')
49 c = nextChar ();
51 return c;
54 static void skipLine (void)
56 int c;
58 c = nextChar ();
59 while (c != EOF && c != '\n');
60 if (c == '\n')
61 fileUngetc (c);
64 static int skipToNonWhite (int c)
66 while (c != '\n' && isspace (c))
67 c = nextChar ();
68 return c;
71 static boolean isIdentifier (int c)
73 return (boolean)(c != '\0' && (isalnum (c) || strchr (".-_/$(){}%", c) != NULL));
76 static boolean isSpecialTarget (vString *const name)
78 size_t i = 0;
79 /* All special targets begin with '.'. */
80 if (vStringLength (name) < 1 || vStringChar (name, i++) != '.') {
81 return FALSE;
83 while (i < vStringLength (name)) {
84 char ch = vStringChar (name, i++);
85 if (ch != '_' && !isupper (ch))
87 return FALSE;
90 return TRUE;
93 static void newTarget (vString *const name)
95 /* Ignore GNU Make's "special targets". */
96 if (isSpecialTarget (name))
98 return;
100 makeSimpleTag (name, MakeKinds, K_TARGET);
103 static void newMacro (vString *const name)
105 makeSimpleTag (name, MakeKinds, K_MACRO);
108 static void readIdentifier (const int first, vString *const id)
110 int depth = 0;
111 int c = first;
112 vStringClear (id);
113 while (isIdentifier (c) || (depth > 0 && c != EOF && c != '\n'))
115 if (c == '(' || c == '{')
116 depth++;
117 else if (depth > 0 && (c == ')' || c == '}'))
118 depth--;
119 vStringPut (id, c);
120 c = nextChar ();
122 fileUngetc (c);
123 vStringTerminate (id);
126 static void findMakeTags (void)
128 stringList *identifiers = stringListNew ();
129 boolean newline = TRUE;
130 boolean in_define = FALSE;
131 boolean in_rule = FALSE;
132 boolean variable_possible = TRUE;
133 int c;
135 while ((c = nextChar ()) != EOF)
137 if (newline)
139 if (in_rule)
141 if (c == '\t' || (c = skipToNonWhite (c)) == '#')
143 skipLine (); /* skip rule or comment */
144 c = nextChar ();
146 else if (c != '\n')
147 in_rule = FALSE;
149 stringListClear (identifiers);
150 variable_possible = (boolean)(!in_rule);
151 newline = FALSE;
153 if (c == '\n')
154 newline = TRUE;
155 else if (isspace (c))
156 continue;
157 else if (c == '#')
158 skipLine ();
159 else if (variable_possible && c == '?')
161 c = nextChar ();
162 fileUngetc (c);
163 variable_possible = (c == '=');
165 else if (variable_possible && c == ':' &&
166 stringListCount (identifiers) > 0)
168 c = nextChar ();
169 fileUngetc (c);
170 if (c != '=')
172 unsigned int i;
173 for (i = 0; i < stringListCount (identifiers); i++)
174 newTarget (stringListItem (identifiers, i));
175 stringListClear (identifiers);
176 in_rule = TRUE;
179 else if (variable_possible && c == '=' &&
180 stringListCount (identifiers) == 1)
182 newMacro (stringListItem (identifiers, 0));
183 skipLine ();
184 in_rule = FALSE;
186 else if (variable_possible && isIdentifier (c))
188 vString *name = vStringNew ();
189 readIdentifier (c, name);
190 stringListAdd (identifiers, name);
192 if (stringListCount (identifiers) == 1)
194 if (in_define && ! strcmp (vStringValue (name), "endef"))
195 in_define = FALSE;
196 else if (in_define)
197 skipLine ();
198 else if (! strcmp (vStringValue (name), "define"))
200 in_define = TRUE;
201 c = skipToNonWhite (nextChar ());
202 vStringClear (name);
203 /* all remaining characters on the line are the name -- even spaces */
204 while (c != EOF && c != '\n')
206 vStringPut (name, c);
207 c = nextChar ();
209 if (c == '\n')
210 fileUngetc (c);
211 vStringTerminate (name);
212 vStringStripTrailing (name);
213 newMacro (name);
215 else if (! strcmp (vStringValue (name), "export"))
216 stringListClear (identifiers);
219 else
220 variable_possible = FALSE;
222 stringListDelete (identifiers);
225 extern parserDefinition* MakefileParser (void)
227 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
228 static const char *const extensions [] = { "mak", "mk", NULL };
229 parserDefinition* const def = parserNew ("Make");
230 def->kinds = MakeKinds;
231 def->kindCount = KIND_COUNT (MakeKinds);
232 def->patterns = patterns;
233 def->extensions = extensions;
234 def->parser = findMakeTags;
235 return def;
238 /* vi:set tabstop=4 shiftwidth=4: */