- Stub routines for _164, _208, _210, _211, _239, _356, _413, _437,
[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     /* try in src file directory */
211     if (!file)
212     {
213         char *p = strrchr(pFile->included_by->name, '/');
214         if (p)
215         {
216             int l = p - pFile->included_by->name + 1;
217             char *filename = xmalloc(l + strlen(pFile->name) + 1);
218             memcpy( filename, pFile->included_by->name, l );
219             strcpy( filename + l, pFile->name );
220             if ((file = fopen( filename, "r" ))) pFile->filename = filename;
221             else free( filename );
222         }
223     }
224
225     if (!file)
226     {
227         if (firstPath) perror( pFile->name );
228         else fprintf( stderr, "%s: %s: File not found\n",
229                       ProgramName, pFile->name );
230         while (pFile->included_by)
231         {
232             fprintf( stderr, "  %s was first included from %s:%d\n",
233                      pFile->name, pFile->included_by->name, pFile->included_line );
234             pFile = pFile->included_by;
235         }
236         exit(1);
237     }
238     return file;
239 }
240
241
242 /*******************************************************************
243  *         parse_file
244  */
245 static void parse_file( INCL_FILE *pFile, int src )
246 {
247     char buffer[1024];
248     char *include;
249     int line = 0;
250     FILE *file;
251
252     if (is_generated( pFile->name ))
253     {
254         /* file is generated during make, don't try to open it */
255         pFile->filename = xstrdup( pFile->name );
256         return;
257     }
258
259     file = src ? open_src_file( pFile ) : open_include_file( pFile );
260
261     while (fgets( buffer, sizeof(buffer)-1, file ))
262     {
263         char *p = buffer;
264         line++;
265         while (*p && isspace(*p)) p++;
266         if (*p++ != '#') continue;
267         while (*p && isspace(*p)) p++;
268         if (strncmp( p, "include", 7 )) continue;
269         p += 7;
270         while (*p && isspace(*p)) p++;
271         if (*p++ != '\"') continue;
272         include = p;
273         while (*p && (*p != '\"')) p++;
274         if (!*p)
275         {
276             fprintf( stderr, "%s:%d: Malformed #include directive\n",
277                      pFile->filename, line );
278             exit(1);
279         }
280         *p = 0;
281         add_include( pFile, include, line );
282     }
283     fclose(file);
284 }
285
286
287 /*******************************************************************
288  *         output_include
289  */
290 static void output_include( FILE *file, INCL_FILE *pFile,
291                             INCL_FILE *owner, int *column )
292 {
293     int i;
294
295     if (pFile->owner == owner) return;
296     pFile->owner = owner;
297     if (*column + strlen(pFile->filename) + 1 > 70)
298     {
299         fprintf( file, " \\\n" );
300         *column = 0;
301     }
302     fprintf( file, " %s", pFile->filename );
303     *column += strlen(pFile->filename) + 1;
304     for (i = 0; i < MAX_INCLUDES; i++)
305         if (pFile->files[i]) output_include( file, pFile->files[i],
306                                              owner, column );
307 }
308
309
310 /*******************************************************************
311  *         output_src
312  */
313 static void output_src( FILE *file, INCL_FILE *pFile, int *column )
314 {
315     char *obj = xstrdup( pFile->name );
316     char *ext = strrchr( obj, '.' );
317     if (ext && strchr( ext, '/' )) ext = NULL;
318     if (ext)
319     {
320         *ext++ = 0;
321         if (!strcmp( ext, "y" ))  /* yacc file */
322         {
323             *column += fprintf( file, "y.tab.o: y.tab.c" );
324         }
325         else if (!strcmp( ext, "l" ))  /* lex file */
326         {
327             *column += fprintf( file, "lex.yy.o: lex.yy.c" );
328         }
329         else if (!strcmp( ext, "rc" ))  /* resource file */
330         {
331             *column += fprintf( file, "%s.res: %s", obj, pFile->filename );
332         }
333         else if (!strcmp( ext, "mc" ))  /* message file */
334         {
335             *column += fprintf( file, "%s.mc.rc: %s", obj, pFile->filename );
336         }
337         else
338         {
339             *column += fprintf( file, "%s.o: %s", obj, pFile->filename );
340         }
341     }
342     free( obj );
343 }
344
345
346 /*******************************************************************
347  *         output_dependencies
348  */
349 static void output_dependencies(void)
350 {
351     INCL_FILE *pFile;
352     int i, column;
353     FILE *file = NULL;
354     char buffer[1024];
355
356     if (Separator && ((file = fopen( OutputFileName, "r+" ))))
357     {
358         while (fgets( buffer, sizeof(buffer), file ))
359             if (!strncmp( buffer, Separator, strlen(Separator) )) break;
360         ftruncate( fileno(file), ftell(file) );
361         fseek( file, 0L, SEEK_END );
362     }
363     if (!file)
364     {
365         if (!(file = fopen( OutputFileName, Separator ? "a" : "w" )))
366         {
367             perror( OutputFileName );
368             exit(1);
369         }
370     }
371     for( pFile = firstSrc; pFile; pFile = pFile->next)
372     {
373         column = 0;
374         output_src( file, pFile, &column );
375         for (i = 0; i < MAX_INCLUDES; i++)
376             if (pFile->files[i]) output_include( file, pFile->files[i],
377                                                  pFile, &column );
378         fprintf( file, "\n" );
379     }
380     fclose(file);
381 }
382
383
384 /*******************************************************************
385  *         parse_option
386  */
387 static void parse_option( const char *opt )
388 {
389     switch(opt[1])
390     {
391     case 'I':
392         if (opt[2]) add_include_path( opt + 2 );
393         break;
394     case 'C':
395         if (opt[2]) SrcDir = opt + 2;
396         else SrcDir = NULL;
397         break;
398     case 'f':
399         if (opt[2]) OutputFileName = opt + 2;
400         break;
401     case 's':
402         if (opt[2]) Separator = opt + 2;
403         else Separator = NULL;
404         break;
405     default:
406         fprintf( stderr, "Unknown option '%s'\n", opt );
407         fprintf( stderr, Usage, ProgramName );
408         exit(1);
409     }
410 }
411
412
413 /*******************************************************************
414  *         main
415  */
416 int main( int argc, char *argv[] )
417 {
418     INCL_FILE *pFile;
419
420     ProgramName = argv[0];
421     while (argc > 1)
422     {
423         if (*argv[1] == '-') parse_option( argv[1] );
424         else
425         {
426             pFile = add_src_file( argv[1] );
427             parse_file( pFile, 1 );
428         }
429         argc--;
430         argv++;
431     }
432     for (pFile = firstInclude; pFile; pFile = pFile->next)
433         parse_file( pFile, 0 );
434     if( firstSrc ) output_dependencies();
435     return 0;
436 }