Remove duplicate NEWS item
[geany-mirror.git] / tagmanager / make.c
blobbe6eb791899267592712f5abf3201d2dd1b152e1
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.
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 "vstring.h"
25 * DATA DEFINITIONS
27 typedef enum {
28 K_MACRO, K_TARGET
29 } shKind;
31 static kindOption MakeKinds [] = {
32 { TRUE, 'm', "macro", "macros"},
33 { TRUE, 't', "function", "targets"}
37 * FUNCTION DEFINITIONS
40 static int nextChar (void)
42 int c = fileGetc ();
43 if (c == '\\')
45 c = fileGetc ();
46 if (c == '\n')
47 c = fileGetc ();
49 return c;
52 static void skipLine (void)
54 int c;
56 c = nextChar ();
57 while (c != EOF && c != '\n');
58 if (c == '\n')
59 fileUngetc (c);
62 static int skipToNonWhite (void)
64 int c;
66 c = nextChar ();
67 while (c != '\n' && isspace (c));
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 (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 newMacroFromDefine (vString *const name)
110 /* name is something like "define JAVAHPP_RULE", find the space and jump to the next char */
111 char *name_val = strchr (vStringValue (name), ' ');
113 if (name_val != NULL) {
114 vStringCopyS (name, name_val + 1);
115 makeSimpleTag (name, MakeKinds, K_MACRO);
119 static void readIdentifier (const int first, vString *const id)
121 int c = first;
122 int c_prev = first;
123 int c_next = first;
124 vStringClear (id);
125 while (isIdentifier (c) || c == ' ')
127 c_next = nextChar ();
128 if (c == ' ') {
129 /* add the space character only if the previous and
130 * next character are valid identifiers */
131 if (isIdentifier (c_prev) && isIdentifier (c_next))
132 vStringPut (id, c);
134 else {
135 vStringPut (id, c);
137 c_prev = c;
138 c = c_next;
140 fileUngetc (c);
141 vStringTerminate (id);
144 static void skipToMatch (const char *const pair)
146 const int begin = pair [0], end = pair [1];
147 const unsigned long inputLineNumber = getInputLineNumber ();
148 int matchLevel = 1;
149 int c = '\0';
151 while (matchLevel > 0)
153 c = nextChar ();
154 if (c == begin)
155 ++matchLevel;
156 else if (c == end)
157 --matchLevel;
158 else if (c == '\n' || c == EOF)
159 break;
161 if (c == EOF)
162 verbose ("%s: failed to find match for '%c' at line %lu\n",
163 getInputFileName (), begin, inputLineNumber);
166 static void findMakeTags (void)
168 vString *name = vStringNew ();
169 boolean newline = TRUE;
170 boolean in_define = FALSE;
171 boolean in_rule = FALSE;
172 boolean variable_possible = TRUE;
173 int c;
175 while ((c = nextChar ()) != EOF)
177 if (newline)
179 if (in_rule)
181 if (c == '\t')
183 skipLine (); /* skip rule */
184 continue;
186 else
187 in_rule = FALSE;
189 variable_possible = (boolean)(!in_rule);
190 newline = FALSE;
192 if (c == '\n')
193 newline = TRUE;
194 else if (isspace (c))
195 continue;
196 else if (c == '#')
197 skipLine ();
198 else if (c == '(')
199 skipToMatch ("()");
200 else if (c == '{')
201 skipToMatch ("{}");
202 else if (c == ':')
204 variable_possible = TRUE;
205 in_rule = TRUE;
207 else if (variable_possible && isIdentifier (c))
209 readIdentifier (c, name);
210 if (strncmp (vStringValue (name), "endef", 5) == 0)
211 in_define = FALSE;
212 else if (in_define)
213 skipLine ();
214 else if (strncmp (vStringValue (name), "define", 6) == 0 &&
215 isIdentifier (c))
217 in_define = TRUE;
218 c = skipToNonWhite ();
219 newMacroFromDefine (name);
220 skipLine ();
222 else {
223 c = skipToNonWhite ();
224 if (strchr (":?+", c) != NULL)
226 boolean append = (boolean)(c == '+');
227 boolean was_colon = (c == ':');
228 c = nextChar ();
229 if (was_colon)
231 if (c == '=')
233 newMacro (name);
234 in_rule = FALSE;
235 skipLine ();
237 else
239 in_rule = TRUE;
240 newTarget (name);
243 else if (append)
245 skipLine ();
246 continue;
248 else
250 fileUngetc (c);
253 else if (c == '=')
255 newMacro (name);
256 in_rule = FALSE;
257 skipLine ();
259 else
261 fileUngetc (c);
265 else
266 variable_possible = FALSE;
268 vStringDelete (name);
271 extern parserDefinition* MakefileParser (void)
273 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
274 static const char *const extensions [] = { "mak", "mk", NULL };
275 parserDefinition* const def = parserNew ("Make");
276 def->kinds = MakeKinds;
277 def->kindCount = KIND_COUNT (MakeKinds);
278 def->patterns = patterns;
279 def->extensions = extensions;
280 def->parser = findMakeTags;
281 return def;
284 /* vi:set tabstop=4 shiftwidth=4: */