Get rid of some warnings about unused variables, signed/unsigned
[wine] / tools / makedep.c
1 /*
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
16 typedef struct _INCL_FILE
17 {
18     struct _INCL_FILE *next;
19     char              *name;
20     char              *filename;
21     struct _INCL_FILE *included_by;   /* file that included this one */
22     int                included_line; /* line where this file was included */
23     struct _INCL_FILE *owner;
24     struct _INCL_FILE *files[MAX_INCLUDES];
25 } INCL_FILE;
26
27 static INCL_FILE *firstSrc;
28 static INCL_FILE *firstInclude;
29
30 typedef struct _INCL_PATH
31 {
32     struct _INCL_PATH *next;
33     const char        *name;
34 } INCL_PATH;
35
36 static INCL_PATH *firstPath;
37
38 static const char *SrcDir = NULL;
39 static const char *OutputFileName = "Makefile";
40 static const char *Separator = "### Dependencies";
41 static const char *ProgramName;
42
43 static const char Usage[] =
44     "Usage: %s [options] [files]\n"
45     "Options:\n"
46     "   -Idir   Search for include files in directory 'dir'\n"
47     "   -Cdir   Search for source files in directory 'dir'\n"
48     "   -fxxx   Store output in file 'xxx' (default: Makefile)\n"
49     "   -sxxx   Use 'xxx' as separator (default: \"### Dependencies\")\n";
50
51
52 /*******************************************************************
53  *         xmalloc
54  */
55 static void *xmalloc( int size )
56 {
57     void *res;
58     if (!(res = malloc (size ? size : 1)))
59     {
60         fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
61         exit(1);
62     }
63     return res;
64 }
65
66
67 /*******************************************************************
68  *         xstrdup
69  */
70 static char *xstrdup( const char *str )
71 {
72     char *res = strdup( str );
73     if (!res)
74     {
75         fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
76         exit(1);
77     }
78     return res;
79 }
80
81
82 /*******************************************************************
83  *         is_generated
84  *
85  * Test if a given file type is generated during the make process
86  */
87 static int is_generated( const char *name )
88 {
89     static const char * const extensions[] = { ".tab.h", ".mc.rc" };
90     size_t i, len = strlen(name);
91     for (i = 0; i < sizeof(extensions)/sizeof(extensions[0]); i++)
92     {
93         if (len <= strlen(extensions[i])) continue;
94         if (!strcmp( name + len - strlen(extensions[i]), extensions[i] )) return 1;
95     }
96     return 0;
97 }
98
99 /*******************************************************************
100  *         add_include_path
101  *
102  * Add a directory to the include path.
103  */
104 static void add_include_path( const char *name )
105 {
106     INCL_PATH *path = xmalloc( sizeof(*path) );
107     INCL_PATH **p = &firstPath;
108     while (*p) p = &(*p)->next;
109     *p = path;
110     path->next = NULL;
111     path->name = name;
112 }
113
114
115 /*******************************************************************
116  *         add_src_file
117  *
118  * Add a source file to the list.
119  */
120 static INCL_FILE *add_src_file( const char *name )
121 {
122     INCL_FILE **p = &firstSrc;
123     INCL_FILE *file = xmalloc( sizeof(*file) );
124     memset( file, 0, sizeof(*file) );
125     file->name = xstrdup(name);
126     while (*p) p = &(*p)->next;
127     *p = file;
128     return file;
129 }
130
131
132 /*******************************************************************
133  *         add_include
134  *
135  * Add an include file if it doesn't already exists.
136  */
137 static INCL_FILE *add_include( INCL_FILE *pFile, const char *name, int line )
138 {
139     INCL_FILE **p = &firstInclude;
140     int pos;
141
142     for (pos = 0; pos < MAX_INCLUDES; pos++) if (!pFile->files[pos]) break;
143     if (pos >= MAX_INCLUDES)
144     {
145         fprintf( stderr, "%s: %s: too many included files, please fix MAX_INCLUDES\n",
146                  ProgramName, pFile->name );
147         exit(1);
148     }
149
150     while (*p && strcmp( name, (*p)->name )) p = &(*p)->next;
151     if (!*p)
152     {
153         *p = xmalloc( sizeof(INCL_FILE) );
154         memset( *p, 0, sizeof(INCL_FILE) );
155         (*p)->name = xstrdup(name);
156         (*p)->included_by = pFile;
157         (*p)->included_line = line;
158     }
159     pFile->files[pos] = *p;
160     return *p;
161 }
162
163
164 /*******************************************************************
165  *         open_src_file
166  */
167 static FILE *open_src_file( INCL_FILE *pFile )
168 {
169     FILE *file;
170
171     if (SrcDir)
172     {
173         pFile->filename = xmalloc( strlen(SrcDir) + strlen(pFile->name) + 2 );
174         strcpy( pFile->filename, SrcDir );
175         strcat( pFile->filename, "/" );
176         strcat( pFile->filename, pFile->name );
177     }
178     else pFile->filename = xstrdup( pFile->name );
179
180     if (!(file = fopen( pFile->filename, "r" )))
181     {
182         perror( pFile->filename );
183         exit(1);
184     }
185     return file;
186 }
187
188
189 /*******************************************************************
190  *         open_include_file
191  */
192 static FILE *open_include_file( INCL_FILE *pFile )
193 {
194     FILE *file = NULL;
195     INCL_PATH *path;
196
197     for (path = firstPath; path; path = path->next)
198     {
199         char *filename = xmalloc(strlen(path->name) + strlen(pFile->name) + 2);
200         strcpy( filename, path->name );
201         strcat( filename, "/" );
202         strcat( filename, pFile->name );
203         if ((file = fopen( filename, "r" )))
204         {
205             pFile->filename = filename;
206             break;
207         }
208         free( filename );
209     }
210     if (!file)
211     {
212         if (firstPath) perror( pFile->name );
213         else fprintf( stderr, "%s: %s: File not found\n",
214                       ProgramName, pFile->name );
215         while (pFile->included_by)
216         {
217             fprintf( stderr, "  %s was first included from %s:%d\n",
218                      pFile->name, pFile->included_by->name, pFile->included_line );
219             pFile = pFile->included_by;
220         }
221         exit(1);
222     }
223     return file;
224 }
225
226
227 /*******************************************************************
228  *         parse_file
229  */
230 static void parse_file( INCL_FILE *pFile, int src )
231 {
232     char buffer[1024];
233     char *include;
234     int line = 0;
235     FILE *file;
236
237     if (is_generated( pFile->name ))
238     {
239         /* file is generated during make, don't try to open it */
240         pFile->filename = xstrdup( pFile->name );
241         return;
242     }
243
244     file = src ? open_src_file( pFile ) : open_include_file( pFile );
245
246     while (fgets( buffer, sizeof(buffer)-1, file ))
247     {
248         char *p = buffer;
249         line++;
250         while (*p && isspace(*p)) p++;
251         if (*p++ != '#') continue;
252         while (*p && isspace(*p)) p++;
253         if (strncmp( p, "include", 7 )) continue;
254         p += 7;
255         while (*p && isspace(*p)) p++;
256         if (*p++ != '\"') continue;
257         include = p;
258         while (*p && (*p != '\"')) p++;
259         if (!*p)
260         {
261             fprintf( stderr, "%s:%d: Malformed #include directive\n",
262                      pFile->filename, line );
263             exit(1);
264         }
265         *p = 0;
266         add_include( pFile, include, line );
267     }
268     fclose(file);
269 }
270
271
272 /*******************************************************************
273  *         output_include
274  */
275 static void output_include( FILE *file, INCL_FILE *pFile,
276                             INCL_FILE *owner, int *column )
277 {
278     int i;
279
280     if (pFile->owner == owner) return;
281     pFile->owner = owner;
282     if (*column + strlen(pFile->filename) + 1 > 70)
283     {
284         fprintf( file, " \\\n" );
285         *column = 0;
286     }
287     fprintf( file, " %s", pFile->filename );
288     *column += strlen(pFile->filename) + 1;
289     for (i = 0; i < MAX_INCLUDES; i++)
290         if (pFile->files[i]) output_include( file, pFile->files[i],
291                                              owner, column );
292 }
293
294
295 /*******************************************************************
296  *         output_src
297  */
298 static void output_src( FILE *file, INCL_FILE *pFile, int *column )
299 {
300     char *obj = xstrdup( pFile->name );
301     char *ext = strrchr( obj, '.' );
302     if (ext && strchr( ext, '/' )) ext = NULL;
303     if (ext)
304     {
305         *ext++ = 0;
306         if (!strcmp( ext, "y" ))  /* yacc file */
307         {
308             *column += fprintf( file, "y.tab.o: y.tab.c" );
309         }
310         else if (!strcmp( ext, "l" ))  /* lex file */
311         {
312             *column += fprintf( file, "lex.yy.o: lex.yy.c" );
313         }
314         else if (!strcmp( ext, "rc" ))  /* resource file */
315         {
316             *column += fprintf( file, "%s.res: %s", obj, pFile->filename );
317         }
318         else if (!strcmp( ext, "mc" ))  /* message file */
319         {
320             *column += fprintf( file, "%s.mc.rc: %s", obj, pFile->filename );
321         }
322         else
323         {
324             *column += fprintf( file, "%s.o: %s", obj, pFile->filename );
325         }
326     }
327     free( obj );
328 }
329
330
331 /*******************************************************************
332  *         output_dependencies
333  */
334 static void output_dependencies(void)
335 {
336     INCL_FILE *pFile;
337     int i, column;
338     FILE *file = NULL;
339     char buffer[1024];
340
341     if (Separator && ((file = fopen( OutputFileName, "r+" ))))
342     {
343         while (fgets( buffer, sizeof(buffer), file ))
344             if (!strncmp( buffer, Separator, strlen(Separator) )) break;
345         ftruncate( fileno(file), ftell(file) );
346         fseek( file, 0L, SEEK_END );
347     }
348     if (!file)
349     {
350         if (!(file = fopen( OutputFileName, "a" )))
351         {
352             perror( OutputFileName );
353             exit(1);
354         }
355     }
356     for( pFile = firstSrc; pFile; pFile = pFile->next)
357     {
358         column = 0;
359         output_src( file, pFile, &column );
360         for (i = 0; i < MAX_INCLUDES; i++)
361             if (pFile->files[i]) output_include( file, pFile->files[i],
362                                                  pFile, &column );
363         fprintf( file, "\n" );
364     }
365     fclose(file);
366 }
367
368
369 /*******************************************************************
370  *         parse_option
371  */
372 static void parse_option( const char *opt )
373 {
374     switch(opt[1])
375     {
376     case 'I':
377         if (opt[2]) add_include_path( opt + 2 );
378         break;
379     case 'C':
380         if (opt[2]) SrcDir = opt + 2;
381         else SrcDir = NULL;
382         break;
383     case 'f':
384         if (opt[2]) OutputFileName = opt + 2;
385         break;
386     case 's':
387         if (opt[2]) Separator = opt + 2;
388         else Separator = NULL;
389         break;
390     default:
391         fprintf( stderr, "Unknown option '%s'\n", opt );
392         fprintf( stderr, Usage, ProgramName );
393         exit(1);
394     }
395 }
396
397
398 /*******************************************************************
399  *         main
400  */
401 int main( int argc, char *argv[] )
402 {
403     INCL_FILE *pFile;
404
405     ProgramName = argv[0];
406     while (argc > 1)
407     {
408         if (*argv[1] == '-') parse_option( argv[1] );
409         else
410         {
411             pFile = add_src_file( argv[1] );
412             parse_file( pFile, 1 );
413         }
414         argc--;
415         argv++;
416     }
417     for (pFile = firstInclude; pFile; pFile = pFile->next)
418         parse_file( pFile, 0 );
419     output_dependencies();
420     return 0;
421 }