blob: 25713598ca21f57241175b9046bd8c6b8c8835c5 [file] [log] [blame]
Alexandre Julliard530ee841996-10-23 16:59:13 +00001/*
2 * Generate include file dependencies
3 *
4 * Copyright 1996 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard530ee841996-10-23 16:59:13 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
Alexandre Julliard8cbdb972003-03-20 21:08:28 +000022#define NO_LIBWINE_PORT
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000023#include "wine/port.h"
24
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +020025#include <assert.h>
Alexandre Julliard530ee841996-10-23 16:59:13 +000026#include <ctype.h>
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020027#include <errno.h>
Alexandre Julliard530ee841996-10-23 16:59:13 +000028#include <stdio.h>
29#include <stdlib.h>
Alexandre Julliardffca0d62004-04-07 04:00:16 +000030#include <stdarg.h>
Alexandre Julliard530ee841996-10-23 16:59:13 +000031#include <string.h>
Dmitry Timoshkovc63d9802002-08-17 18:28:43 +000032#ifdef HAVE_UNISTD_H
33# include <unistd.h>
34#endif
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020035#include "wine/list.h"
Alexandre Julliard530ee841996-10-23 16:59:13 +000036
37/* Max first-level includes per file */
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +000038#define MAX_INCLUDES 200
Alexandre Julliard530ee841996-10-23 16:59:13 +000039
40typedef struct _INCL_FILE
41{
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020042 struct list entry;
Alexandre Julliard530ee841996-10-23 16:59:13 +000043 char *name;
44 char *filename;
Alexandre Julliarde4fca882006-09-10 22:04:42 +020045 char *sourcename; /* source file name for generated headers */
Alexandre Julliardd19ad392000-11-06 05:32:59 +000046 struct _INCL_FILE *included_by; /* file that included this one */
47 int included_line; /* line where this file was included */
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +000048 int system; /* is it a system include (#include <name>) */
Alexandre Julliard530ee841996-10-23 16:59:13 +000049 struct _INCL_FILE *owner;
50 struct _INCL_FILE *files[MAX_INCLUDES];
51} INCL_FILE;
52
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020053static struct list sources = LIST_INIT(sources);
54static struct list includes = LIST_INIT(includes);
Alexandre Julliard530ee841996-10-23 16:59:13 +000055
56typedef struct _INCL_PATH
57{
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020058 struct list entry;
59 const char *name;
Alexandre Julliard530ee841996-10-23 16:59:13 +000060} INCL_PATH;
61
Alexandre Julliardf25c4d42006-08-01 12:13:57 +020062static struct list paths = LIST_INIT(paths);
Alexandre Julliard530ee841996-10-23 16:59:13 +000063
Alexandre Julliarddea28ee2006-08-01 12:27:22 +020064static const char *src_dir;
65static const char *top_src_dir;
66static const char *top_obj_dir;
Alexandre Julliard530ee841996-10-23 16:59:13 +000067static const char *OutputFileName = "Makefile";
68static const char *Separator = "### Dependencies";
69static const char *ProgramName;
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +020070static int input_line;
Alexandre Julliard530ee841996-10-23 16:59:13 +000071
72static const char Usage[] =
73 "Usage: %s [options] [files]\n"
74 "Options:\n"
75 " -Idir Search for include files in directory 'dir'\n"
76 " -Cdir Search for source files in directory 'dir'\n"
Alexandre Julliarddea28ee2006-08-01 12:27:22 +020077 " -Sdir Set the top source directory\n"
Detlef Riekenberg5073aae2008-06-13 05:09:38 +020078 " -Tdir Set the top object directory\n"
Alexandre Julliard530ee841996-10-23 16:59:13 +000079 " -fxxx Store output in file 'xxx' (default: Makefile)\n"
80 " -sxxx Use 'xxx' as separator (default: \"### Dependencies\")\n";
81
82
83/*******************************************************************
Alexandre Julliardffca0d62004-04-07 04:00:16 +000084 * fatal_error
85 */
86static void fatal_error( const char *msg, ... )
87{
88 va_list valist;
89 va_start( valist, msg );
90 vfprintf( stderr, msg, valist );
91 va_end( valist );
92 exit(1);
93}
94
95
96/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +000097 * xmalloc
98 */
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +020099static void *xmalloc( size_t size )
Alexandre Julliard530ee841996-10-23 16:59:13 +0000100{
101 void *res;
102 if (!(res = malloc (size ? size : 1)))
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000103 fatal_error( "%s: Virtual memory exhausted.\n", ProgramName );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000104 return res;
105}
106
107
108/*******************************************************************
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200109 * xrealloc
110 */
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200111static void *xrealloc (void *ptr, size_t size)
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200112{
113 void *res;
114 assert( size );
115 if (!(res = realloc( ptr, size )))
116 fatal_error( "%s: Virtual memory exhausted.\n", ProgramName );
117 return res;
118}
119
120/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000121 * xstrdup
122 */
123static char *xstrdup( const char *str )
124{
125 char *res = strdup( str );
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000126 if (!res) fatal_error( "%s: Virtual memory exhausted.\n", ProgramName );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000127 return res;
128}
129
130
131/*******************************************************************
Alexandre Julliardded32d52006-08-01 12:37:18 +0200132 * strmake
133 */
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200134static char *strmake( const char* fmt, ... )
Alexandre Julliardded32d52006-08-01 12:37:18 +0200135{
136 int n;
137 size_t size = 100;
138 va_list ap;
139
140 for (;;)
141 {
142 char *p = xmalloc (size);
143 va_start(ap, fmt);
144 n = vsnprintf (p, size, fmt, ap);
145 va_end(ap);
146 if (n == -1) size *= 2;
147 else if ((size_t)n >= size) size = n + 1;
148 else return p;
149 free(p);
150 }
151}
152
153
154/*******************************************************************
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200155 * strendswith
156 */
157static int strendswith( const char* str, const char* end )
158{
159 int l = strlen(str);
160 int m = strlen(end);
161
162 return l >= m && strcmp(str + l - m, end) == 0;
163}
164
165/*******************************************************************
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000166 * get_extension
167 */
168static char *get_extension( char *filename )
169{
170 char *ext = strrchr( filename, '.' );
171 if (ext && strchr( ext, '/' )) ext = NULL;
172 return ext;
173}
174
175
176/*******************************************************************
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200177 * get_line
178 */
179static char *get_line( FILE *file )
180{
181 static char *buffer;
182 static unsigned int size;
183
184 if (!size)
185 {
186 size = 1024;
187 buffer = xmalloc( size );
188 }
189 if (!fgets( buffer, size, file )) return NULL;
190 input_line++;
191
192 for (;;)
193 {
194 char *p = buffer + strlen(buffer);
195 /* if line is larger than buffer, resize buffer */
196 while (p == buffer + size - 1 && p[-1] != '\n')
197 {
198 buffer = xrealloc( buffer, size * 2 );
199 fgets( buffer + size - 1, size + 1, file );
200 p = buffer + strlen(buffer);
201 size *= 2;
202 }
203 if (p > buffer && p[-1] == '\n')
204 {
205 *(--p) = 0;
206 if (p > buffer && p[-1] == '\r') *(--p) = 0;
207 if (p > buffer && p[-1] == '\\')
208 {
209 *(--p) = 0;
210 /* line ends in backslash, read continuation line */
211 fgets( p, size - (p - buffer), file );
212 input_line++;
213 continue;
214 }
215 }
216 return buffer;
217 }
218}
219
220/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000221 * add_include_path
222 *
223 * Add a directory to the include path.
224 */
225static void add_include_path( const char *name )
226{
227 INCL_PATH *path = xmalloc( sizeof(*path) );
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200228 list_add_tail( &paths, &path->entry );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000229 path->name = name;
230}
231
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200232/*******************************************************************
233 * find_src_file
234 */
235static INCL_FILE *find_src_file( const char *name )
236{
237 INCL_FILE *file;
238
239 LIST_FOR_EACH_ENTRY( file, &sources, INCL_FILE, entry )
240 if (!strcmp( name, file->name )) return file;
241 return NULL;
242}
Alexandre Julliard530ee841996-10-23 16:59:13 +0000243
244/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000245 * add_include
246 *
247 * Add an include file if it doesn't already exists.
248 */
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000249static INCL_FILE *add_include( INCL_FILE *pFile, const char *name, int line, int system )
Alexandre Julliard530ee841996-10-23 16:59:13 +0000250{
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200251 INCL_FILE *include;
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000252 char *ext;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000253 int pos;
254
255 for (pos = 0; pos < MAX_INCLUDES; pos++) if (!pFile->files[pos]) break;
256 if (pos >= MAX_INCLUDES)
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000257 fatal_error( "%s: %s: too many included files, please fix MAX_INCLUDES\n",
258 ProgramName, pFile->name );
259
260 /* enforce some rules for the Wine tree */
261
262 if (!memcmp( name, "../", 3 ))
263 fatal_error( "%s:%d: #include directive with relative path not allowed\n",
264 pFile->filename, line );
265
266 if (!strcmp( name, "config.h" ))
Alexandre Julliard530ee841996-10-23 16:59:13 +0000267 {
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000268 if ((ext = strrchr( pFile->filename, '.' )) && !strcmp( ext, ".h" ))
269 fatal_error( "%s:%d: config.h must not be included by a header file\n",
270 pFile->filename, line );
271 if (pos)
272 fatal_error( "%s:%d: config.h must be included before anything else\n",
273 pFile->filename, line );
274 }
275 else if (!strcmp( name, "wine/port.h" ))
276 {
277 if ((ext = strrchr( pFile->filename, '.' )) && !strcmp( ext, ".h" ))
278 fatal_error( "%s:%d: wine/port.h must not be included by a header file\n",
279 pFile->filename, line );
280 if (!pos) fatal_error( "%s:%d: config.h must be included before wine/port.h\n",
281 pFile->filename, line );
282 if (pos > 1)
283 fatal_error( "%s:%d: wine/port.h must be included before everything except config.h\n",
284 pFile->filename, line );
285 if (strcmp( pFile->files[0]->name, "config.h" ))
286 fatal_error( "%s:%d: config.h must be included before wine/port.h\n",
287 pFile->filename, line );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000288 }
289
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200290 LIST_FOR_EACH_ENTRY( include, &includes, INCL_FILE, entry )
291 if (!strcmp( name, include->name )) goto found;
292
293 include = xmalloc( sizeof(INCL_FILE) );
294 memset( include, 0, sizeof(INCL_FILE) );
295 include->name = xstrdup(name);
296 include->included_by = pFile;
297 include->included_line = line;
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200298 include->system = system;
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200299 list_add_tail( &includes, &include->entry );
300found:
301 pFile->files[pos] = include;
302 return include;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000303}
304
305
306/*******************************************************************
307 * open_src_file
308 */
309static FILE *open_src_file( INCL_FILE *pFile )
310{
311 FILE *file;
312
Alexandre Julliard184c40a2002-12-11 01:30:14 +0000313 /* first try name as is */
314 if ((file = fopen( pFile->name, "r" )))
315 {
316 pFile->filename = xstrdup( pFile->name );
317 return file;
318 }
319 /* now try in source dir */
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200320 if (src_dir)
Alexandre Julliard530ee841996-10-23 16:59:13 +0000321 {
Alexandre Julliardded32d52006-08-01 12:37:18 +0200322 pFile->filename = strmake( "%s/%s", src_dir, pFile->name );
Alexandre Julliard184c40a2002-12-11 01:30:14 +0000323 file = fopen( pFile->filename, "r" );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000324 }
Alexandre Julliard184c40a2002-12-11 01:30:14 +0000325 if (!file)
Alexandre Julliard530ee841996-10-23 16:59:13 +0000326 {
Alexandre Julliard184c40a2002-12-11 01:30:14 +0000327 perror( pFile->name );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000328 exit(1);
329 }
330 return file;
331}
332
333
334/*******************************************************************
335 * open_include_file
336 */
337static FILE *open_include_file( INCL_FILE *pFile )
338{
339 FILE *file = NULL;
Alexandre Julliardded32d52006-08-01 12:37:18 +0200340 char *filename, *p;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000341 INCL_PATH *path;
342
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200343 errno = ENOENT;
344
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200345 /* check for generated bison header */
346
347 if (strendswith( pFile->name, ".tab.h" ))
348 {
349 if (src_dir)
350 filename = strmake( "%s/%.*s.y", src_dir, strlen(pFile->name) - 6, pFile->name );
351 else
352 filename = strmake( "%.*s.y", strlen(pFile->name) - 6, pFile->name );
353
354 if ((file = fopen( filename, "r" )))
355 {
356 pFile->sourcename = filename;
357 pFile->filename = xstrdup( pFile->name );
358 /* don't bother to parse it */
359 fclose( file );
360 return NULL;
361 }
362 free( filename );
363 }
364
365 /* check for generated message resource */
366
367 if (strendswith( pFile->name, ".mc.rc" ))
368 {
369 if (src_dir)
370 filename = strmake( "%s/%s", src_dir, pFile->name );
371 else
372 filename = xstrdup( pFile->name );
373
374 filename[strlen(filename) - 3] = 0;
375
376 if ((file = fopen( filename, "r" )))
377 {
378 pFile->sourcename = filename;
379 pFile->filename = xstrdup( pFile->name );
380 /* don't bother to parse it */
381 fclose( file );
382 return NULL;
383 }
384 free( filename );
385 }
386
387 /* check for corresponding idl file in source dir */
388
389 if (strendswith( pFile->name, ".h" ))
390 {
391 if (src_dir)
392 filename = strmake( "%s/%.*s.idl", src_dir, strlen(pFile->name) - 2, pFile->name );
393 else
394 filename = strmake( "%.*s.idl", strlen(pFile->name) - 2, pFile->name );
395
396 if ((file = fopen( filename, "r" )))
397 {
398 pFile->sourcename = filename;
399 pFile->filename = xstrdup( pFile->name );
400 return file;
401 }
402 free( filename );
403 }
404
Alexandre Julliardded32d52006-08-01 12:37:18 +0200405 /* first try name as is */
406 if ((file = fopen( pFile->name, "r" )))
Alexandre Julliard530ee841996-10-23 16:59:13 +0000407 {
Alexandre Julliardded32d52006-08-01 12:37:18 +0200408 pFile->filename = xstrdup( pFile->name );
409 return file;
410 }
411
412 /* now try in source dir */
413 if (src_dir)
414 {
415 filename = strmake( "%s/%s", src_dir, pFile->name );
416 if ((file = fopen( filename, "r" ))) goto found;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000417 free( filename );
418 }
Alexandre Julliardded32d52006-08-01 12:37:18 +0200419
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200420 /* check for corresponding idl file in global includes */
421
422 if (strendswith( pFile->name, ".h" ))
423 {
424 if (top_src_dir)
425 filename = strmake( "%s/include/%.*s.idl",
426 top_src_dir, strlen(pFile->name) - 2, pFile->name );
427 else if (top_obj_dir)
428 filename = strmake( "%s/include/%.*s.idl",
429 top_obj_dir, strlen(pFile->name) - 2, pFile->name );
430 else
431 filename = NULL;
432
433 if (filename && (file = fopen( filename, "r" )))
434 {
435 pFile->sourcename = filename;
436 pFile->filename = strmake( "%s/include/%s", top_obj_dir, pFile->name );
437 return file;
438 }
439 free( filename );
440 }
441
Alexandre Julliardded32d52006-08-01 12:37:18 +0200442 /* now try in global includes */
443 if (top_obj_dir)
444 {
445 filename = strmake( "%s/include/%s", top_obj_dir, pFile->name );
446 if ((file = fopen( filename, "r" ))) goto found;
447 free( filename );
448 }
449 if (top_src_dir)
450 {
451 filename = strmake( "%s/include/%s", top_src_dir, pFile->name );
452 if ((file = fopen( filename, "r" ))) goto found;
453 free( filename );
454 }
455
456 /* now search in include paths */
457 LIST_FOR_EACH_ENTRY( path, &paths, INCL_PATH, entry )
458 {
459 filename = strmake( "%s/%s", path->name, pFile->name );
460 if ((file = fopen( filename, "r" ))) goto found;
461 free( filename );
462 }
463 if (pFile->system) return NULL; /* ignore system files we cannot find */
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000464
Eric Pouechd848c252000-12-13 21:27:26 +0000465 /* try in src file directory */
Alexandre Julliardded32d52006-08-01 12:37:18 +0200466 if ((p = strrchr(pFile->included_by->filename, '/')))
Eric Pouechd848c252000-12-13 21:27:26 +0000467 {
Alexandre Julliardded32d52006-08-01 12:37:18 +0200468 int l = p - pFile->included_by->filename + 1;
469 filename = xmalloc(l + strlen(pFile->name) + 1);
470 memcpy( filename, pFile->included_by->filename, l );
471 strcpy( filename + l, pFile->name );
472 if ((file = fopen( filename, "r" ))) goto found;
473 free( filename );
Eric Pouechd848c252000-12-13 21:27:26 +0000474 }
475
Alexandre Julliardded32d52006-08-01 12:37:18 +0200476 perror( pFile->name );
477 while (pFile->included_by)
Alexandre Julliard530ee841996-10-23 16:59:13 +0000478 {
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200479 const char *parent = pFile->included_by->sourcename;
480 if (!parent) parent = pFile->included_by->name;
Alexandre Julliardded32d52006-08-01 12:37:18 +0200481 fprintf( stderr, " %s was first included from %s:%d\n",
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200482 pFile->name, parent, pFile->included_line );
Alexandre Julliardded32d52006-08-01 12:37:18 +0200483 pFile = pFile->included_by;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000484 }
Alexandre Julliardded32d52006-08-01 12:37:18 +0200485 exit(1);
486
487found:
488 pFile->filename = filename;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000489 return file;
490}
491
492
493/*******************************************************************
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000494 * parse_idl_file
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200495 *
496 * If for_h_file is non-zero, it means we are not interested in the idl file
497 * itself, but only in the contents of the .h file that will be generated from it.
Alexandre Julliard530ee841996-10-23 16:59:13 +0000498 */
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200499static void parse_idl_file( INCL_FILE *pFile, FILE *file, int for_h_file )
Alexandre Julliard530ee841996-10-23 16:59:13 +0000500{
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200501 char *buffer, *include;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000502
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200503 if (for_h_file)
504 {
505 /* generated .h file always includes these */
506 add_include( pFile, "rpc.h", 0, 1 );
507 add_include( pFile, "rpcndr.h", 0, 1 );
508 }
509
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200510 input_line = 0;
511 while ((buffer = get_line( file )))
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000512 {
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000513 char quote;
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000514 char *p = buffer;
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000515 while (*p && isspace(*p)) p++;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000516
517 if (!strncmp( p, "import", 6 ))
518 {
519 p += 6;
520 while (*p && isspace(*p)) p++;
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200521 if (*p != '"') continue;
522 include = ++p;
523 while (*p && (*p != '"')) p++;
524 if (!*p) fatal_error( "%s:%d: Malformed import directive\n", pFile->filename, input_line );
525 *p = 0;
526 if (for_h_file && strendswith( include, ".idl" )) strcpy( p - 4, ".h" );
527 add_include( pFile, include, input_line, 0 );
528 continue;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000529 }
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200530
531 if (for_h_file) /* only check for #include inside cpp_quote */
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000532 {
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200533 if (strncmp( p, "cpp_quote", 9 )) continue;
534 p += 9;
535 while (*p && isspace(*p)) p++;
536 if (*p++ != '(') continue;
537 while (*p && isspace(*p)) p++;
538 if (*p++ != '"') continue;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000539 if (*p++ != '#') continue;
540 while (*p && isspace(*p)) p++;
541 if (strncmp( p, "include", 7 )) continue;
542 p += 7;
543 while (*p && isspace(*p)) p++;
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200544 if (*p == '\\' && p[1] == '"')
545 {
546 p += 2;
547 quote = '"';
548 }
549 else
550 {
551 if (*p++ != '<' ) continue;
552 quote = '>';
553 }
554 include = p;
555 while (*p && (*p != quote)) p++;
556 if (!*p || (quote == '"' && p[-1] != '\\'))
557 fatal_error( "%s:%d: Malformed #include directive inside cpp_quote\n",
558 pFile->filename, input_line );
559 if (quote == '"') p--; /* remove backslash */
560 *p = 0;
561 add_include( pFile, include, input_line, (quote == '>') );
562 continue;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000563 }
564
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200565 /* check for normal #include */
566 if (*p++ != '#') continue;
567 while (*p && isspace(*p)) p++;
568 if (strncmp( p, "include", 7 )) continue;
569 p += 7;
570 while (*p && isspace(*p)) p++;
571 if (*p != '\"' && *p != '<' ) continue;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000572 quote = *p++;
573 if (quote == '<') quote = '>';
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000574 include = p;
Alexandre Julliard0bcf7752003-06-20 21:31:13 +0000575 while (*p && (*p != quote)) p++;
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200576 if (!*p) fatal_error( "%s:%d: Malformed #include directive\n", pFile->filename, input_line );
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000577 *p = 0;
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200578 add_include( pFile, include, input_line, (quote == '>') );
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000579 }
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000580}
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000581
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000582/*******************************************************************
583 * parse_c_file
584 */
585static void parse_c_file( INCL_FILE *pFile, FILE *file )
586{
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200587 char *buffer, *include;
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000588
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200589 input_line = 0;
590 while ((buffer = get_line( file )))
Alexandre Julliard530ee841996-10-23 16:59:13 +0000591 {
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000592 char quote;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000593 char *p = buffer;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000594 while (*p && isspace(*p)) p++;
595 if (*p++ != '#') continue;
596 while (*p && isspace(*p)) p++;
597 if (strncmp( p, "include", 7 )) continue;
598 p += 7;
599 while (*p && isspace(*p)) p++;
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000600 if (*p != '\"' && *p != '<' ) continue;
601 quote = *p++;
602 if (quote == '<') quote = '>';
Alexandre Julliard530ee841996-10-23 16:59:13 +0000603 include = p;
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000604 while (*p && (*p != quote)) p++;
Alexandre Julliardffca0d62004-04-07 04:00:16 +0000605 if (!*p) fatal_error( "%s:%d: Malformed #include directive\n",
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200606 pFile->filename, input_line );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000607 *p = 0;
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200608 add_include( pFile, include, input_line, (quote == '>') );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000609 }
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000610}
611
612
613/*******************************************************************
Alexandre Julliardf92ef1c2006-12-26 15:02:03 +0100614 * parse_rc_file
615 */
616static void parse_rc_file( INCL_FILE *pFile, FILE *file )
617{
618 char *buffer, *include;
619
620 input_line = 0;
621 while ((buffer = get_line( file )))
622 {
623 char quote;
624 char *p = buffer;
625 while (*p && isspace(*p)) p++;
626
627 if (p[0] == '/' && p[1] == '*') /* check for magic makedep comment */
628 {
629 p += 2;
630 while (*p && isspace(*p)) p++;
631 if (strncmp( p, "@makedep:", 9 )) continue;
632 p += 9;
633 while (*p && isspace(*p)) p++;
634 quote = '"';
635 if (*p == quote)
636 {
637 include = ++p;
638 while (*p && *p != quote) p++;
639 }
640 else
641 {
642 include = p;
643 while (*p && !isspace(*p) && *p != '*') p++;
644 }
645 if (!*p)
646 fatal_error( "%s:%d: Malformed makedep comment\n", pFile->filename, input_line );
647 *p = 0;
648 }
649 else /* check for #include */
650 {
651 if (*p++ != '#') continue;
652 while (*p && isspace(*p)) p++;
653 if (strncmp( p, "include", 7 )) continue;
654 p += 7;
655 while (*p && isspace(*p)) p++;
656 if (*p != '\"' && *p != '<' ) continue;
657 quote = *p++;
658 if (quote == '<') quote = '>';
659 include = p;
660 while (*p && (*p != quote)) p++;
661 if (!*p) fatal_error( "%s:%d: Malformed #include directive\n",
662 pFile->filename, input_line );
663 *p = 0;
664 }
665 add_include( pFile, include, input_line, (quote == '>') );
666 }
667}
668
669
670/*******************************************************************
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200671 * parse_generated_idl
672 */
673static void parse_generated_idl( INCL_FILE *source )
674{
675 char *header, *basename;
676
677 basename = xstrdup( source->name );
678 basename[strlen(basename) - 4] = 0;
679 header = strmake( "%s.h", basename );
680 source->filename = xstrdup( source->name );
681
682 if (strendswith( source->name, "_c.c" ))
683 {
684 add_include( source, header, 0, 0 );
685 }
686 else if (strendswith( source->name, "_i.c" ))
687 {
688 add_include( source, "rpc.h", 0, 1 );
689 add_include( source, "rpcndr.h", 0, 1 );
690 add_include( source, "guiddef.h", 0, 1 );
691 }
692 else if (strendswith( source->name, "_p.c" ))
693 {
Alexandre Julliard75c21842007-01-19 13:17:17 +0100694 add_include( source, "objbase.h", 0, 1 );
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200695 add_include( source, "rpcproxy.h", 0, 1 );
Alexandre Julliardd8202082008-07-03 12:59:50 +0200696 add_include( source, "wine/exception.h", 0, 1 );
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200697 add_include( source, header, 0, 0 );
698 }
699 else if (strendswith( source->name, "_s.c" ))
700 {
Alexandre Julliardd8202082008-07-03 12:59:50 +0200701 add_include( source, "wine/exception.h", 0, 1 );
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200702 add_include( source, header, 0, 0 );
703 }
Alexandre Julliardb9966052007-12-10 14:26:25 +0100704 else if (!strcmp( source->name, "dlldata.c" ))
705 {
706 add_include( source, "objbase.h", 0, 1 );
707 add_include( source, "rpcproxy.h", 0, 1 );
708 }
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200709
710 free( header );
711 free( basename );
712}
713
714/*******************************************************************
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000715 * parse_file
716 */
717static void parse_file( INCL_FILE *pFile, int src )
718{
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000719 FILE *file;
720
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200721 /* special case for source files generated from idl */
722 if (strendswith( pFile->name, "_c.c" ) ||
723 strendswith( pFile->name, "_i.c" ) ||
724 strendswith( pFile->name, "_p.c" ) ||
Alexandre Julliardb9966052007-12-10 14:26:25 +0100725 strendswith( pFile->name, "_s.c" ) ||
726 !strcmp( pFile->name, "dlldata.c" ))
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200727 {
728 parse_generated_idl( pFile );
729 return;
730 }
731
Alexandre Julliard5f4f2c02008-04-24 23:43:04 +0200732 /* don't try to open .tlb files */
733 if (strendswith( pFile->name, ".tlb" ))
734 {
735 pFile->filename = xstrdup( pFile->name );
736 return;
737 }
738
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000739 file = src ? open_src_file( pFile ) : open_include_file( pFile );
740 if (!file) return;
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200741
742 if (pFile->sourcename && strendswith( pFile->sourcename, ".idl" ))
743 parse_idl_file( pFile, file, 1 );
744 else if (strendswith( pFile->filename, ".idl" ))
745 parse_idl_file( pFile, file, 0 );
Alexandre Julliardf92ef1c2006-12-26 15:02:03 +0100746 else if (strendswith( pFile->filename, ".c" ) ||
747 strendswith( pFile->filename, ".h" ) ||
748 strendswith( pFile->filename, ".l" ) ||
749 strendswith( pFile->filename, ".y" ))
Alexandre Julliarde4fca882006-09-10 22:04:42 +0200750 parse_c_file( pFile, file );
Alexandre Julliardf92ef1c2006-12-26 15:02:03 +0100751 else if (strendswith( pFile->filename, ".rc" ))
752 parse_rc_file( pFile, file );
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000753 fclose(file);
Alexandre Julliard530ee841996-10-23 16:59:13 +0000754}
755
756
757/*******************************************************************
Alexandre Julliardb9966052007-12-10 14:26:25 +0100758 * add_src_file
759 *
760 * Add a source file to the list.
761 */
762static INCL_FILE *add_src_file( const char *name )
763{
764 INCL_FILE *file;
765
766 if (find_src_file( name )) return NULL; /* we already have it */
767 file = xmalloc( sizeof(*file) );
768 memset( file, 0, sizeof(*file) );
769 file->name = xstrdup(name);
770 list_add_tail( &sources, &file->entry );
771 parse_file( file, 1 );
772 return file;
773}
774
775
776/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000777 * output_include
778 */
779static void output_include( FILE *file, INCL_FILE *pFile,
780 INCL_FILE *owner, int *column )
781{
782 int i;
783
784 if (pFile->owner == owner) return;
Alexandre Julliardfed8f1c2002-02-15 19:57:27 +0000785 if (!pFile->filename) return;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000786 pFile->owner = owner;
787 if (*column + strlen(pFile->filename) + 1 > 70)
788 {
789 fprintf( file, " \\\n" );
790 *column = 0;
791 }
792 fprintf( file, " %s", pFile->filename );
793 *column += strlen(pFile->filename) + 1;
794 for (i = 0; i < MAX_INCLUDES; i++)
795 if (pFile->files[i]) output_include( file, pFile->files[i],
796 owner, column );
797}
798
799
800/*******************************************************************
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000801 * output_src
802 */
Alexandre Julliardda191222008-04-24 22:13:57 +0200803static int output_src( FILE *file, INCL_FILE *pFile, int *column )
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000804{
Alexandre Julliard2d4b33a2000-03-19 21:20:16 +0000805 char *obj = xstrdup( pFile->name );
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000806 char *ext = get_extension( obj );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000807 if (ext)
808 {
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000809 *ext++ = 0;
810 if (!strcmp( ext, "y" )) /* yacc file */
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000811 {
Alexandre Julliardcd91bc62005-09-28 18:17:08 +0000812 *column += fprintf( file, "%s.tab.o: %s.tab.c", obj, obj );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000813 }
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000814 else if (!strcmp( ext, "l" )) /* lex file */
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000815 {
Alexandre Julliard560c9ee2006-09-09 13:16:59 +0200816 *column += fprintf( file, "%s.yy.o: %s.yy.c", obj, obj );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000817 }
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000818 else if (!strcmp( ext, "rc" )) /* resource file */
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000819 {
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000820 *column += fprintf( file, "%s.res: %s", obj, pFile->filename );
821 }
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000822 else if (!strcmp( ext, "mc" )) /* message file */
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000823 {
Alexandre Julliardd19ad392000-11-06 05:32:59 +0000824 *column += fprintf( file, "%s.mc.rc: %s", obj, pFile->filename );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000825 }
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000826 else if (!strcmp( ext, "idl" )) /* IDL file */
827 {
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200828 char *name;
Alexandre Julliardda191222008-04-24 22:13:57 +0200829 int got_header = 0;
830 const char *suffix = "cips";
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200831
Alexandre Julliardda191222008-04-24 22:13:57 +0200832 name = strmake( "%s.tlb", obj );
833 if (find_src_file( name )) *column += fprintf( file, "%s", name );
834 else
835 {
836 got_header = 1;
837 *column += fprintf( file, "%s.h", obj );
838 }
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200839 free( name );
840
Alexandre Julliardda191222008-04-24 22:13:57 +0200841 while (*suffix)
842 {
843 name = strmake( "%s_%c.c", obj, *suffix );
844 if (find_src_file( name ))
845 {
846 if (!got_header++) *column += fprintf( file, " %s.h", obj );
847 *column += fprintf( file, " %s", name );
848 }
849 free( name );
850 suffix++;
851 }
Alexandre Julliard8f31f922006-10-16 17:19:07 +0200852 *column += fprintf( file, ": %s", pFile->filename );
Alexandre Julliardaa89ecc2003-04-11 00:38:56 +0000853 }
Alexandre Julliardda191222008-04-24 22:13:57 +0200854 else if (!strcmp( ext, "tlb" ))
855 {
856 return 0; /* nothing to do for typelib files */
857 }
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000858 else
859 {
Alexandre Julliard21ec0062000-10-23 21:39:39 +0000860 *column += fprintf( file, "%s.o: %s", obj, pFile->filename );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000861 }
862 }
863 free( obj );
Alexandre Julliardda191222008-04-24 22:13:57 +0200864 return 1;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000865}
866
867
868/*******************************************************************
Alexandre Julliard530ee841996-10-23 16:59:13 +0000869 * output_dependencies
870 */
871static void output_dependencies(void)
872{
873 INCL_FILE *pFile;
874 int i, column;
875 FILE *file = NULL;
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200876 char *buffer;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000877
878 if (Separator && ((file = fopen( OutputFileName, "r+" ))))
879 {
Alexandre Julliardb7ef1b22006-08-01 12:16:29 +0200880 while ((buffer = get_line( file )))
Alexandre Julliard1b9535a2006-09-22 09:25:49 +0200881 {
882 if (strncmp( buffer, Separator, strlen(Separator) )) continue;
883 ftruncate( fileno(file), ftell(file) );
884 fseek( file, 0L, SEEK_END );
885 break;
886 }
Alexandre Julliard530ee841996-10-23 16:59:13 +0000887 }
888 if (!file)
889 {
Dimitrie O. Paunb631a812000-12-05 03:57:35 +0000890 if (!(file = fopen( OutputFileName, Separator ? "a" : "w" )))
Alexandre Julliard530ee841996-10-23 16:59:13 +0000891 {
892 perror( OutputFileName );
893 exit(1);
894 }
895 }
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200896 LIST_FOR_EACH_ENTRY( pFile, &sources, INCL_FILE, entry )
Alexandre Julliard530ee841996-10-23 16:59:13 +0000897 {
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000898 column = 0;
Alexandre Julliardda191222008-04-24 22:13:57 +0200899 if (!output_src( file, pFile, &column )) continue;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000900 for (i = 0; i < MAX_INCLUDES; i++)
901 if (pFile->files[i]) output_include( file, pFile->files[i],
902 pFile, &column );
903 fprintf( file, "\n" );
904 }
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000905 fclose(file);
Alexandre Julliard530ee841996-10-23 16:59:13 +0000906}
907
908
909/*******************************************************************
910 * parse_option
911 */
912static void parse_option( const char *opt )
913{
914 switch(opt[1])
915 {
916 case 'I':
917 if (opt[2]) add_include_path( opt + 2 );
918 break;
919 case 'C':
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200920 src_dir = opt + 2;
921 break;
922 case 'S':
923 top_src_dir = opt + 2;
924 break;
925 case 'T':
926 top_obj_dir = opt + 2;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000927 break;
928 case 'f':
929 if (opt[2]) OutputFileName = opt + 2;
930 break;
931 case 's':
932 if (opt[2]) Separator = opt + 2;
933 else Separator = NULL;
934 break;
935 default:
936 fprintf( stderr, "Unknown option '%s'\n", opt );
937 fprintf( stderr, Usage, ProgramName );
938 exit(1);
939 }
940}
941
942
943/*******************************************************************
944 * main
945 */
946int main( int argc, char *argv[] )
947{
948 INCL_FILE *pFile;
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200949 INCL_PATH *path, *next;
950 int i, j;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000951
952 ProgramName = argv[0];
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200953
954 i = 1;
955 while (i < argc)
Alexandre Julliard530ee841996-10-23 16:59:13 +0000956 {
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200957 if (argv[i][0] == '-')
Alexandre Julliard530ee841996-10-23 16:59:13 +0000958 {
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200959 parse_option( argv[i] );
960 for (j = i; j < argc; j++) argv[j] = argv[j+1];
961 argc--;
Alexandre Julliard530ee841996-10-23 16:59:13 +0000962 }
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200963 else i++;
964 }
965
Alexandre Julliardded32d52006-08-01 12:37:18 +0200966 /* ignore redundant source paths */
967 if (src_dir && !strcmp( src_dir, "." )) src_dir = NULL;
968 if (top_src_dir && top_obj_dir && !strcmp( top_src_dir, top_obj_dir )) top_src_dir = NULL;
969
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200970 /* get rid of absolute paths that don't point into the source dir */
971 LIST_FOR_EACH_ENTRY_SAFE( path, next, &paths, INCL_PATH, entry )
972 {
973 if (path->name[0] != '/') continue;
974 if (top_src_dir)
975 {
Alexandre Julliard4fff18b2007-03-01 15:21:39 +0100976 if (!strncmp( path->name, top_src_dir, strlen(top_src_dir) ) &&
977 path->name[strlen(top_src_dir)] == '/') continue;
Alexandre Julliarddea28ee2006-08-01 12:27:22 +0200978 }
979 list_remove( &path->entry );
980 free( path );
981 }
982
983 for (i = 1; i < argc; i++)
984 {
Alexandre Julliardb9966052007-12-10 14:26:25 +0100985 add_src_file( argv[i] );
986 if (strendswith( argv[i], "_p.c" )) add_src_file( "dlldata.c" );
Alexandre Julliard530ee841996-10-23 16:59:13 +0000987 }
Alexandre Julliardf25c4d42006-08-01 12:13:57 +0200988 LIST_FOR_EACH_ENTRY( pFile, &includes, INCL_FILE, entry ) parse_file( pFile, 0 );
Alexandre Julliard1b9535a2006-09-22 09:25:49 +0200989 output_dependencies();
Alexandre Julliard530ee841996-10-23 16:59:13 +0000990 return 0;
991}