Refactor snippets_complete_constructs().
[geany-mirror.git] / tagmanager / make.c
blobf59ce46f0e3070a540fb3b7c05e2587cbbf6a82f
1 /*
2 * $Id$
4 * Copyright (c) 2000-2005, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for generating tags for makefiles.
13 * INCLUDE FILES
15 #include "general.h" /* must always come first */
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
21 #include "options.h"
22 #include "parse.h"
23 #include "read.h"
24 #include "vstring.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', "function", "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 = fileGetc ();
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 (void)
66 int c;
68 c = nextChar ();
69 while (c != '\n' && isspace (c));
70 return c;
73 static boolean isIdentifier (int c)
75 return (boolean)(c != '\0' && (isalnum (c) || strchr (".-_/", c) != NULL));
78 static boolean isSpecialTarget (vString *const name)
80 size_t i = 0;
81 /* All special targets begin with '.'. */
82 if (vStringChar (name, i++) != '.') {
83 return FALSE;
85 while (i < vStringLength (name)) {
86 char ch = vStringChar (name, i++);
87 if (ch != '_' && !isupper (ch))
89 return FALSE;
92 return TRUE;
95 static void newTarget (vString *const name)
97 /* Ignore GNU Make's "special targets". */
98 if (isSpecialTarget (name))
100 return;
102 makeSimpleTag (name, MakeKinds, K_TARGET);
105 static void newMacro (vString *const name)
107 makeSimpleTag (name, MakeKinds, K_MACRO);
110 static void newMacroFromDefine (vString *const name)
112 /* name is something like "define JAVAHPP_RULE", find the space and jump to the next char */
113 char *name_val = strchr (vStringValue (name), ' ');
115 if (name_val != NULL) {
116 vStringCopyS (name, name_val + 1);
117 makeSimpleTag (name, MakeKinds, K_MACRO);
121 static void readIdentifier (const int first, vString *const id)
123 int c = first;
124 int c_prev = first;
125 int c_next = first;
126 vStringClear (id);
127 while (isIdentifier (c) || c == ' ')
129 c_next = nextChar ();
130 if (c == ' ') {
131 /* add the space character only if the previous and
132 * next character are valid identifiers */
133 if (isIdentifier (c_prev) && isIdentifier (c_next))
134 vStringPut (id, c);
136 else {
137 vStringPut (id, c);
139 c_prev = c;
140 c = c_next;
142 fileUngetc (c);
143 vStringTerminate (id);
146 static void skipToMatch (const char *const pair)
148 const int begin = pair [0], end = pair [1];
149 const unsigned long inputLineNumber = getInputLineNumber ();
150 int matchLevel = 1;
151 int c = '\0';
153 while (matchLevel > 0)
155 c = nextChar ();
156 if (c == begin)
157 ++matchLevel;
158 else if (c == end)
159 --matchLevel;
160 else if (c == '\n')
161 break;
163 if (c == EOF)
164 verbose ("%s: failed to find match for '%c' at line %lu\n",
165 getInputFileName (), begin, inputLineNumber);
168 static void findMakeTags (void)
170 vString *name = vStringNew ();
171 boolean newline = TRUE;
172 boolean in_define = FALSE;
173 boolean in_rule = FALSE;
174 boolean variable_possible = TRUE;
175 int c;
177 while ((c = nextChar ()) != EOF)
179 if (newline)
181 if (in_rule)
183 if (c == '\t')
185 skipLine (); /* skip rule */
186 continue;
188 else
189 in_rule = FALSE;
191 variable_possible = (boolean)(!in_rule);
192 newline = FALSE;
194 if (c == '\n')
195 newline = TRUE;
196 else if (isspace (c))
197 continue;
198 else if (c == '#')
199 skipLine ();
200 else if (c == '(')
201 skipToMatch ("()");
202 else if (c == '{')
203 skipToMatch ("{}");
204 else if (c == ':')
206 variable_possible = TRUE;
207 in_rule = TRUE;
209 else if (variable_possible && isIdentifier (c))
211 readIdentifier (c, name);
212 if (strncmp (vStringValue (name), "endef", 5) == 0)
213 in_define = FALSE;
214 else if (in_define)
215 skipLine ();
216 else if (strncmp (vStringValue (name), "define", 6) == 0 &&
217 isIdentifier (c))
219 in_define = TRUE;
220 c = skipToNonWhite ();
221 newMacroFromDefine (name);
222 skipLine ();
224 else {
225 c = skipToNonWhite ();
226 if (strchr (":?+", c) != NULL)
228 boolean append = (boolean)(c == '+');
229 boolean was_colon = (c == ':');
230 c = nextChar ();
231 if (was_colon)
233 if (c == '=')
235 newMacro (name);
236 in_rule = FALSE;
237 skipLine ();
239 else
241 in_rule = TRUE;
242 newTarget (name);
245 else if (append)
247 skipLine ();
248 continue;
250 else
252 fileUngetc (c);
255 else if (c == '=')
257 newMacro (name);
258 in_rule = FALSE;
259 skipLine ();
261 else
263 fileUngetc (c);
267 else
268 variable_possible = FALSE;
270 vStringDelete (name);
273 extern parserDefinition* MakefileParser (void)
275 static const char *const patterns [] = { "[Mm]akefile", NULL };
276 static const char *const extensions [] = { "mak", "mk", NULL };
277 parserDefinition* const def = parserNew ("Make");
278 def->kinds = MakeKinds;
279 def->kindCount = KIND_COUNT (MakeKinds);
280 def->patterns = patterns;
281 def->extensions = extensions;
282 def->parser = findMakeTags;
283 return def;
286 /* vi:set tabstop=4 shiftwidth=4: */