make: fix a typo in parenthesis handling
[geany-mirror.git] / tagmanager / ctags / make.c
blobea777e45ec0f05e0da8a3d7cf68a6ccf38963347
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 = nextChar ();
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 (int c)
64 while (c != '\n' && isspace (c))
65 c = nextChar ();
66 return c;
69 static boolean isIdentifier (int c)
71 return (boolean)(c != '\0' && (isalnum (c) || strchr (".-_/$(){}%", c) != NULL));
74 static boolean isSpecialTarget (vString *const name)
76 size_t i = 0;
77 /* All special targets begin with '.'. */
78 if (vStringLength (name) < 1 || vStringChar (name, i++) != '.') {
79 return FALSE;
81 while (i < vStringLength (name)) {
82 char ch = vStringChar (name, i++);
83 if (ch != '_' && !isupper (ch))
85 return FALSE;
88 return TRUE;
91 static void newTarget (vString *const name)
93 /* Ignore GNU Make's "special targets". */
94 if (isSpecialTarget (name))
96 return;
98 makeSimpleTag (name, MakeKinds, K_TARGET);
101 static void newMacro (vString *const name)
103 makeSimpleTag (name, MakeKinds, K_MACRO);
106 static void readIdentifier (const int first, vString *const id)
108 int depth = 0;
109 int c = first;
110 vStringClear (id);
111 while (isIdentifier (c) || (depth > 0 && c != EOF && c != '\n'))
113 if (c == '(' || c == '{')
114 depth++;
115 else if (depth > 0 && (c == ')' || c == '}'))
116 depth--;
117 vStringPut (id, c);
118 c = nextChar ();
120 fileUngetc (c);
121 vStringTerminate (id);
124 static void findMakeTags (void)
126 stringList *identifiers = stringListNew ();
127 boolean newline = TRUE;
128 boolean in_define = FALSE;
129 boolean in_rule = FALSE;
130 boolean variable_possible = TRUE;
131 int c;
133 while ((c = nextChar ()) != EOF)
135 if (newline)
137 if (in_rule)
139 if (c == '\t' || (c = skipToNonWhite (c)) == '#')
141 skipLine (); /* skip rule or comment */
142 c = nextChar ();
144 else if (c != '\n')
145 in_rule = FALSE;
147 stringListClear (identifiers);
148 variable_possible = (boolean)(!in_rule);
149 newline = FALSE;
151 if (c == '\n')
152 newline = TRUE;
153 else if (isspace (c))
154 continue;
155 else if (c == '#')
156 skipLine ();
157 else if (variable_possible && c == '?')
159 c = nextChar ();
160 fileUngetc (c);
161 variable_possible = (c == '=');
163 else if (variable_possible && c == ':' &&
164 stringListCount (identifiers) > 0)
166 c = nextChar ();
167 fileUngetc (c);
168 if (c != '=')
170 unsigned int i;
171 for (i = 0; i < stringListCount (identifiers); i++)
172 newTarget (stringListItem (identifiers, i));
173 stringListClear (identifiers);
174 in_rule = TRUE;
177 else if (variable_possible && c == '=' &&
178 stringListCount (identifiers) == 1)
180 newMacro (stringListItem (identifiers, 0));
181 skipLine ();
182 in_rule = FALSE;
184 else if (variable_possible && isIdentifier (c))
186 vString *name = vStringNew ();
187 readIdentifier (c, name);
188 stringListAdd (identifiers, name);
190 if (stringListCount (identifiers) == 1)
192 if (in_define && ! strcmp (vStringValue (name), "endef"))
193 in_define = FALSE;
194 else if (in_define)
195 skipLine ();
196 else if (! strcmp (vStringValue (name), "define"))
198 in_define = TRUE;
199 c = skipToNonWhite (nextChar ());
200 vStringClear (name);
201 /* all remaining characters on the line are the name -- even spaces */
202 while (c != EOF && c != '\n')
204 vStringPut (name, c);
205 c = nextChar ();
207 if (c == '\n')
208 fileUngetc (c);
209 vStringTerminate (name);
210 vStringStripTrailing (name);
211 newMacro (name);
213 else if (! strcmp (vStringValue (name), "export"))
214 stringListClear (identifiers);
217 else
218 variable_possible = FALSE;
220 stringListDelete (identifiers);
223 extern parserDefinition* MakefileParser (void)
225 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
226 static const char *const extensions [] = { "mak", "mk", NULL };
227 parserDefinition* const def = parserNew ("Make");
228 def->kinds = MakeKinds;
229 def->kindCount = KIND_COUNT (MakeKinds);
230 def->patterns = patterns;
231 def->extensions = extensions;
232 def->parser = findMakeTags;
233 return def;
236 /* vi:set tabstop=4 shiftwidth=4: */