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 *owner;
22 struct _INCL_FILE *files[MAX_INCLUDES];
25 static INCL_FILE *firstSrc;
26 static INCL_FILE *firstInclude;
28 typedef struct _INCL_PATH
30 struct _INCL_PATH *next;
34 static INCL_PATH *firstPath;
36 static const char *SrcDir = NULL;
37 static const char *OutputFileName = "Makefile";
38 static const char *Separator = "### Dependencies";
39 static const char *ProgramName;
41 static const char Usage[] =
42 "Usage: %s [options] [files]\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";
50 /*******************************************************************
53 static void *xmalloc( int size )
56 if (!(res = malloc (size ? size : 1)))
58 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
65 /*******************************************************************
68 static char *xstrdup( const char *str )
70 char *res = strdup( str );
73 fprintf( stderr, "%s: Virtual memory exhausted.\n", ProgramName );
80 /*******************************************************************
83 * Add a directory to the include path.
85 static void add_include_path( const char *name )
87 INCL_PATH *path = xmalloc( sizeof(*path) );
88 INCL_PATH **p = &firstPath;
89 while (*p) p = &(*p)->next;
96 /*******************************************************************
99 * Add a source file to the list.
101 static INCL_FILE *add_src_file( const char *name )
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;
113 /*******************************************************************
116 * Add an include file if it doesn't already exists.
118 static INCL_FILE *add_include( INCL_FILE *pFile, const char *name )
120 INCL_FILE **p = &firstInclude;
123 for (pos = 0; pos < MAX_INCLUDES; pos++) if (!pFile->files[pos]) break;
124 if (pos >= MAX_INCLUDES)
126 fprintf( stderr, "%s: %s: too many included files, please fix MAX_INCLUDES\n",
127 ProgramName, pFile->name );
131 while (*p && strcmp( name, (*p)->name )) p = &(*p)->next;
134 *p = xmalloc( sizeof(INCL_FILE) );
135 memset( *p, 0, sizeof(INCL_FILE) );
136 (*p)->name = xstrdup(name);
138 pFile->files[pos] = *p;
143 /*******************************************************************
146 static FILE *open_src_file( INCL_FILE *pFile )
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 );
157 else pFile->filename = xstrdup( pFile->name );
159 if (!(file = fopen( pFile->filename, "r" )))
161 perror( pFile->filename );
168 /*******************************************************************
171 static FILE *open_include_file( INCL_FILE *pFile )
176 for (path = firstPath; path; path = path->next)
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" )))
184 pFile->filename = filename;
191 if (firstPath) perror( pFile->name );
192 else fprintf( stderr, "%s: %s: File not found\n",
193 ProgramName, pFile->name );
200 /*******************************************************************
203 static void parse_file( INCL_FILE *pFile, int src )
209 FILE *file = src ? open_src_file( pFile ) : open_include_file( pFile );
210 while (fgets( buffer, sizeof(buffer)-1, file ))
214 while (*p && isspace(*p)) p++;
215 if (*p++ != '#') continue;
216 while (*p && isspace(*p)) p++;
217 if (strncmp( p, "include", 7 )) continue;
219 while (*p && isspace(*p)) p++;
220 if (*p++ != '\"') continue;
222 while (*p && (*p != '\"')) p++;
225 fprintf( stderr, "%s:%d: Malformed #include directive\n",
226 pFile->filename, line );
230 add_include( pFile, include );
236 /*******************************************************************
239 static void output_include( FILE *file, INCL_FILE *pFile,
240 INCL_FILE *owner, int *column )
244 if (pFile->owner == owner) return;
245 pFile->owner = owner;
246 if (*column + strlen(pFile->filename) + 1 > 70)
248 fprintf( file, " \\\n" );
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],
259 /*******************************************************************
262 static void output_src( FILE *file, INCL_FILE *pFile, int *column )
264 char *name = strrchr( pFile->name, '/' );
265 char *obj = xstrdup( name ? name + 1 : pFile->name );
266 char *ext = strrchr( obj, '.' );
269 if (!strcmp( ext, ".y" )) /* yacc file */
271 fprintf( file, "y.tab.o: y.tab.c" );
274 else if (!strcmp( ext, ".l" )) /* lex file */
276 fprintf( file, "lex.yy.o: lex.yy.c" );
279 else if (!strcmp( ext, ".rc" )) /* resource file */
282 fprintf( file, "%s.s: %s", obj, pFile->filename );
283 *column += 2 * strlen(obj) + strlen(pFile->filename) + 7;
288 fprintf( file, "%s: %s", obj, pFile->filename );
289 *column += strlen(obj) + strlen(pFile->filename) + 2;
296 /*******************************************************************
297 * output_dependencies
299 static void output_dependencies(void)
306 if (Separator && ((file = fopen( OutputFileName, "r+" ))))
308 while (fgets( buffer, sizeof(buffer), file ))
309 if (!strncmp( buffer, Separator, strlen(Separator) )) break;
310 ftruncate( fileno(file), ftell(file) );
311 fseek( file, 0L, SEEK_END );
315 if (!(file = fopen( OutputFileName, "a" )))
317 perror( OutputFileName );
321 for( pFile = firstSrc; pFile; pFile = pFile->next)
324 output_src( file, pFile, &column );
325 for (i = 0; i < MAX_INCLUDES; i++)
326 if (pFile->files[i]) output_include( file, pFile->files[i],
328 fprintf( file, "\n" );
334 /*******************************************************************
337 static void parse_option( const char *opt )
342 if (opt[2]) add_include_path( opt + 2 );
345 if (opt[2]) SrcDir = opt + 2;
349 if (opt[2]) OutputFileName = opt + 2;
352 if (opt[2]) Separator = opt + 2;
353 else Separator = NULL;
356 fprintf( stderr, "Unknown option '%s'\n", opt );
357 fprintf( stderr, Usage, ProgramName );
363 /*******************************************************************
366 int main( int argc, char *argv[] )
370 ProgramName = argv[0];
373 if (*argv[1] == '-') parse_option( argv[1] );
376 pFile = add_src_file( argv[1] );
377 parse_file( pFile, 1 );
382 for (pFile = firstInclude; pFile; pFile = pFile->next)
383 parse_file( pFile, 0 );
384 output_dependencies();