blob: c45eb0c50c830353e5158b026ac1bd1dc109a604 [file] [log] [blame]
Alexandre Julliard530ee841996-10-23 16:59:13 +00001/*
2 * Generate include file dependencies
3 *
4 * Copyright 1996 Alexandre Julliard
5 */
6
7#include <ctype.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13/* Max first-level includes per file */
14#define MAX_INCLUDES 124
15
16typedef struct _INCL_FILE
17{
18 struct _INCL_FILE *next;
19 char *name;
20 char *filename;
21 struct _INCL_FILE *owner;
22 struct _INCL_FILE *files[MAX_INCLUDES];
23} INCL_FILE;
24
25static INCL_FILE *firstSrc;
26static INCL_FILE *firstInclude;
27
28typedef struct _INCL_PATH
29{
30 struct _INCL_PATH *next;
31 const char *name;
32} INCL_PATH;
33
34static INCL_PATH *firstPath;
35
36static const char *SrcDir = NULL;
37static const char *OutputFileName = "Makefile";
38static const char *Separator = "### Dependencies";
39static const char *ProgramName;
40
41static const char Usage[] =
42 "Usage: %s [options] [files]\n"
43 "Options:\n"
44 " -Idir Search for include files in directory 'dir'\n"
45 " -Cdir Search for source files in directory 'dir'\n"
46 " -fxxx Store output in file 'xxx' (default: Makefile)\n"
47 " -sxxx Use 'xxx' as separator (default: \"### Dependencies\")\n";
48
49
50/*******************************************************************
51 * xmalloc
52 */
53static void *xmalloc( int size )
54{
55 void *res;
56 if (!(res = malloc (size ? size : 1)))
57 {
58 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
59 exit(1);
60 }
61 return res;
62}
63
64
65/*******************************************************************
66 * xstrdup
67 */
68static char *xstrdup( const char *str )
69{
70 char *res = strdup( str );
71 if (!res)
72 {
73 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
74 exit(1);
75 }
76 return res;
77}
78
79
80/*******************************************************************
81 * add_include_path
82 *
83 * Add a directory to the include path.
84 */
85static void add_include_path( const char *name )
86{
87 INCL_PATH *path = xmalloc( sizeof(*path) );
88 INCL_PATH **p = &firstPath;
89 while (*p) p = &(*p)->next;
90 *p = path;
91 path->next = NULL;
92 path->name = name;
93}
94
95
96/*******************************************************************
97 * add_src_file
98 *
99 * Add a source file to the list.
100 */
101static INCL_FILE *add_src_file( const char *name )
102{
103 INCL_FILE **p = &firstSrc;
104 INCL_FILE *file = xmalloc( sizeof(*file) );
105 memset( file, 0, sizeof(*file) );
106 file->name = xstrdup(name);
107 while (*p) p = &(*p)->next;
108 *p = file;
109 return file;
110}
111
112
113/*******************************************************************
114 * add_include
115 *
116 * Add an include file if it doesn't already exists.
117 */
118static INCL_FILE *add_include( INCL_FILE *pFile, const char *name )
119{
120 INCL_FILE **p = &firstInclude;
121 int pos;
122
123 for (pos = 0; pos < MAX_INCLUDES; pos++) if (!pFile->files[pos]) break;
124 if (pos >= MAX_INCLUDES)
125 {
126 fprintf( stderr, "%s: %s: too many included files, please fix MAX_INCLUDES\n",
127 ProgramName, pFile->name );
128 exit(1);
129 }
130
131 while (*p && strcmp( name, (*p)->name )) p = &(*p)->next;
132 if (!*p)
133 {
134 *p = xmalloc( sizeof(INCL_FILE) );
135 memset( *p, 0, sizeof(INCL_FILE) );
136 (*p)->name = xstrdup(name);
137 }
138 pFile->files[pos] = *p;
139 return *p;
140}
141
142
143/*******************************************************************
144 * open_src_file
145 */
146static FILE *open_src_file( INCL_FILE *pFile )
147{
148 FILE *file;
149
150 if (SrcDir)
151 {
152 pFile->filename = xmalloc( strlen(SrcDir) + strlen(pFile->name) + 2 );
153 strcpy( pFile->filename, SrcDir );
154 strcat( pFile->filename, "/" );
155 strcat( pFile->filename, pFile->name );
156 }
157 else pFile->filename = xstrdup( pFile->name );
158
159 if (!(file = fopen( pFile->filename, "r" )))
160 {
161 perror( pFile->filename );
162 exit(1);
163 }
164 return file;
165}
166
167
168/*******************************************************************
169 * open_include_file
170 */
171static FILE *open_include_file( INCL_FILE *pFile )
172{
173 FILE *file = NULL;
174 INCL_PATH *path;
175
176 for (path = firstPath; path; path = path->next)
177 {
178 char *filename = xmalloc(strlen(path->name) + strlen(pFile->name) + 2);
179 strcpy( filename, path->name );
180 strcat( filename, "/" );
181 strcat( filename, pFile->name );
182 if ((file = fopen( filename, "r" )))
183 {
184 pFile->filename = filename;
185 break;
186 }
187 free( filename );
188 }
189 if (!file)
190 {
191 if (firstPath) perror( pFile->name );
192 else fprintf( stderr, "%s: %s: File not found\n",
193 ProgramName, pFile->name );
194 exit(1);
195 }
196 return file;
197}
198
199
200/*******************************************************************
201 * parse_file
202 */
203static void parse_file( INCL_FILE *pFile, int src )
204{
205 char buffer[1024];
206 char *include;
207 int line = 0;
208
209 FILE *file = src ? open_src_file( pFile ) : open_include_file( pFile );
210 while (fgets( buffer, sizeof(buffer)-1, file ))
211 {
212 char *p = buffer;
213 line++;
214 while (*p && isspace(*p)) p++;
215 if (*p++ != '#') continue;
216 while (*p && isspace(*p)) p++;
217 if (strncmp( p, "include", 7 )) continue;
218 p += 7;
219 while (*p && isspace(*p)) p++;
220 if (*p++ != '\"') continue;
221 include = p;
222 while (*p && (*p != '\"')) p++;
223 if (!*p)
224 {
225 fprintf( stderr, "%s:%d: Malformed #include directive\n",
226 pFile->filename, line );
227 exit(1);
228 }
229 *p = 0;
230 add_include( pFile, include );
231 }
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000232 fclose(file);
Alexandre Julliard530ee841996-10-23 16:59:13 +0000233}
234
235
236/*******************************************************************
237 * output_include
238 */
239static void output_include( FILE *file, INCL_FILE *pFile,
240 INCL_FILE *owner, int *column )
241{
242 int i;
243
244 if (pFile->owner == owner) return;
245 pFile->owner = owner;
246 if (*column + strlen(pFile->filename) + 1 > 70)
247 {
248 fprintf( file, " \\\n" );
249 *column = 0;
250 }
251 fprintf( file, " %s", pFile->filename );
252 *column += strlen(pFile->filename) + 1;
253 for (i = 0; i < MAX_INCLUDES; i++)
254 if (pFile->files[i]) output_include( file, pFile->files[i],
255 owner, column );
256}
257
258
259/*******************************************************************
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000260 * output_src
261 */
262static void output_src( FILE *file, INCL_FILE *pFile, int *column )
263{
264 char *name = strrchr( pFile->name, '/' );
265 char *obj = xstrdup( name ? name + 1 : pFile->name );
266 char *ext = strrchr( obj, '.' );
267 if (ext)
268 {
269 if (!strcmp( ext, ".y" )) /* yacc file */
270 {
Alexandre Julliard17216f51997-10-12 16:30:17 +0000271 fprintf( file, "y.tab.o: y.tab.c" );
272 *column += 16;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000273 }
274 else if (!strcmp( ext, ".l" )) /* lex file */
275 {
Alexandre Julliard17216f51997-10-12 16:30:17 +0000276 fprintf( file, "lex.yy.o: lex.yy.c" );
277 *column += 18;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000278 }
279 else if (!strcmp( ext, ".rc" )) /* resource file */
280 {
281 *ext = '\0';
Alexandre Julliarda845b881998-06-01 10:44:35 +0000282 fprintf( file, "%s.s: %s", obj, pFile->filename );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000283 *column += 2 * strlen(obj) + strlen(pFile->filename) + 7;
284 }
285 else
286 {
287 strcpy( ext, ".o" );
288 fprintf( file, "%s: %s", obj, pFile->filename );
289 *column += strlen(obj) + strlen(pFile->filename) + 2;
290 }
291 }
292 free( obj );
293}
294
295
296/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000297 * output_dependencies
298 */
299static void output_dependencies(void)
300{
301 INCL_FILE *pFile;
302 int i, column;
303 FILE *file = NULL;
304 char buffer[1024];
305
306 if (Separator && ((file = fopen( OutputFileName, "r+" ))))
307 {
308 while (fgets( buffer, sizeof(buffer), file ))
309 if (!strncmp( buffer, Separator, strlen(Separator) )) break;
310 ftruncate( fileno(file), ftell(file) );
Alexandre Julliard01d63461997-01-20 19:43:45 +0000311 fseek( file, 0L, SEEK_END );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000312 }
313 if (!file)
314 {
315 if (!(file = fopen( OutputFileName, "a" )))
316 {
317 perror( OutputFileName );
318 exit(1);
319 }
320 }
321 for( pFile = firstSrc; pFile; pFile = pFile->next)
322 {
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000323 column = 0;
324 output_src( file, pFile, &column );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000325 for (i = 0; i < MAX_INCLUDES; i++)
326 if (pFile->files[i]) output_include( file, pFile->files[i],
327 pFile, &column );
328 fprintf( file, "\n" );
329 }
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000330 fclose(file);
Alexandre Julliard530ee841996-10-23 16:59:13 +0000331}
332
333
334/*******************************************************************
335 * parse_option
336 */
337static void parse_option( const char *opt )
338{
339 switch(opt[1])
340 {
341 case 'I':
342 if (opt[2]) add_include_path( opt + 2 );
343 break;
344 case 'C':
345 if (opt[2]) SrcDir = opt + 2;
346 else SrcDir = NULL;
347 break;
348 case 'f':
349 if (opt[2]) OutputFileName = opt + 2;
350 break;
351 case 's':
352 if (opt[2]) Separator = opt + 2;
353 else Separator = NULL;
354 break;
355 default:
356 fprintf( stderr, "Unknown option '%s'\n", opt );
357 fprintf( stderr, Usage, ProgramName );
358 exit(1);
359 }
360}
361
362
363/*******************************************************************
364 * main
365 */
366int main( int argc, char *argv[] )
367{
368 INCL_FILE *pFile;
369
370 ProgramName = argv[0];
371 while (argc > 1)
372 {
373 if (*argv[1] == '-') parse_option( argv[1] );
374 else
375 {
376 pFile = add_src_file( argv[1] );
377 parse_file( pFile, 1 );
378 }
379 argc--;
380 argv++;
381 }
382 for (pFile = firstInclude; pFile; pFile = pFile->next)
383 parse_file( pFile, 0 );
384 output_dependencies();
385 return 0;
386}