Use extern "C" for Winelib C++ apps.
[wine/hacks.git] / tools / makedep.c
blob8b2049894b79df45f01f010e8c8c8ad94f2c9935
1 /*
2 * Generate include file dependencies
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
13 /* Max first-level includes per file */
14 #define MAX_INCLUDES 124
16 typedef struct _INCL_FILE
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;
27 static INCL_FILE *firstSrc;
28 static INCL_FILE *firstInclude;
30 typedef struct _INCL_PATH
32 struct _INCL_PATH *next;
33 const char *name;
34 } INCL_PATH;
36 static INCL_PATH *firstPath;
38 static const char *SrcDir = NULL;
39 static const char *OutputFileName = "Makefile";
40 static const char *Separator = "### Dependencies";
41 static const char *ProgramName;
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";
52 /*******************************************************************
53 * xmalloc
55 static void *xmalloc( int size )
57 void *res;
58 if (!(res = malloc (size ? size : 1)))
60 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
61 exit(1);
63 return res;
67 /*******************************************************************
68 * xstrdup
70 static char *xstrdup( const char *str )
72 char *res = strdup( str );
73 if (!res)
75 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
76 exit(1);
78 return res;
82 /*******************************************************************
83 * is_generated
85 * Test if a given file type is generated during the make process
87 static int is_generated( const char *name )
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++)
93 if (len <= strlen(extensions[i])) continue;
94 if (!strcmp( name + len - strlen(extensions[i]), extensions[i] )) return 1;
96 return 0;
99 /*******************************************************************
100 * add_include_path
102 * Add a directory to the include path.
104 static void add_include_path( const char *name )
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;
115 /*******************************************************************
116 * add_src_file
118 * Add a source file to the list.
120 static INCL_FILE *add_src_file( const char *name )
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;
132 /*******************************************************************
133 * add_include
135 * Add an include file if it doesn't already exists.
137 static INCL_FILE *add_include( INCL_FILE *pFile, const char *name, int line )
139 INCL_FILE **p = &firstInclude;
140 int pos;
142 for (pos = 0; pos < MAX_INCLUDES; pos++) if (!pFile->files[pos]) break;
143 if (pos >= MAX_INCLUDES)
145 fprintf( stderr, "%s: %s: too many included files, please fix MAX_INCLUDES\n",
146 ProgramName, pFile->name );
147 exit(1);
150 while (*p && strcmp( name, (*p)->name )) p = &(*p)->next;
151 if (!*p)
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;
159 pFile->files[pos] = *p;
160 return *p;
164 /*******************************************************************
165 * open_src_file
167 static FILE *open_src_file( INCL_FILE *pFile )
169 FILE *file;
171 if (SrcDir)
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 );
178 else pFile->filename = xstrdup( pFile->name );
180 if (!(file = fopen( pFile->filename, "r" )))
182 perror( pFile->filename );
183 exit(1);
185 return file;
189 /*******************************************************************
190 * open_include_file
192 static FILE *open_include_file( INCL_FILE *pFile )
194 FILE *file = NULL;
195 INCL_PATH *path;
197 for (path = firstPath; path; path = path->next)
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" )))
205 pFile->filename = filename;
206 break;
208 free( filename );
210 /* try in src file directory */
211 if (!file)
213 char *p = strrchr(pFile->included_by->name, '/');
214 if (p)
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 );
225 if (!file)
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)
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;
236 exit(1);
238 return file;
242 /*******************************************************************
243 * parse_file
245 static void parse_file( INCL_FILE *pFile, int src )
247 char buffer[1024];
248 char *include;
249 int line = 0;
250 FILE *file;
252 if (is_generated( pFile->name ))
254 /* file is generated during make, don't try to open it */
255 pFile->filename = xstrdup( pFile->name );
256 return;
259 file = src ? open_src_file( pFile ) : open_include_file( pFile );
261 while (fgets( buffer, sizeof(buffer)-1, file ))
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)
276 fprintf( stderr, "%s:%d: Malformed #include directive\n",
277 pFile->filename, line );
278 exit(1);
280 *p = 0;
281 add_include( pFile, include, line );
283 fclose(file);
287 /*******************************************************************
288 * output_include
290 static void output_include( FILE *file, INCL_FILE *pFile,
291 INCL_FILE *owner, int *column )
293 int i;
295 if (pFile->owner == owner) return;
296 pFile->owner = owner;
297 if (*column + strlen(pFile->filename) + 1 > 70)
299 fprintf( file, " \\\n" );
300 *column = 0;
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 );
310 /*******************************************************************
311 * output_src
313 static void output_src( FILE *file, INCL_FILE *pFile, int *column )
315 char *obj = xstrdup( pFile->name );
316 char *ext = strrchr( obj, '.' );
317 if (ext && strchr( ext, '/' )) ext = NULL;
318 if (ext)
320 *ext++ = 0;
321 if (!strcmp( ext, "y" )) /* yacc file */
323 *column += fprintf( file, "y.tab.o: y.tab.c" );
325 else if (!strcmp( ext, "l" )) /* lex file */
327 *column += fprintf( file, "lex.yy.o: lex.yy.c" );
329 else if (!strcmp( ext, "rc" )) /* resource file */
331 *column += fprintf( file, "%s.res: %s", obj, pFile->filename );
333 else if (!strcmp( ext, "mc" )) /* message file */
335 *column += fprintf( file, "%s.mc.rc: %s", obj, pFile->filename );
337 else
339 *column += fprintf( file, "%s.o: %s", obj, pFile->filename );
342 free( obj );
346 /*******************************************************************
347 * output_dependencies
349 static void output_dependencies(void)
351 INCL_FILE *pFile;
352 int i, column;
353 FILE *file = NULL;
354 char buffer[1024];
356 if (Separator && ((file = fopen( OutputFileName, "r+" ))))
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 );
363 if (!file)
365 if (!(file = fopen( OutputFileName, Separator ? "a" : "w" )))
367 perror( OutputFileName );
368 exit(1);
371 for( pFile = firstSrc; pFile; pFile = pFile->next)
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" );
380 fclose(file);
384 /*******************************************************************
385 * parse_option
387 static void parse_option( const char *opt )
389 switch(opt[1])
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);
413 /*******************************************************************
414 * main
416 int main( int argc, char *argv[] )
418 INCL_FILE *pFile;
420 ProgramName = argv[0];
421 while (argc > 1)
423 if (*argv[1] == '-') parse_option( argv[1] );
424 else
426 pFile = add_src_file( argv[1] );
427 parse_file( pFile, 1 );
429 argc--;
430 argv++;
432 for (pFile = firstInclude; pFile; pFile = pFile->next)
433 parse_file( pFile, 0 );
434 if( firstSrc ) output_dependencies();
435 return 0;