1 /*
2 * $Id: make.c 751 2010-02-27 17:41:57Z elliotth $
3 *
4 * Copyright (c) 2000-2005, Darren Hiebert
5 *
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
8 *
9 * This module contains functions for generating tags for makefiles.
10 */
11
12 /*
13 * INCLUDE FILES
14 */
15 #include "general.h" /* must always come first */
16
17 #include <string.h>
18 #include <ctype.h>
19
20 #include "options.h"
21 #include "parse.h"
22 #include "read.h"
23 #include "vstring.h"
24
25 /*
26 * DATA DEFINITIONS
27 */
28 typedef enum {
29 K_MACRO
30 } shKind;
31
32 static kindOption MakeKinds [] = {
33 { TRUE, 'm', "macro", "macros"}
34 };
35
36 /*
37 * FUNCTION DEFINITIONS
38 */
39
nextChar(void)40 static int nextChar (void)
41 {
42 int c = fileGetc ();
43 if (c == '\\')
44 {
45 c = fileGetc ();
46 if (c == '\n')
47 c = fileGetc ();
48 }
49 return c;
50 }
51
skipLine(void)52 static void skipLine (void)
53 {
54 int c;
55 do
56 c = nextChar ();
57 while (c != EOF && c != '\n');
58 if (c == '\n')
59 fileUngetc (c);
60 }
61
skipToNonWhite(void)62 static int skipToNonWhite (void)
63 {
64 int c;
65 do
66 c = nextChar ();
67 while (c != '\n' && isspace (c));
68 return c;
69 }
70
isIdentifier(int c)71 static boolean isIdentifier (int c)
72 {
73 return (boolean)(c != '\0' && (isalnum (c) || strchr (".-_", c) != NULL));
74 }
75
readIdentifier(const int first,vString * const id)76 static void readIdentifier (const int first, vString *const id)
77 {
78 int c = first;
79 vStringClear (id);
80 while (isIdentifier (c))
81 {
82 vStringPut (id, c);
83 c = nextChar ();
84 }
85 fileUngetc (c);
86 vStringTerminate (id);
87 }
88
skipToMatch(const char * const pair)89 static void skipToMatch (const char *const pair)
90 {
91 const int begin = pair [0], end = pair [1];
92 const unsigned long inputLineNumber = getInputLineNumber ();
93 int matchLevel = 1;
94 int c = '\0';
95
96 while (matchLevel > 0)
97 {
98 c = nextChar ();
99 if (c == begin)
100 ++matchLevel;
101 else if (c == end)
102 --matchLevel;
103 else if (c == '\n' || c == EOF)
104 break;
105 }
106 if (c == EOF)
107 verbose ("%s: failed to find match for '%c' at line %lu\n",
108 getInputFileName (), begin, inputLineNumber);
109 }
110
findMakeTags(void)111 static void findMakeTags (void)
112 {
113 vString *name = vStringNew ();
114 boolean newline = TRUE;
115 boolean in_define = FALSE;
116 boolean in_rule = FALSE;
117 boolean variable_possible = TRUE;
118 int c;
119
120 while ((c = nextChar ()) != EOF)
121 {
122 if (newline)
123 {
124 if (in_rule)
125 {
126 if (c == '\t')
127 {
128 skipLine (); /* skip rule */
129 continue;
130 }
131 else
132 in_rule = FALSE;
133 }
134 variable_possible = (boolean)(!in_rule);
135 newline = FALSE;
136 }
137 if (c == '\n')
138 newline = TRUE;
139 else if (isspace (c))
140 continue;
141 else if (c == '#')
142 skipLine ();
143 else if (c == '(')
144 skipToMatch ("()");
145 else if (c == '{')
146 skipToMatch ("{}");
147 else if (c == ':')
148 {
149 variable_possible = TRUE;
150 in_rule = TRUE;
151 }
152 else if (variable_possible && isIdentifier (c))
153 {
154 readIdentifier (c, name);
155 if (strcmp (vStringValue (name), "endef") == 0)
156 in_define = FALSE;
157 else if (in_define)
158 skipLine ();
159 else if (strcmp (vStringValue (name), "define") == 0 &&
160 isIdentifier (c))
161 {
162 in_define = TRUE;
163 c = skipToNonWhite ();
164 readIdentifier (c, name);
165 makeSimpleTag (name, MakeKinds, K_MACRO);
166 skipLine ();
167 }
168 else {
169 if (strcmp(vStringValue (name), "export") == 0 &&
170 isIdentifier (c))
171 {
172 c = skipToNonWhite ();
173 readIdentifier (c, name);
174 }
175 c = skipToNonWhite ();
176 if (strchr (":?+", c) != NULL)
177 {
178 boolean append = (boolean)(c == '+');
179 if (c == ':')
180 in_rule = TRUE;
181 c = nextChar ();
182 if (c != '=')
183 fileUngetc (c);
184 else if (append)
185 {
186 skipLine ();
187 continue;
188 }
189 }
190 if (c == '=')
191 {
192 makeSimpleTag (name, MakeKinds, K_MACRO);
193 in_rule = FALSE;
194 skipLine ();
195 }
196 }
197 }
198 else
199 variable_possible = FALSE;
200 }
201 vStringDelete (name);
202 }
203
MakefileParser(void)204 extern parserDefinition* MakefileParser (void)
205 {
206 static const char *const patterns [] = { "[Mm]akefile", "GNUmakefile", NULL };
207 static const char *const extensions [] = { "mak", "mk", NULL };
208 parserDefinition* const def = parserNew ("Make");
209 def->kinds = MakeKinds;
210 def->kindCount = KIND_COUNT (MakeKinds);
211 def->patterns = patterns;
212 def->extensions = extensions;
213 def->parser = findMakeTags;
214 return def;
215 }
216
217 /* vi:set tabstop=4 shiftwidth=4: */
218