1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <string>
26 #include <vector>
27 #include <set>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 #include <cctype>
32 #include <unistd.h>
33
34 using namespace std;
35
36 const char* arg0;
37
38 struct Options
39 {
40 vector<string> paths;
41 string objdir;
42 };
43 mike 1.1
44 static Options opts;
45
46 static void _GetOptions(
47 int& argc,
48 char**& argv,
49 Options& opts)
50 {
51 /* For each argument */
52 for (int i = 0; i < argc; )
53 {
54 /* Number of argv[] elements to remove at end of loop */
55 int r = 0;
56
57 /* Check for -I option */
58 if (strncmp(argv[i], "-I", 2) == 0)
59 {
60 const char* fn = argv[i] + 2;
61
62 /* Check for mandatory option argument */
63 if (*fn)
64 mike 1.1 {
65 r = 1;
66 }
67 else
68 {
69 if (i + 1 == argc)
70 {
71 fprintf(stderr, "%s: missing option argument for -I", arg0);
72 exit(1);
73 }
74
75 fn = argv[i+1];
76 r = 2;
77 }
78
79 opts.paths.push_back(fn);
80 }
81 else if (strcmp(argv[i], "--objdir") == 0)
82 {
83 if (i + 1 == argc)
84 {
85 mike 1.1 fprintf(stderr, "%s: missing option argument for --objdir",
86 arg0);
87 exit(1);
88 }
89
90 opts.objdir = argv[i+1];
91 r = 2;
92 }
93 else if (argv[i][0] == '-')
94 {
95 fprintf(stderr, "%s: unknown option: %s", arg0, argv[i]);
96 exit(1);
97 }
98 else
99 i++;
100
101 if (r)
102 {
103 memmove(&argv[i], &argv[i+r], sizeof(char*) * (argc-i-r));
104 argc -= r;
105 }
106 mike 1.1 }
107 }
108
109 void PrintDependencies(
110 const char* path,
111 set<string>& found,
112 size_t level = 0)
113 {
114 vector<string> includes;
115
116 // Recurse no deeper than this!
117 if (level > 10)
118 return;
119
120 // Open file:
121 FILE* is = fopen(path, "rb");
122 {
123 if (!is)
124 {
125 if (level == 0)
126 {
127 mike 1.1 fprintf(stderr, "%s: failed to open: %s\n", arg0, path);
128 return;
129 }
130
131 return;
132 }
133 }
134
135 // Find #include directives.
136 char buf[1024];
137 while (fgets(buf, sizeof(buf), is) != NULL)
138 {
139 char* p = buf;
140
141 // Skip leading whitespace:
142 while (*p && isspace(*p))
143 p++;
144
145 // Skip lines that do not begin with preprocessor directives.
146 if (*p != '#')
147 continue;
148 mike 1.1 p++;
149
150 // Skip whitespace:
151 while (*p && isspace(*p))
152 p++;
153
154 // Skip line if not 'include' directive.
155 if (strncmp(p, "include", 7) != 0)
156 continue;
157 p += 7;
158
159 // Skip whitespace:
160 while (*p && isspace(*p))
161 p++;
162
163 // Skip if not '"' or '<':
164 if (*p != '"' && *p != '<')
165 continue;
166 p++;
167
168 // Extract file name (between "..." or <...>).
169 mike 1.1 {
170 const char* start = p;
171 while (*p && *p != '"' && *p != '>')
172 p++;
173
174 if (p == start)
175 continue;
176
177 includes.push_back(string(start, p - start));
178 }
179 }
180
181 // Close file:
182 fclose(is);
183
184 // Search for each include file on the paths.
185 for (size_t i = 0; i < includes.size(); i++)
186 {
187 for (size_t j = 0; j < opts.paths.size(); j++)
188 {
189 string path = includes[i];
190 mike 1.1
191 // Check relative first:
192 if (access(path.c_str(), R_OK) == 0)
193 {
194 if (found.find(path) == found.end())
195 {
196 printf(" \\\n %s", path.c_str());
197 found.insert(path);
198 PrintDependencies(path.c_str(), found, level+1);
199 }
200 }
201
202 // Find absolute path:
203 path = opts.paths[j] + "/" + includes[i];
204 if (path[0] != '/')
205 {
206 char cwd[1024];
207 if (getcwd(cwd, sizeof(cwd)) == NULL)
208 {
209 fprintf(stdout, "%s: failed to stat current dir\n", arg0);
210 exit(1);
211 mike 1.1 }
212
213 path = string(cwd) + string("/") + path;
214 }
215
216 if (access(path.c_str(), R_OK) == 0)
217 {
218 if (found.find(path) == found.end())
219 {
220 printf(" \\\n %s", path.c_str());
221 found.insert(path);
222 PrintDependencies(path.c_str(), found, level+1);
223 }
224 }
225 }
226 }
227 }
228
229 int main(int argc, char** argv)
230 {
231 arg0 = argv[0];
232 mike 1.1
233 // Get command line options.
234 _GetOptions(argc, argv, opts);
235
236 // Check arguments:
237 if (argc < 2)
238 {
239 fprintf(stderr, "Usage: %s [OPTIONS-AND-ARGUMENTS]\n", argv[0]);
240 exit(1);
241 }
242
243 // Make dependencies for each file.
244 for (int i = 1; i < argc; i++)
245 {
246 string srcfile = argv[i];
247 string objfile;
248
249 // Replace '.cpp' with '.o'
250 if (srcfile.size() >= 4 && srcfile.substr(srcfile.size()-4) == ".cpp")
251 {
252 objfile = srcfile.substr(0, srcfile.size()-4) + ".o";
253 mike 1.1 }
254
255 // Replace '.c' with '.o'
256 if (srcfile.size() >= 2 && srcfile.substr(srcfile.size()-2) == ".c")
257 {
258 objfile = srcfile.substr(0, srcfile.size()-2) + ".o";
259 }
260
261 set<string> found;
262
263 if (opts.objdir.size())
264 printf("%s/%s:", opts.objdir.c_str(), objfile.c_str());
265 else
266 printf("%s:", objfile.c_str());
267
268 PrintDependencies(srcfile.c_str(), found);
269 printf("\n\n");
270 }
271
272 return 0;
273 }
|