Update HACKING
[geany-mirror.git] / ctags / parsers / make.c
blobd49c42108d6d994c1d70f67720c636deb4957109
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 "strlist.h"
24 #include "vstring.h"
25 #include "xtag.h"
28 * DATA DEFINITIONS
30 typedef enum {
31 K_MACRO, K_TARGET
32 } shKind;
34 static kindDefinition MakeKinds [] = {
35 { true, 'm', "macro", "macros"},
36 { true, 't', "target", "targets"}
40 * FUNCTION DEFINITIONS
43 static int nextChar (void)
45 int c = getcFromInputFile ();
46 if (c == '\\')
48 c = getcFromInputFile ();
49 if (c == '\n')
50 c = nextChar ();
52 return c;
55 static void skipLine (void)
57 int c;
59 c = nextChar ();
60 while (c != EOF && c != '\n');
61 if (c == '\n')
62 ungetcToInputFile (c);
65 static int skipToNonWhite (int c)
67 while (c != '\n' && isspace (c))
68 c = nextChar ();
69 return c;
72 static bool isIdentifier (int c)
74 return (bool)(c != '\0' && (isalnum (c) || strchr (".-_/$(){}%", c) != NULL));
77 static bool isSpecialTarget (vString *const name)
79 size_t i = 0;
80 /* All special targets begin with '.'. */
81 if (vStringLength (name) < 1 || vStringChar (name, i++) != '.') {
82 return false;
84 while (i < vStringLength (name)) {
85 char ch = vStringChar (name, i++);
86 if (ch != '_' && !isupper (ch))
88 return false;
91 return true;
94 static void newTarget (vString *const name)
96 /* Ignore GNU Make's "special targets". */
97 if (isSpecialTarget (name))
99 return;
101 makeSimpleTag (name, K_TARGET);
104 static void newMacro (vString *const name)
106 makeSimpleTag (name, K_MACRO);
109 static void readIdentifier (const int first, vString *const id)
111 int depth = 0;
112 int c = first;
113 vStringClear (id);
114 while (isIdentifier (c) || (depth > 0 && c != EOF && c != '\n'))
116 if (c == '(' || c == '{')
117 depth++;
118 else if (depth > 0 && (c == ')' || c == '}'))
119 depth--;
120 vStringPut (id, c);
121 c = nextChar ();
123 ungetcToInputFile (c);
126 static void findMakeTags (void)
128 stringList *identifiers = stringListNew ();
129 bool newline = true;
130 bool in_define = false;
131 bool in_rule = false;
132 bool 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 = (bool)(!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 ungetcToInputFile (c);
163 variable_possible = (c == '=');
165 else if (variable_possible && c == ':' &&
166 stringListCount (identifiers) > 0)
168 c = nextChar ();
169 ungetcToInputFile (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 ungetcToInputFile (c);
211 vStringStripTrailing (name);
212 newMacro (name);
214 else if (! strcmp (vStringValue (name), "export"))
215 stringListClear (identifiers);
218 else
219 variable_possible = false;
221 stringListDelete (identifiers);
224 extern parserDefinition* MakefileParser (void)
226 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
227 static const char *const extensions [] = { "mak", "mk", NULL };
228 parserDefinition* const def = parserNew ("Make");
229 def->kindTable = MakeKinds;
230 def->kindCount = ARRAY_SIZE (MakeKinds);
231 def->patterns = patterns;
232 def->extensions = extensions;
233 def->parser = findMakeTags;
234 return def;