2 * Generate include file dependencies
4 * Copyright 1996 Alexandre Julliard
13 /* Max first-level includes per file */
14 #define MAX_INCLUDES 124
16 typedef struct _INCL_FILE
18 struct _INCL_FILE *next;
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];
27 static INCL_FILE *firstSrc;
28 static INCL_FILE *firstInclude;
30 typedef struct _INCL_PATH
32 struct _INCL_PATH *next;
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"
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 /*******************************************************************
55 static void *xmalloc( int size )
58 if (!(res = malloc (size ? size : 1)))
60 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
67 /*******************************************************************
70 static char *xstrdup( const char *str )
72 char *res = strdup( str );
75 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
82 /*******************************************************************
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;
99 /*******************************************************************
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;
115 /*******************************************************************
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;
132 /*******************************************************************
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;
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 );
150 while (*p && strcmp( name, (*p)->name )) p = &(*p)->next;
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;
164 /*******************************************************************
167 static FILE *open_src_file( INCL_FILE *pFile )
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 );
189 /*******************************************************************
192 static FILE *open_include_file( INCL_FILE *pFile )
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;
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)
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;
227 /*******************************************************************
230 static void parse_file( INCL_FILE *pFile, int src )
237 if (is_generated( pFile->name ))
239 /* file is generated during make, don't try to open it */
240 pFile->filename = xstrdup( pFile->name );
244 file = src ? open_src_file( pFile ) : open_include_file( pFile );
246 while (fgets( buffer, sizeof(buffer)-1, file ))
250 while (*p && isspace(*p)) p++;
251 if (*p++ != '#') continue;
252 while (*p && isspace(*p)) p++;
253 if (strncmp( p, "include", 7 )) continue;
255 while (*p && isspace(*p)) p++;
256 if (*p++ != '\"') continue;
258 while (*p && (*p != '\"')) p++;
261 fprintf( stderr, "%s:%d: Malformed #include directive\n",
262 pFile->filename, line );
266 add_include( pFile, include, line );
272 /*******************************************************************
275 static void output_include( FILE *file, INCL_FILE *pFile,
276 INCL_FILE *owner, int *column )
280 if (pFile->owner == owner) return;
281 pFile->owner = owner;
282 if (*column + strlen(pFile->filename) + 1 > 70)
284 fprintf( file, " \\\n" );
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],
295 /*******************************************************************
298 static void output_src( FILE *file, INCL_FILE *pFile, int *column )
300 char *obj = xstrdup( pFile->name );
301 char *ext = strrchr( obj, '.' );
302 if (ext && strchr( ext, '/' )) ext = NULL;
306 if (!strcmp( ext, "y" )) /* yacc file */
308 *column += fprintf( file, "y.tab.o: y.tab.c" );
310 else if (!strcmp( ext, "l" )) /* lex file */
312 *column += fprintf( file, "lex.yy.o: lex.yy.c" );
314 else if (!strcmp( ext, "rc" )) /* resource file */
316 *column += fprintf( file, "%s.res: %s", obj, pFile->filename );
318 else if (!strcmp( ext, "mc" )) /* message file */
320 *column += fprintf( file, "%s.mc.rc: %s", obj, pFile->filename );
324 *column += fprintf( file, "%s.o: %s", obj, pFile->filename );
331 /*******************************************************************
332 * output_dependencies
334 static void output_dependencies(void)
341 if (Separator && ((file = fopen( OutputFileName, "r+" ))))
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 );
350 if (!(file = fopen( OutputFileName, "a" )))
352 perror( OutputFileName );
356 for( pFile = firstSrc; pFile; pFile = pFile->next)
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],
363 fprintf( file, "\n" );
369 /*******************************************************************
372 static void parse_option( const char *opt )
377 if (opt[2]) add_include_path( opt + 2 );
380 if (opt[2]) SrcDir = opt + 2;
384 if (opt[2]) OutputFileName = opt + 2;
387 if (opt[2]) Separator = opt + 2;
388 else Separator = NULL;
391 fprintf( stderr, "Unknown option '%s'\n", opt );
392 fprintf( stderr, Usage, ProgramName );
398 /*******************************************************************
401 int main( int argc, char *argv[] )
405 ProgramName = argv[0];
408 if (*argv[1] == '-') parse_option( argv[1] );
411 pFile = add_src_file( argv[1] );
412 parse_file( pFile, 1 );
417 for (pFile = firstInclude; pFile; pFile = pFile->next)
418 parse_file( pFile, 0 );
419 output_dependencies();