Newer
Older
* Copyright 1996, 2013 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "config.h"
#define NO_LIBWINE_PORT
#include "wine/port.h"

Alexandre Julliard
committed
#include <assert.h>
#include <stdarg.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
char *sourcename; /* source file name for generated headers */

Alexandre Julliard
committed
char *args; /* custom arguments for makefile rule */
struct incl_file *included_by; /* file that included this one */
int included_line; /* line where this file was included */

Alexandre Julliard
committed
unsigned int flags; /* flags (see below) */
unsigned int files_count; /* files in use */
unsigned int files_size; /* total allocated size */
struct incl_file **files;

Alexandre Julliard
committed
#define FLAG_SYSTEM 0x000001 /* is it a system include (#include <name>) */
#define FLAG_GENERATED 0x000002 /* generated file */
#define FLAG_INSTALL 0x000004 /* file to install */
#define FLAG_IDL_PROXY 0x000100 /* generates a proxy (_p.c) file */
#define FLAG_IDL_CLIENT 0x000200 /* generates a client (_c.c) file */
#define FLAG_IDL_SERVER 0x000400 /* generates a server (_s.c) file */
#define FLAG_IDL_IDENT 0x000800 /* generates an ident (_i.c) file */
#define FLAG_IDL_REGISTER 0x001000 /* generates a registration (_r.res) file */
#define FLAG_IDL_TYPELIB 0x002000 /* generates a typelib (.tlb) file */
#define FLAG_IDL_REGTYPELIB 0x004000 /* generates a registered typelib (_t.res) file */
#define FLAG_IDL_HEADER 0x008000 /* generates a header (.h) file */
#define FLAG_RC_PO 0x010000 /* rc file contains translations */
#define FLAG_C_IMPLIB 0x020000 /* file is part of an import library */

Alexandre Julliard
committed
static const struct
{
unsigned int flag;
const char *ext;
} idl_outputs[] =
{
{ FLAG_IDL_TYPELIB, ".tlb" },
{ FLAG_IDL_REGTYPELIB, "_t.res" },
{ FLAG_IDL_CLIENT, "_c.c" },
{ FLAG_IDL_IDENT, "_i.c" },
{ FLAG_IDL_PROXY, "_p.c" },
{ FLAG_IDL_SERVER, "_s.c" },
{ FLAG_IDL_REGISTER, "_r.res" },
{ FLAG_IDL_HEADER, ".h" }

Alexandre Julliard
committed
};
static struct list sources = LIST_INIT(sources);
static struct list includes = LIST_INIT(includes);
struct strarray
{
unsigned int count; /* strings in use */
unsigned int size; /* total allocated size */
const char **str;
};
static const struct strarray empty_strarray;
static struct strarray include_args;
static struct strarray define_args;

Alexandre Julliard
committed
static struct strarray appmode;
static struct strarray dllflags;
static struct strarray imports;
static struct strarray make_vars;
static struct strarray cmdline_vars;

Alexandre Julliard
committed
static const char *base_dir;
static const char *src_dir;
static const char *top_src_dir;
static const char *top_obj_dir;

Alexandre Julliard
committed
static const char *parent_dir;
static const char *tools_dir;
static const char *tools_ext;

Alexandre Julliard
committed
static const char *makefile_name = "Makefile";
static const char *input_file_name;
static const char *output_file_name;
static const char *temp_file_name;
static int relative_dir_mode;

Alexandre Julliard
committed
static int input_line;
static int output_column;
static FILE *output_file;

Alexandre Julliard
committed
"Usage: makedep [options] directories\n"

Alexandre Julliard
committed
" -R from to Compute the relative path between two directories\n"
" -fxxx Store output in file 'xxx' (default: Makefile)\n"
" -sxxx Use 'xxx' as separator (default: \"### Dependencies\")\n";
#ifndef __GNUC__
#define __attribute__(x)
#endif
static void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
static void fatal_perror( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
static void output( const char *format, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));

Alexandre Julliard
committed
static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
/*******************************************************************
* fatal_error
*/
static void fatal_error( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (input_line) fprintf( stderr, "%d:", input_line );
fprintf( stderr, " error: " );
}
else fprintf( stderr, "makedep: error: " );
vfprintf( stderr, msg, valist );
va_end( valist );
exit(1);
}
/*******************************************************************
* fatal_perror
*/
static void fatal_perror( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (input_line) fprintf( stderr, "%d:", input_line );

Alexandre Julliard
committed
fprintf( stderr, " error: " );

Alexandre Julliard
committed
else fprintf( stderr, "makedep: error: " );
vfprintf( stderr, msg, valist );
perror( " " );
va_end( valist );
exit(1);
}
/*******************************************************************
* cleanup_files
*/
static void cleanup_files(void)
{
if (temp_file_name) unlink( temp_file_name );
if (output_file_name) unlink( output_file_name );
}
/*******************************************************************
* exit_on_signal
*/
static void exit_on_signal( int sig )
{
exit( 1 ); /* this will call the atexit functions */
}
/*******************************************************************
* xmalloc
*/

Alexandre Julliard
committed
static void *xmalloc( size_t size )
{
void *res;
if (!(res = malloc (size ? size : 1)))
fatal_error( "Virtual memory exhausted.\n" );

Alexandre Julliard
committed
/*******************************************************************
* xrealloc
*/
static void *xrealloc (void *ptr, size_t size)

Alexandre Julliard
committed
{
void *res;
assert( size );
if (!(res = realloc( ptr, size )))
fatal_error( "Virtual memory exhausted.\n" );

Alexandre Julliard
committed
return res;
}
/*******************************************************************
* xstrdup
*/
static char *xstrdup( const char *str )
{
char *res = strdup( str );
if (!res) fatal_error( "Virtual memory exhausted.\n" );

Alexandre Julliard
committed
/*******************************************************************
* strmake
*/
static char *strmake( const char* fmt, ... )

Alexandre Julliard
committed
{
int n;
size_t size = 100;
va_list ap;
for (;;)
{
char *p = xmalloc (size);
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
if (n == -1) size *= 2;
else if ((size_t)n >= size) size = n + 1;
else return p;
free(p);
}
}
/*******************************************************************
* strendswith
*/
static int strendswith( const char* str, const char* end )
{
int l = strlen(str);
int m = strlen(end);
return l >= m && strcmp(str + l - m, end) == 0;
}
/*******************************************************************
* output
*/
static void output( const char *format, ... )
{
int ret;
va_list valist;
va_start( valist, format );
ret = vfprintf( output_file, format, valist );
va_end( valist );
if (ret < 0) fatal_perror( "output" );
if (format[0] && format[strlen(format) - 1] == '\n') output_column = 0;
else output_column += ret;
}
/*******************************************************************
* strarray_add
*/
static void strarray_add( struct strarray *array, const char *str )
{
if (array->count == array->size)
{
if (array->size) array->size *= 2;
else array->size = 16;
array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size );
}
array->str[array->count++] = str;
}
/*******************************************************************
* strarray_addall
*/
static void strarray_addall( struct strarray *array, struct strarray added )
{
unsigned int i;
for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] );
/*******************************************************************
* strarray_add_uniq
*/
static void strarray_add_uniq( struct strarray *array, const char *str )
{
unsigned int i;
for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return;
strarray_add( array, str );
}
/*******************************************************************
* output_filename
*/
static void output_filename( const char *name )
if (output_column + strlen(name) + 1 > 100)
output( " \\\n" );
output( " " );
else if (output_column) output( " " );
output( "%s", name );
}
/*******************************************************************
* output_filenames
*/
static void output_filenames( struct strarray array )
{
unsigned int i;
for (i = 0; i < array.count; i++) output_filename( array.str[i] );
}
/*******************************************************************
* get_extension
*/
static char *get_extension( char *filename )
{
char *ext = strrchr( filename, '.' );
if (ext && strchr( ext, '/' )) ext = NULL;
return ext;
}
/*******************************************************************
* replace_extension
*/
static char *replace_extension( const char *name, const char *old_ext, const char *new_ext )
char *ret;
int name_len = strlen( name );
int ext_len = strlen( old_ext );
if (name_len >= ext_len && !strcmp( name + name_len - ext_len, old_ext )) name_len -= ext_len;
ret = xmalloc( name_len + strlen( new_ext ) + 1 );
memcpy( ret, name, name_len );
strcpy( ret + name_len, new_ext );
return ret;
}
/*******************************************************************
* strarray_replace_extension
*/
static struct strarray strarray_replace_extension( const struct strarray *array,
const char *old_ext, const char *new_ext )
{
unsigned int i;
struct strarray ret;
ret.count = ret.size = array->count;
ret.str = xmalloc( sizeof(ret.str[0]) * ret.size );
for (i = 0; i < array->count; i++) ret.str[i] = replace_extension( array->str[i], old_ext, new_ext );
return ret;
}

Alexandre Julliard
committed
/*******************************************************************
* replace_substr
*/
static char *replace_substr( const char *str, const char *start, unsigned int len, const char *replace )
{
unsigned int pos = start - str;
char *ret = xmalloc( pos + strlen(replace) + strlen(start + len) + 1 );
memcpy( ret, str, pos );
strcpy( ret + pos, replace );
strcat( ret + pos, start + len );
return ret;
}
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/*******************************************************************
* get_relative_path
*
* Determine where the destination path is located relative to the 'from' path.
*/
static char *get_relative_path( const char *from, const char *dest )
{
const char *start;
char *ret, *p;
unsigned int dotdots = 0;
/* a path of "." is equivalent to an empty path */
if (!strcmp( from, "." )) from = "";
for (;;)
{
while (*from == '/') from++;
while (*dest == '/') dest++;
start = dest; /* save start of next path element */
if (!*from) break;
while (*from && *from != '/' && *from == *dest) { from++; dest++; }
if ((!*from || *from == '/') && (!*dest || *dest == '/')) continue;
/* count remaining elements in 'from' */
do
{
dotdots++;
while (*from && *from != '/') from++;
while (*from == '/') from++;
}
while (*from);
break;
}
if (!start[0] && !dotdots) return NULL; /* empty path */
ret = xmalloc( 3 * dotdots + strlen( start ) + 1 );
for (p = ret; dotdots; dotdots--, p += 3) memcpy( p, "../", 3 );
if (start[0]) strcpy( p, start );
else p[-1] = 0; /* remove trailing slash */
return ret;
}
/*******************************************************************
* base_dir_path
*/
static char *base_dir_path( const char *path )
{
if (base_dir && path[0] != '/') return strmake( "%s/%s", base_dir, path );
return xstrdup( path );
}
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/*******************************************************************
* src_dir_path
*/
static char *src_dir_path( const char *path )
{
if (src_dir) return strmake( "%s/%s", src_dir, path );
return xstrdup( path );
}
/*******************************************************************
* top_obj_dir_path
*/
static char *top_obj_dir_path( const char *path )
{
if (top_obj_dir) return strmake( "%s/%s", top_obj_dir, path );
return xstrdup( path );
}
/*******************************************************************
* top_dir_path
*/
static char *top_dir_path( const char *path )
{
if (top_src_dir) return strmake( "%s/%s", top_src_dir, path );
return top_obj_dir_path( path );
}
/*******************************************************************
* tools_dir_path
*/
static char *tools_dir_path( const char *path )
{
if (tools_dir) return strmake( "%s/tools/%s", tools_dir, path );
if (top_obj_dir) return strmake( "%s/tools/%s", top_obj_dir, path );
return strmake( "tools/%s", path );
}
/*******************************************************************
* tools_path
*/
static char *tools_path( const char *name )
{
if (tools_dir) return strmake( "%s/tools/%s/%s%s", tools_dir, name, name, tools_ext );
if (top_obj_dir) return strmake( "%s/tools/%s/%s%s", top_obj_dir, name, name, tools_ext );
return strmake( "tools/%s/%s%s", name, name, tools_ext );
}

Alexandre Julliard
committed
/*******************************************************************
* get_line
*/
static char *get_line( FILE *file )
{
static char *buffer;
static unsigned int size;
if (!size)
{
size = 1024;
buffer = xmalloc( size );
}
if (!fgets( buffer, size, file )) return NULL;
input_line++;
for (;;)
{
char *p = buffer + strlen(buffer);
/* if line is larger than buffer, resize buffer */
while (p == buffer + size - 1 && p[-1] != '\n')
{
buffer = xrealloc( buffer, size * 2 );
if (!fgets( buffer + size - 1, size + 1, file )) break;

Alexandre Julliard
committed
p = buffer + strlen(buffer);
size *= 2;
}
if (p > buffer && p[-1] == '\n')
{
*(--p) = 0;
if (p > buffer && p[-1] == '\r') *(--p) = 0;
if (p > buffer && p[-1] == '\\')
{
*(--p) = 0;
/* line ends in backslash, read continuation line */
if (!fgets( p, size - (p - buffer), file )) return buffer;

Alexandre Julliard
committed
input_line++;
continue;
}
}
return buffer;
}
}

Alexandre Julliard
committed
/*******************************************************************
* find_src_file
*/
static struct incl_file *find_src_file( const char *name )

Alexandre Julliard
committed
{

Alexandre Julliard
committed
LIST_FOR_EACH_ENTRY( file, &sources, struct incl_file, entry )

Alexandre Julliard
committed
if (!strcmp( name, file->name )) return file;
return NULL;
}

Alexandre Julliard
committed
/*******************************************************************
* find_include_file
*/
static struct incl_file *find_include_file( const char *name )

Alexandre Julliard
committed
{

Alexandre Julliard
committed
LIST_FOR_EACH_ENTRY( file, &includes, struct incl_file, entry )

Alexandre Julliard
committed
if (!strcmp( name, file->name )) return file;
return NULL;
}
/*******************************************************************
* add_include
*
* Add an include file if it doesn't already exists.
*/
static struct incl_file *add_include( struct incl_file *parent, const char *name, int system )
struct incl_file *include;
char *ext;
if (parent->files_count >= parent->files_size)
{
parent->files_size *= 2;
if (parent->files_size < 16) parent->files_size = 16;
parent->files = xrealloc( parent->files, parent->files_size * sizeof(*parent->files) );
}
/* enforce some rules for the Wine tree */
if (!memcmp( name, "../", 3 ))
fatal_error( "#include directive with relative path not allowed\n" );
if (!strcmp( name, "config.h" ))
if ((ext = strrchr( parent->filename, '.' )) && !strcmp( ext, ".h" ))
fatal_error( "config.h must not be included by a header file\n" );
if (parent->files_count)
fatal_error( "config.h must be included before anything else\n" );
}
else if (!strcmp( name, "wine/port.h" ))
{
if ((ext = strrchr( parent->filename, '.' )) && !strcmp( ext, ".h" ))
fatal_error( "wine/port.h must not be included by a header file\n" );
if (!parent->files_count) fatal_error( "config.h must be included before wine/port.h\n" );
if (parent->files_count > 1)
fatal_error( "wine/port.h must be included before everything except config.h\n" );
if (strcmp( parent->files[0]->name, "config.h" ))
fatal_error( "config.h must be included before wine/port.h\n" );
LIST_FOR_EACH_ENTRY( include, &includes, struct incl_file, entry )
if (!strcmp( name, include->name )) goto found;
include = xmalloc( sizeof(*include) );
memset( include, 0, sizeof(*include) );
include->name = xstrdup(name);
include->included_by = parent;
include->included_line = input_line;

Alexandre Julliard
committed
if (system) include->flags |= FLAG_SYSTEM;
list_add_tail( &includes, &include->entry );
found:
parent->files[parent->files_count++] = include;

Alexandre Julliard
committed
/*******************************************************************
* add_generated_source
*
* Add a generated source file to the list.
*/
static struct incl_file *add_generated_source( const char *name, const char *filename )
{
struct incl_file *file;
if ((file = find_src_file( name ))) return file; /* we already have it */
file = xmalloc( sizeof(*file) );
memset( file, 0, sizeof(*file) );
file->name = xstrdup( name );
file->filename = xstrdup( filename ? filename : name );
file->flags = FLAG_GENERATED;
list_add_tail( &sources, &file->entry );
return file;
}

Alexandre Julliard
committed
/*******************************************************************
* open_file
*/
static FILE *open_file( const char *path )
{
return fopen( base_dir_path( path ), "r" );

Alexandre Julliard
committed
}
/*******************************************************************
* open_src_file
*/
static FILE *open_src_file( struct incl_file *pFile )
/* first try name as is */

Alexandre Julliard
committed
if ((file = open_file( pFile->name )))
{
pFile->filename = xstrdup( pFile->name );
return file;
}
/* now try in source dir */
pFile->filename = src_dir_path( pFile->name );

Alexandre Julliard
committed
file = open_file( pFile->filename );

Alexandre Julliard
committed
/* now try parent dir */
if (!file && parent_dir)
{
pFile->filename = src_dir_path( strmake( "%s/%s", parent_dir, pFile->name ));

Alexandre Julliard
committed
file = open_file( pFile->filename );

Alexandre Julliard
committed
}
if (!file) fatal_perror( "open %s", pFile->name );
return file;
}
/*******************************************************************
* open_include_file
*/
static FILE *open_include_file( struct incl_file *pFile )

Alexandre Julliard
committed
char *filename, *p;
unsigned int i, len;
/* check for generated bison header */
if (strendswith( pFile->name, ".tab.h" ))
{
filename = src_dir_path( replace_extension( pFile->name, ".tab.h", ".y" ));

Alexandre Julliard
committed
if ((file = open_file( filename )))
{
pFile->sourcename = filename;
pFile->filename = xstrdup( pFile->name );
/* don't bother to parse it */
fclose( file );
return NULL;
}
free( filename );
}
/* check for corresponding idl file in source dir */
if (strendswith( pFile->name, ".h" ))
{
filename = src_dir_path( replace_extension( pFile->name, ".h", ".idl" ));

Alexandre Julliard
committed
if ((file = open_file( filename )))
{
pFile->sourcename = filename;
pFile->filename = xstrdup( pFile->name );
return file;
}
free( filename );
}

Alexandre Julliard
committed
/* now try in source dir */
filename = src_dir_path( pFile->name );

Alexandre Julliard
committed
if ((file = open_file( filename ))) goto found;
free( filename );

Alexandre Julliard
committed

Alexandre Julliard
committed
/* now try in parent source dir */
if (parent_dir)
{
filename = src_dir_path( strmake( "%s/%s", parent_dir, pFile->name ));

Alexandre Julliard
committed
if ((file = open_file( filename ))) goto found;

Alexandre Julliard
committed
free( filename );
}
/* check for corresponding idl file in global includes */
if (strendswith( pFile->name, ".h" ))
{
filename = top_dir_path( strmake( "include/%s", replace_extension( pFile->name, ".h", ".idl" )));
if ((file = open_file( filename )))
{
pFile->sourcename = filename;
pFile->filename = top_obj_dir_path( strmake( "include/%s", pFile->name ));
return file;
}
free( filename );
}
/* check for corresponding .in file in global includes (for config.h.in) */
if (strendswith( pFile->name, ".h" ))
{
filename = top_dir_path( strmake( "include/%s", replace_extension( pFile->name, ".h", ".h.in" )));
if ((file = open_file( filename )))
{
pFile->sourcename = filename;
pFile->filename = top_obj_dir_path( strmake( "include/%s", pFile->name ));
return file;
}
free( filename );
}
/* check for corresponding .x file in global includes */
if (strendswith( pFile->name, "tmpl.h" ))
{
filename = top_dir_path( strmake( "include/%s", replace_extension( pFile->name, ".h", ".x" )));
if ((file = open_file( filename )))
{
pFile->sourcename = filename;
pFile->filename = top_obj_dir_path( strmake( "include/%s", pFile->name ));
return file;
}
free( filename );
}

Alexandre Julliard
committed
/* now search in include paths */
for (i = 0; i < include_args.count; i++)
const char *dir = include_args.str[i] + 2; /* skip -I */
if (*dir == '/')
{
/* ignore absolute paths that don't point into the source dir */
if (!top_src_dir) continue;
len = strlen( top_src_dir );
if (strncmp( dir, top_src_dir, len )) continue;
if (dir[len] && dir[len] != '/') continue;
}
filename = strmake( "%s/%s", dir, pFile->name );

Alexandre Julliard
committed
if ((file = open_file( filename ))) goto found;

Alexandre Julliard
committed
if (pFile->flags & FLAG_SYSTEM) return NULL; /* ignore system files we cannot find */
/* try in src file directory */

Alexandre Julliard
committed
if ((p = strrchr(pFile->included_by->filename, '/')))

Alexandre Julliard
committed
int l = p - pFile->included_by->filename + 1;
filename = xmalloc(l + strlen(pFile->name) + 1);
memcpy( filename, pFile->included_by->filename, l );
strcpy( filename + l, pFile->name );

Alexandre Julliard
committed
if ((file = open_file( filename ))) goto found;

Alexandre Julliard
committed
free( filename );
fprintf( stderr, "%s:%d: error: ", pFile->included_by->filename, pFile->included_line );

Alexandre Julliard
committed
perror( pFile->name );
pFile = pFile->included_by;
while (pFile && pFile->included_by)
const char *parent = pFile->included_by->sourcename;
if (!parent) parent = pFile->included_by->name;
fprintf( stderr, "%s:%d: note: %s was first included here\n",
parent, pFile->included_line, pFile->name );

Alexandre Julliard
committed
pFile = pFile->included_by;

Alexandre Julliard
committed
exit(1);
found:
pFile->filename = filename;

Alexandre Julliard
committed
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
/*******************************************************************
* parse_include_directive
*/
static void parse_include_directive( struct incl_file *source, char *str )
{
char quote, *include, *p = str;
while (*p && isspace(*p)) p++;
if (*p != '\"' && *p != '<' ) return;
quote = *p++;
if (quote == '<') quote = '>';
include = p;
while (*p && (*p != quote)) p++;
if (!*p) fatal_error( "malformed include directive '%s'\n", str );
*p = 0;
add_include( source, include, (quote == '>') );
}
/*******************************************************************
* parse_pragma_directive
*/
static void parse_pragma_directive( struct incl_file *source, char *str )
{
char *flag, *p = str;
if (!isspace( *p )) return;
while (*p && isspace(*p)) p++;
p = strtok( p, " \t" );
if (strcmp( p, "makedep" )) return;
while ((flag = strtok( NULL, " \t" )))
{
if (!strcmp( flag, "depend" ))
{
while ((p = strtok( NULL, " \t" ))) add_include( source, p, 0 );
return;
}

Alexandre Julliard
committed
else if (!strcmp( flag, "install" )) source->flags |= FLAG_INSTALL;

Alexandre Julliard
committed
if (strendswith( source->name, ".idl" ))
{
if (!strcmp( flag, "header" )) source->flags |= FLAG_IDL_HEADER;
else if (!strcmp( flag, "proxy" )) source->flags |= FLAG_IDL_PROXY;
else if (!strcmp( flag, "client" )) source->flags |= FLAG_IDL_CLIENT;
else if (!strcmp( flag, "server" )) source->flags |= FLAG_IDL_SERVER;
else if (!strcmp( flag, "ident" )) source->flags |= FLAG_IDL_IDENT;
else if (!strcmp( flag, "typelib" )) source->flags |= FLAG_IDL_TYPELIB;
else if (!strcmp( flag, "register" )) source->flags |= FLAG_IDL_REGISTER;

Alexandre Julliard
committed
else if (!strcmp( flag, "regtypelib" )) source->flags |= FLAG_IDL_REGTYPELIB;

Alexandre Julliard
committed
}
else if (strendswith( source->name, ".rc" ))
{
if (!strcmp( flag, "po" )) source->flags |= FLAG_RC_PO;
}

Alexandre Julliard
committed
else if (strendswith( source->name, ".sfd" ))
{
if (!strcmp( flag, "font" ))
{
struct incl_file *file;
char *obj = strtok( NULL, " \t" );
if (!strendswith( obj, ".fon" )) return;
file = add_generated_source( obj, NULL );
file->sourcename = replace_extension( source->name, ".sfd", ".ttf" );
file->args = xstrdup( strtok( NULL, "" ));
return;
}
}

Alexandre Julliard
committed
else if (!strcmp( flag, "implib" )) source->flags |= FLAG_C_IMPLIB;

Alexandre Julliard
committed
}
}
/*******************************************************************
* parse_cpp_directive
*/
static void parse_cpp_directive( struct incl_file *source, char *str )
{
while (*str && isspace(*str)) str++;
if (*str++ != '#') return;
while (*str && isspace(*str)) str++;
if (!strncmp( str, "include", 7 ))
parse_include_directive( source, str + 7 );
else if (!strncmp( str, "import", 6 ) && strendswith( source->name, ".m" ))
parse_include_directive( source, str + 6 );
else if (!strncmp( str, "pragma", 6 ))
parse_pragma_directive( source, str + 6 );
}
/*******************************************************************
* parse_idl_file
*
* If for_h_file is non-zero, it means we are not interested in the idl file
* itself, but only in the contents of the .h file that will be generated from it.
static void parse_idl_file( struct incl_file *pFile, FILE *file, int for_h_file )

Alexandre Julliard
committed
char *buffer, *include;
input_line = 0;
if (for_h_file)
{
/* generated .h file always includes these */
add_include( pFile, "rpc.h", 1 );
add_include( pFile, "rpcndr.h", 1 );
}

Alexandre Julliard
committed
while ((buffer = get_line( file )))
{
char quote;
char *p = buffer;
while (*p && isspace(*p)) p++;
if (!strncmp( p, "import", 6 ))
{
p += 6;
while (*p && isspace(*p)) p++;
if (*p != '"') continue;
include = ++p;
while (*p && (*p != '"')) p++;
if (!*p) fatal_error( "malformed import directive\n" );
*p = 0;
if (for_h_file && strendswith( include, ".idl" )) strcpy( p - 4, ".h" );
add_include( pFile, include, 0 );
continue;
}
if (for_h_file) /* only check for #include inside cpp_quote */
{
if (strncmp( p, "cpp_quote", 9 )) continue;
p += 9;
while (*p && isspace(*p)) p++;
if (*p++ != '(') continue;
while (*p && isspace(*p)) p++;
if (*p++ != '"') continue;
if (*p++ != '#') continue;
while (*p && isspace(*p)) p++;
if (strncmp( p, "include", 7 )) continue;
p += 7;
while (*p && isspace(*p)) p++;
if (*p == '\\' && p[1] == '"')
{
p += 2;
quote = '"';
}
else
{
if (*p++ != '<' ) continue;
quote = '>';
}
include = p;
while (*p && (*p != quote)) p++;
if (!*p || (quote == '"' && p[-1] != '\\'))
fatal_error( "malformed #include directive inside cpp_quote\n" );
if (quote == '"') p--; /* remove backslash */
*p = 0;
add_include( pFile, include, (quote == '>') );
continue;