mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 00:52:16 +00:00
Boost Build/Jam cleanup - stylistic code changes.
[SVN r79244]
This commit is contained in:
@@ -7,13 +7,12 @@
|
||||
# typed targets.
|
||||
|
||||
import "class" : new ;
|
||||
import errors ;
|
||||
import feature ;
|
||||
import generators : * ;
|
||||
import os ;
|
||||
import project ;
|
||||
import property ;
|
||||
import scanner ;
|
||||
import os ;
|
||||
|
||||
# The following import would create a circular dependency:
|
||||
# project -> project-root -> builtin -> type -> targets -> project
|
||||
@@ -39,11 +38,14 @@ rule register ( type : suffixes * : base-type ? )
|
||||
# decomposed.
|
||||
switch $(type)
|
||||
{
|
||||
case *-* : errors.error "type name \"$(type)\" contains a hyphen" ;
|
||||
case *-* :
|
||||
import errors ;
|
||||
errors.error "type name \"$(type)\" contains a hyphen" ;
|
||||
}
|
||||
|
||||
if $(type) in $(.types)
|
||||
{
|
||||
import errors ;
|
||||
errors.error "Type $(type) is already registered." ;
|
||||
}
|
||||
else
|
||||
@@ -52,7 +54,7 @@ rule register ( type : suffixes * : base-type ? )
|
||||
.base.$(type) = $(base-type) ;
|
||||
.derived.$(base-type) += $(type) ;
|
||||
|
||||
if $(suffixes)-is-not-empty
|
||||
if $(suffixes)-is-defined
|
||||
{
|
||||
# Specify mapping from suffixes to type.
|
||||
register-suffixes $(suffixes) : $(type) ;
|
||||
@@ -119,6 +121,7 @@ rule register-suffixes ( suffixes + : type )
|
||||
}
|
||||
else if $(.type.$(s)) != $(type)
|
||||
{
|
||||
import errors ;
|
||||
errors.error Attempting to specify multiple types for suffix
|
||||
\"$(s)\" : "Old type $(.type.$(s)), New type $(type)" ;
|
||||
}
|
||||
@@ -143,6 +146,7 @@ rule validate ( type )
|
||||
{
|
||||
if ! [ registered $(type) ]
|
||||
{
|
||||
import errors ;
|
||||
errors.error "Unknown target type $(type)" ;
|
||||
}
|
||||
}
|
||||
@@ -336,7 +340,7 @@ local rule generated-target-ps-real ( ps : type : properties * )
|
||||
# If the prefix/suffix is explicitly set to an empty string, we consider
|
||||
# prefix/suffix to be found. If we were not to compare with "", there
|
||||
# would be no way to specify an empty prefix/suffix.
|
||||
if $(result)-is-not-empty
|
||||
if $(result)-is-defined
|
||||
{
|
||||
found = true ;
|
||||
}
|
||||
@@ -381,7 +385,7 @@ rule type ( filename )
|
||||
if [ os.name ] in NT CYGWIN
|
||||
{
|
||||
filename = $(filename:L) ;
|
||||
}
|
||||
}
|
||||
local type ;
|
||||
while ! $(type) && $(filename:S)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -175,13 +175,10 @@ evaluate_rule(
|
||||
{
|
||||
backtrace_line( frame->prev );
|
||||
if ( frame->module->name )
|
||||
{
|
||||
printf( "rule %s unknown in module %s\n", object_str( rule->name ), object_str( frame->module->name ) );
|
||||
}
|
||||
printf( "rule %s unknown in module %s\n", object_str( rule->name ),
|
||||
object_str( frame->module->name ) );
|
||||
else
|
||||
{
|
||||
printf( "rule %s unknown in module \n", object_str( rule->name ) );
|
||||
}
|
||||
backtrace( frame->prev );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
@@ -698,8 +698,8 @@ static time_t filetime_dt( FILETIME t_utc )
|
||||
FILETIME f0_;
|
||||
SYSTEMTIME s0_;
|
||||
GetSystemTime( &s0_ );
|
||||
t0_.tm_year = s0_.wYear-1900;
|
||||
t0_.tm_mon = s0_.wMonth-1;
|
||||
t0_.tm_year = s0_.wYear - 1900;
|
||||
t0_.tm_mon = s0_.wMonth - 1;
|
||||
t0_.tm_wday = s0_.wDayOfWeek;
|
||||
t0_.tm_mday = s0_.wDay;
|
||||
t0_.tm_hour = s0_.wHour;
|
||||
|
||||
@@ -335,13 +335,12 @@ static int read_descriptor( int i, int s )
|
||||
}
|
||||
}
|
||||
|
||||
/* If buffer full, ensure last buffer char is newline
|
||||
* so process jam log finds command status at beginning
|
||||
* of it own line, not appended to end of buffer output.
|
||||
/* If buffer full, ensure last buffer char is newline so that jam log
|
||||
* contains the command status at beginning of it own line instead of
|
||||
* appended to end of the previous output.
|
||||
*/
|
||||
if ( globs.max_buf && cmdtab[i].buf_size[s] == globs.max_buf ) {
|
||||
cmdtab[i].buffer[s][cmdtab[i].buf_size[s]-2] = '\n';
|
||||
}
|
||||
if ( globs.max_buf && cmdtab[ i ].buf_size[ s ] == globs.max_buf )
|
||||
cmdtab[ i ].buffer[ s ][ cmdtab[ i ].buf_size[ s ] - 2 ] = '\n';
|
||||
|
||||
return feof( cmdtab[ i ].stream[ s ] );
|
||||
}
|
||||
|
||||
@@ -11,29 +11,6 @@
|
||||
* (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
# include "strings.h"
|
||||
# include "object.h"
|
||||
|
||||
# ifdef OS_NT
|
||||
|
||||
# ifdef __BORLANDC__
|
||||
# if __BORLANDC__ < 0x550
|
||||
# include <dir.h>
|
||||
# include <dos.h>
|
||||
# endif
|
||||
# undef FILENAME /* cpp namespace collision */
|
||||
# define _finddata_t ffblk
|
||||
# endif
|
||||
|
||||
# include <io.h>
|
||||
# include <sys/stat.h>
|
||||
# include <ctype.h>
|
||||
# include <direct.h>
|
||||
|
||||
/*
|
||||
* filent.c - scan directories and archives on NT
|
||||
*
|
||||
@@ -43,16 +20,40 @@
|
||||
* file_time() - get timestamp of file, if not done by file_dirscan()
|
||||
* file_archscan() - scan an archive for files
|
||||
*
|
||||
* File_dirscan() and file_archscan() call back a caller provided function
|
||||
* for each file found. A flag to this callback function lets file_dirscan()
|
||||
* and file_archscan() indicate that a timestamp is being provided with the
|
||||
* file. If file_dirscan() or file_archscan() do not provide the file's
|
||||
* timestamp, interested parties may later call file_time().
|
||||
*
|
||||
* 07/10/95 (taylor) Findfirst() returns the first file on NT.
|
||||
* 05/03/96 (seiwald) split apart into pathnt.c
|
||||
* File_dirscan() and file_archscan() call back a caller provided function for
|
||||
* each file found. A flag to this callback function lets file_dirscan() and
|
||||
* file_archscan() indicate whether a timestamp is being provided with the file.
|
||||
* If file_dirscan() or file_archscan() do not provide the file's timestamp,
|
||||
* interested parties may later call file_time() for it.
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
|
||||
#ifdef OS_NT
|
||||
|
||||
#include "filesys.h"
|
||||
|
||||
#include "object.h"
|
||||
#include "pathsys.h"
|
||||
#include "strings.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# if __BORLANDC__ < 0x550
|
||||
# include <dir.h>
|
||||
# include <dos.h>
|
||||
# endif
|
||||
# undef FILENAME /* cpp namespace collision */
|
||||
# define _finddata_t ffblk
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
/*
|
||||
* file_dirscan() - scan a directory for files
|
||||
*/
|
||||
@@ -61,12 +62,9 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
{
|
||||
PROFILE_ENTER( FILE_DIRSCAN );
|
||||
|
||||
file_info_t * d = 0;
|
||||
|
||||
/* First enter directory itself */
|
||||
|
||||
d = file_query( dir );
|
||||
/* First enter the directory itself. */
|
||||
|
||||
file_info_t * const d = file_query( dir );
|
||||
if ( !d || !d->is_dir )
|
||||
{
|
||||
object_free( dir );
|
||||
@@ -101,12 +99,11 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
string_copy( filespec, ".\\*" );
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We can not simply assume the given folder name will never include
|
||||
/* We can not simply assume the given folder name will never include
|
||||
* its trailing path separator or otherwise we would not support the
|
||||
* Windows root folder specified without its drive letter, i.e. '\'.
|
||||
*/
|
||||
char trailingChar = object_str( dir )[ d_length - 1 ] ;
|
||||
char const trailingChar = object_str( dir )[ d_length - 1 ] ;
|
||||
string_copy( filespec, object_str( dir ) );
|
||||
if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
|
||||
string_append( filespec, "\\" );
|
||||
@@ -125,10 +122,10 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
return;
|
||||
}
|
||||
|
||||
string_new ( filename );
|
||||
string_new( filename );
|
||||
while ( !ret )
|
||||
{
|
||||
file_info_t * ff = 0;
|
||||
file_info_t * ff;
|
||||
|
||||
f.f_base.ptr = finfo->ff_name;
|
||||
f.f_base.len = strlen( finfo->ff_name );
|
||||
@@ -136,16 +133,16 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
string_truncate( filename, 0 );
|
||||
path_build( &f, filename );
|
||||
|
||||
files = list_push_back( files, object_new(filename->value) );
|
||||
files = list_push_back( files, object_new( filename->value ) );
|
||||
ff = file_info( filename->value );
|
||||
ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
|
||||
ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
|
||||
ff->is_dir = !ff->is_file;
|
||||
ff->size = finfo->ff_fsize;
|
||||
ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime;
|
||||
ff->time = ( finfo->ff_ftime << 16 ) | finfo->ff_ftime;
|
||||
|
||||
ret = findnext( finfo );
|
||||
}
|
||||
# else
|
||||
#else
|
||||
handle = _findfirst( filespec->value, finfo );
|
||||
|
||||
if ( ret = ( handle < 0L ) )
|
||||
@@ -160,7 +157,7 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
while ( !ret )
|
||||
{
|
||||
OBJECT * filename_obj;
|
||||
file_info_t * ff = 0;
|
||||
file_info_t * ff;
|
||||
|
||||
f.f_base.ptr = finfo->name;
|
||||
f.f_base.len = strlen( finfo->name );
|
||||
@@ -173,7 +170,7 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
files = list_push_back( files, filename_obj );
|
||||
ff = file_info( filename_obj );
|
||||
ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
|
||||
ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
|
||||
ff->is_dir = !ff->is_file;
|
||||
ff->size = finfo->size;
|
||||
ff->time = finfo->time_write;
|
||||
|
||||
@@ -181,7 +178,7 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
}
|
||||
|
||||
_findclose( handle );
|
||||
# endif
|
||||
#endif
|
||||
string_free( filename );
|
||||
string_free( filespec );
|
||||
object_free( dir );
|
||||
@@ -192,32 +189,32 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
/* Special case \ or d:\ : enter it */
|
||||
{
|
||||
unsigned long len = strlen( object_str( d->name ) );
|
||||
if ( len == 1 && object_str( d->name )[0] == '\\' )
|
||||
if ( len == 1 && object_str( d->name )[ 0 ] == '\\' )
|
||||
{
|
||||
OBJECT * dir = short_path_to_long_path( d->name );
|
||||
OBJECT * const dir = short_path_to_long_path( d->name );
|
||||
(*func)( closure, dir, 1 /* stat()'ed */, d->time );
|
||||
object_free( dir );
|
||||
}
|
||||
else if ( len == 3 && object_str( d->name )[1] == ':' )
|
||||
else if ( len == 3 && object_str( d->name )[ 1 ] == ':' )
|
||||
{
|
||||
char buf[4];
|
||||
OBJECT * dir1 = short_path_to_long_path( d->name );
|
||||
char buf[ 4 ];
|
||||
OBJECT * const dir1 = short_path_to_long_path( d->name );
|
||||
OBJECT * dir2;
|
||||
(*func)( closure, dir1, 1 /* stat()'ed */, d->time );
|
||||
/* We've just entered 3-letter drive name spelling (with trailing
|
||||
slash), into the hash table. Now enter two-letter variant,
|
||||
without trailing slash, so that if we try to check whether
|
||||
"c:" exists, we hit it.
|
||||
|
||||
Jam core has workarounds for that. Given:
|
||||
x = c:\whatever\foo ;
|
||||
p = $(x:D) ;
|
||||
p2 = $(p:D) ;
|
||||
There will be no trailing slash in $(p), but there will be one
|
||||
in $(p2). But, that seems rather fragile.
|
||||
*/
|
||||
/* We have just entered a 3-letter drive name spelling (with a
|
||||
* trailing slash), into the hash table. Now enter its two-letter
|
||||
* variant, without the trailing slash, so that if we try to check
|
||||
* whether "c:" exists, we hit it.
|
||||
*
|
||||
* Jam core has workarounds for that. Given:
|
||||
* x = c:\whatever\foo ;
|
||||
* p = $(x:D) ;
|
||||
* p2 = $(p:D) ;
|
||||
* There will be no trailing slash in $(p), but there will be one in
|
||||
* $(p2). But, that seems rather fragile.
|
||||
*/
|
||||
strcpy( buf, object_str( dir1 ) );
|
||||
buf[2] = 0;
|
||||
buf[ 2 ] = 0;
|
||||
dir2 = object_new( buf );
|
||||
(*func)( closure, dir2, 1 /* stat()'ed */, d->time );
|
||||
object_free( dir2 );
|
||||
@@ -228,11 +225,12 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
/* Now enter contents of directory */
|
||||
if ( !list_empty( d->files ) )
|
||||
{
|
||||
LIST * files = d->files;
|
||||
LISTITER iter = list_begin( files ), end = list_end( files );
|
||||
LIST * const files = d->files;
|
||||
LISTITER iter = list_begin( files );
|
||||
LISTITER const end = list_end( files );
|
||||
for ( ; iter != end; iter = list_next( iter ) )
|
||||
{
|
||||
file_info_t * ff = file_info( list_item( iter ) );
|
||||
file_info_t const * const ff = file_info( list_item( iter ) );
|
||||
(*func)( closure, list_item( iter ), 1 /* stat()'ed */, ff->time );
|
||||
}
|
||||
}
|
||||
@@ -240,51 +238,71 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
PROFILE_EXIT( FILE_DIRSCAN );
|
||||
}
|
||||
|
||||
|
||||
file_info_t * file_query( OBJECT * filename )
|
||||
{
|
||||
file_info_t * ff = file_info( filename );
|
||||
if ( ! ff->time )
|
||||
file_info_t * const ff = file_info( filename );
|
||||
if ( !ff->time )
|
||||
{
|
||||
char const * const name = *object_str( filename )
|
||||
? object_str( filename )
|
||||
: ".";
|
||||
|
||||
/* POSIX stat() function on Windows suffers from several issues:
|
||||
* * Does not support file timestamps with resolution finer than 1
|
||||
* second. This means it can not be used to detect file timestamp
|
||||
* changes of less than one second. One possible consequence is that
|
||||
* some fast-pased touch commands (such as those done by Boost
|
||||
* Build's internal testing system if it does not do extra waiting
|
||||
* before those touch operations) will not be detected correctly by
|
||||
* the build system.
|
||||
* * Returns file modification times automatically adjusted for
|
||||
* daylight savings time even though daylight savings time should
|
||||
* have nothing to do with internal time representation.
|
||||
*/
|
||||
struct stat statbuf;
|
||||
|
||||
if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
|
||||
if ( stat( name, &statbuf ) < 0 )
|
||||
return 0;
|
||||
|
||||
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
|
||||
ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
|
||||
ff->size = statbuf.st_size;
|
||||
/* Set the file's timestamp to 1 in case it is 0 or undetected to avoid
|
||||
* confusion with non-existing files.
|
||||
*/
|
||||
ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
|
||||
}
|
||||
return ff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* file_time() - get timestamp of file, if not done by file_dirscan()
|
||||
*/
|
||||
|
||||
int
|
||||
file_time(
|
||||
OBJECT * filename,
|
||||
time_t * time )
|
||||
int file_time( OBJECT * filename, time_t * time )
|
||||
{
|
||||
file_info_t * ff = file_query( filename );
|
||||
file_info_t const * const ff = file_query( filename );
|
||||
if ( !ff ) return -1;
|
||||
*time = ff->time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int file_is_file( OBJECT * filename )
|
||||
{
|
||||
file_info_t * ff = file_query( filename );
|
||||
if ( !ff ) return -1;
|
||||
return ff->is_file;
|
||||
file_info_t const * const ff = file_query( filename );
|
||||
return ff ? ff->is_file : -1;
|
||||
}
|
||||
|
||||
int file_mkdir( const char * pathname )
|
||||
|
||||
int file_mkdir( char const * pathname )
|
||||
{
|
||||
return _mkdir(pathname);
|
||||
return _mkdir( pathname );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* file_archscan() - scan an archive for files
|
||||
*/
|
||||
@@ -297,35 +315,30 @@ int file_mkdir( const char * pathname )
|
||||
#define ARFMAG "`\n"
|
||||
|
||||
struct ar_hdr {
|
||||
char ar_name[16];
|
||||
char ar_date[12];
|
||||
char ar_uid[6];
|
||||
char ar_gid[6];
|
||||
char ar_mode[8];
|
||||
char ar_size[10];
|
||||
char ar_fmag[2];
|
||||
char ar_name[ 16 ];
|
||||
char ar_date[ 12 ];
|
||||
char ar_uid[ 6 ];
|
||||
char ar_gid[ 6 ];
|
||||
char ar_mode[ 8 ];
|
||||
char ar_size[ 10 ];
|
||||
char ar_fmag[ 2 ];
|
||||
};
|
||||
|
||||
# define SARFMAG 2
|
||||
# define SARHDR sizeof( struct ar_hdr )
|
||||
#define SARFMAG 2
|
||||
#define SARHDR sizeof( struct ar_hdr )
|
||||
|
||||
void
|
||||
file_archscan(
|
||||
const char * archive,
|
||||
scanback func,
|
||||
void * closure )
|
||||
void file_archscan( char const * archive, scanback func, void * closure )
|
||||
{
|
||||
struct ar_hdr ar_hdr;
|
||||
char *string_table = 0;
|
||||
char * string_table = 0;
|
||||
char buf[ MAXJPATH ];
|
||||
long offset;
|
||||
int fd;
|
||||
int const fd = open( archive, O_RDONLY | O_BINARY, 0 );
|
||||
|
||||
if ( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
|
||||
if ( fd < 0 )
|
||||
return;
|
||||
|
||||
if ( read( fd, buf, SARMAG ) != SARMAG ||
|
||||
strncmp( ARMAG, buf, SARMAG ) )
|
||||
if ( read( fd, buf, SARMAG ) != SARMAG || strncmp( ARMAG, buf, SARMAG ) )
|
||||
{
|
||||
close( fd );
|
||||
return;
|
||||
@@ -337,13 +350,13 @@ file_archscan(
|
||||
printf( "scan archive %s\n", archive );
|
||||
|
||||
while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
|
||||
!memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
|
||||
!memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
|
||||
{
|
||||
long lar_date;
|
||||
long lar_size;
|
||||
char * name = 0;
|
||||
char * endname;
|
||||
char * c;
|
||||
long lar_date;
|
||||
long lar_size;
|
||||
char * name = 0;
|
||||
char * endname;
|
||||
char * c;
|
||||
OBJECT * member;
|
||||
|
||||
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
|
||||
@@ -351,29 +364,27 @@ file_archscan(
|
||||
|
||||
lar_size = ( lar_size + 1 ) & ~1;
|
||||
|
||||
if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
|
||||
if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] == '/' )
|
||||
{
|
||||
/* this is the "string table" entry of the symbol table,
|
||||
** which holds strings of filenames that are longer than
|
||||
** 15 characters (ie. don't fit into a ar_name
|
||||
*/
|
||||
|
||||
string_table = BJAM_MALLOC_ATOMIC(lar_size+1);
|
||||
if (read(fd, string_table, lar_size) != lar_size)
|
||||
printf("error reading string table\n");
|
||||
string_table[lar_size] = '\0';
|
||||
offset += SARHDR + lar_size;
|
||||
continue;
|
||||
/* This is the "string table" entry of the symbol table, holding
|
||||
* filename strings longer than 15 characters, i.e. those that do
|
||||
* not fit into ar_name.
|
||||
*/
|
||||
string_table = BJAM_MALLOC_ATOMIC( lar_size + 1 );
|
||||
if ( read( fd, string_table, lar_size ) != lar_size )
|
||||
printf( "error reading string table\n" );
|
||||
string_table[ lar_size ] = '\0';
|
||||
offset += SARHDR + lar_size;
|
||||
continue;
|
||||
}
|
||||
else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
|
||||
else if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] != ' ' )
|
||||
{
|
||||
/* Long filenames are recognized by "/nnnn" where nnnn is
|
||||
** the offset of the string in the string table represented
|
||||
** in ASCII decimals.
|
||||
*/
|
||||
|
||||
/* Long filenames are recognized by "/nnnn" where nnnn is the
|
||||
* string's offset in the string table represented in ASCII
|
||||
* decimals.
|
||||
*/
|
||||
name = string_table + atoi( ar_hdr.ar_name + 1 );
|
||||
for ( endname = name; *endname && *endname != '\n'; ++endname) {}
|
||||
for ( endname = name; *endname && *endname != '\n'; ++endname );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -385,16 +396,17 @@ file_archscan(
|
||||
/* strip trailing white-space, slashes, and backslashes */
|
||||
|
||||
while ( endname-- > name )
|
||||
if ( !isspace(*endname) && ( *endname != '\\' ) && ( *endname != '/' ) )
|
||||
if ( !isspace( *endname ) && ( *endname != '\\' ) && ( *endname !=
|
||||
'/' ) )
|
||||
break;
|
||||
*++endname = 0;
|
||||
|
||||
/* strip leading directory names, an NT specialty */
|
||||
|
||||
if ( c = strrchr( name, '/' ) )
|
||||
name = c + 1;
|
||||
name = c + 1;
|
||||
if ( c = strrchr( name, '\\' ) )
|
||||
name = c + 1;
|
||||
name = c + 1;
|
||||
|
||||
sprintf( buf, "%s(%.*s)", archive, endname - name, name );
|
||||
member = object_new( buf );
|
||||
@@ -408,4 +420,4 @@ file_archscan(
|
||||
close( fd );
|
||||
}
|
||||
|
||||
# endif /* NT */
|
||||
#endif /* OS_NT */
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# include "jam.h"
|
||||
# include "pathsys.h"
|
||||
# include "strings.h"
|
||||
# include "object.h"
|
||||
# include "filesys.h"
|
||||
# include "lists.h"
|
||||
#include "jam.h"
|
||||
#include "filesys.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "object.h"
|
||||
#include "pathsys.h"
|
||||
#include "strings.h"
|
||||
|
||||
|
||||
void file_build1( PATHNAME * f, string * file )
|
||||
{
|
||||
if ( DEBUG_SEARCH )
|
||||
{
|
||||
printf("build file: ");
|
||||
printf( "build file: " );
|
||||
if ( f->f_root.len )
|
||||
printf( "root = '%.*s' ", f->f_root.len, f->f_root.ptr );
|
||||
if ( f->f_dir.len )
|
||||
@@ -19,26 +21,27 @@ void file_build1( PATHNAME * f, string * file )
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
/* Start with the grist. If the current grist isn't */
|
||||
/* surrounded by <>'s, add them. */
|
||||
|
||||
/* Start with the grist. If the current grist is not surrounded by <>'s, add
|
||||
* them.
|
||||
*/
|
||||
if ( f->f_grist.len )
|
||||
{
|
||||
if ( f->f_grist.ptr[0] != '<' )
|
||||
string_push_back( file, '<' );
|
||||
string_append_range(
|
||||
file, f->f_grist.ptr, f->f_grist.ptr + f->f_grist.len );
|
||||
if ( file->value[file->size - 1] != '>' )
|
||||
if ( file->value[ file->size - 1 ] != '>' )
|
||||
string_push_back( file, '>' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct hash * filecache_hash = 0;
|
||||
static file_info_t filecache_finfo;
|
||||
|
||||
file_info_t * file_info( OBJECT * filename )
|
||||
{
|
||||
file_info_t *finfo = &filecache_finfo;
|
||||
file_info_t * finfo = &filecache_finfo;
|
||||
int found;
|
||||
|
||||
if ( !filecache_hash )
|
||||
@@ -49,7 +52,6 @@ file_info_t * file_info( OBJECT * filename )
|
||||
finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
|
||||
if ( !found )
|
||||
{
|
||||
/* printf( "file_info: %s\n", filename ); */
|
||||
finfo->name = object_copy( filename );
|
||||
finfo->is_file = 0;
|
||||
finfo->is_dir = 0;
|
||||
@@ -63,26 +65,28 @@ file_info_t * file_info( OBJECT * filename )
|
||||
return finfo;
|
||||
}
|
||||
|
||||
|
||||
static LIST * files_to_remove = L0;
|
||||
|
||||
static void remove_files_atexit(void)
|
||||
static void remove_files_atexit( void )
|
||||
{
|
||||
LISTITER iter = list_begin( files_to_remove ), end = list_end( files_to_remove );
|
||||
LISTITER iter = list_begin( files_to_remove );
|
||||
LISTITER const end = list_end( files_to_remove );
|
||||
for ( ; iter != end; iter = list_next( iter ) )
|
||||
{
|
||||
remove( object_str( list_item( iter ) ) );
|
||||
}
|
||||
list_free( files_to_remove );
|
||||
files_to_remove = L0;
|
||||
}
|
||||
|
||||
static void free_file_info ( void * xfile, void * data )
|
||||
|
||||
static void free_file_info( void * xfile, void * data )
|
||||
{
|
||||
file_info_t * file = (file_info_t *)xfile;
|
||||
file_info_t * const file = (file_info_t *)xfile;
|
||||
object_free( file->name );
|
||||
list_free( file->files );
|
||||
}
|
||||
|
||||
|
||||
void file_done()
|
||||
{
|
||||
remove_files_atexit();
|
||||
@@ -93,7 +97,8 @@ void file_done()
|
||||
}
|
||||
}
|
||||
|
||||
void file_remove_atexit( OBJECT * path )
|
||||
|
||||
void file_remove_atexit( OBJECT * const path )
|
||||
{
|
||||
files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
|
||||
}
|
||||
|
||||
@@ -15,33 +15,34 @@
|
||||
*/
|
||||
|
||||
#ifndef FILESYS_DWA20011025_H
|
||||
# define FILESYS_DWA20011025_H
|
||||
#define FILESYS_DWA20011025_H
|
||||
|
||||
# include "pathsys.h"
|
||||
#include "hash.h"
|
||||
#include "lists.h"
|
||||
#include "object.h"
|
||||
#include "pathsys.h"
|
||||
|
||||
|
||||
typedef void (*scanback)( void *closure, OBJECT * file, int found, time_t t );
|
||||
|
||||
void file_dirscan( OBJECT * dir, scanback func, void * closure );
|
||||
void file_archscan( const char * arch, scanback func, void * closure );
|
||||
void file_archscan( char const * arch, scanback func, void * closure );
|
||||
|
||||
int file_time( OBJECT * filename, time_t * time );
|
||||
|
||||
void file_build1(PATHNAME *f, string* file) ;
|
||||
void file_build1( PATHNAME * f, string * file ) ;
|
||||
int file_is_file( OBJECT * filename );
|
||||
int file_mkdir( const char * pathname );
|
||||
int file_mkdir( char const * pathname );
|
||||
|
||||
typedef struct file_info_t file_info_t ;
|
||||
struct file_info_t
|
||||
{
|
||||
OBJECT * name;
|
||||
short is_file;
|
||||
short is_dir;
|
||||
unsigned long size;
|
||||
time_t time;
|
||||
LIST * files;
|
||||
OBJECT * name;
|
||||
short is_file;
|
||||
short is_dir;
|
||||
unsigned long size;
|
||||
time_t time;
|
||||
LIST * files;
|
||||
};
|
||||
|
||||
|
||||
@@ -55,7 +56,7 @@ file_info_t * file_query( OBJECT * filename );
|
||||
|
||||
void file_done();
|
||||
|
||||
/* Marks a path/file to be removed when jam exits. */
|
||||
void file_remove_atexit( OBJECT * path );
|
||||
/* Marks a path/file to be removed when JAM exits. */
|
||||
void file_remove_atexit( OBJECT * const path );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,17 +107,11 @@ struct ar_hdr /* archive file member header - printable ascii */
|
||||
* file_time() - get timestamp of file, if not done by file_dirscan()
|
||||
* file_archscan() - scan an archive for files
|
||||
*
|
||||
* File_dirscan() and file_archscan() call back a caller provided function
|
||||
* for each file found. A flag to this callback function lets file_dirscan()
|
||||
* and file_archscan() indicate that a timestamp is being provided with the
|
||||
* file. If file_dirscan() or file_archscan() do not provide the file's
|
||||
* timestamp, interested parties may later call file_time().
|
||||
*
|
||||
* 04/08/94 (seiwald) - Coherent/386 support added.
|
||||
* 12/19/94 (mikem) - solaris string table insanity support
|
||||
* 02/14/95 (seiwald) - parse and build /xxx properly
|
||||
* 05/03/96 (seiwald) - split into pathunix.c
|
||||
* 11/21/96 (peterk) - BEOS does not have Unix-style archives
|
||||
* File_dirscan() and file_archscan() call back a caller provided function for
|
||||
* each file found. A flag to this callback function lets file_dirscan() and
|
||||
* file_archscan() indicate whether a timestamp is being provided with the file.
|
||||
* If file_dirscan() or file_archscan() do not provide the file's timestamp,
|
||||
* interested parties may later call file_time() for it.
|
||||
*/
|
||||
|
||||
|
||||
@@ -204,10 +198,11 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
if ( !list_empty( d->files ) )
|
||||
{
|
||||
LIST * files = d->files;
|
||||
LISTITER iter = list_begin( files ), end = list_end( files );
|
||||
LISTITER iter = list_begin( files );
|
||||
LISTITER const end = list_end( files );
|
||||
for ( ; iter != end; iter = list_next( iter ) )
|
||||
{
|
||||
file_info_t * ff = file_info( list_item( iter ) );
|
||||
file_info_t * const ff = file_info( list_item( iter ) );
|
||||
(*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
|
||||
files = list_next( files );
|
||||
}
|
||||
@@ -219,17 +214,21 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure )
|
||||
|
||||
file_info_t * file_query( OBJECT * filename )
|
||||
{
|
||||
file_info_t * ff = file_info( filename );
|
||||
if ( ! ff->time )
|
||||
file_info_t * const ff = file_info( filename );
|
||||
if ( !ff->time )
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
|
||||
if ( stat( *object_str( filename ) ? object_str( filename ) : ".",
|
||||
&statbuf ) < 0 )
|
||||
return 0;
|
||||
|
||||
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
|
||||
ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
|
||||
ff->size = statbuf.st_size;
|
||||
/* Set the file's timestamp to 1 in case it is 0 or undetected to avoid
|
||||
* confusion with non-existing files.
|
||||
*/
|
||||
ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
|
||||
}
|
||||
return ff;
|
||||
@@ -239,12 +238,9 @@ file_info_t * file_query( OBJECT * filename )
|
||||
* file_time() - get timestamp of file, if not done by file_dirscan()
|
||||
*/
|
||||
|
||||
int
|
||||
file_time(
|
||||
OBJECT * filename,
|
||||
time_t * time )
|
||||
int file_time( OBJECT * filename, time_t * time )
|
||||
{
|
||||
file_info_t * ff = file_query( filename );
|
||||
file_info_t const * const ff = file_query( filename );
|
||||
if ( !ff ) return -1;
|
||||
*time = ff->time;
|
||||
return 0;
|
||||
@@ -252,12 +248,13 @@ file_time(
|
||||
|
||||
int file_is_file( OBJECT * filename )
|
||||
{
|
||||
file_info_t * ff = file_query( filename );
|
||||
file_info_t const * const ff = file_query( filename );
|
||||
if ( !ff ) return -1;
|
||||
return ff->is_file;
|
||||
}
|
||||
|
||||
int file_mkdir( const char * pathname )
|
||||
|
||||
int file_mkdir( char const * pathname )
|
||||
{
|
||||
return mkdir( pathname, 0766 );
|
||||
}
|
||||
@@ -266,22 +263,18 @@ int file_mkdir( const char * pathname )
|
||||
* file_archscan() - scan an archive for files
|
||||
*/
|
||||
|
||||
# ifndef AIAMAG /* God-fearing UNIX */
|
||||
#ifndef AIAMAG /* God-fearing UNIX */
|
||||
|
||||
# define SARFMAG 2
|
||||
# define SARHDR sizeof( struct ar_hdr )
|
||||
#define SARFMAG 2
|
||||
#define SARHDR sizeof( struct ar_hdr )
|
||||
|
||||
void
|
||||
file_archscan(
|
||||
const char * archive,
|
||||
scanback func,
|
||||
void * closure )
|
||||
void file_archscan( char const * archive, scanback func, void * closure )
|
||||
{
|
||||
# ifndef NO_AR
|
||||
#ifndef NO_AR
|
||||
struct ar_hdr ar_hdr;
|
||||
char * string_table = 0;
|
||||
char buf[ MAXJPATH ];
|
||||
long offset;
|
||||
char *string_table = 0;
|
||||
int fd;
|
||||
|
||||
if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
|
||||
@@ -299,13 +292,13 @@ file_archscan(
|
||||
if ( DEBUG_BINDSCAN )
|
||||
printf( "scan archive %s\n", archive );
|
||||
|
||||
while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR )
|
||||
&& !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
|
||||
while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
|
||||
!( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
|
||||
#ifdef ARFZMAG
|
||||
/* OSF also has a compressed format */
|
||||
&& memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
|
||||
/* OSF also has a compressed format */
|
||||
&& memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
|
||||
#endif
|
||||
) )
|
||||
) )
|
||||
{
|
||||
char lar_name_[257];
|
||||
char * lar_name = lar_name_ + 1;
|
||||
@@ -317,46 +310,45 @@ file_archscan(
|
||||
char * dest;
|
||||
OBJECT * member;
|
||||
|
||||
strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
|
||||
strncpy( lar_name, ar_hdr.ar_name, sizeof( ar_hdr.ar_name ) );
|
||||
|
||||
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
|
||||
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
|
||||
|
||||
if (ar_hdr.ar_name[0] == '/')
|
||||
if ( ar_hdr.ar_name[ 0 ] == '/' )
|
||||
{
|
||||
if (ar_hdr.ar_name[1] == '/')
|
||||
{
|
||||
/* this is the "string table" entry of the symbol table,
|
||||
** which holds strings of filenames that are longer than
|
||||
** 15 characters (ie. don't fit into a ar_name
|
||||
*/
|
||||
|
||||
string_table = (char *)BJAM_MALLOC_ATOMIC(lar_size);
|
||||
lseek(fd, offset + SARHDR, 0);
|
||||
if (read(fd, string_table, lar_size) != lar_size)
|
||||
printf("error reading string table\n");
|
||||
}
|
||||
else if (string_table && ar_hdr.ar_name[1] != ' ')
|
||||
{
|
||||
/* Long filenames are recognized by "/nnnn" where nnnn is
|
||||
** the offset of the string in the string table represented
|
||||
** in ASCII decimals.
|
||||
*/
|
||||
dest = lar_name;
|
||||
lar_offset = atoi(lar_name + 1);
|
||||
src = &string_table[lar_offset];
|
||||
while (*src != '/')
|
||||
*dest++ = *src++;
|
||||
*dest = '/';
|
||||
}
|
||||
if ( ar_hdr.ar_name[ 1 ] == '/' )
|
||||
{
|
||||
/* This is the "string table" entry of the symbol table, holding
|
||||
* filename strings longer than 15 characters, i.e. those that
|
||||
* do not fit into ar_name.
|
||||
*/
|
||||
string_table = (char *)BJAM_MALLOC_ATOMIC( lar_size );
|
||||
lseek( fd, offset + SARHDR, 0 );
|
||||
if ( read( fd, string_table, lar_size ) != lar_size )
|
||||
printf("error reading string table\n");
|
||||
}
|
||||
else if ( string_table && ar_hdr.ar_name[ 1 ] != ' ' )
|
||||
{
|
||||
/* Long filenames are recognized by "/nnnn" where nnnn is the
|
||||
* offset of the string in the string table represented in ASCII
|
||||
* decimals.
|
||||
*/
|
||||
dest = lar_name;
|
||||
lar_offset = atoi( lar_name + 1 );
|
||||
src = &string_table[ lar_offset ];
|
||||
while ( *src != '/' )
|
||||
*dest++ = *src++;
|
||||
*dest = '/';
|
||||
}
|
||||
}
|
||||
|
||||
c = lar_name - 1;
|
||||
while ( ( *++c != ' ' ) && ( *c != '/' ) ) ;
|
||||
while ( ( *++c != ' ' ) && ( *c != '/' ) );
|
||||
*c = '\0';
|
||||
|
||||
if ( DEBUG_BINDSCAN )
|
||||
printf( "archive name %s found\n", lar_name );
|
||||
printf( "archive name %s found\n", lar_name );
|
||||
|
||||
sprintf( buf, "%s(%s)", archive, lar_name );
|
||||
|
||||
@@ -373,14 +365,14 @@ file_archscan(
|
||||
|
||||
close( fd );
|
||||
|
||||
# endif /* NO_AR */
|
||||
#endif /* NO_AR */
|
||||
|
||||
}
|
||||
|
||||
# else /* AIAMAG - RS6000 AIX */
|
||||
#else /* AIAMAG - RS6000 AIX */
|
||||
|
||||
static void file_archscan_small(
|
||||
int fd, char const *archive, scanback func, void *closure)
|
||||
static void file_archscan_small( int fd, char const * archive, scanback func,
|
||||
void * closure )
|
||||
{
|
||||
struct fl_hdr fl_hdr;
|
||||
|
||||
@@ -400,12 +392,11 @@ static void file_archscan_small(
|
||||
if ( DEBUG_BINDSCAN )
|
||||
printf( "scan archive %s\n", archive );
|
||||
|
||||
while ( ( offset > 0 )
|
||||
&& ( lseek( fd, offset, 0 ) >= 0 )
|
||||
&& ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) )
|
||||
while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
|
||||
read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) )
|
||||
{
|
||||
long lar_date;
|
||||
int lar_namlen;
|
||||
int lar_namlen;
|
||||
OBJECT * member;
|
||||
|
||||
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
|
||||
@@ -428,8 +419,8 @@ static void file_archscan_small(
|
||||
/* Check for OS version which supports the big variant. */
|
||||
#ifdef AR_HSZ_BIG
|
||||
|
||||
static void file_archscan_big(
|
||||
int fd, char const *archive, scanback func, void *closure)
|
||||
static void file_archscan_big( int fd, char const * archive, scanback func,
|
||||
void * closure )
|
||||
{
|
||||
struct fl_hdr_big fl_hdr;
|
||||
|
||||
@@ -449,9 +440,8 @@ static void file_archscan_big(
|
||||
if ( DEBUG_BINDSCAN )
|
||||
printf( "scan archive %s\n", archive );
|
||||
|
||||
while ( ( offset > 0 )
|
||||
&& ( lseek( fd, offset, 0 ) >= 0 )
|
||||
&& ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
|
||||
while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
|
||||
read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
|
||||
{
|
||||
long lar_date;
|
||||
int lar_namlen;
|
||||
@@ -472,33 +462,32 @@ static void file_archscan_big(
|
||||
(*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
|
||||
object_free( member );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* AR_HSZ_BIG */
|
||||
|
||||
void file_archscan( const char * archive, scanback func, void *closure)
|
||||
void file_archscan( char const * archive, scanback func, void * closure )
|
||||
{
|
||||
int fd;
|
||||
char fl_magic[SAIAMAG];
|
||||
char fl_magic[ SAIAMAG ];
|
||||
|
||||
if (( fd = open( archive, O_RDONLY, 0)) < 0)
|
||||
if ( ( fd = open( archive, O_RDONLY, 0)) < 0 )
|
||||
return;
|
||||
|
||||
if (read( fd, fl_magic, SAIAMAG) != SAIAMAG
|
||||
|| lseek(fd, 0, SEEK_SET) == -1)
|
||||
if ( read( fd, fl_magic, SAIAMAG ) != SAIAMAG ||
|
||||
lseek( fd, 0, SEEK_SET ) == -1 )
|
||||
{
|
||||
close(fd);
|
||||
close( fd );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strncmp( AIAMAG, fl_magic, SAIAMAG ) == 0 )
|
||||
if ( !strncmp( AIAMAG, fl_magic, SAIAMAG ) )
|
||||
{
|
||||
/* read small variant */
|
||||
file_archscan_small( fd, archive, func, closure );
|
||||
}
|
||||
#ifdef AR_HSZ_BIG
|
||||
else if ( strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) == 0 )
|
||||
else if ( !strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) )
|
||||
{
|
||||
/* read big variant */
|
||||
file_archscan_big( fd, archive, func, closure );
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
#include "jam.h"
|
||||
#include "function.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "pathsys.h"
|
||||
#include "mem.h"
|
||||
#include "constants.h"
|
||||
#include "frames.h"
|
||||
#include "rules.h"
|
||||
#include "variable.h"
|
||||
#include "compile.h"
|
||||
#include "search.h"
|
||||
#include "class.h"
|
||||
#include "pathsys.h"
|
||||
#include "compile.h"
|
||||
#include "constants.h"
|
||||
#include "filesys.h"
|
||||
#include "frames.h"
|
||||
#include "lists.h"
|
||||
#include "mem.h"
|
||||
#include "pathsys.h"
|
||||
#include "rules.h"
|
||||
#include "search.h"
|
||||
#include "variable.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef OS_CYGWIN
|
||||
# include <cygwin/version.h>
|
||||
@@ -650,7 +649,9 @@ static void var_edit_cyg2win( string * out, size_t pos, VAR_EDITS * edits )
|
||||
if ( edits->to_windows )
|
||||
{
|
||||
#ifdef CYGWIN_VERSION_CYGWIN_CONV
|
||||
/* Use new Cygwin API added with Cygwin 1.7. */
|
||||
/* Use new Cygwin API added with Cygwin 1.7. Old one had no error
|
||||
* handling and has been deprecated.
|
||||
*/
|
||||
char * dynamicBuffer = 0;
|
||||
char buffer[ MAX_PATH + 1001 ];
|
||||
char const * result = buffer;
|
||||
|
||||
141
v2/engine/hash.c
141
v2/engine/hash.c
@@ -4,28 +4,26 @@
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "hash.h"
|
||||
# include "compile.h"
|
||||
# include "object.h"
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* hash.c - simple in-memory hashing routines
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* hashinit() - initialize a hash table, returning a handle
|
||||
* hashitem() - find a record in the table, and optionally enter a new one
|
||||
* hashdone() - free a hash table, given its handle
|
||||
*
|
||||
* Internal routines:
|
||||
*
|
||||
* hashrehash() - resize and rebuild hp->tab, the hash table
|
||||
*
|
||||
* 4/29/93 - ensure ITEM's are aligned
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "compile.h"
|
||||
#include "object.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* */
|
||||
#define HASH_DEBUG_PROFILE 1
|
||||
/* */
|
||||
@@ -51,7 +49,7 @@ struct hash
|
||||
*/
|
||||
struct {
|
||||
int nel;
|
||||
ITEM **base;
|
||||
ITEM * * base;
|
||||
} tab;
|
||||
|
||||
int bloat; /* tab.nel / items.nel */
|
||||
@@ -62,66 +60,61 @@ struct hash
|
||||
* essentially a microallocator
|
||||
*/
|
||||
struct {
|
||||
int more; /* how many more ITEMs fit in lists[ list ] */
|
||||
ITEM *free; /* free list of items */
|
||||
char *next; /* where to put more ITEMs in lists[ list ] */
|
||||
int size; /* sizeof( ITEM ) + aligned datalen */
|
||||
int nel; /* total ITEMs held by all lists[] */
|
||||
int list; /* index into lists[] */
|
||||
int more; /* how many more ITEMs fit in lists[ list ] */
|
||||
ITEM * free; /* free list of items */
|
||||
char * next; /* where to put more ITEMs in lists[ list ] */
|
||||
int size; /* sizeof( ITEM ) + aligned datalen */
|
||||
int nel; /* total ITEMs held by all lists[] */
|
||||
int list; /* index into lists[] */
|
||||
|
||||
struct {
|
||||
int nel; /* total ITEMs held by this list */
|
||||
char *base; /* base of ITEMs array */
|
||||
int nel; /* total ITEMs held by this list */
|
||||
char *base; /* base of ITEMs array */
|
||||
} lists[ MAX_LISTS ];
|
||||
} items;
|
||||
|
||||
const char * name; /* just for hashstats() */
|
||||
char const * name; /* just for hashstats() */
|
||||
};
|
||||
|
||||
static void hashrehash( struct hash *hp );
|
||||
static void hashstat( struct hash *hp );
|
||||
static void hashrehash( struct hash * );
|
||||
static void hashstat( struct hash * );
|
||||
|
||||
static unsigned int hash_keyval( OBJECT * key )
|
||||
{
|
||||
return object_hash( key );
|
||||
}
|
||||
|
||||
#define hash_bucket(hp,keyval) ((hp)->tab.base + ( (keyval) % (hp)->tab.nel ))
|
||||
#define hash_bucket(hp, keyval) ((hp)->tab.base + ((keyval) % (hp)->tab.nel))
|
||||
|
||||
#define hash_data_key(data) (*(OBJECT * *)(data))
|
||||
#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(struct hashhdr)))
|
||||
#define hash_item_key(item) (hash_data_key(hash_item_data(item)))
|
||||
|
||||
/* Find the hash item for the given data. Returns pointer to the
|
||||
item and if given a pointer to the item before the found item.
|
||||
If it's the first item in a bucket, there is no previous item,
|
||||
and zero is returned for the previous item instead.
|
||||
*/
|
||||
static ITEM * hash_search(
|
||||
struct hash *hp,
|
||||
unsigned int keyval,
|
||||
OBJECT * keydata,
|
||||
ITEM * * previous )
|
||||
{
|
||||
ITEM * i = *hash_bucket(hp,keyval);
|
||||
ITEM * p = 0;
|
||||
|
||||
/* Find the hash item for the given data. Returns a pointer to a hashed item
|
||||
* with the given key. If given a 'previous' pointer, makes it point to the item
|
||||
* prior to the found item in the same bucket or to 0 if our item is the first
|
||||
* item in its bucket.
|
||||
*/
|
||||
static ITEM * hash_search( struct hash * hp, unsigned int keyval,
|
||||
OBJECT * keydata, ITEM * * previous )
|
||||
{
|
||||
ITEM * i = *hash_bucket( hp, keyval );
|
||||
ITEM * p = 0;
|
||||
for ( ; i; i = i->hdr.next )
|
||||
{
|
||||
if ( object_equal( hash_item_key( i ), keydata ) )
|
||||
{
|
||||
if (previous)
|
||||
{
|
||||
if ( previous )
|
||||
*previous = p;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
p = i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hash_insert() - insert a record in the table or return the existing one
|
||||
*/
|
||||
@@ -132,7 +125,7 @@ HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
|
||||
unsigned int keyval = hash_keyval( key );
|
||||
|
||||
#ifdef HASH_DEBUG_PROFILE
|
||||
profile_frame prof[1];
|
||||
profile_frame prof[ 1 ];
|
||||
if ( DEBUG_PROFILE )
|
||||
profile_enter( 0, prof );
|
||||
#endif
|
||||
@@ -142,14 +135,12 @@ HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
|
||||
|
||||
i = hash_search( hp, keyval, key, 0 );
|
||||
if ( i )
|
||||
{
|
||||
*found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ITEM * * base = hash_bucket( hp, keyval );
|
||||
|
||||
/* try to grab one from the free list */
|
||||
/* Try to grab one from the free list. */
|
||||
if ( hp->items.free )
|
||||
{
|
||||
i = hp->items.free;
|
||||
@@ -161,7 +152,7 @@ HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
|
||||
i = (ITEM *)hp->items.next;
|
||||
hp->items.next += hp->items.size;
|
||||
}
|
||||
hp->items.more--;
|
||||
--hp->items.more;
|
||||
i->hdr.next = *base;
|
||||
*base = i;
|
||||
*found = 0;
|
||||
@@ -175,17 +166,18 @@ HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
|
||||
return hash_item_data( i );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hash_find() - find a record in the table or NULL if none exists
|
||||
*/
|
||||
|
||||
HASHDATA * hash_find( struct hash *hp, OBJECT *key )
|
||||
HASHDATA * hash_find( struct hash * hp, OBJECT * key )
|
||||
{
|
||||
ITEM *i;
|
||||
unsigned int keyval = hash_keyval(key);
|
||||
ITEM * i;
|
||||
unsigned int keyval = hash_keyval( key );
|
||||
|
||||
#ifdef HASH_DEBUG_PROFILE
|
||||
profile_frame prof[1];
|
||||
profile_frame prof[ 1 ];
|
||||
if ( DEBUG_PROFILE )
|
||||
profile_enter( 0, prof );
|
||||
#endif
|
||||
@@ -206,16 +198,10 @@ HASHDATA * hash_find( struct hash *hp, OBJECT *key )
|
||||
profile_exit( prof );
|
||||
#endif
|
||||
|
||||
if (i)
|
||||
{
|
||||
return hash_item_data( i );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return i ? hash_item_data( i ) : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hashrehash() - resize and rebuild hp->tab, the hash table
|
||||
*/
|
||||
@@ -227,8 +213,8 @@ static void hashrehash( register struct hash *hp )
|
||||
hp->items.next = (char *)BJAM_MALLOC( hp->items.more * hp->items.size );
|
||||
hp->items.free = 0;
|
||||
|
||||
hp->items.lists[i].nel = hp->items.more;
|
||||
hp->items.lists[i].base = hp->items.next;
|
||||
hp->items.lists[ i ].nel = hp->items.more;
|
||||
hp->items.lists[ i ].base = hp->items.next;
|
||||
hp->items.nel += hp->items.more;
|
||||
|
||||
if ( hp->tab.base )
|
||||
@@ -241,13 +227,13 @@ static void hashrehash( register struct hash *hp )
|
||||
|
||||
for ( i = 0; i < hp->items.list; ++i )
|
||||
{
|
||||
int nel = hp->items.lists[i].nel;
|
||||
char *next = hp->items.lists[i].base;
|
||||
int nel = hp->items.lists[ i ].nel;
|
||||
char * next = hp->items.lists[ i ].base;
|
||||
|
||||
for ( ; nel--; next += hp->items.size )
|
||||
{
|
||||
register ITEM *i = (ITEM *)next;
|
||||
ITEM **ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
|
||||
register ITEM * i = (ITEM *)next;
|
||||
ITEM * * ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
|
||||
/* code currently assumes rehashing only when there are no free items */
|
||||
assert( hash_item_key( i ) != 0 );
|
||||
|
||||
@@ -257,6 +243,7 @@ static void hashrehash( register struct hash *hp )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data )
|
||||
{
|
||||
int i;
|
||||
@@ -270,7 +257,7 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
|
||||
for ( ; nel--; next += hp->items.size )
|
||||
{
|
||||
ITEM * i = (ITEM *)next;
|
||||
if ( hash_item_key( i ) != 0 ) /* DO not enumerate freed items. */
|
||||
if ( hash_item_key( i ) != 0 ) /* Do not enumerate freed items. */
|
||||
f( hash_item_data( i ), data );
|
||||
}
|
||||
}
|
||||
@@ -278,33 +265,31 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
|
||||
|
||||
/* --- */
|
||||
|
||||
# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
|
||||
#define ALIGNED(x) ((x + sizeof(ITEM) - 1) & ~(sizeof(ITEM) - 1))
|
||||
|
||||
/*
|
||||
* hashinit() - initialize a hash table, returning a handle
|
||||
*/
|
||||
|
||||
struct hash *
|
||||
hashinit(
|
||||
int datalen,
|
||||
const char *name )
|
||||
struct hash * hashinit( int datalen, char const * name )
|
||||
{
|
||||
struct hash *hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
|
||||
struct hash * hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
|
||||
|
||||
hp->bloat = 3;
|
||||
hp->tab.nel = 0;
|
||||
hp->tab.base = (ITEM **)0;
|
||||
hp->tab.base = (ITEM * *)0;
|
||||
hp->items.more = 0;
|
||||
hp->items.free = 0;
|
||||
hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
|
||||
hp->items.list = -1;
|
||||
hp->items.nel = 0;
|
||||
hp->inel = 11 /* 47 */;
|
||||
hp->inel = 11; /* 47 */
|
||||
hp->name = name;
|
||||
|
||||
return hp;
|
||||
}
|
||||
|
||||
|
||||
void hashdone( struct hash * hp )
|
||||
{
|
||||
if ( !hp )
|
||||
@@ -314,22 +299,20 @@ void hashdone( struct hash * hp )
|
||||
hash_free( hp );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hash_free() - free a hash table, given its handle
|
||||
*/
|
||||
|
||||
void
|
||||
hash_free( struct hash * hp )
|
||||
void hash_free( struct hash * hp )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( !hp )
|
||||
return;
|
||||
|
||||
if ( hp->tab.base )
|
||||
BJAM_FREE( (char *)hp->tab.base );
|
||||
for ( i = 0; i <= hp->items.list; ++i )
|
||||
BJAM_FREE( hp->items.lists[i].base );
|
||||
BJAM_FREE( hp->items.lists[ i ].base );
|
||||
BJAM_FREE( (char *)hp );
|
||||
}
|
||||
|
||||
@@ -367,7 +350,7 @@ void hashstats_add( struct hashstats * stats, struct hash * hp )
|
||||
{
|
||||
ITEM * item;
|
||||
int here = 0;
|
||||
for ( item = tab[ i ]; item != 0; item = item->hdr.next )
|
||||
for ( item = tab[ i ]; item; item = item->hdr.next )
|
||||
++here;
|
||||
|
||||
count += here;
|
||||
@@ -383,7 +366,7 @@ void hashstats_add( struct hashstats * stats, struct hash * hp )
|
||||
}
|
||||
}
|
||||
|
||||
void hashstats_print( struct hashstats * stats, const char * name )
|
||||
void hashstats_print( struct hashstats * stats, char const * name )
|
||||
{
|
||||
printf( "%s table: %d+%d+%d (%dK+%luK) items+table+hash, %f density\n",
|
||||
name,
|
||||
|
||||
@@ -11,57 +11,57 @@
|
||||
#ifndef BOOST_JAM_HASH_H
|
||||
#define BOOST_JAM_HASH_H
|
||||
|
||||
#include "object.h"
|
||||
|
||||
/*
|
||||
* An opaque struct representing an item in the
|
||||
* hash table. The first element of every struct
|
||||
* stored in the table must be an OBJECT * which
|
||||
* is treated as the key.
|
||||
* An opaque struct representing an item in the hash table. The first element of
|
||||
* every struct stored in the table must be an OBJECT * which is treated as the
|
||||
* key.
|
||||
*/
|
||||
typedef struct hashdata HASHDATA;
|
||||
|
||||
/*
|
||||
* hashinit() - initialize a hash table, returning a handle.
|
||||
* datalen is the size of the items. name is used for debugging.
|
||||
*
|
||||
* Parameters:
|
||||
* datalen - item size
|
||||
* name - used for debugging
|
||||
*/
|
||||
struct hash * hashinit ( int datalen, const char * name );
|
||||
struct hash * hashinit( int datalen, char const * name );
|
||||
|
||||
/*
|
||||
* hash_free() - free a hash table, given its handle
|
||||
*/
|
||||
void hash_free( struct hash * hp );
|
||||
void hashdone( struct hash * hp );
|
||||
void hash_free( struct hash * );
|
||||
void hashdone( struct hash * );
|
||||
|
||||
/*
|
||||
* hashenumerate() - call f(i, data) on each item, i in the hash
|
||||
* table. The order of the items is unspecified.
|
||||
* hashenumerate() - call f(i, data) on each item, i in the hash table. The
|
||||
* enumeration order is unspecified.
|
||||
*/
|
||||
void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
|
||||
void hashenumerate( struct hash *, void (* f)( void *, void * ), void * data );
|
||||
|
||||
/*
|
||||
* hash_insert() - insert a new item in a hash table, or return an
|
||||
* existing one.
|
||||
* hash_insert() - insert a new item in a hash table, or return an existing one.
|
||||
*
|
||||
* Preconditions:
|
||||
* - hp must be a hash table created by hashinit
|
||||
* - key must be an object created by object_new
|
||||
* - hp must be a hash table created by hashinit()
|
||||
* - key must be an object created by object_new()
|
||||
*
|
||||
* Postconditions:
|
||||
* - if the key does not already exist in the hash
|
||||
* table, *found == 0 and the result will be a
|
||||
* pointer to an uninitialized item. The key
|
||||
* of the new item must be set to a value equal to
|
||||
* key before any further operations on the
|
||||
* hash table except hashdone.
|
||||
* - if the key is present then *found == 1 and
|
||||
* the result is a pointer to the existing
|
||||
* record.
|
||||
* - if the key does not already exist in the hash table, *found == 0 and the
|
||||
* result will be a pointer to an uninitialized item. The key of the new
|
||||
* item must be set to a value equal to key before any further operations on
|
||||
* the hash table except hashdone().
|
||||
* - if the key is present then *found == 1 and the result is a pointer to the
|
||||
* existing record.
|
||||
*/
|
||||
HASHDATA * hash_insert ( struct hash * hp, OBJECT * key, int * found );
|
||||
HASHDATA * hash_insert( struct hash *, OBJECT * key, int * found );
|
||||
|
||||
/*
|
||||
* hash_find() - find a record in the table or NULL if none exists
|
||||
*/
|
||||
HASHDATA * hash_find ( struct hash * hp, OBJECT * key );
|
||||
HASHDATA * hash_find( struct hash *, OBJECT * key );
|
||||
|
||||
struct hashstats {
|
||||
int count;
|
||||
@@ -73,6 +73,6 @@ struct hashstats {
|
||||
|
||||
void hashstats_init( struct hashstats * stats );
|
||||
void hashstats_add( struct hashstats * stats, struct hash * hp );
|
||||
void hashstats_print( struct hashstats * stats, const char * name );
|
||||
void hashstats_print( struct hashstats * stats, char const * name );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,21 +2,6 @@
|
||||
* This file has been donated to Jam.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "lists.h"
|
||||
# include "parse.h"
|
||||
# include "rules.h"
|
||||
# include "regexp.h"
|
||||
# include "headers.h"
|
||||
# include "object.h"
|
||||
# include "hash.h"
|
||||
# include "hcache.h"
|
||||
# include "variable.h"
|
||||
# include "search.h"
|
||||
# include "modules.h"
|
||||
|
||||
#ifdef OPT_HEADER_CACHE_EXT
|
||||
|
||||
/*
|
||||
* Craig W. McPheeters, Alias|Wavefront.
|
||||
*
|
||||
@@ -28,7 +13,7 @@
|
||||
* files found in their scan. During the binding phase of jam, look in the
|
||||
* header cache first for the headers contained in a file. If the cache is
|
||||
* present and valid, use its contents. This results in dramatic speedups with
|
||||
* large projects (eg. 3min -> 1min startup for one project.)
|
||||
* large projects (e.g. 3min -> 1min startup for one project.)
|
||||
*
|
||||
* External routines:
|
||||
* hcache_init() - read and parse the local .jamdeps file.
|
||||
@@ -37,9 +22,25 @@
|
||||
*
|
||||
* The dependency file format is an ASCII file with 1 line per target. Each line
|
||||
* has the following fields:
|
||||
* @boundname@ timestamp @file@ @file@ @file@ ... \n
|
||||
* @boundname@ timestamp @file@ @file@ @file@ ...
|
||||
*/
|
||||
|
||||
#ifdef OPT_HEADER_CACHE_EXT
|
||||
|
||||
#include "jam.h"
|
||||
#include "hcache.h"
|
||||
|
||||
#include "hash.h"
|
||||
#include "headers.h"
|
||||
#include "lists.h"
|
||||
#include "modules.h"
|
||||
#include "object.h"
|
||||
#include "parse.h"
|
||||
#include "regexp.h"
|
||||
#include "rules.h"
|
||||
#include "search.h"
|
||||
#include "variable.h"
|
||||
|
||||
typedef struct hcachedata HCACHEDATA ;
|
||||
|
||||
struct hcachedata
|
||||
@@ -48,13 +49,13 @@ struct hcachedata
|
||||
time_t time;
|
||||
LIST * includes;
|
||||
LIST * hdrscan; /* the HDRSCAN value for this target */
|
||||
int age; /* if too old, we'll remove it from cache */
|
||||
int age; /* if too old, we will remove it from cache */
|
||||
HCACHEDATA * next;
|
||||
};
|
||||
|
||||
|
||||
static struct hash * hcachehash = 0;
|
||||
static HCACHEDATA * hcachelist = 0;
|
||||
static HCACHEDATA * hcachelist = 0;
|
||||
|
||||
static int queries = 0;
|
||||
static int hits = 0;
|
||||
@@ -76,11 +77,11 @@ static const char * cache_name( void )
|
||||
static OBJECT * name = 0;
|
||||
if ( !name )
|
||||
{
|
||||
LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );
|
||||
LIST * const hcachevar = var_get( root_module(), constant_HCACHEFILE );
|
||||
|
||||
if ( !list_empty( hcachevar ) )
|
||||
{
|
||||
TARGET * t = bindtarget( list_front( hcachevar ) );
|
||||
TARGET * const t = bindtarget( list_front( hcachevar ) );
|
||||
|
||||
pushsettings( root_module(), t->settings );
|
||||
/* Do not expect the cache file to be generated, so pass 0 as the
|
||||
@@ -99,14 +100,14 @@ static const char * cache_name( void )
|
||||
|
||||
|
||||
/*
|
||||
* Return the maximum age a cache entry can have before it is purged ftom the
|
||||
* Return the maximum age a cache entry can have before it is purged from the
|
||||
* cache.
|
||||
*/
|
||||
|
||||
static int cache_maxage( void )
|
||||
{
|
||||
int age = 100;
|
||||
LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
|
||||
LIST * const var = var_get( root_module(), constant_HCACHEMAXAGE );
|
||||
if ( !list_empty( var ) )
|
||||
{
|
||||
age = atoi( object_str( list_front( var ) ) );
|
||||
@@ -235,7 +236,8 @@ void hcache_init()
|
||||
age_str = read_netstring( f );
|
||||
includes_count_str = read_netstring( f );
|
||||
|
||||
if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
|
||||
if ( !cachedata.boundname || !time_str || !age_str ||
|
||||
!includes_count_str )
|
||||
{
|
||||
fprintf( stderr, "invalid %s\n", hcachename );
|
||||
goto cleanup;
|
||||
@@ -268,7 +270,7 @@ void hcache_init()
|
||||
count = atoi( object_str( hdrscan_count_str ) );
|
||||
for ( l = L0, i = 0; i < count; ++i )
|
||||
{
|
||||
OBJECT * s = read_netstring( f );
|
||||
OBJECT * const s = read_netstring( f );
|
||||
if ( !s )
|
||||
{
|
||||
fprintf( stderr, "invalid %s\n", hcachename );
|
||||
@@ -279,7 +281,8 @@ void hcache_init()
|
||||
}
|
||||
cachedata.hdrscan = l;
|
||||
|
||||
c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found );
|
||||
c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found )
|
||||
;
|
||||
if ( !found )
|
||||
{
|
||||
c->boundname = cachedata.boundname;
|
||||
@@ -290,8 +293,8 @@ void hcache_init()
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "can't insert header cache item, bailing on %s\n",
|
||||
hcachename );
|
||||
fprintf( stderr, "can not insert header cache item, bailing on %s"
|
||||
"\n", hcachename );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -299,7 +302,7 @@ void hcache_init()
|
||||
hcachelist = c;
|
||||
|
||||
++header_count;
|
||||
|
||||
|
||||
object_free( record_type );
|
||||
object_free( time_str );
|
||||
object_free( age_str );
|
||||
@@ -357,11 +360,12 @@ void hcache_done()
|
||||
c = hcachelist;
|
||||
for ( c = hcachelist; c; c = c->next )
|
||||
{
|
||||
LISTITER iter, end;
|
||||
char time_str[ 30 ];
|
||||
char age_str[ 30 ];
|
||||
char includes_count_str[ 30 ];
|
||||
char hdrscan_count_str[ 30 ];
|
||||
LISTITER iter;
|
||||
LISTITER end;
|
||||
char time_str[ 30 ];
|
||||
char age_str[ 30 ];
|
||||
char includes_count_str[ 30 ];
|
||||
char hdrscan_count_str[ 30 ];
|
||||
|
||||
if ( maxage == 0 )
|
||||
c->age = 0;
|
||||
@@ -370,8 +374,8 @@ void hcache_done()
|
||||
|
||||
sprintf( includes_count_str, "%lu", (long unsigned) list_length( c->includes ) );
|
||||
sprintf( hdrscan_count_str, "%lu", (long unsigned) list_length( c->hdrscan ) );
|
||||
sprintf( time_str, "%lu", (long unsigned) c->time );
|
||||
sprintf( age_str, "%lu", (long unsigned) c->age );
|
||||
sprintf( time_str, "%lu", (long unsigned)c->time );
|
||||
sprintf( age_str, "%lu", (long unsigned)c->age );
|
||||
|
||||
write_netstring( f, CACHE_RECORD_HEADER );
|
||||
write_netstring( f, object_str( c->boundname ) );
|
||||
@@ -395,7 +399,7 @@ void hcache_done()
|
||||
hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
|
||||
|
||||
fclose ( f );
|
||||
|
||||
|
||||
cleanup:
|
||||
for ( c = hcachelist; c; c = c->next )
|
||||
{
|
||||
@@ -423,15 +427,16 @@ LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
|
||||
{
|
||||
if ( c->time == t->time )
|
||||
{
|
||||
LIST *l1 = hdrscan, *l2 = c->hdrscan;
|
||||
LISTITER iter1 = list_begin( l1 ), end1 = list_end( l1 ),
|
||||
iter2 = list_begin( l2 ), end2 = list_end( l2 );
|
||||
LIST * const l1 = hdrscan;
|
||||
LIST * const l2 = c->hdrscan;
|
||||
LISTITER iter1 = list_begin( l1 );
|
||||
LISTITER const end1 = list_end( l1 );
|
||||
LISTITER iter2 = list_begin( l2 );
|
||||
LISTITER const end2 = list_end( l2 );
|
||||
while ( iter1 != end1 && iter2 != end2 )
|
||||
{
|
||||
if ( !object_equal( list_item( iter1 ), list_item( iter2 ) ) )
|
||||
{
|
||||
iter1 = end1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter1 = list_next( iter1 );
|
||||
@@ -440,12 +445,12 @@ LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
|
||||
}
|
||||
if ( iter1 != end1 || iter2 != end2 )
|
||||
{
|
||||
if (DEBUG_HEADER)
|
||||
if ( DEBUG_HEADER )
|
||||
printf( "HDRSCAN out of date in cache for %s\n",
|
||||
object_str( t->boundname ) );
|
||||
|
||||
printf( "HDRSCAN out of date for %s\n",
|
||||
object_str( t->boundname ) );
|
||||
printf( "HDRSCAN out of date for %s\n", object_str(
|
||||
t->boundname ) );
|
||||
printf(" real : ");
|
||||
list_print( hdrscan );
|
||||
printf( "\n cached: " );
|
||||
@@ -459,9 +464,9 @@ LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_HEADER)
|
||||
printf( "using header cache for %s\n",
|
||||
object_str( t->boundname ) );
|
||||
if ( DEBUG_HEADER )
|
||||
printf( "using header cache for %s\n", object_str(
|
||||
t->boundname ) );
|
||||
c->age = 0;
|
||||
++hits;
|
||||
l = list_copy( c->includes );
|
||||
@@ -470,9 +475,9 @@ LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_HEADER)
|
||||
printf ("header cache out of date for %s\n",
|
||||
object_str( t->boundname ) );
|
||||
if ( DEBUG_HEADER )
|
||||
printf ("header cache out of date for %s\n", object_str(
|
||||
t->boundname ) );
|
||||
list_free( c->includes );
|
||||
list_free( c->hdrscan );
|
||||
c->includes = L0;
|
||||
@@ -503,4 +508,4 @@ LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
|
||||
return l;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* OPT_HEADER_CACHE_EXT */
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
* hcache.h - handle #includes in source files
|
||||
*/
|
||||
#ifndef HCACHE_H
|
||||
# define HCACHE_H
|
||||
#define HCACHE_H
|
||||
|
||||
# include "regexp.h"
|
||||
# include "lists.h"
|
||||
#include "lists.h"
|
||||
#include "regexp.h"
|
||||
#include "rules.h"
|
||||
|
||||
void hcache_init( void );
|
||||
void hcache_done( void );
|
||||
LIST * hcache( TARGET *t, int rec, regexp * re[], LIST * hdrscan );
|
||||
LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,8 +12,11 @@
|
||||
#ifndef HDRMACRO_SW20111118_H
|
||||
#define HDRMACRO_SW20111118_H
|
||||
|
||||
void macro_headers( TARGET *t );
|
||||
#include "object.h"
|
||||
#include "rules.h"
|
||||
|
||||
OBJECT * macro_header_get( OBJECT * macro_name );
|
||||
void macro_headers( TARGET * t );
|
||||
|
||||
OBJECT * macro_header_get( OBJECT * macro_name );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -440,7 +440,7 @@ extern struct globs globs;
|
||||
#define DEBUG_MAKE ( globs.debug[ 1 ] ) /* show actions when executed */
|
||||
#define DEBUG_MAKEQ ( globs.debug[ 2 ] ) /* show even quiet actions */
|
||||
#define DEBUG_EXEC ( globs.debug[ 2 ] ) /* show text of actons */
|
||||
#define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show progress of make0 */
|
||||
#define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show make0 progress */
|
||||
#define DEBUG_BIND ( globs.debug[ 3 ] ) /* show when files bound */
|
||||
|
||||
#define DEBUG_EXECCMD ( globs.debug[ 4 ] ) /* show execcmds()'s work */
|
||||
@@ -449,7 +449,7 @@ extern struct globs globs;
|
||||
|
||||
#define DEBUG_HEADER ( globs.debug[ 6 ] ) /* show result of header scan */
|
||||
#define DEBUG_BINDSCAN ( globs.debug[ 6 ] ) /* show result of dir scan */
|
||||
#define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show attempts at binding */
|
||||
#define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show binding attempts */
|
||||
|
||||
#define DEBUG_VARSET ( globs.debug[ 7 ] ) /* show variable settings */
|
||||
#define DEBUG_VARGET ( globs.debug[ 8 ] ) /* show variable fetches */
|
||||
@@ -462,7 +462,7 @@ extern struct globs globs;
|
||||
#define DEBUG_PROFILE ( globs.debug[ 10 ] ) /* dump rule execution times */
|
||||
#define DEBUG_PARSE ( globs.debug[ 11 ] ) /* debug parsing */
|
||||
#define DEBUG_GRAPH ( globs.debug[ 12 ] ) /* debug dependencies */
|
||||
#define DEBUG_FATE ( globs.debug[ 13 ] ) /* show changes to fate in make0() */
|
||||
#define DEBUG_FATE ( globs.debug[ 13 ] ) /* show fate changes in make0() */
|
||||
|
||||
/* Everyone gets the memory definitions. */
|
||||
#include "mem.h"
|
||||
|
||||
134
v2/engine/make.c
134
v2/engine/make.c
@@ -27,45 +27,27 @@
|
||||
* Internal routines:
|
||||
* make0() - bind and scan everything to make a TARGET
|
||||
* make0sort() - reorder TARGETS chain by their time (newest to oldest)
|
||||
*
|
||||
* 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>).
|
||||
* 01/04/94 (seiwald) - print all targets, bounded, when tracing commands.
|
||||
* 04/08/94 (seiwald) - progress report now reflects only targets with actions.
|
||||
* 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
|
||||
* 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
|
||||
* 12/20/94 (seiwald) - make0() headers after determining fate of target, so
|
||||
* that headers are not seen as being dependent on
|
||||
* themselves.
|
||||
* 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
|
||||
* 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule.
|
||||
* 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target.
|
||||
* 08/22/95 (seiwald) - NOUPDATE targets immune to anyhow (-a) flag.
|
||||
* 09/06/00 (seiwald) - NOCARE affects targets with sources/actions.
|
||||
* 03/02/01 (seiwald) - reverse NOCARE change.
|
||||
* 03/14/02 (seiwald) - TEMPORARY targets no longer take on parents age.
|
||||
* 03/16/02 (seiwald) - support for -g (reorder builds by source time).
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "parse.h"
|
||||
#include "variable.h"
|
||||
#include "rules.h"
|
||||
|
||||
#ifdef OPT_HEADER_CACHE_EXT
|
||||
#include "hcache.h"
|
||||
#endif
|
||||
|
||||
#include "search.h"
|
||||
#include "object.h"
|
||||
#include "make.h"
|
||||
#include "headers.h"
|
||||
#include "command.h"
|
||||
#ifdef OPT_HEADER_CACHE_EXT
|
||||
# include "hcache.h"
|
||||
#endif
|
||||
#include "headers.h"
|
||||
#include "lists.h"
|
||||
#include "make.h"
|
||||
#include "object.h"
|
||||
#include "parse.h"
|
||||
#include "rules.h"
|
||||
#include "search.h"
|
||||
#include "variable.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef max
|
||||
#define max( a,b ) ((a)>(b)?(a):(b))
|
||||
# define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
static TARGETS * make0sort( TARGETS * c );
|
||||
@@ -99,7 +81,7 @@ static const char * target_bind[] =
|
||||
"exists",
|
||||
};
|
||||
|
||||
# define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
|
||||
#define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
|
||||
|
||||
|
||||
/*
|
||||
@@ -109,7 +91,7 @@ static const char * target_bind[] =
|
||||
int make( LIST * targets, int anyhow )
|
||||
{
|
||||
COUNTS counts[ 1 ];
|
||||
int status = 0; /* 1 if anything fails */
|
||||
int status = 0; /* 1 if anything fails */
|
||||
|
||||
#ifdef OPT_HEADER_CACHE_EXT
|
||||
hcache_init();
|
||||
@@ -165,9 +147,11 @@ int make( LIST * targets, int anyhow )
|
||||
status = counts->cantfind || counts->cantmake;
|
||||
|
||||
{
|
||||
LISTITER iter, end;
|
||||
LISTITER iter;
|
||||
LISTITER end;
|
||||
PROFILE_ENTER( MAKE_MAKE1 );
|
||||
for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
|
||||
for ( iter = list_begin( targets ), end = list_end( targets ); iter !=
|
||||
end; iter = list_next( iter ) )
|
||||
status |= make1( bindtarget( list_item( iter ) ) );
|
||||
PROFILE_EXIT( MAKE_MAKE1 );
|
||||
}
|
||||
@@ -310,7 +294,8 @@ void make0
|
||||
SETTINGS * s;
|
||||
|
||||
#ifdef OPT_GRAPH_DEBUG_EXT
|
||||
int savedFate, oldTimeStamp;
|
||||
int savedFate;
|
||||
int oldTimeStamp;
|
||||
#endif
|
||||
|
||||
if ( DEBUG_MAKEPROG )
|
||||
@@ -327,8 +312,8 @@ void make0
|
||||
t->depth = depth;
|
||||
|
||||
/*
|
||||
* Step 2: under the influence of "on target" variables,
|
||||
* bind the target and search for headers.
|
||||
* Step 2: under the influence of "on target" variables, bind the target and
|
||||
* search for headers.
|
||||
*/
|
||||
|
||||
/* Step 2a: set "on target" variables. */
|
||||
@@ -341,10 +326,10 @@ void make0
|
||||
OBJECT * another_target;
|
||||
object_free( t->boundname );
|
||||
t->boundname = search( t->name, &t->time, &another_target,
|
||||
t->flags & T_FLAG_ISFILE );
|
||||
t->flags & T_FLAG_ISFILE );
|
||||
/* If it was detected that this target refers to an already existing and
|
||||
* bound one, we add a dependency, so that every target
|
||||
* depending on us will depend on that other target as well.
|
||||
* bound target, we add a dependency so that every target depending on
|
||||
* us will depend on that other target as well.
|
||||
*/
|
||||
if ( another_target )
|
||||
located_target = bindtarget( another_target );
|
||||
@@ -370,7 +355,7 @@ void make0
|
||||
LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
|
||||
if ( !list_empty( var ) )
|
||||
{
|
||||
TARGET * semaphore = bindtarget( list_front( var ) );
|
||||
TARGET * const semaphore = bindtarget( list_front( var ) );
|
||||
semaphore->progress = T_MAKE_SEMAPHORE;
|
||||
t->semaphore = semaphore;
|
||||
}
|
||||
@@ -386,27 +371,27 @@ void make0
|
||||
freesettings( s );
|
||||
|
||||
/*
|
||||
* Pause for a little progress reporting .
|
||||
* Pause for a little progress reporting.
|
||||
*/
|
||||
|
||||
if ( DEBUG_BIND )
|
||||
{
|
||||
if ( ! object_equal( t->name, t->boundname ) )
|
||||
printf( "bind\t--\t%s%s: %s\n",
|
||||
spaces( depth ), object_str( t->name ), object_str( t->boundname ) );
|
||||
if ( !object_equal( t->name, t->boundname ) )
|
||||
printf( "bind\t--\t%s%s: %s\n", spaces( depth ),
|
||||
object_str( t->name ), object_str( t->boundname ) );
|
||||
|
||||
switch ( t->binding )
|
||||
{
|
||||
case T_BIND_UNBOUND:
|
||||
case T_BIND_MISSING:
|
||||
case T_BIND_PARENTS:
|
||||
printf( "time\t--\t%s%s: %s\n",
|
||||
spaces( depth ), object_str( t->name ), target_bind[ (int) t->binding ] );
|
||||
printf( "time\t--\t%s%s: %s\n", spaces( depth ),
|
||||
object_str( t->name ), target_bind[ (int)t->binding ] );
|
||||
break;
|
||||
|
||||
case T_BIND_EXISTS:
|
||||
printf( "time\t--\t%s%s: %s",
|
||||
spaces( depth ), object_str( t->name ), ctime( &t->time ) );
|
||||
printf( "time\t--\t%s%s: %s", spaces( depth ),
|
||||
object_str( t->name ), ctime( &t->time ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -418,7 +403,7 @@ void make0
|
||||
/* Step 3a: recursively make0() dependencies. */
|
||||
for ( c = t->depends; c; c = c->next )
|
||||
{
|
||||
int internal = t->flags & T_FLAG_INTERNAL;
|
||||
int const internal = t->flags & T_FLAG_INTERNAL;
|
||||
|
||||
/* Warn about circular deps, except for includes, which include each
|
||||
* other alot.
|
||||
@@ -426,17 +411,20 @@ void make0
|
||||
if ( c->target->fate == T_FATE_INIT )
|
||||
make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
|
||||
else if ( c->target->fate == T_FATE_MAKING && !internal )
|
||||
printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
|
||||
printf( "warning: %s depends on itself\n", object_str(
|
||||
c->target->name ) );
|
||||
else if ( c->target->fate != T_FATE_MAKING && rescanning )
|
||||
make0rescan( c->target, rescanning );
|
||||
if ( rescanning && c->target->includes && c->target->includes->fate != T_FATE_MAKING )
|
||||
if ( rescanning && c->target->includes && c->target->includes->fate !=
|
||||
T_FATE_MAKING )
|
||||
make0rescan( target_scc( c->target->includes ), rescanning );
|
||||
}
|
||||
|
||||
if ( located_target )
|
||||
{
|
||||
if ( located_target->fate == T_FATE_INIT )
|
||||
make0( located_target, ptime, depth + 1, counts, anyhow, rescanning );
|
||||
make0( located_target, ptime, depth + 1, counts, anyhow, rescanning
|
||||
);
|
||||
else if ( located_target->fate != T_FATE_MAKING && rescanning )
|
||||
make0rescan( located_target, rescanning );
|
||||
}
|
||||
@@ -486,12 +474,12 @@ void make0
|
||||
fate = T_FATE_STABLE;
|
||||
for ( c = t->depends; c; c = c->next )
|
||||
{
|
||||
/* If we're in a different strongly connected component,
|
||||
* pull timestamps from the root.
|
||||
/* If we are in a different strongly connected component, pull
|
||||
* timestamps from the root.
|
||||
*/
|
||||
if ( c->target->scc_root )
|
||||
{
|
||||
TARGET * scc_root = target_scc( c->target );
|
||||
TARGET * const scc_root = target_scc( c->target );
|
||||
if ( scc_root != t->scc_root )
|
||||
{
|
||||
c->target->leaf = max( c->target->leaf, scc_root->leaf );
|
||||
@@ -504,13 +492,11 @@ void make0
|
||||
* source nodes.
|
||||
*/
|
||||
leaf = max( leaf, c->target->leaf );
|
||||
|
||||
if ( t->flags & T_FLAG_LEAVES )
|
||||
{
|
||||
last = leaf;
|
||||
continue;
|
||||
}
|
||||
|
||||
last = max( last, c->target->time );
|
||||
fate = max( fate, c->target->fate );
|
||||
|
||||
@@ -518,18 +504,18 @@ void make0
|
||||
if ( DEBUG_FATE )
|
||||
if ( fate < c->target->fate )
|
||||
printf( "fate change %s from %s to %s by dependency %s\n",
|
||||
object_str( t->name ), target_fate[(int) fate], target_fate[(int) c->target->fate],
|
||||
object_str( c->target->name ) );
|
||||
object_str( t->name ), target_fate[ (int)fate ],
|
||||
target_fate[ (int)c->target->fate ], object_str(
|
||||
c->target->name ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Step 4b: pick up included headers time */
|
||||
|
||||
/*
|
||||
* If a header is newer than a temp source that includes it,
|
||||
* the temp source will need building.
|
||||
* If a header is newer than a temp source that includes it, the temp source
|
||||
* will need building.
|
||||
*/
|
||||
|
||||
hlast = t->includes ? t->includes->time : 0;
|
||||
|
||||
/* Step 4c: handle NOUPDATE oddity.
|
||||
@@ -571,9 +557,8 @@ void make0
|
||||
If target newer than non-notfile parent, mark target newer.
|
||||
Otherwise, stable!
|
||||
|
||||
Note this block runs from least to most stable:
|
||||
as we make it further down the list, the target's
|
||||
fate is getting stabler.
|
||||
Note this block runs from least to most stable: as we make it further
|
||||
down the list, the target's fate gets more stable.
|
||||
*/
|
||||
|
||||
#ifdef OPT_GRAPH_DEBUG_EXT
|
||||
@@ -643,8 +628,8 @@ void make0
|
||||
target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
|
||||
else
|
||||
printf( "fate change %s from %s to %s%s\n", object_str( t->name ),
|
||||
target_fate[ savedFate ], target_fate[ fate ],
|
||||
oldTimeStamp ? " (by timestamp)" : "" );
|
||||
target_fate[ savedFate ], target_fate[ fate ], oldTimeStamp ?
|
||||
" (by timestamp)" : "" );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -737,7 +722,7 @@ void make0
|
||||
flag = "*";
|
||||
|
||||
if ( DEBUG_MAKEPROG )
|
||||
printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int) t->fate ],
|
||||
printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int)t->fate ],
|
||||
spaces( depth ), object_str( t->name ) );
|
||||
}
|
||||
|
||||
@@ -837,7 +822,7 @@ static void dependGraphOutput( TARGET * t, int depth )
|
||||
for ( c = t->depends; c; c = c->next )
|
||||
{
|
||||
printf( " %s : Depends on %s (%s)", spaces( depth ),
|
||||
target_name( c->target ), target_fate[ (int) c->target->fate ] );
|
||||
target_name( c->target ), target_fate[ (int)c->target->fate ] );
|
||||
if ( c->target->time == t->time )
|
||||
printf( " (max time)");
|
||||
printf( "\n" );
|
||||
@@ -877,9 +862,7 @@ static TARGETS * make0sort( TARGETS * chain )
|
||||
while ( s && ( s->target->time > c->target->time ) )
|
||||
s = s->next;
|
||||
|
||||
/* Insert c in front of s (might be 0). Do not even think of deciphering
|
||||
* this.
|
||||
*/
|
||||
/* Insert c in front of s (might be 0). */
|
||||
c->next = s; /* good even if s = 0 */
|
||||
if ( result == s ) result = c; /* new head of chain? */
|
||||
if ( !s ) s = result; /* wrap to ensure a next */
|
||||
@@ -898,7 +881,8 @@ static LIST * targets_to_update_ = L0;
|
||||
|
||||
void mark_target_for_updating( OBJECT * target )
|
||||
{
|
||||
targets_to_update_ = list_push_back( targets_to_update_, object_copy( target ) );
|
||||
targets_to_update_ = list_push_back( targets_to_update_, object_copy(
|
||||
target ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1262,7 +1262,7 @@ static void make1bind( TARGET * t )
|
||||
|
||||
pushsettings( root_module(), t->settings );
|
||||
object_free( t->boundname );
|
||||
t->boundname = search( t->name, &t->time, 0, ( t->flags & T_FLAG_ISFILE ) );
|
||||
t->boundname = search( t->name, &t->time, 0, t->flags & T_FLAG_ISFILE );
|
||||
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
|
||||
popsettings( root_module(), t->settings );
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/* Use Boehm GC memory allocator. */
|
||||
#include <gc.h>
|
||||
|
||||
#define bjam_malloc_x(s) memset(GC_malloc(s),0,s)
|
||||
#define bjam_malloc_atomic_x(s) memset(GC_malloc_atomic(s),0,s)
|
||||
#define bjam_calloc_x(n,s) memset(GC_malloc((n)*(s)),0,(n)*(s))
|
||||
@@ -27,13 +28,14 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
#define bjam_free_raw_x(p) free(p)
|
||||
|
||||
#ifndef BJAM_NEWSTR_NO_ALLOCATE
|
||||
#define BJAM_NEWSTR_NO_ALLOCATE
|
||||
# define BJAM_NEWSTR_NO_ALLOCATE
|
||||
#endif
|
||||
|
||||
#elif defined(OPT_DUMA)
|
||||
|
||||
/* Use Duma memory debugging library. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _DUMA_CONFIG_H_
|
||||
#define DUMA_NO_GLOBAL_MALLOC_FREE
|
||||
#define DUMA_EXPLICIT_INIT
|
||||
@@ -50,13 +52,14 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
typedef unsigned int DUMA_ADDR;
|
||||
typedef unsigned int DUMA_SIZE;
|
||||
#include <duma.h>
|
||||
|
||||
#define bjam_malloc_x(s) malloc(s)
|
||||
#define bjam_calloc_x(n,s) calloc(n,s)
|
||||
#define bjam_realloc_x(p,s) realloc(p,s)
|
||||
#define bjam_free_x(p) free(p)
|
||||
|
||||
#ifndef BJAM_NEWSTR_NO_ALLOCATE
|
||||
#define BJAM_NEWSTR_NO_ALLOCATE
|
||||
# define BJAM_NEWSTR_NO_ALLOCATE
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -95,7 +98,6 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
#endif
|
||||
|
||||
#ifdef OPT_DEBUG_PROFILE
|
||||
|
||||
/* Profile tracing of memory allocations. */
|
||||
#define BJAM_MALLOC(s) (profile_memory(s), bjam_malloc_x(s))
|
||||
#define BJAM_MALLOC_ATOMIC(s) (profile_memory(s), bjam_malloc_atomic_x(s))
|
||||
@@ -106,9 +108,7 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
#define BJAM_MALLOC_RAW(s) (profile_memory(s), bjam_malloc_raw_x(s))
|
||||
#define BJAM_CALLOC_RAW(n,s) (profile_memory(n*s), bjam_calloc_raw_x(n,s))
|
||||
#define BJAM_REALLOC_RAW(p,s) (profile_memory(s), bjam_realloc_raw_x(p,s))
|
||||
|
||||
#else
|
||||
|
||||
/* No mem tracing. */
|
||||
#define BJAM_MALLOC(s) bjam_malloc_x(s)
|
||||
#define BJAM_MALLOC_ATOMIC(s) bjam_malloc_atomic_x(s)
|
||||
@@ -119,13 +119,12 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
#define BJAM_MALLOC_RAW(s) bjam_malloc_raw_x(s)
|
||||
#define BJAM_CALLOC_RAW(n,s) bjam_calloc_raw_x(n,s)
|
||||
#define BJAM_REALLOC_RAW(p,s) bjam_realloc_raw_x(p,s)
|
||||
|
||||
#endif
|
||||
|
||||
#define BJAM_MEM_INIT() bjam_mem_init_x()
|
||||
#define BJAM_MEM_CLOSE() bjam_mem_close_x()
|
||||
#define BJAM_MEM_INIT() bjam_mem_init_x()
|
||||
#define BJAM_MEM_CLOSE() bjam_mem_close_x()
|
||||
|
||||
#define BJAM_FREE(p) bjam_free_x(p)
|
||||
#define BJAM_FREE_RAW(p) bjam_free_raw_x(p)
|
||||
#define BJAM_FREE(p) bjam_free_x(p)
|
||||
#define BJAM_FREE_RAW(p) bjam_free_raw_x(p)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,30 +3,20 @@
|
||||
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
|
||||
|
||||
#include "../native.h"
|
||||
#include "../timestamp.h"
|
||||
#include "../object.h"
|
||||
#include "../timestamp.h"
|
||||
|
||||
LIST *path_exists( FRAME *frame, int flags )
|
||||
|
||||
LIST * path_exists( FRAME * frame, int flags )
|
||||
{
|
||||
LIST* l = lol_get( frame->args, 0 );
|
||||
|
||||
time_t time;
|
||||
timestamp(list_front(l), &time);
|
||||
if (time != 0)
|
||||
{
|
||||
return list_new(object_new("true"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return L0;
|
||||
}
|
||||
timestamp( list_front( lol_get( frame->args, 0 ) ), &time );
|
||||
return time ? list_new( object_new( "true" ) ) : L0;
|
||||
}
|
||||
|
||||
|
||||
void init_path()
|
||||
{
|
||||
{
|
||||
const char* args[] = { "location", 0 };
|
||||
declare_native_rule("path", "exists", args, path_exists, 1);
|
||||
}
|
||||
|
||||
char const * args[] = { "location", 0 };
|
||||
declare_native_rule( "path", "exists", args, path_exists, 1 );
|
||||
}
|
||||
|
||||
@@ -5,17 +5,10 @@
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "object.h"
|
||||
# include <stddef.h>
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* object.c - object manipulation routines
|
||||
*
|
||||
* External functions:
|
||||
*
|
||||
* object_new() - create an object from a string
|
||||
* object_copy() - return a copy of an object
|
||||
* object_free() - free an object
|
||||
@@ -27,6 +20,14 @@
|
||||
* Strings are never actually freed.
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
#include "object.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define OBJECT_MAGIC 0xa762e0e3u
|
||||
|
||||
#ifndef object_copy
|
||||
@@ -45,10 +46,10 @@ struct hash_header
|
||||
struct hash_item
|
||||
{
|
||||
struct hash_header header;
|
||||
char data[1];
|
||||
char data[ 1 ];
|
||||
};
|
||||
|
||||
#define ALLOC_ALIGNMENT ( sizeof( struct hash_item ) - sizeof( struct hash_header ) )
|
||||
#define ALLOC_ALIGNMENT (sizeof(struct hash_item) - sizeof(struct hash_header))
|
||||
|
||||
typedef struct string_set
|
||||
{
|
||||
@@ -57,10 +58,10 @@ typedef struct string_set
|
||||
struct hash_item * * data;
|
||||
} string_set;
|
||||
|
||||
static string_set strhash;
|
||||
static int strtotal = 0;
|
||||
static int strcount_in = 0;
|
||||
static int strcount_out = 0;
|
||||
static string_set strhash;
|
||||
static int strtotal = 0;
|
||||
static int strcount_in = 0;
|
||||
static int strcount_out = 0;
|
||||
|
||||
|
||||
/*
|
||||
@@ -68,11 +69,11 @@ static int strcount_out = 0;
|
||||
* down on internal fragmentation.
|
||||
*/
|
||||
|
||||
# define STRING_BLOCK 4096
|
||||
#define STRING_BLOCK 4096
|
||||
typedef struct strblock
|
||||
{
|
||||
struct strblock * next;
|
||||
char data[STRING_BLOCK];
|
||||
char data[ STRING_BLOCK ];
|
||||
} strblock;
|
||||
|
||||
static strblock * strblock_chain = 0;
|
||||
@@ -89,18 +90,18 @@ static char * storage_finish = 0;
|
||||
static char * allocate( size_t n )
|
||||
{
|
||||
#ifdef BJAM_NEWSTR_NO_ALLOCATE
|
||||
return (char*)BJAM_MALLOC(n);
|
||||
return (char *)BJAM_MALLOC( n );
|
||||
#else
|
||||
/* See if we can grab storage from an existing block. */
|
||||
size_t remaining = storage_finish - storage_start;
|
||||
n = ((n + ALLOC_ALIGNMENT - 1) / ALLOC_ALIGNMENT) * ALLOC_ALIGNMENT;
|
||||
n = ( ( n + ALLOC_ALIGNMENT - 1 ) / ALLOC_ALIGNMENT ) * ALLOC_ALIGNMENT;
|
||||
if ( remaining >= n )
|
||||
{
|
||||
char * result = storage_start;
|
||||
storage_start += n;
|
||||
return result;
|
||||
}
|
||||
else /* Must allocate a new block. */
|
||||
else /* Must allocate a new block. */
|
||||
{
|
||||
strblock * new_block;
|
||||
size_t nalloc = n;
|
||||
@@ -108,7 +109,8 @@ static char * allocate( size_t n )
|
||||
nalloc = STRING_BLOCK;
|
||||
|
||||
/* Allocate a new block and link into the chain. */
|
||||
new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
|
||||
new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[ 0 ] ) +
|
||||
nalloc * sizeof( new_block->data[ 0 ] ) );
|
||||
if ( new_block == 0 )
|
||||
return 0;
|
||||
new_block->next = strblock_chain;
|
||||
@@ -125,7 +127,8 @@ static char * allocate( size_t n )
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int hash_keyval( const char * key )
|
||||
|
||||
static unsigned int hash_keyval( char const * key )
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
unsigned i;
|
||||
@@ -146,11 +149,11 @@ static unsigned int hash_keyval( const char * key )
|
||||
}
|
||||
|
||||
hash += (hash >> 17);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void string_set_init(string_set * set)
|
||||
|
||||
static void string_set_init( string_set * set )
|
||||
{
|
||||
set->size = 0;
|
||||
set->num = 4;
|
||||
@@ -158,67 +161,67 @@ static void string_set_init(string_set * set)
|
||||
memset( set->data, 0, set->num * sizeof( struct hash_item * ) );
|
||||
}
|
||||
|
||||
static void string_set_done(string_set * set)
|
||||
|
||||
static void string_set_done( string_set * set )
|
||||
{
|
||||
BJAM_FREE( set->data );
|
||||
}
|
||||
|
||||
static void string_set_resize(string_set *set)
|
||||
|
||||
static void string_set_resize( string_set * set )
|
||||
{
|
||||
unsigned i;
|
||||
string_set new_set;
|
||||
new_set.num = set->num * 2;
|
||||
new_set.size = set->size;
|
||||
new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item * ) * new_set.num );
|
||||
memset(new_set.data, 0, sizeof(struct hash_item *) * new_set.num);
|
||||
new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item *
|
||||
) * new_set.num );
|
||||
memset( new_set.data, 0, sizeof( struct hash_item * ) * new_set.num );
|
||||
for ( i = 0; i < set->num; ++i )
|
||||
{
|
||||
while ( set->data[i] )
|
||||
while ( set->data[ i ] )
|
||||
{
|
||||
struct hash_item * temp = set->data[i];
|
||||
struct hash_item * temp = set->data[ i ];
|
||||
unsigned pos = temp->header.hash % new_set.num;
|
||||
set->data[i] = temp->header.next;
|
||||
temp->header.next = new_set.data[pos];
|
||||
new_set.data[pos] = temp;
|
||||
set->data[ i ] = temp->header.next;
|
||||
temp->header.next = new_set.data[ pos ];
|
||||
new_set.data[ pos ] = temp;
|
||||
}
|
||||
}
|
||||
BJAM_FREE( set->data );
|
||||
*set = new_set;
|
||||
}
|
||||
|
||||
static const char * string_set_insert ( string_set * set, const char * string )
|
||||
|
||||
static char const * string_set_insert( string_set * set, char const * string )
|
||||
{
|
||||
unsigned hash = hash_keyval( string );
|
||||
unsigned pos = hash % set->num;
|
||||
unsigned l;
|
||||
unsigned len;
|
||||
|
||||
struct hash_item * result;
|
||||
|
||||
for ( result = set->data[pos]; result; result = result->header.next )
|
||||
{
|
||||
if ( strcmp( result->data, string ) == 0 )
|
||||
{
|
||||
for ( result = set->data[ pos ]; result; result = result->header.next )
|
||||
if ( !strcmp( result->data, string ) )
|
||||
return result->data;
|
||||
}
|
||||
}
|
||||
|
||||
if( set->size >= set->num )
|
||||
if ( set->size >= set->num )
|
||||
{
|
||||
string_set_resize( set );
|
||||
pos = hash % set->num;
|
||||
}
|
||||
|
||||
l = strlen( string );
|
||||
result = (struct hash_item *)allocate( sizeof( struct hash_header ) + l + 1 );
|
||||
len = strlen( string ) + 1;
|
||||
result = (struct hash_item *)allocate( sizeof( struct hash_header ) + len );
|
||||
result->header.hash = hash;
|
||||
result->header.next = set->data[pos];
|
||||
result->header.next = set->data[ pos ];
|
||||
#ifndef NDEBUG
|
||||
result->header.magic = OBJECT_MAGIC;
|
||||
#endif
|
||||
memcpy( result->data, string, l + 1 );
|
||||
memcpy( result->data, string, len );
|
||||
assert( hash_keyval( result->data ) == result->header.hash );
|
||||
set->data[pos] = result;
|
||||
strtotal += l + 1;
|
||||
set->data[ pos ] = result;
|
||||
strtotal += len;
|
||||
++set->size;
|
||||
|
||||
return result->data;
|
||||
@@ -227,12 +230,14 @@ static const char * string_set_insert ( string_set * set, const char * string )
|
||||
|
||||
static struct hash_item * object_get_item( OBJECT * obj )
|
||||
{
|
||||
return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data ) );
|
||||
return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
static void object_validate( OBJECT * obj )
|
||||
{
|
||||
assert( obj );
|
||||
assert( object_get_item( obj )->header.magic == OBJECT_MAGIC );
|
||||
}
|
||||
|
||||
@@ -241,26 +246,26 @@ static void object_validate( OBJECT * obj )
|
||||
* object_new() - create an object from a string.
|
||||
*/
|
||||
|
||||
OBJECT * object_new( const char * string )
|
||||
OBJECT * object_new( char const * string )
|
||||
{
|
||||
#ifdef BJAM_NO_MEM_CACHE
|
||||
int l = strlen( string );
|
||||
struct hash_item * m = (struct hash_item *)BJAM_MALLOC( sizeof(struct hash_header) + l + 1 );
|
||||
int const len = strlen( string ) + 1;
|
||||
struct hash_item * const m = (struct hash_item *)BJAM_MALLOC( sizeof( struct
|
||||
hash_header) + len );
|
||||
|
||||
strtotal += l + 1;
|
||||
memcpy( m->data, string, l + 1 );
|
||||
strtotal += len;
|
||||
memcpy( m->data, string, len );
|
||||
m->header.magic = OBJECT_MAGIC;
|
||||
return (OBJECT *)m->data;
|
||||
#else
|
||||
if ( ! strhash.data )
|
||||
if ( !strhash.data )
|
||||
string_set_init( &strhash );
|
||||
|
||||
strcount_in += 1;
|
||||
|
||||
++strcount_in;
|
||||
return (OBJECT *)string_set_insert( &strhash, string );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifndef object_copy
|
||||
|
||||
/*
|
||||
@@ -273,7 +278,7 @@ OBJECT * object_copy( OBJECT * obj )
|
||||
#ifdef BJAM_NO_MEM_CACHE
|
||||
return object_new( object_str( obj ) );
|
||||
#else
|
||||
strcount_in += 1;
|
||||
++strcount_in;
|
||||
return obj;
|
||||
#endif
|
||||
}
|
||||
@@ -289,18 +294,18 @@ void object_free( OBJECT * obj )
|
||||
#ifdef BJAM_NO_MEM_CACHE
|
||||
BJAM_FREE( object_get_item( obj ) );
|
||||
#endif
|
||||
strcount_out += 1;
|
||||
++strcount_out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* object_str() - return the
|
||||
* object_str() - return the OBJECT's internal C string
|
||||
*/
|
||||
|
||||
const char * object_str( OBJECT * obj )
|
||||
char const * object_str( OBJECT * obj )
|
||||
{
|
||||
object_validate( obj );
|
||||
return (const char *)obj;
|
||||
return (char const *)obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -313,9 +318,9 @@ int object_equal( OBJECT * lhs, OBJECT * rhs )
|
||||
object_validate( lhs );
|
||||
object_validate( rhs );
|
||||
#ifdef BJAM_NO_MEM_CACHE
|
||||
return strcmp(object_str(lhs), object_str(rhs)) == 0;
|
||||
return !strcmp( object_str( lhs ), object_str( rhs ) );
|
||||
#else
|
||||
assert( (lhs == rhs) == ( strcmp(object_str(lhs), object_str(rhs)) == 0 ) );
|
||||
assert( ( lhs == rhs ) == !strcmp( object_str( lhs ), object_str( rhs ) ) );
|
||||
return lhs == rhs;
|
||||
#endif
|
||||
}
|
||||
@@ -343,37 +348,34 @@ unsigned int object_hash( OBJECT * obj )
|
||||
|
||||
void object_done()
|
||||
{
|
||||
|
||||
#ifdef BJAM_NEWSTR_NO_ALLOCATE
|
||||
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < strhash.num; ++i )
|
||||
{
|
||||
while ( strhash.data[i] )
|
||||
while ( strhash.data[ i ] )
|
||||
{
|
||||
struct hash_item * item = strhash.data[i];
|
||||
strhash.data[i] = item->header.next;
|
||||
struct hash_item * item = strhash.data[ i ];
|
||||
strhash.data[ i ] = item->header.next;
|
||||
BJAM_FREE( item );
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Reclaim string blocks. */
|
||||
while ( strblock_chain != 0 )
|
||||
while ( strblock_chain )
|
||||
{
|
||||
strblock * n = strblock_chain->next;
|
||||
BJAM_FREE(strblock_chain);
|
||||
strblock * const n = strblock_chain->next;
|
||||
BJAM_FREE( strblock_chain );
|
||||
strblock_chain = n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
string_set_done( &strhash );
|
||||
|
||||
if ( DEBUG_MEM )
|
||||
{
|
||||
printf( "%dK in strings\n", strtotal / 1024 );
|
||||
|
||||
/* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
|
||||
/* if ( strcount_in != strcount_out )
|
||||
printf( "--- %d strings of %d dangling\n", strcount_in -
|
||||
strcount_out, strcount_in ); */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,20 @@
|
||||
/*
|
||||
* PATHNAME - a name of a file, broken into <grist>dir/base/suffix(member)
|
||||
*
|
||||
* <grist> is salt to distinguish between targets that otherwise would
|
||||
* have the same name: it never appears in the bound name of a target.
|
||||
* (member) is an archive member name: the syntax is arbitrary, but must
|
||||
* agree in path_parse(), path_build() and the Jambase.
|
||||
* <grist> - salt to distinguish between targets that would otherwise have the
|
||||
* same name - it never appears in the bound name of a target.
|
||||
*
|
||||
* (member) - archive member name: the syntax is arbitrary, but must agree in
|
||||
* path_parse(), path_build() and the Jambase.
|
||||
*/
|
||||
|
||||
#ifndef PATHSYS_VP_20020211_H
|
||||
# define PATHSYS_VP_20020211_H
|
||||
#define PATHSYS_VP_20020211_H
|
||||
|
||||
#include "jam.h"
|
||||
#include "strings.h"
|
||||
#include "object.h"
|
||||
#include "strings.h"
|
||||
|
||||
|
||||
typedef struct _pathname PATHNAME;
|
||||
typedef struct _pathpart PATHPART;
|
||||
@@ -35,14 +37,14 @@ struct _pathpart
|
||||
|
||||
struct _pathname
|
||||
{
|
||||
PATHPART part[6];
|
||||
PATHPART part[ 6 ];
|
||||
|
||||
#define f_grist part[0]
|
||||
#define f_root part[1]
|
||||
#define f_dir part[2]
|
||||
#define f_base part[3]
|
||||
#define f_suffix part[4]
|
||||
#define f_member part[5]
|
||||
#define f_grist part[ 0 ]
|
||||
#define f_root part[ 1 ]
|
||||
#define f_dir part[ 2 ]
|
||||
#define f_base part[ 3 ]
|
||||
#define f_suffix part[ 4 ]
|
||||
#define f_member part[ 5 ]
|
||||
};
|
||||
|
||||
void path_build( PATHNAME * f, string * file, int binding );
|
||||
@@ -53,42 +55,44 @@ void path_parent( PATHNAME * f );
|
||||
|
||||
#ifdef NT
|
||||
|
||||
/** Returns object_new-allocated string with long equivivalent of 'short_name'.
|
||||
If none exists -- i.e. 'short_path' is already long path, it's returned
|
||||
unaltered. */
|
||||
/* Returns object_new-allocated string with long equivivalent of 'short_name'.
|
||||
* If none exists, i.e. 'short_path' is already long, it is returned unaltered.
|
||||
*/
|
||||
OBJECT * short_path_to_long_path( OBJECT * short_path );
|
||||
|
||||
#endif
|
||||
|
||||
/** Given a path, returns an object that can be
|
||||
used as a unique key for that path. Equivalent
|
||||
paths such as a/b, A\B, and a\B on NT all yield the
|
||||
same key.
|
||||
/* Given a path, returns an object that can be used as a unique key for that
|
||||
* path. Equivalent paths such as a/b, A\B, and a\B on NT all yield the same
|
||||
* key.
|
||||
*/
|
||||
OBJECT * path_as_key( OBJECT * path );
|
||||
void path_add_key( OBJECT * path );
|
||||
|
||||
/* Called as an optimization when we know we have a path that is already in its
|
||||
* long form. Avoids the need for some subsequent path_as_key() call to do a
|
||||
* potentially expensive short-->long path conversion.
|
||||
*/
|
||||
void path_add_key( OBJECT * long_path );
|
||||
|
||||
#ifdef USE_PATHUNIX
|
||||
/** Returns a static pointer to the system dependent path to the temporary
|
||||
directory. NOTE: *without* a trailing path separator.
|
||||
*/
|
||||
/* Returns a static pointer to the system dependent path to the temporary
|
||||
* directory. NOTE: *without* a trailing path separator.
|
||||
*/
|
||||
string const * path_tmpdir( void );
|
||||
|
||||
/** Returns a new temporary name.
|
||||
*/
|
||||
/* Returns a new temporary name. */
|
||||
OBJECT * path_tmpnam( void );
|
||||
|
||||
/** Returns a new temporary path.
|
||||
*/
|
||||
/* Returns a new temporary path. */
|
||||
OBJECT * path_tmpfile( void );
|
||||
#endif
|
||||
|
||||
/** Give the first argument to 'main', return a full path to our executable.
|
||||
Returns null in the unlikely case it cannot be determined. Caller is
|
||||
responsible for freeing the string.
|
||||
|
||||
Implemented in jam.c
|
||||
*/
|
||||
/* Give the first argument to 'main', return a full path to our executable.
|
||||
* Returns null in the unlikely case it cannot be determined. Caller is
|
||||
* responsible for freeing the string.
|
||||
*
|
||||
* Implemented in jam.c
|
||||
*/
|
||||
char * executable_path( char const * argv0 );
|
||||
|
||||
void path_done( void );
|
||||
|
||||
@@ -11,48 +11,36 @@
|
||||
* (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "pathsys.h"
|
||||
# include "strings.h"
|
||||
# include "object.h"
|
||||
# include "filesys.h"
|
||||
# include <time.h>
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
# ifndef OS_NT
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
|
||||
# ifdef USE_PATHUNIX
|
||||
|
||||
/*
|
||||
* pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*
|
||||
* File_parse() and path_build() just manipuate a string and a structure;
|
||||
* File_parse() and path_build() just manipulate a string and a structure;
|
||||
* they do not make system calls.
|
||||
*
|
||||
* 04/08/94 (seiwald) - Coherent/386 support added.
|
||||
* 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
|
||||
* 12/19/94 (mikem) - solaris string table insanity support
|
||||
* 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
|
||||
* 02/14/95 (seiwald) - parse and build /xxx properly
|
||||
* 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
|
||||
* should expect hdr searches to come up with strings
|
||||
* like "thing/thing.h". So we need to test for "/" as
|
||||
* well as "\" when parsing pathnames.
|
||||
* 03/16/95 (seiwald) - fixed accursed typo on line 69.
|
||||
* 05/03/96 (seiwald) - split from filent.c, fileunix.c
|
||||
* 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
|
||||
* don't include the archive member name.
|
||||
* 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
|
||||
#ifdef USE_PATHUNIX
|
||||
|
||||
#include "pathsys.h"
|
||||
|
||||
#include "filesys.h"
|
||||
#include "object.h"
|
||||
#include "strings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#ifndef OS_NT
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
*/
|
||||
@@ -65,26 +53,26 @@ void path_parse( char const * file, PATHNAME * f )
|
||||
|
||||
memset( (char *)f, 0, sizeof( *f ) );
|
||||
|
||||
/* Look for <grist> */
|
||||
/* Look for '<grist>'. */
|
||||
|
||||
if ( ( file[0] == '<' ) && ( p = strchr( file, '>' ) ) )
|
||||
if ( ( file[ 0 ] == '<' ) && ( p = strchr( file, '>' ) ) )
|
||||
{
|
||||
f->f_grist.ptr = file;
|
||||
f->f_grist.len = p - file;
|
||||
file = p + 1;
|
||||
}
|
||||
|
||||
/* Look for dir/ */
|
||||
/* Look for 'dir/'. */
|
||||
|
||||
p = strrchr( file, '/' );
|
||||
|
||||
# if PATH_DELIM == '\\'
|
||||
#if PATH_DELIM == '\\'
|
||||
/* On NT, look for dir\ as well */
|
||||
{
|
||||
char *p1 = strrchr( file, '\\' );
|
||||
char * const p1 = strrchr( file, '\\' );
|
||||
p = p1 > p ? p1 : p;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if ( p )
|
||||
{
|
||||
@@ -92,24 +80,21 @@ void path_parse( char const * file, PATHNAME * f )
|
||||
f->f_dir.len = p - file;
|
||||
|
||||
/* Special case for / - dirname is /, not "" */
|
||||
|
||||
if ( !f->f_dir.len )
|
||||
f->f_dir.len = 1;
|
||||
++f->f_dir.len;
|
||||
|
||||
# if PATH_DELIM == '\\'
|
||||
#if PATH_DELIM == '\\'
|
||||
/* Special case for D:/ - dirname is D:/, not "D:" */
|
||||
|
||||
if ( f->f_dir.len == 2 && file[1] == ':' )
|
||||
f->f_dir.len = 3;
|
||||
# endif
|
||||
if ( f->f_dir.len == 2 && file[ 1 ] == ':' )
|
||||
++f->f_dir.len;
|
||||
#endif
|
||||
|
||||
file = p + 1;
|
||||
}
|
||||
|
||||
end = file + strlen( file );
|
||||
|
||||
/* Look for (member) */
|
||||
|
||||
/* Look for '(member)'. */
|
||||
if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) )
|
||||
{
|
||||
f->f_member.ptr = p + 1;
|
||||
@@ -117,15 +102,10 @@ void path_parse( char const * file, PATHNAME * f )
|
||||
end = p;
|
||||
}
|
||||
|
||||
/* Look for .suffix */
|
||||
/* This would be memrchr() */
|
||||
|
||||
/* Look for '.suffix'. This would be memrchr(). */
|
||||
p = 0;
|
||||
q = file;
|
||||
|
||||
while ( ( q = (char *)memchr( q, '.', end - q ) ) )
|
||||
p = q++;
|
||||
|
||||
for ( q = file; ( q = (char *)memchr( q, '.', end - q ) ); ++q )
|
||||
p = q;
|
||||
if ( p )
|
||||
{
|
||||
f->f_suffix.ptr = p;
|
||||
@@ -133,135 +113,123 @@ void path_parse( char const * file, PATHNAME * f )
|
||||
end = p;
|
||||
}
|
||||
|
||||
/* Leaves base */
|
||||
|
||||
/* Leaves base. */
|
||||
f->f_base.ptr = file;
|
||||
f->f_base.len = end - file;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* path_delims - the string of legal path delimiters
|
||||
*/
|
||||
|
||||
static char path_delims[] = {
|
||||
PATH_DELIM,
|
||||
# if PATH_DELIM == '\\'
|
||||
#if PATH_DELIM == '\\'
|
||||
'/',
|
||||
# endif
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* is_path_delim() - true iff c is a path delimiter
|
||||
*/
|
||||
static int is_path_delim( char c )
|
||||
|
||||
static int is_path_delim( char const c )
|
||||
{
|
||||
char* p = strchr( path_delims, c );
|
||||
char const * const p = strchr( path_delims, c );
|
||||
return p && *p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* as_path_delim() - convert c to a path delimiter if it isn't one
|
||||
* already
|
||||
* as_path_delim() - convert c to a path delimiter if it is not one already
|
||||
*/
|
||||
static char as_path_delim( char c )
|
||||
|
||||
static char as_path_delim( char const c )
|
||||
{
|
||||
return is_path_delim( c ) ? c : PATH_DELIM;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
*
|
||||
* To avoid changing slash direction on NT when reconstituting paths,
|
||||
* instead of unconditionally appending PATH_DELIM we check the
|
||||
* past-the-end character of the previous path element. If it is in
|
||||
* path_delims, we append that, and only append PATH_DELIM as a last
|
||||
* resort. This heuristic is based on the fact that PATHNAME objects
|
||||
* are usually the result of calling path_parse, which leaves the
|
||||
* original slashes in the past-the-end position. Correctness depends
|
||||
* on the assumption that all strings are zero terminated, so a
|
||||
* past-the-end character will always be available.
|
||||
* To avoid changing slash direction on NT when reconstituting paths, instead of
|
||||
* unconditionally appending PATH_DELIM we check the past-the-end character of
|
||||
* the previous path element. If it is in path_delims, we append that, and only
|
||||
* append PATH_DELIM as a last resort. This heuristic is based on the fact that
|
||||
* PATHNAME objects are usually the result of calling path_parse, which leaves
|
||||
* the original slashes in the past-the-end position. Correctness depends on the
|
||||
* assumption that all strings are zero terminated, so a past-the-end character
|
||||
* will always be available.
|
||||
*
|
||||
* As an attendant patch, we had to ensure that backslashes are used
|
||||
* explicitly in timestamp.c
|
||||
* As an attendant patch, we had to ensure that backslashes are used explicitly
|
||||
* in 'timestamp.c'.
|
||||
*/
|
||||
|
||||
void
|
||||
path_build(
|
||||
PATHNAME *f,
|
||||
string *file,
|
||||
int binding )
|
||||
void path_build( PATHNAME * f, string * file, int binding )
|
||||
{
|
||||
file_build1( f, file );
|
||||
|
||||
/* Don't prepend root if it's . or directory is rooted */
|
||||
# if PATH_DELIM == '/'
|
||||
|
||||
/* Do not prepend root if it is '.' or the directory is rooted. */
|
||||
if ( f->f_root.len
|
||||
&& !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )
|
||||
|
||||
# else /* unix */
|
||||
|
||||
if ( f->f_root.len
|
||||
&& !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
|
||||
|
||||
# endif /* unix */
|
||||
|
||||
&& !( f->f_root.len == 1 && f->f_root.ptr[ 0 ] == '.' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '/' )
|
||||
#if PATH_DELIM == '\\'
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '\\' )
|
||||
&& !( f->f_dir.len && f->f_dir.ptr[ 1 ] == ':' )
|
||||
#endif
|
||||
)
|
||||
{
|
||||
string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
|
||||
/* If 'root' already ends with path delimeter,
|
||||
don't add yet another one. */
|
||||
if ( ! is_path_delim( f->f_root.ptr[f->f_root.len-1] ) )
|
||||
string_push_back( file, as_path_delim( f->f_root.ptr[f->f_root.len] ) );
|
||||
string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len
|
||||
);
|
||||
/* If 'root' already ends with a path delimeter, do not add yet another
|
||||
* one.
|
||||
*/
|
||||
if ( !is_path_delim( f->f_root.ptr[ f->f_root.len - 1 ] ) )
|
||||
string_push_back( file, as_path_delim( f->f_root.ptr[ f->f_root.len
|
||||
] ) );
|
||||
}
|
||||
|
||||
if ( f->f_dir.len )
|
||||
string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
|
||||
string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
|
||||
|
||||
/* UNIX: Put / between dir and file */
|
||||
/* NT: Put \ between dir and file */
|
||||
|
||||
if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
|
||||
{
|
||||
/* UNIX: Special case for dir \ : don't add another \ */
|
||||
/* NT: Special case for dir / : don't add another / */
|
||||
|
||||
# if PATH_DELIM == '\\'
|
||||
if ( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
|
||||
# endif
|
||||
if ( !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[0] ) ) )
|
||||
string_push_back( file, as_path_delim( f->f_dir.ptr[f->f_dir.len] ) );
|
||||
}
|
||||
/* Put path separator between dir and file. */
|
||||
/* Special case for root dir: do not add another path separator. */
|
||||
if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len )
|
||||
#if PATH_DELIM == '\\'
|
||||
&& !( f->f_dir.len == 3 && f->f_dir.ptr[ 1 ] == ':' )
|
||||
#endif
|
||||
&& !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[ 0 ] ) ) )
|
||||
string_push_back( file, as_path_delim( f->f_dir.ptr[ f->f_dir.len ] ) );
|
||||
|
||||
if ( f->f_base.len )
|
||||
{
|
||||
string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
|
||||
}
|
||||
string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len
|
||||
);
|
||||
|
||||
if ( f->f_suffix.len )
|
||||
{
|
||||
string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
|
||||
}
|
||||
string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr +
|
||||
f->f_suffix.len );
|
||||
|
||||
if ( f->f_member.len )
|
||||
{
|
||||
string_push_back( file, '(' );
|
||||
string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
|
||||
string_append_range( file, f->f_member.ptr, f->f_member.ptr +
|
||||
f->f_member.len );
|
||||
string_push_back( file, ')' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*/
|
||||
|
||||
void
|
||||
path_parent( PATHNAME *f )
|
||||
void path_parent( PATHNAME * f )
|
||||
{
|
||||
/* just set everything else to nothing */
|
||||
/* Just clear everything. */
|
||||
|
||||
f->f_base.ptr =
|
||||
f->f_suffix.ptr =
|
||||
@@ -279,31 +247,30 @@ path_parent( PATHNAME *f )
|
||||
#undef INVALID_FILE_ATTRIBUTES
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||
|
||||
OBJECT * path_as_key( OBJECT * path );
|
||||
static void path_write_key( char * path_, string * out );
|
||||
static void path_write_key( char const * const path_, string * const out );
|
||||
|
||||
void ShortPathToLongPath( char * short_path, string * out )
|
||||
|
||||
static void ShortPathToLongPath( char const * const short_path,
|
||||
string * const out )
|
||||
{
|
||||
char const * new_element;
|
||||
unsigned long saved_size;
|
||||
char * p;
|
||||
|
||||
if ( short_path[0] == '\0' )
|
||||
{
|
||||
if ( short_path[ 0 ] == '\0' )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( short_path[0] == '\\' && short_path[1] == '\0')
|
||||
if ( short_path[ 0 ] == '\\' && short_path[ 1 ] == '\0' )
|
||||
{
|
||||
string_push_back( out, '\\' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( short_path[1] == ':' &&
|
||||
( short_path[2] == '\0' ||
|
||||
( short_path[2] == '\\' && short_path[3] == '\0' ) ) )
|
||||
if ( short_path[ 1 ] == ':' &&
|
||||
( short_path[ 2 ] == '\0' ||
|
||||
( short_path[ 2 ] == '\\' && short_path[ 3 ] == '\0' ) ) )
|
||||
{
|
||||
string_push_back( out, toupper( short_path[0] ) );
|
||||
string_push_back( out, toupper( short_path[ 0 ] ) );
|
||||
string_push_back( out, ':' );
|
||||
string_push_back( out, '\\' );
|
||||
return;
|
||||
@@ -315,12 +282,12 @@ void ShortPathToLongPath( char * short_path, string * out )
|
||||
char saved;
|
||||
new_element = p + 1;
|
||||
|
||||
/* special case \ */
|
||||
/* special case '\' */
|
||||
if ( p == short_path )
|
||||
++p;
|
||||
|
||||
/* special case D:\ */
|
||||
if ( p == short_path + 2 && short_path[1] == ':' )
|
||||
/* special case 'D:\' */
|
||||
if ( p == short_path + 2 && short_path[ 1 ] == ':' )
|
||||
++p;
|
||||
|
||||
saved = *p;
|
||||
@@ -329,59 +296,58 @@ void ShortPathToLongPath( char * short_path, string * out )
|
||||
*p = saved;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_element = short_path;
|
||||
}
|
||||
|
||||
if ( out->size && out->value[ out->size - 1 ] != '\\' )
|
||||
{
|
||||
string_push_back( out, '\\' );
|
||||
}
|
||||
|
||||
saved_size = out->size;
|
||||
string_append( out, new_element );
|
||||
|
||||
if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
|
||||
new_element[0] == '.' && new_element[1] == '.'
|
||||
&& new_element[2] == '\0' ) )
|
||||
/* If the file exists, replace its name with its long name variant. */
|
||||
{
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hf = 0;
|
||||
hf = FindFirstFile( out->value, &fd );
|
||||
|
||||
/* If the file exists, replace the name. */
|
||||
if ( hf != INVALID_HANDLE_VALUE )
|
||||
char const * const n = new_element;
|
||||
if ( !( n[ 0 ] == '.' && n[ 1 ] == '\0' ||
|
||||
n[ 0 ] == '.' && n[ 1 ] == '.' && n[ 2 ] == '\0' ) )
|
||||
{
|
||||
string_truncate( out, saved_size );
|
||||
string_append( out, fd.cFileName );
|
||||
FindClose( hf );
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE const hf = FindFirstFile( out->value, &fd );
|
||||
if ( hf != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
string_truncate( out, saved_size );
|
||||
string_append( out, fd.cFileName );
|
||||
FindClose( hf );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OBJECT * short_path_to_long_path( OBJECT * short_path )
|
||||
{
|
||||
return path_as_key( short_path );
|
||||
}
|
||||
|
||||
struct path_key_entry
|
||||
|
||||
typedef struct path_key_entry
|
||||
{
|
||||
OBJECT * path;
|
||||
OBJECT * key;
|
||||
};
|
||||
} path_key_entry;
|
||||
|
||||
static struct hash * path_key_cache;
|
||||
|
||||
static void path_write_key( char * path_, string * out )
|
||||
|
||||
static void path_write_key( char const * const path_, string * const out )
|
||||
{
|
||||
struct path_key_entry * result;
|
||||
OBJECT * path = object_new( path_ );
|
||||
path_key_entry * result;
|
||||
OBJECT * const path = object_new( path_ );
|
||||
int found;
|
||||
|
||||
/* This is only called by path_as_key, which initializes the cache. */
|
||||
/* This is only called via path_as_key(), which initializes the cache. */
|
||||
assert( path_key_cache );
|
||||
|
||||
result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
result = (path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
if ( !found )
|
||||
{
|
||||
/* path_ is already normalized. */
|
||||
@@ -394,46 +360,42 @@ static void path_write_key( char * path_, string * out )
|
||||
object_free( path );
|
||||
string_append( out, object_str( result->key ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void normalize_path( string * path )
|
||||
{
|
||||
char * s;
|
||||
for ( s = path->value; s < path->value + path->size; ++s )
|
||||
{
|
||||
if ( *s == '/' )
|
||||
*s = '\\';
|
||||
else
|
||||
*s = tolower( *s );
|
||||
}
|
||||
/* Strip trailing "/" */
|
||||
if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' )
|
||||
{
|
||||
*s = *s == '/' ? '\\' : tolower( *s );
|
||||
/* Strip trailing "/". */
|
||||
if ( path->size && path->size != 3 && path->value[ path->size - 1 ] == '\\'
|
||||
)
|
||||
string_pop_back( path );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void path_add_key( OBJECT * path )
|
||||
{
|
||||
struct path_key_entry * result;
|
||||
path_key_entry * result;
|
||||
int found;
|
||||
|
||||
if ( ! path_key_cache )
|
||||
path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
|
||||
if ( !path_key_cache )
|
||||
path_key_cache = hashinit( sizeof( path_key_entry ), "path to key" );
|
||||
|
||||
result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
result = (path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
if ( !found )
|
||||
{
|
||||
string buf[1];
|
||||
string buf[ 1 ];
|
||||
OBJECT * normalized;
|
||||
struct path_key_entry * nresult;
|
||||
path_key_entry * nresult;
|
||||
result->path = path;
|
||||
string_copy( buf, object_str( path ) );
|
||||
normalize_path( buf );
|
||||
normalized = object_new( buf->value );
|
||||
string_free( buf );
|
||||
nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
|
||||
nresult = (path_key_entry *)hash_insert( path_key_cache, normalized,
|
||||
&found );
|
||||
if ( !found || nresult == result )
|
||||
{
|
||||
nresult->path = object_copy( normalized );
|
||||
@@ -448,28 +410,30 @@ void path_add_key( OBJECT * path )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OBJECT * path_as_key( OBJECT * path )
|
||||
{
|
||||
struct path_key_entry * result;
|
||||
path_key_entry * result;
|
||||
int found;
|
||||
|
||||
if ( ! path_key_cache )
|
||||
path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
|
||||
if ( !path_key_cache )
|
||||
path_key_cache = hashinit( sizeof( path_key_entry ), "path to key" );
|
||||
|
||||
result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
result = (path_key_entry *)hash_insert( path_key_cache, path, &found );
|
||||
if ( !found )
|
||||
{
|
||||
string buf[1];
|
||||
string buf[ 1 ];
|
||||
OBJECT * normalized;
|
||||
struct path_key_entry * nresult;
|
||||
path_key_entry * nresult;
|
||||
result->path = path;
|
||||
string_copy( buf, object_str( path ) );
|
||||
normalize_path( buf );
|
||||
normalized = object_new( buf->value );
|
||||
nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
|
||||
nresult = (path_key_entry *)hash_insert( path_key_cache, normalized,
|
||||
&found );
|
||||
if ( !found || nresult == result )
|
||||
{
|
||||
string long_path[1];
|
||||
string long_path[ 1 ];
|
||||
nresult->path = normalized;
|
||||
string_new( long_path );
|
||||
ShortPathToLongPath( buf->value, long_path );
|
||||
@@ -489,13 +453,15 @@ OBJECT * path_as_key( OBJECT * path )
|
||||
return object_copy( result->key );
|
||||
}
|
||||
|
||||
static void free_path_key_entry( void * xentry, void * data )
|
||||
|
||||
static void free_path_key_entry( void * xentry, void * const data )
|
||||
{
|
||||
struct path_key_entry * entry = (struct path_key_entry *)xentry;
|
||||
path_key_entry * const entry = (path_key_entry *)xentry;
|
||||
object_free( entry->path );
|
||||
object_free( entry->key );
|
||||
}
|
||||
|
||||
|
||||
void path_done( void )
|
||||
{
|
||||
if ( path_key_cache )
|
||||
@@ -505,22 +471,26 @@ void path_done( void )
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#else /* NT */
|
||||
|
||||
|
||||
void path_add_key( OBJECT * path )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OBJECT * path_as_key( OBJECT * path )
|
||||
{
|
||||
return object_copy( path );
|
||||
}
|
||||
|
||||
|
||||
void path_done( void )
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* NT */
|
||||
|
||||
|
||||
string const * path_tmpdir()
|
||||
{
|
||||
@@ -549,15 +519,16 @@ string const * path_tmpdir()
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
OBJECT * path_tmpnam( void )
|
||||
{
|
||||
char name_buffer[ 64 ];
|
||||
unsigned long const c0 =
|
||||
# ifdef OS_NT
|
||||
#ifdef OS_NT
|
||||
GetCurrentProcessId();
|
||||
# else
|
||||
#else
|
||||
getpid();
|
||||
# endif
|
||||
#endif
|
||||
static unsigned long c1;
|
||||
if ( !c1 ) c1 = time( 0 ) & 0xffff;
|
||||
c1 += 1;
|
||||
@@ -565,6 +536,7 @@ OBJECT * path_tmpnam( void )
|
||||
return object_new( name_buffer );
|
||||
}
|
||||
|
||||
|
||||
OBJECT * path_tmpfile( void )
|
||||
{
|
||||
OBJECT * result;
|
||||
@@ -583,4 +555,4 @@ OBJECT * path_tmpfile( void )
|
||||
}
|
||||
|
||||
|
||||
# endif /* unix, NT, OS/2, AmigaOS */
|
||||
#endif /* USE_PATHUNIX */
|
||||
|
||||
@@ -4,19 +4,6 @@
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "lists.h"
|
||||
# include "parse.h"
|
||||
# include "variable.h"
|
||||
# include "rules.h"
|
||||
# include "object.h"
|
||||
# include "hash.h"
|
||||
# include "modules.h"
|
||||
# include "search.h"
|
||||
# include "lists.h"
|
||||
# include "pathsys.h"
|
||||
# include "timestamp.h"
|
||||
|
||||
/* This file is ALSO:
|
||||
* Copyright 2001-2004 David Abrahams.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -27,7 +14,6 @@
|
||||
* rules.c - access to RULEs, TARGETs, and ACTIONs
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* bindrule() - return pointer to RULE, creating it if necessary.
|
||||
* bindtarget() - return pointer to TARGET, creating it if necessary.
|
||||
* touch_target() - mark a target to simulate being new.
|
||||
@@ -39,11 +25,22 @@
|
||||
* popsettings() - reset target specific variables to their pre-push values.
|
||||
* freesettings() - delete a settings list.
|
||||
* rules_done() - free RULE and TARGET tables.
|
||||
*
|
||||
* 04/12/94 (seiwald) - actionlist() now just appends a single action.
|
||||
* 08/23/94 (seiwald) - Support for '+=' (append to variable)
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
#include "rules.h"
|
||||
|
||||
#include "hash.h"
|
||||
#include "lists.h"
|
||||
#include "modules.h"
|
||||
#include "object.h"
|
||||
#include "parse.h"
|
||||
#include "pathsys.h"
|
||||
#include "search.h"
|
||||
#include "timestamp.h"
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
static void set_rule_actions( RULE *, rule_actions * );
|
||||
static void set_rule_body ( RULE *, FUNCTION * procedure );
|
||||
|
||||
@@ -99,19 +96,17 @@ static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
|
||||
* src_module.
|
||||
*/
|
||||
|
||||
static RULE * define_rule
|
||||
(
|
||||
module_t * src_module,
|
||||
OBJECT * rulename,
|
||||
module_t * target_module
|
||||
)
|
||||
static RULE * define_rule( module_t * src_module, OBJECT * rulename,
|
||||
module_t * target_module )
|
||||
{
|
||||
RULE * r = enter_rule( rulename, target_module );
|
||||
if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
|
||||
RULE * const r = enter_rule( rulename, target_module );
|
||||
if ( r->module != src_module )
|
||||
{
|
||||
/* If the rule was imported from elsewhere, clear it now. */
|
||||
set_rule_body( r, 0 );
|
||||
set_rule_actions( r, 0 );
|
||||
r->module = src_module; /* r will be executed in the source module */
|
||||
/* r will be executed in the source module. */
|
||||
r->module = src_module;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -159,7 +154,7 @@ static void bind_explicitly_located_target( void * xtarget, void * data )
|
||||
TARGET * t = (TARGET *)xtarget;
|
||||
if ( !( t->flags & T_FLAG_NOTFILE ) )
|
||||
{
|
||||
/* Check if there's a setting for LOCATE */
|
||||
/* Check if there is a setting for LOCATE. */
|
||||
SETTINGS * s = t->settings;
|
||||
for ( ; s ; s = s->next )
|
||||
{
|
||||
@@ -189,7 +184,7 @@ void bind_explicitly_located_targets()
|
||||
/*
|
||||
* copytarget() - make a new target with the old target's name.
|
||||
*
|
||||
* Not entered into hash table -- for internal nodes.
|
||||
* Not entered into the hash table -- for internal nodes.
|
||||
*/
|
||||
|
||||
TARGET * copytarget( const TARGET * ot )
|
||||
@@ -198,9 +193,7 @@ TARGET * copytarget( const TARGET * ot )
|
||||
memset( (char *)t, '\0', sizeof( *t ) );
|
||||
t->name = object_copy( ot->name );
|
||||
t->boundname = object_copy( t->name );
|
||||
|
||||
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -214,11 +207,12 @@ void touch_target( OBJECT * t )
|
||||
bindtarget( t )->flags |= T_FLAG_TOUCHED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* target_scc() - returns the root of the strongly
|
||||
* connected component that this target
|
||||
* is a part of.
|
||||
* target_scc() - returns the root of a strongly connected component that this
|
||||
* target is a part of.
|
||||
*/
|
||||
|
||||
TARGET * target_scc( TARGET * t )
|
||||
{
|
||||
TARGET * result = t;
|
||||
@@ -239,13 +233,14 @@ TARGET * target_scc( TARGET * t )
|
||||
* targetlist() - turn list of target names into a TARGET chain.
|
||||
*
|
||||
* Inputs:
|
||||
* chain existing TARGETS to append to
|
||||
* targets list of target names
|
||||
* chain existing TARGETS to append to
|
||||
* targets list of target names
|
||||
*/
|
||||
|
||||
TARGETS * targetlist( TARGETS * chain, LIST * target_names )
|
||||
{
|
||||
LISTITER iter = list_begin( target_names ), end = list_end( target_names );
|
||||
LISTITER iter = list_begin( target_names );
|
||||
LISTITER const end = list_end( target_names );
|
||||
for ( ; iter != end; iter = list_next( iter ) )
|
||||
chain = targetentry( chain, bindtarget( list_item( iter ) ) );
|
||||
return chain;
|
||||
@@ -262,7 +257,7 @@ TARGETS * targetlist( TARGETS * chain, LIST * target_names )
|
||||
|
||||
TARGETS * targetentry( TARGETS * chain, TARGET * target )
|
||||
{
|
||||
TARGETS * c = (TARGETS *)BJAM_MALLOC( sizeof( TARGETS ) );
|
||||
TARGETS * const c = (TARGETS *)BJAM_MALLOC( sizeof( TARGETS ) );
|
||||
c->target = target;
|
||||
|
||||
if ( !chain ) chain = c;
|
||||
@@ -278,27 +273,25 @@ TARGETS * targetentry( TARGETS * chain, TARGET * target )
|
||||
* targetchain() - append two TARGET chains.
|
||||
*
|
||||
* Inputs:
|
||||
* chain exisitng TARGETS to append to
|
||||
* chain existing TARGETS to append to
|
||||
* target new target to append
|
||||
*/
|
||||
|
||||
TARGETS * targetchain( TARGETS * chain, TARGETS * targets )
|
||||
{
|
||||
if ( !targets ) return chain;
|
||||
if ( !chain ) return targets;
|
||||
if ( !chain ) return targets;
|
||||
|
||||
chain->tail->next = targets;
|
||||
chain->tail = targets->tail;
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
/*
|
||||
* action_free - decrement the ACTIONs refrence count
|
||||
* and (maybe) free it.
|
||||
* action_free - decrement the ACTIONs refrence count and (maybe) free it.
|
||||
*/
|
||||
|
||||
void action_free ( ACTION * action )
|
||||
void action_free( ACTION * action )
|
||||
{
|
||||
if ( --action->refs == 0 )
|
||||
{
|
||||
@@ -308,22 +301,20 @@ void action_free ( ACTION * action )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* actionlist() - append to an ACTION chain.
|
||||
*/
|
||||
|
||||
ACTIONS * actionlist( ACTIONS * chain, ACTION * action )
|
||||
{
|
||||
ACTIONS * actions = (ACTIONS *)BJAM_MALLOC( sizeof( ACTIONS ) );
|
||||
|
||||
ACTIONS * const actions = (ACTIONS *)BJAM_MALLOC( sizeof( ACTIONS ) );
|
||||
actions->action = action;
|
||||
|
||||
++action->refs;
|
||||
if ( !chain ) chain = actions;
|
||||
else chain->tail->next = actions;
|
||||
chain->tail = actions;
|
||||
actions->next = 0;
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
@@ -335,11 +326,12 @@ static SETTINGS * settings_freelist;
|
||||
*
|
||||
* Adds a variable setting (varname=list) onto a chain of settings for a
|
||||
* particular target. 'flag' controls the relationship between new and old
|
||||
* values in the same way as in var_set() function (see variable.c). Returns
|
||||
* the head of the settings chain.
|
||||
* values in the same way as in var_set() function (see variable.c). Returns the
|
||||
* head of the settings chain.
|
||||
*/
|
||||
|
||||
SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value )
|
||||
SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol,
|
||||
LIST * value )
|
||||
{
|
||||
SETTINGS * v;
|
||||
|
||||
@@ -354,7 +346,6 @@ SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value
|
||||
if ( !v )
|
||||
{
|
||||
v = settings_freelist;
|
||||
|
||||
if ( v )
|
||||
settings_freelist = v->next;
|
||||
else
|
||||
@@ -425,7 +416,7 @@ void freetargets( TARGETS * chain )
|
||||
{
|
||||
while ( chain )
|
||||
{
|
||||
TARGETS * n = chain->next;
|
||||
TARGETS * const n = chain->next;
|
||||
BJAM_FREE( chain );
|
||||
chain = n;
|
||||
}
|
||||
@@ -440,7 +431,7 @@ void freeactions( ACTIONS * chain )
|
||||
{
|
||||
while ( chain )
|
||||
{
|
||||
ACTIONS * n = chain->next;
|
||||
ACTIONS * const n = chain->next;
|
||||
action_free( chain->action );
|
||||
BJAM_FREE( chain );
|
||||
chain = n;
|
||||
@@ -456,7 +447,7 @@ void freesettings( SETTINGS * v )
|
||||
{
|
||||
while ( v )
|
||||
{
|
||||
SETTINGS * n = v->next;
|
||||
SETTINGS * const n = v->next;
|
||||
object_free( v->symbol );
|
||||
list_free( v->value );
|
||||
v->next = settings_freelist;
|
||||
@@ -468,7 +459,7 @@ void freesettings( SETTINGS * v )
|
||||
|
||||
static void freetarget( void * xt, void * data )
|
||||
{
|
||||
TARGET * t = (TARGET *)xt;
|
||||
TARGET * const t = (TARGET *)xt;
|
||||
if ( t->name ) object_free ( t->name );
|
||||
if ( t->boundname ) object_free ( t->boundname );
|
||||
if ( t->settings ) freesettings( t->settings );
|
||||
@@ -476,7 +467,6 @@ static void freetarget( void * xt, void * data )
|
||||
if ( t->dependants ) freetargets ( t->dependants );
|
||||
if ( t->parents ) freetargets ( t->parents );
|
||||
if ( t->actions ) freeactions ( t->actions );
|
||||
|
||||
if ( t->includes )
|
||||
{
|
||||
freetarget( t->includes, (void *)0 );
|
||||
@@ -498,7 +488,7 @@ void rules_done()
|
||||
}
|
||||
while ( settings_freelist )
|
||||
{
|
||||
SETTINGS * n = settings_freelist->next;
|
||||
SETTINGS * const n = settings_freelist->next;
|
||||
BJAM_FREE( settings_freelist );
|
||||
settings_freelist = n;
|
||||
}
|
||||
@@ -516,7 +506,7 @@ void actions_refer( rule_actions * a )
|
||||
|
||||
|
||||
/*
|
||||
* actions_free() - release a reference to the given actions.
|
||||
* actions_free() - release a reference to given actions.
|
||||
*/
|
||||
|
||||
void actions_free( rule_actions * a )
|
||||
@@ -529,6 +519,7 @@ void actions_free( rule_actions * a )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* set_rule_body() - set the argument list and procedure of the given rule.
|
||||
*/
|
||||
@@ -554,7 +545,7 @@ static OBJECT * global_rule_name( RULE * r )
|
||||
return object_copy( r->name );
|
||||
|
||||
{
|
||||
char name[4096] = "";
|
||||
char name[ 4096 ] = "";
|
||||
if ( r->module->name )
|
||||
{
|
||||
strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
|
||||
@@ -567,7 +558,7 @@ static OBJECT * global_rule_name( RULE * r )
|
||||
|
||||
|
||||
/*
|
||||
* global_rule() - given a rule, produce the corresponding entry in the global
|
||||
* global_rule() - given a rule, produce a corresponding entry in the global
|
||||
* module.
|
||||
*/
|
||||
|
||||
@@ -591,7 +582,8 @@ static RULE * global_rule( RULE * r )
|
||||
* exported to the global module as modulename.rulename.
|
||||
*/
|
||||
|
||||
RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure, int exported )
|
||||
RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure,
|
||||
int exported )
|
||||
{
|
||||
RULE * local = define_rule( m, rulename, m );
|
||||
local->exported = exported;
|
||||
@@ -619,9 +611,11 @@ static void set_rule_actions( RULE * rule, rule_actions * actions )
|
||||
}
|
||||
|
||||
|
||||
static rule_actions * actions_new( FUNCTION * command, LIST * bindlist, int flags )
|
||||
static rule_actions * actions_new( FUNCTION * command, LIST * bindlist,
|
||||
int flags )
|
||||
{
|
||||
rule_actions * result = (rule_actions *)BJAM_MALLOC( sizeof( rule_actions ) );
|
||||
rule_actions * const result = (rule_actions *)BJAM_MALLOC( sizeof(
|
||||
rule_actions ) );
|
||||
function_refer( command );
|
||||
result->command = command;
|
||||
result->bindlist = bindlist;
|
||||
@@ -631,10 +625,11 @@ static rule_actions * actions_new( FUNCTION * command, LIST * bindlist, int flag
|
||||
}
|
||||
|
||||
|
||||
RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags )
|
||||
RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command,
|
||||
LIST * bindlist, int flags )
|
||||
{
|
||||
RULE * local = define_rule( m, rulename, m );
|
||||
RULE * global = global_rule( local );
|
||||
RULE * const local = define_rule( m, rulename, m );
|
||||
RULE * const global = global_rule( local );
|
||||
set_rule_actions( local, actions_new( command, bindlist, flags ) );
|
||||
set_rule_actions( global, local->actions );
|
||||
return local;
|
||||
@@ -643,8 +638,8 @@ RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command, LI
|
||||
|
||||
/*
|
||||
* Looks for a rule in the specified module, and returns it, if found. First
|
||||
* checks if the rule is present in the module's rule table. Second, if name of
|
||||
* the rule is in the form name1.name2 and name1 is in the list of imported
|
||||
* checks if the rule is present in the module's rule table. Second, if the
|
||||
* rule's name is in the form name1.name2 and name1 is in the list of imported
|
||||
* modules, look in module 'name1' for rule 'name2'.
|
||||
*/
|
||||
|
||||
@@ -686,18 +681,17 @@ RULE * lookup_rule( OBJECT * rulename, module_t * m, int local_only )
|
||||
{
|
||||
if ( local_only && !result->exported )
|
||||
result = 0;
|
||||
else
|
||||
else if ( original_module != m )
|
||||
{
|
||||
/* Lookup started in class module. We have found a rule in class
|
||||
* module, which is marked for execution in that module, or in some
|
||||
* instances. Mark it for execution in the instance where we started
|
||||
* the lookup.
|
||||
*/
|
||||
int execute_in_class = ( result->module == m );
|
||||
int execute_in_some_instance = ( result->module->class_module &&
|
||||
( result->module->class_module == m ) );
|
||||
if ( ( original_module != m ) &&
|
||||
( execute_in_class || execute_in_some_instance ) )
|
||||
int const execute_in_class = result->module == m;
|
||||
int const execute_in_some_instance =
|
||||
result->module->class_module == m;
|
||||
if ( execute_in_class || execute_in_some_instance )
|
||||
result->module = original_module;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
#ifndef RULES_DWA_20011020_H
|
||||
#define RULES_DWA_20011020_H
|
||||
|
||||
#include "modules.h"
|
||||
#include "jam.h"
|
||||
|
||||
#include "function.h"
|
||||
#include "modules.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -33,14 +34,6 @@
|
||||
* SETTINGS - variables to set when executing a TARGET's ACTIONS.
|
||||
* TARGETS - a chain of TARGETs.
|
||||
* TARGET - an entity (e.g. a file) that can be built.
|
||||
*
|
||||
* 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
|
||||
* 04/12/94 (seiwald) - actionlist() now just appends a single action.
|
||||
* 06/01/94 (seiwald) - new 'actions existing' does existing sources
|
||||
* 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
|
||||
* 01/19/95 (seiwald) - split DONTKNOW into CANTFIND/CANTMAKE.
|
||||
* 02/02/95 (seiwald) - new LEAVES modifier on targets.
|
||||
* 02/14/95 (seiwald) - new NOUPDATE modifier on targets.
|
||||
*/
|
||||
|
||||
typedef struct _rule RULE;
|
||||
@@ -146,19 +139,18 @@ struct _target
|
||||
|
||||
/* This flag was added to support a new built-in rule named "FAIL_EXPECTED" used
|
||||
* to indicate that the result of running a given action should be inverted,
|
||||
* i.e. ok <=> fail. This is useful for launching certain test runs from a
|
||||
* Jamfile.
|
||||
* i.e. ok <=> fail. Useful for launching certain test runs from a Jamfile.
|
||||
*/
|
||||
#define T_FLAG_FAIL_EXPECTED 0x0100 /* FAIL_EXPECTED applied */
|
||||
|
||||
#define T_FLAG_INTERNAL 0x0200 /* internal INCLUDES node */
|
||||
|
||||
/* Indicates that the target must be a file. This prevents matching non-files,
|
||||
* like directories, when a target is searched.
|
||||
/* Indicates that the target must be a file. Prevents matching non-files, like
|
||||
* directories, when a target is searched.
|
||||
*/
|
||||
#define T_FLAG_ISFILE 0x0400
|
||||
|
||||
#define T_FLAG_PRECIOUS 0x0800
|
||||
#define T_FLAG_PRECIOUS 0x0800
|
||||
|
||||
char binding; /* how target relates to a real file or
|
||||
* folder
|
||||
@@ -188,13 +180,13 @@ struct _target
|
||||
|
||||
#define T_FATE_STABLE 2 /* target did not need updating */
|
||||
#define T_FATE_NEWER 3 /* target newer than parent */
|
||||
|
||||
|
||||
#define T_FATE_SPOIL 4 /* >= SPOIL rebuilds parents */
|
||||
#define T_FATE_ISTMP 4 /* unneeded temp target oddly present */
|
||||
|
||||
#define T_FATE_BUILD 5 /* >= BUILD rebuilds target */
|
||||
#define T_FATE_TOUCHED 5 /* manually touched with -t */
|
||||
#define T_FATE_REBUILD 6
|
||||
#define T_FATE_REBUILD 6
|
||||
#define T_FATE_MISSING 7 /* is missing, needs updating */
|
||||
#define T_FATE_NEEDTMP 8 /* missing temp that must be rebuild */
|
||||
#define T_FATE_OUTDATED 9 /* is out of date, needs updating */
|
||||
@@ -230,7 +222,7 @@ struct _target
|
||||
int depth; /* The depth of the target in the make0 stack. */
|
||||
char * cmds; /* type-punned command list */
|
||||
|
||||
const char * failed;
|
||||
char const * failed;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
#include "lists.h"
|
||||
#include "search.h"
|
||||
#include "timestamp.h"
|
||||
#include "pathsys.h"
|
||||
#include "variable.h"
|
||||
#include "object.h"
|
||||
|
||||
#include "compile.h"
|
||||
#include "strings.h"
|
||||
#include "hash.h"
|
||||
#include "filesys.h"
|
||||
#include "hash.h"
|
||||
#include "lists.h"
|
||||
#include "object.h"
|
||||
#include "pathsys.h"
|
||||
#include "strings.h"
|
||||
#include "timestamp.h"
|
||||
#include "variable.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -30,14 +32,10 @@ typedef struct _binding
|
||||
OBJECT * target;
|
||||
} BINDING;
|
||||
|
||||
static struct hash *explicit_bindings = 0;
|
||||
static struct hash * explicit_bindings = 0;
|
||||
|
||||
|
||||
void call_bind_rule
|
||||
(
|
||||
OBJECT * target_,
|
||||
OBJECT * boundname_
|
||||
)
|
||||
void call_bind_rule( OBJECT * target_, OBJECT * boundname_ )
|
||||
{
|
||||
LIST * bind_rule = var_get( root_module(), constant_BINDRULE );
|
||||
if ( !list_empty( bind_rule ) )
|
||||
@@ -47,7 +45,7 @@ void call_bind_rule
|
||||
if ( boundname && target )
|
||||
{
|
||||
/* Prepare the argument list. */
|
||||
FRAME frame[1];
|
||||
FRAME frame[ 1 ];
|
||||
frame_init( frame );
|
||||
|
||||
/* First argument is the target name. */
|
||||
@@ -70,48 +68,45 @@ void call_bind_rule
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* search.c - find a target along $(SEARCH) or $(LOCATE)
|
||||
* First, check if LOCATE is set. If so, use it to determine
|
||||
* the location of target and return, regardless of whether anything
|
||||
* exists on that location.
|
||||
* search.c - find a target along $(SEARCH) or $(LOCATE).
|
||||
*
|
||||
* Second, examine all directories in SEARCH. If there's file already
|
||||
* or there's another target with the same name which was placed
|
||||
* to this location via LOCATE setting, stop and return the location.
|
||||
* In case of previous target, return it's name via the third argument.
|
||||
* First, check if LOCATE is set. If so, use it to determine the location of
|
||||
* target and return, regardless of whether anything exists at that location.
|
||||
*
|
||||
* This bevahiour allow to handle dependency on generated files. If
|
||||
* caller does not expect that target is generated, 0 can be passed as
|
||||
* the third argument.
|
||||
* Second, examine all directories in SEARCH. If the file exists there or there
|
||||
* is another target with the same name already placed at this location via the
|
||||
* LOCATE setting, stop and return the location. In case of a previous target,
|
||||
* return its name via the 'another_target' argument.
|
||||
*
|
||||
* This bevahiour allows handling dependencies on generated files. If caller
|
||||
* does not expect that the target is generated, 0 can be passed as
|
||||
* 'another_target'.
|
||||
*/
|
||||
|
||||
OBJECT *
|
||||
search(
|
||||
OBJECT * target,
|
||||
time_t *time,
|
||||
OBJECT * * another_target,
|
||||
int file
|
||||
)
|
||||
OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target,
|
||||
int file )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
LIST * varlist;
|
||||
string buf[1];
|
||||
int found = 0;
|
||||
/* Will be set to 1 if target location is specified via LOCATE. */
|
||||
int explicitly_located = 0;
|
||||
PATHNAME f[ 1 ];
|
||||
LIST * varlist;
|
||||
string buf[ 1 ];
|
||||
int found = 0;
|
||||
OBJECT * boundname = 0;
|
||||
|
||||
/* Set to 1 if target location is specified via LOCATE. */
|
||||
int explicitly_located = 0;
|
||||
|
||||
if ( another_target )
|
||||
*another_target = 0;
|
||||
|
||||
if (! explicit_bindings )
|
||||
explicit_bindings = hashinit( sizeof(BINDING),
|
||||
"explicitly specified locations");
|
||||
if ( !explicit_bindings )
|
||||
explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
|
||||
"locations" );
|
||||
|
||||
string_new( buf );
|
||||
/* Parse the filename */
|
||||
|
||||
/* Parse the filename. */
|
||||
path_parse( object_str( target ), f );
|
||||
|
||||
f->f_grist.ptr = 0;
|
||||
@@ -136,13 +131,15 @@ search(
|
||||
object_free( key );
|
||||
found = 1;
|
||||
}
|
||||
else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
|
||||
else if ( varlist = var_get( root_module(), constant_SEARCH ),
|
||||
!list_empty( varlist ) )
|
||||
{
|
||||
LISTITER iter = list_begin( varlist ), end = list_end( varlist );
|
||||
LISTITER iter = list_begin( varlist );
|
||||
LISTITER const end = list_end( varlist );
|
||||
for ( ; iter != end; iter = list_next( iter ) )
|
||||
{
|
||||
BINDING * ba;
|
||||
file_info_t *ff;
|
||||
file_info_t * ff;
|
||||
OBJECT * key;
|
||||
OBJECT * test_path;
|
||||
|
||||
@@ -187,9 +184,10 @@ search(
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
/* Look for the obvious */
|
||||
/* This is a questionable move. Should we look in the */
|
||||
/* obvious place if SEARCH is set? */
|
||||
/* Look for the obvious. */
|
||||
/* This is a questionable move. Should we look in the obvious place if
|
||||
* SEARCH is set?
|
||||
*/
|
||||
OBJECT * key;
|
||||
|
||||
f->f_root.ptr = 0;
|
||||
@@ -213,10 +211,11 @@ search(
|
||||
{
|
||||
int found;
|
||||
BINDING * ba;
|
||||
OBJECT * key = path_as_key( boundname );
|
||||
/* CONSIDER: we probably should issue a warning is another file
|
||||
is explicitly bound to the same location. This might break
|
||||
compatibility, though. */
|
||||
OBJECT * const key = path_as_key( boundname );
|
||||
/* CONSIDER: We should probably issue a warning if another file is
|
||||
* explicitly bound to the same location. This might break
|
||||
* compatibility, though.
|
||||
*/
|
||||
ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
|
||||
if ( !found )
|
||||
{
|
||||
@@ -224,12 +223,10 @@ search(
|
||||
ba->target = target;
|
||||
}
|
||||
else
|
||||
{
|
||||
object_free( key );
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare a call to BINDRULE if the variable is set */
|
||||
/* Prepare a call to BINDRULE if the variable is set. */
|
||||
call_bind_rule( target, boundname );
|
||||
|
||||
return boundname;
|
||||
@@ -238,10 +235,11 @@ search(
|
||||
|
||||
static void free_binding( void * xbinding, void * data )
|
||||
{
|
||||
BINDING * binding = (BINDING *)xbinding;
|
||||
BINDING * const binding = (BINDING *)xbinding;
|
||||
object_free( binding->binding );
|
||||
}
|
||||
|
||||
|
||||
void search_done( void )
|
||||
{
|
||||
if ( explicit_bindings )
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
#include "object.h"
|
||||
#include <time.h>
|
||||
|
||||
OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target, int file );
|
||||
OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target,
|
||||
int file );
|
||||
void search_done( void );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,21 +10,20 @@
|
||||
* (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
|
||||
# include "hash.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
# include "timestamp.h"
|
||||
# include "object.h"
|
||||
# include "strings.h"
|
||||
|
||||
/*
|
||||
* timestamp.c - get the timestamp of a file or archive member
|
||||
*
|
||||
* 09/22/00 (seiwald) - downshift names on OS2, too
|
||||
*/
|
||||
|
||||
#include "jam.h"
|
||||
#include "timestamp.h"
|
||||
|
||||
#include "filesys.h"
|
||||
#include "hash.h"
|
||||
#include "object.h"
|
||||
#include "pathsys.h"
|
||||
#include "strings.h"
|
||||
|
||||
|
||||
/*
|
||||
* BINDING - all known files
|
||||
*/
|
||||
@@ -35,21 +34,22 @@ struct _binding {
|
||||
OBJECT * name;
|
||||
short flags;
|
||||
|
||||
# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
|
||||
#define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
|
||||
|
||||
short progress;
|
||||
|
||||
# define BIND_INIT 0 /* never seen */
|
||||
# define BIND_NOENTRY 1 /* timestamp requested but file never found */
|
||||
# define BIND_SPOTTED 2 /* file found but not timed yet */
|
||||
# define BIND_MISSING 3 /* file found but can't get timestamp */
|
||||
# define BIND_FOUND 4 /* file found and time stamped */
|
||||
#define BIND_INIT 0 /* never seen */
|
||||
#define BIND_NOENTRY 1 /* timestamp requested but file never found */
|
||||
#define BIND_SPOTTED 2 /* file found but not timed yet */
|
||||
#define BIND_MISSING 3 /* file found but can not get timestamp */
|
||||
#define BIND_FOUND 4 /* file found and time stamped */
|
||||
|
||||
time_t time; /* update time - 0 if not exist */
|
||||
/* update time - 0 if not exist */
|
||||
time_t time;
|
||||
};
|
||||
|
||||
static struct hash * bindhash = 0;
|
||||
static void time_enter( void *, OBJECT *, int, time_t );
|
||||
static void time_enter( void *, OBJECT *, int const found, time_t );
|
||||
|
||||
static char * time_progress[] =
|
||||
{
|
||||
@@ -69,11 +69,11 @@ void timestamp( OBJECT * target, time_t * time )
|
||||
{
|
||||
PROFILE_ENTER( timestamp );
|
||||
|
||||
PATHNAME f1;
|
||||
PATHNAME f2;
|
||||
int found;
|
||||
BINDING * b;
|
||||
string buf[ 1 ];
|
||||
PATHNAME f1;
|
||||
PATHNAME f2;
|
||||
int found;
|
||||
BINDING * b;
|
||||
string buf[ 1 ];
|
||||
|
||||
target = path_as_key( target );
|
||||
|
||||
@@ -172,19 +172,20 @@ void timestamp( OBJECT * target, time_t * time )
|
||||
}
|
||||
|
||||
*time = b->progress == BIND_FOUND ? b->time : 0;
|
||||
string_free( buf );
|
||||
|
||||
string_free( buf );
|
||||
object_free( target );
|
||||
|
||||
PROFILE_EXIT( timestamp );
|
||||
}
|
||||
|
||||
|
||||
static void time_enter( void * closure, OBJECT * target, int found, time_t time )
|
||||
static void time_enter( void * closure, OBJECT * target, int const found,
|
||||
time_t time )
|
||||
{
|
||||
int item_found;
|
||||
BINDING * b;
|
||||
struct hash * bindhash = (struct hash *)closure;
|
||||
struct hash * const bindhash = (struct hash *)closure;
|
||||
|
||||
target = path_as_key( target );
|
||||
|
||||
@@ -199,16 +200,18 @@ static void time_enter( void * closure, OBJECT * target, int found, time_t time
|
||||
b->progress = found ? BIND_FOUND : BIND_SPOTTED;
|
||||
|
||||
if ( DEBUG_BINDSCAN )
|
||||
printf( "time ( %s ) : %s\n", object_str( target ), time_progress[ b->progress ] );
|
||||
printf( "time ( %s ) : %s\n", object_str( target ), time_progress[
|
||||
b->progress ] );
|
||||
|
||||
object_free( target );
|
||||
}
|
||||
|
||||
static void free_timestamps ( void * xbinding, void * data )
|
||||
static void free_timestamps( void * xbinding, void * data )
|
||||
{
|
||||
object_free( ((BINDING *)xbinding)->name );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* stamps_done() - free timestamp tables.
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#define TIMESTAMP_H_SW_2011_11_18
|
||||
|
||||
#include "object.h"
|
||||
#include "time.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
void timestamp( OBJECT * target, time_t * time );
|
||||
void stamps_done();
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import TestCmd
|
||||
|
||||
import copy
|
||||
import fnmatch
|
||||
import glob
|
||||
import math
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
@@ -29,8 +31,7 @@ annotations = []
|
||||
|
||||
|
||||
def print_annotation(name, value, xml):
|
||||
"""Writes some named bits of information about test run.
|
||||
"""
|
||||
"""Writes some named bits of information about the current test run."""
|
||||
if xml:
|
||||
print escape(name) + " {{{"
|
||||
print escape(value)
|
||||
@@ -40,18 +41,20 @@ def print_annotation(name, value, xml):
|
||||
print value
|
||||
print "}}}"
|
||||
|
||||
|
||||
def flush_annotations(xml=0):
|
||||
global annotations
|
||||
for ann in annotations:
|
||||
print_annotation(ann[0], ann[1], xml)
|
||||
annotations = []
|
||||
|
||||
|
||||
def clear_annotations():
|
||||
global annotations
|
||||
annotations = []
|
||||
|
||||
defer_annotations = 0
|
||||
|
||||
defer_annotations = 0
|
||||
|
||||
def set_defer_annotations(n):
|
||||
global defer_annotations
|
||||
@@ -59,16 +62,15 @@ def set_defer_annotations(n):
|
||||
|
||||
|
||||
def annotate_stack_trace(tb=None):
|
||||
if tb is None:
|
||||
trace = TestCmd.caller(traceback.extract_stack(), 1)
|
||||
else:
|
||||
if tb:
|
||||
trace = TestCmd.caller(traceback.extract_tb(tb), 0)
|
||||
else:
|
||||
trace = TestCmd.caller(traceback.extract_stack(), 1)
|
||||
annotation("stacktrace", trace)
|
||||
|
||||
|
||||
def annotation(name, value):
|
||||
"""Records an annotation about the test run.
|
||||
"""
|
||||
"""Records an annotation about the test run."""
|
||||
annotations.append((name, value))
|
||||
if not defer_annotations:
|
||||
flush_annotations()
|
||||
@@ -83,57 +85,65 @@ def get_toolset():
|
||||
|
||||
|
||||
# Detect the host OS.
|
||||
windows = False
|
||||
cygwin = False
|
||||
if os.environ.get('OS', '').lower().startswith('windows'):
|
||||
windows = True
|
||||
|
||||
if os.__dict__.has_key('uname') and \
|
||||
os.uname()[0].lower().startswith('cygwin'):
|
||||
windows = True
|
||||
cygwin = True
|
||||
|
||||
suffixes = {}
|
||||
cygwin = hasattr(os, 'uname') and os.uname()[0].lower().startswith('cygwin')
|
||||
windows = cygwin or os.environ.get('OS', '').lower().startswith('windows')
|
||||
|
||||
|
||||
# Configuration stating whether Boost Build is expected to automatically prepend
|
||||
# prefixes to built library targets.
|
||||
lib_prefix = "lib"
|
||||
dll_prefix = "lib"
|
||||
def prepare_prefixes_and_suffixes(toolset):
|
||||
prepare_suffix_map(toolset)
|
||||
prepare_library_prefix(toolset)
|
||||
|
||||
|
||||
# Prepare the map of suffixes
|
||||
def prepare_suffix_map(toolset):
|
||||
global windows
|
||||
"""
|
||||
Set up suffix translation performed by the Boost Build testing framework
|
||||
to accomodate different toolsets generating targets of the same type using
|
||||
different filename extensions (suffixes).
|
||||
|
||||
"""
|
||||
global suffixes
|
||||
global cygwin
|
||||
global lib_prefix
|
||||
global dll_prefix
|
||||
suffixes = {'.exe': '', '.dll': '.so', '.lib': '.a', '.obj': '.o'}
|
||||
suffixes['.implib'] = '.no_implib_files_on_this_platform'
|
||||
suffixes = {}
|
||||
if windows:
|
||||
suffixes = {}
|
||||
if toolset in ["gcc"]:
|
||||
suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
|
||||
if toolset == "gcc":
|
||||
suffixes['.lib'] = '.a' # mingw static libs use suffix '.a'.
|
||||
suffixes['.obj'] = '.o'
|
||||
if cygwin:
|
||||
suffixes['.implib'] = '.lib.a'
|
||||
else:
|
||||
suffixes['.implib'] = '.lib'
|
||||
if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
|
||||
suffixes['.dll'] = '.dylib'
|
||||
else:
|
||||
suffixes['.exe'] = ''
|
||||
suffixes['.dll'] = '.so'
|
||||
suffixes['.lib'] = '.a'
|
||||
suffixes['.obj'] = '.o'
|
||||
suffixes['.implib'] = '.no_implib_files_on_this_platform'
|
||||
|
||||
if hasattr(os, 'uname') and os.uname()[0] == 'Darwin':
|
||||
suffixes['.dll'] = '.dylib'
|
||||
|
||||
|
||||
def prepare_library_prefix(toolset):
|
||||
"""
|
||||
Setup whether Boost Build is expected to automatically prepend prefixes
|
||||
to its built library targets.
|
||||
|
||||
"""
|
||||
global lib_prefix
|
||||
lib_prefix = "lib"
|
||||
dll_prefix = "lib"
|
||||
|
||||
global dll_prefix
|
||||
if cygwin:
|
||||
dll_prefix = "cyg"
|
||||
elif windows and not toolset in ["gcc"]:
|
||||
elif windows and toolset != "gcc":
|
||||
dll_prefix = None
|
||||
else:
|
||||
dll_prefix = "lib"
|
||||
|
||||
|
||||
def re_remove(sequence, regex):
|
||||
me = re.compile(regex)
|
||||
result = filter(lambda x: me.match(x), sequence)
|
||||
if 0 == len(result):
|
||||
if not result:
|
||||
raise ValueError()
|
||||
for r in result:
|
||||
sequence.remove(r)
|
||||
@@ -141,13 +151,12 @@ def re_remove(sequence, regex):
|
||||
|
||||
def glob_remove(sequence, pattern):
|
||||
result = fnmatch.filter(sequence, pattern)
|
||||
if 0 == len(result):
|
||||
if not result:
|
||||
raise ValueError()
|
||||
for r in result:
|
||||
sequence.remove(r)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# FIXME: this is copy-pasted from TestSCons.py
|
||||
# Should be moved to TestCmd.py?
|
||||
@@ -160,8 +169,7 @@ if os.name == 'posix':
|
||||
def _status(self):
|
||||
if os.WIFEXITED(self.status):
|
||||
return os.WEXITSTATUS(self.status)
|
||||
else:
|
||||
return -1
|
||||
return -1
|
||||
elif os.name == 'nt':
|
||||
def _failed(self, status=0):
|
||||
return not self.status is None and self.status != status
|
||||
@@ -194,8 +202,8 @@ class Tester(TestCmd.TestCmd):
|
||||
configuration file.
|
||||
`ignore_toolset_requirements` - Whether the test system should tell the run
|
||||
executable to ignore toolset requirements.
|
||||
`workdir` - indicates an absolute directory where the
|
||||
test will be run from.
|
||||
`workdir` - Absolute directory where the test will be
|
||||
run from.
|
||||
|
||||
Optional arguments inherited from the base class:
|
||||
|
||||
@@ -217,7 +225,7 @@ class Tester(TestCmd.TestCmd):
|
||||
ignore_toolset_requirements=True, workdir="", pass_d0=True, **keywords):
|
||||
|
||||
self.original_workdir = os.getcwd()
|
||||
if workdir != '' and not os.path.isabs(workdir):
|
||||
if workdir and not os.path.isabs(workdir):
|
||||
raise ("Parameter workdir <%s> must point to an absolute "
|
||||
"directory: " % workdir)
|
||||
|
||||
@@ -229,9 +237,11 @@ class Tester(TestCmd.TestCmd):
|
||||
self.pass_toolset = pass_toolset
|
||||
self.ignore_toolset_requirements = ignore_toolset_requirements
|
||||
|
||||
prepare_suffix_map(pass_toolset and self.toolset or 'gcc')
|
||||
prepare_prefixes_and_suffixes(pass_toolset and self.toolset or 'gcc')
|
||||
|
||||
if not '--default-bjam' in sys.argv:
|
||||
use_default_bjam = '--default-bjam' in sys.argv
|
||||
|
||||
if not use_default_bjam:
|
||||
jam_build_dir = ""
|
||||
if os.name == 'nt':
|
||||
jam_build_dir = "bin.ntx86"
|
||||
@@ -265,9 +275,11 @@ class Tester(TestCmd.TestCmd):
|
||||
elif os.uname()[0] == "OSF1":
|
||||
jam_build_dir = "bin.osf"
|
||||
else:
|
||||
raise "Don't know directory where Jam is built for this system: " + os.name + "/" + os.uname()[0]
|
||||
raise ("Do not know directory where Jam is built for this "
|
||||
"system: %s/%s" % (os.name, os.uname()[0]))
|
||||
else:
|
||||
raise "Don't know directory where Jam is built for this system: " + os.name
|
||||
raise ("Do not know directory where Jam is built for this "
|
||||
"system: %s" % os.name)
|
||||
|
||||
# Find where jam_src is located. Try for the debug version if it is
|
||||
# lying around.
|
||||
@@ -278,7 +290,7 @@ class Tester(TestCmd.TestCmd):
|
||||
jam_build_dir = d
|
||||
break
|
||||
else:
|
||||
print "Cannot find built Boost.Jam"
|
||||
print("Cannot find built Boost.Jam")
|
||||
sys.exit(1)
|
||||
|
||||
verbosity = ['-d0', '--quiet']
|
||||
@@ -292,26 +304,18 @@ class Tester(TestCmd.TestCmd):
|
||||
boost_build_path = self.original_workdir + "/.."
|
||||
|
||||
program_list = []
|
||||
|
||||
if '--default-bjam' in sys.argv:
|
||||
if use_default_bjam:
|
||||
program_list.append(executable)
|
||||
inpath_bjam = True
|
||||
else:
|
||||
program_list.append(os.path.join(jam_build_dir, executable))
|
||||
inpath_bjam = None
|
||||
program_list.append('-sBOOST_BUILD_PATH="' + boost_build_path + '"')
|
||||
if verbosity:
|
||||
program_list += verbosity
|
||||
if arguments:
|
||||
program_list += arguments.split(" ")
|
||||
|
||||
TestCmd.TestCmd.__init__(
|
||||
self
|
||||
, program=program_list
|
||||
, match=match
|
||||
, workdir=workdir
|
||||
, inpath=inpath_bjam
|
||||
, **keywords)
|
||||
TestCmd.TestCmd.__init__(self, program=program_list, match=match,
|
||||
workdir=workdir, inpath=use_default_bjam, **keywords)
|
||||
|
||||
os.chdir(self.workdir)
|
||||
|
||||
@@ -432,9 +436,10 @@ class Tester(TestCmd.TestCmd):
|
||||
#
|
||||
# FIXME: Large portion copied from TestSCons.py, should be moved?
|
||||
#
|
||||
def run_build_system(self, extra_args="", subdir="", stdout=None, stderr="",
|
||||
status=0, match=None, pass_toolset=None, use_test_config=None,
|
||||
ignore_toolset_requirements=None, expected_duration=None, **kw):
|
||||
def run_build_system(self, extra_args="", subdir="", stdout=None,
|
||||
stderr="", status=0, match=None, pass_toolset=None,
|
||||
use_test_config=None, ignore_toolset_requirements=None,
|
||||
expected_duration=None, **kw):
|
||||
|
||||
build_time_start = time.time()
|
||||
|
||||
@@ -466,8 +471,8 @@ class Tester(TestCmd.TestCmd):
|
||||
if pass_toolset:
|
||||
kw['program'].append("toolset=" + self.toolset)
|
||||
if use_test_config:
|
||||
kw['program'].append('--test-config="%s"'
|
||||
% os.path.join(self.original_workdir, "test-config.jam"))
|
||||
kw['program'].append('--test-config="%s"' % os.path.join(
|
||||
self.original_workdir, "test-config.jam"))
|
||||
if ignore_toolset_requirements:
|
||||
kw['program'].append("--ignore-toolset-requirements")
|
||||
if "--python" in sys.argv:
|
||||
@@ -482,18 +487,18 @@ class Tester(TestCmd.TestCmd):
|
||||
old_last_build_time_finish = self.last_build_time_finish
|
||||
self.last_build_time_finish = time.time()
|
||||
|
||||
if (status != None) and _failed(self, status):
|
||||
if status is not None and _failed(self, status):
|
||||
expect = ''
|
||||
if status != 0:
|
||||
expect = " (expected %d)" % status
|
||||
|
||||
annotation("failure", '"%s" returned %d%s'
|
||||
% (kw['program'], _status(self), expect))
|
||||
annotation("failure", '"%s" returned %d%s' % (kw['program'],
|
||||
_status(self), expect))
|
||||
|
||||
annotation("reason", "unexpected status returned by bjam")
|
||||
self.fail_test(1)
|
||||
|
||||
if not (stdout is None) and not match(self.stdout(), stdout):
|
||||
if stdout is not None and not match(self.stdout(), stdout):
|
||||
annotation("failure", "Unexpected stdout")
|
||||
annotation("Expected STDOUT", stdout)
|
||||
annotation("Actual STDOUT", self.stdout())
|
||||
@@ -507,7 +512,7 @@ class Tester(TestCmd.TestCmd):
|
||||
intel_workaround = re.compile("^xi(link|lib): executing.*\n", re.M)
|
||||
actual_stderr = re.sub(intel_workaround, "", self.stderr())
|
||||
|
||||
if not (stderr is None) and not match(actual_stderr, stderr):
|
||||
if stderr is not None and not match(actual_stderr, stderr):
|
||||
annotation("failure", "Unexpected stderr")
|
||||
annotation("Expected STDERR", stderr)
|
||||
annotation("Actual STDERR", self.stderr())
|
||||
@@ -515,7 +520,7 @@ class Tester(TestCmd.TestCmd):
|
||||
self.maybe_do_diff(actual_stderr, stderr)
|
||||
self.fail_test(1, dump_stdio=False)
|
||||
|
||||
if not expected_duration is None:
|
||||
if expected_duration is not None:
|
||||
actual_duration = self.last_build_time_finish - build_time_start
|
||||
if actual_duration > expected_duration:
|
||||
print "Test run lasted %f seconds while it was expected to " \
|
||||
@@ -528,9 +533,10 @@ class Tester(TestCmd.TestCmd):
|
||||
if self.difference.empty():
|
||||
# If nothing has been changed by this build and sufficient time has
|
||||
# passed since the last build that actually changed something,
|
||||
# there may be no need to wait for touched or newly created files
|
||||
# to get newer timestamps than the currently existing ones.
|
||||
# there is no need to wait for touched or newly created files to
|
||||
# start getting newer timestamps than the currently existing ones.
|
||||
self.last_build_time_finish = old_last_build_time_finish
|
||||
|
||||
self.difference.ignore_directories()
|
||||
self.unexpected_difference = copy.deepcopy(self.difference)
|
||||
|
||||
@@ -714,8 +720,11 @@ class Tester(TestCmd.TestCmd):
|
||||
self.ignore('gmon.out')
|
||||
self.ignore('*/gmon.out')
|
||||
|
||||
# Boost Build's 'configure' functionality (unfinished at the time)
|
||||
# produces this file.
|
||||
self.ignore("bin/config.log")
|
||||
|
||||
# Compiled Python files created when running Python based Boost Build.
|
||||
self.ignore("*.pyc")
|
||||
|
||||
if not self.unexpected_difference.empty():
|
||||
@@ -883,7 +892,8 @@ class Tester(TestCmd.TestCmd):
|
||||
names = [names]
|
||||
r = map(self.adjust_lib_name, names)
|
||||
r = map(self.adjust_suffix, r)
|
||||
r = map(lambda x, t=self.toolset: string.replace(x, "$toolset", t+"*"), r)
|
||||
r = map(lambda x, t=self.toolset: string.replace(x, "$toolset", t+"*"),
|
||||
r)
|
||||
return r
|
||||
|
||||
def native_file_name(self, name):
|
||||
@@ -891,11 +901,14 @@ class Tester(TestCmd.TestCmd):
|
||||
elements = string.split(name, "/")
|
||||
return os.path.normpath(apply(os.path.join, [self.workdir]+elements))
|
||||
|
||||
# Wait while time is no longer equal to the time last "run_build_system"
|
||||
# call finished. Used to avoid subsequent builds treating existing files as
|
||||
# 'current'.
|
||||
def wait_for_time_change_since_last_build(self):
|
||||
while 1:
|
||||
"""
|
||||
Wait until newly assigned file system timestamps are larger than the
|
||||
one assigned to files created by our previous build run. Used to make
|
||||
subsequent builds correctly recognize newly created or touched files.
|
||||
|
||||
"""
|
||||
while True:
|
||||
# In fact, I'm not sure why "+ 2" as opposed to "+ 1" is needed but
|
||||
# empirically, "+ 1" sometimes causes 'touch' and other functions
|
||||
# not to bump the file time enough for a rebuild to happen.
|
||||
@@ -915,10 +928,7 @@ class List:
|
||||
elements = string.split(s)
|
||||
else:
|
||||
elements = s
|
||||
|
||||
self.l = []
|
||||
for e in elements:
|
||||
self.l.append(string.replace(e, '\001', ' '))
|
||||
self.l = [string.replace(e, '\001', ' ') for e in elements]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.l)
|
||||
@@ -964,4 +974,4 @@ class List:
|
||||
if __name__ == '__main__':
|
||||
assert str(List("foo bar") * "/baz") == "['foo/baz', 'bar/baz']"
|
||||
assert repr("foo/" * List("bar baz")) == "__main__.List('foo/bar foo/baz')"
|
||||
print 'tests passed'
|
||||
print('tests passed')
|
||||
|
||||
@@ -21,6 +21,7 @@ or NO RESULT respectively and exiting with status 0 (success), 1 or 2
|
||||
respectively. This allows for a distinction between an actual failed test and a
|
||||
test that could not be properly evaluated because of an external condition (such
|
||||
as a full file system or incorrect permissions).
|
||||
|
||||
"""
|
||||
|
||||
# Copyright 2000 Steven Knight
|
||||
@@ -102,9 +103,10 @@ def caller(tblist, skip):
|
||||
def fail_test(self=None, condition=True, function=None, skip=0):
|
||||
"""Cause the test to fail.
|
||||
|
||||
By default, the fail_test() method reports that the test FAILED and exits
|
||||
with a status of 1. If a condition argument is supplied, the test fails only
|
||||
if the condition is true.
|
||||
By default, the fail_test() method reports that the test FAILED and exits
|
||||
with a status of 1. If a condition argument is supplied, the test fails
|
||||
only if the condition is true.
|
||||
|
||||
"""
|
||||
if not condition:
|
||||
return
|
||||
@@ -131,9 +133,10 @@ in directory: """ + os.getcwd() )
|
||||
def no_result(self=None, condition=True, function=None, skip=0):
|
||||
"""Causes a test to exit with no valid result.
|
||||
|
||||
By default, the no_result() method reports NO RESULT for the test and exits
|
||||
with a status of 2. If a condition argument is supplied, the test fails only
|
||||
if the condition is true.
|
||||
By default, the no_result() method reports NO RESULT for the test and
|
||||
exits with a status of 2. If a condition argument is supplied, the test
|
||||
fails only if the condition is true.
|
||||
|
||||
"""
|
||||
if not condition:
|
||||
return
|
||||
@@ -158,9 +161,10 @@ def no_result(self=None, condition=True, function=None, skip=0):
|
||||
def pass_test(self=None, condition=True, function=None):
|
||||
"""Causes a test to pass.
|
||||
|
||||
By default, the pass_test() method reports PASSED for the test and exits
|
||||
By default, the pass_test() method reports PASSED for the test and exits
|
||||
with a status of 0. If a condition argument is supplied, the test passes
|
||||
only if the condition is true.
|
||||
|
||||
"""
|
||||
if not condition:
|
||||
return
|
||||
@@ -171,8 +175,10 @@ def pass_test(self=None, condition=True, function=None):
|
||||
|
||||
|
||||
def match_exact(lines=None, matches=None):
|
||||
"""Returns whether the given lists or strings containing lines separated
|
||||
"""
|
||||
Returns whether the given lists or strings containing lines separated
|
||||
using newline characters contain exactly the same data.
|
||||
|
||||
"""
|
||||
if not type(lines) is ListType:
|
||||
lines = split(lines, "\n")
|
||||
@@ -187,9 +193,11 @@ def match_exact(lines=None, matches=None):
|
||||
|
||||
|
||||
def match_re(lines=None, res=None):
|
||||
"""Given lists or strings contain lines separated using newline characters.
|
||||
"""
|
||||
Given lists or strings contain lines separated using newline characters.
|
||||
This function matches those lines one by one, interpreting the lines in the
|
||||
res parameter as regular expressions.
|
||||
|
||||
"""
|
||||
if not type(lines) is ListType:
|
||||
lines = split(lines, "\n")
|
||||
@@ -204,42 +212,35 @@ def match_re(lines=None, res=None):
|
||||
|
||||
|
||||
class TestCmd:
|
||||
"""Class TestCmd.
|
||||
"""
|
||||
|
||||
def __init__(self, description=None, program=None, workdir=None,
|
||||
subdir=None, verbose=False, match=None, inpath=None):
|
||||
|
||||
self._cwd = os.getcwd()
|
||||
self.description_set(description)
|
||||
if inpath:
|
||||
self.program = program
|
||||
else:
|
||||
self.program_set(program)
|
||||
self.program_set(program, inpath)
|
||||
self.verbose_set(verbose)
|
||||
if not match is None:
|
||||
self.match_func = match
|
||||
else:
|
||||
if match is None:
|
||||
self.match_func = match_re
|
||||
else:
|
||||
self.match_func = match
|
||||
self._dirlist = []
|
||||
self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
|
||||
if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
|
||||
self._preserve['pass_test'] = os.environ['PRESERVE']
|
||||
self._preserve['fail_test'] = os.environ['PRESERVE']
|
||||
self._preserve['no_result'] = os.environ['PRESERVE']
|
||||
env = os.environ.get('PRESERVE')
|
||||
if env:
|
||||
self._preserve['pass_test'] = env
|
||||
self._preserve['fail_test'] = env
|
||||
self._preserve['no_result'] = env
|
||||
else:
|
||||
try:
|
||||
self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
|
||||
except KeyError:
|
||||
pass
|
||||
env = os.environ.get('PRESERVE_PASS')
|
||||
if env is not None:
|
||||
self._preserve['pass_test'] = env
|
||||
env = os.environ.get('PRESERVE_FAIL')
|
||||
if env is not None:
|
||||
self._preserve['fail_test'] = env
|
||||
env = os.environ.get('PRESERVE_PASS')
|
||||
if env is not None:
|
||||
self._preserve['PRESERVE_NO_RESULT'] = env
|
||||
self._stdout = []
|
||||
self._stderr = []
|
||||
self.status = None
|
||||
@@ -254,7 +255,8 @@ class TestCmd:
|
||||
return "%x" % id(self)
|
||||
|
||||
def cleanup(self, condition=None):
|
||||
"""Removes any temporary working directories for the specified TestCmd
|
||||
"""
|
||||
Removes any temporary working directories for the specified TestCmd
|
||||
environment. If the environment variable PRESERVE was set when the
|
||||
TestCmd environment was created, temporary working directories are not
|
||||
removed. If any of the environment variables PRESERVE_PASS,
|
||||
@@ -264,9 +266,10 @@ class TestCmd:
|
||||
Temporary working directories are also preserved for conditions
|
||||
specified via the preserve method.
|
||||
|
||||
Typically, this method is not called directly, but is used when the
|
||||
Typically, this method is not called directly, but is used when the
|
||||
script exits to clean up temporary working directories as appropriate
|
||||
for the exit status.
|
||||
|
||||
"""
|
||||
if not self._dirlist:
|
||||
return
|
||||
@@ -274,13 +277,13 @@ class TestCmd:
|
||||
condition = self.condition
|
||||
if self._preserve[condition]:
|
||||
for dir in self._dirlist:
|
||||
print "Preserved directory", dir
|
||||
print("Preserved directory %s" % dir)
|
||||
else:
|
||||
list = self._dirlist[:]
|
||||
list.reverse()
|
||||
for dir in list:
|
||||
self.writable(dir, 1)
|
||||
shutil.rmtree(dir, ignore_errors = 1)
|
||||
shutil.rmtree(dir, ignore_errors=1)
|
||||
|
||||
self._dirlist = []
|
||||
self.workdir = None
|
||||
@@ -292,13 +295,11 @@ class TestCmd:
|
||||
pass
|
||||
|
||||
def description_set(self, description):
|
||||
"""Set the description of the functionality being tested.
|
||||
"""
|
||||
"""Set the description of the functionality being tested."""
|
||||
self.description = description
|
||||
|
||||
def fail_test(self, condition=True, function=None, skip=0):
|
||||
"""Cause the test to fail.
|
||||
"""
|
||||
"""Cause the test to fail."""
|
||||
if not condition:
|
||||
return
|
||||
self.condition = 'fail_test'
|
||||
@@ -308,23 +309,19 @@ class TestCmd:
|
||||
skip = skip)
|
||||
|
||||
def match(self, lines, matches):
|
||||
"""Compare actual and expected file contents.
|
||||
"""
|
||||
"""Compare actual and expected file contents."""
|
||||
return self.match_func(lines, matches)
|
||||
|
||||
def match_exact(self, lines, matches):
|
||||
"""Compare actual and expected file contents.
|
||||
"""
|
||||
"""Compare actual and expected file content exactly."""
|
||||
return match_exact(lines, matches)
|
||||
|
||||
def match_re(self, lines, res):
|
||||
"""Compare actual and expected file contents.
|
||||
"""
|
||||
"""Compare file content with a regular expression."""
|
||||
return match_re(lines, res)
|
||||
|
||||
def no_result(self, condition=True, function=None, skip=0):
|
||||
"""Report that the test could not be run.
|
||||
"""
|
||||
"""Report that the test could not be run."""
|
||||
if not condition:
|
||||
return
|
||||
self.condition = 'no_result'
|
||||
@@ -334,38 +331,40 @@ class TestCmd:
|
||||
skip = skip)
|
||||
|
||||
def pass_test(self, condition=True, function=None):
|
||||
"""Cause the test to pass.
|
||||
"""
|
||||
"""Cause the test to pass."""
|
||||
if not condition:
|
||||
return
|
||||
self.condition = 'pass_test'
|
||||
pass_test(self = self, condition = condition, function = function)
|
||||
pass_test(self, condition, function)
|
||||
|
||||
def preserve(self, *conditions):
|
||||
"""Arrange for the temporary working directories for the specified
|
||||
"""
|
||||
Arrange for the temporary working directories for the specified
|
||||
TestCmd environment to be preserved for one or more conditions. If no
|
||||
conditions are specified, arranges for the temporary working directories
|
||||
to be preserved for all conditions.
|
||||
conditions are specified, arranges for the temporary working
|
||||
directories to be preserved for all conditions.
|
||||
|
||||
"""
|
||||
if conditions is ():
|
||||
conditions = ('pass_test', 'fail_test', 'no_result')
|
||||
for cond in conditions:
|
||||
self._preserve[cond] = 1
|
||||
|
||||
def program_set(self, program):
|
||||
"""Set the executable program or script to be tested.
|
||||
"""
|
||||
if program and program[0] and not os.path.isabs(program[0]):
|
||||
def program_set(self, program, inpath):
|
||||
"""Set the executable program or script to be tested."""
|
||||
if not inpath and program and not os.path.isabs(program[0]):
|
||||
program[0] = os.path.join(self._cwd, program[0])
|
||||
self.program = program
|
||||
|
||||
def read(self, file, mode='rb'):
|
||||
"""Reads and returns the contents of the specified file name. The file
|
||||
name may be a list, in which case the elements are concatenated with the
|
||||
os.path.join() method. The file is assumed to be under the temporary
|
||||
working directory unless it is an absolute path name. The I/O mode for
|
||||
the file may be specified; it must begin with an 'r'. The default is
|
||||
'rb' (binary read).
|
||||
"""
|
||||
Reads and returns the contents of the specified file name. The file
|
||||
name may be a list, in which case the elements are concatenated with
|
||||
the os.path.join() method. The file is assumed to be under the
|
||||
temporary working directory unless it is an absolute path name. The I/O
|
||||
mode for the file may be specified; it must begin with an 'r'. The
|
||||
default is 'rb' (binary read).
|
||||
|
||||
"""
|
||||
if type(file) is ListType:
|
||||
file = apply(os.path.join, tuple(file))
|
||||
@@ -376,9 +375,11 @@ class TestCmd:
|
||||
return open(file, mode).read()
|
||||
|
||||
def run(self, program=None, arguments=None, chdir=None, stdin=None):
|
||||
"""Runs a test of the program or script for the test environment.
|
||||
"""
|
||||
Runs a test of the program or script for the test environment.
|
||||
Standard output and error output are saved for future retrieval via the
|
||||
stdout() and stderr() methods.
|
||||
|
||||
"""
|
||||
if chdir:
|
||||
oldcwd = os.getcwd()
|
||||
@@ -417,8 +418,8 @@ class TestCmd:
|
||||
# This is a workaround for a longstanding Python bug on Windows
|
||||
# when using os.popen(), os.system() and similar functions to
|
||||
# execute a command containing quote characters. The bug seems
|
||||
# to be related to the quote stripping functionality used by the
|
||||
# Windows cmd.exe interpreter when its /S is not specified.
|
||||
# to be related to the quote stripping functionality used by
|
||||
# the Windows cmd.exe interpreter when its /S is not specified.
|
||||
#
|
||||
# Cleaned up quote from the cmd.exe help screen as displayed on
|
||||
# Windows XP SP2:
|
||||
@@ -441,15 +442,15 @@ class TestCmd:
|
||||
# command line, preserving any text after the last quote
|
||||
# character.
|
||||
#
|
||||
# This causes some commands containing quotes not to be executed
|
||||
# correctly. For example:
|
||||
# This causes some commands containing quotes not to be
|
||||
# executed correctly. For example:
|
||||
#
|
||||
# "\Long folder name\aaa.exe" --name="Jurko" --no-surname
|
||||
# "\Long folder name\aaa.exe" --name="Foo" --no-surname
|
||||
#
|
||||
# would get its outermost quotes stripped and would be executed
|
||||
# as:
|
||||
#
|
||||
# \Long folder name\aaa.exe" --name="Jurko --no-surname
|
||||
# \Long folder name\aaa.exe" --name="Foo --no-surname
|
||||
#
|
||||
# which would report an error about '\Long' not being a valid
|
||||
# command.
|
||||
@@ -464,8 +465,8 @@ class TestCmd:
|
||||
# not work correctly should Python ever fix this bug.
|
||||
# (01.05.2008.) (Jurko)
|
||||
if command_string.find('"') != -1:
|
||||
command_string = '"' + command_string + '"'
|
||||
(tochild, fromchild, childerr) = os.popen3(command_string)
|
||||
command_string = '"%s"' % command_string
|
||||
tochild, fromchild, childerr = os.popen3(command_string)
|
||||
if stdin:
|
||||
if type(stdin) is ListType:
|
||||
for line in stdin:
|
||||
@@ -501,10 +502,12 @@ class TestCmd:
|
||||
os.chdir(oldcwd)
|
||||
|
||||
def stderr(self, run=None):
|
||||
"""Returns the error output from the specified run number. If there is
|
||||
"""
|
||||
Returns the error output from the specified run number. If there is
|
||||
no specified run number, then returns the error output of the last run.
|
||||
If the run number is less than zero, then returns the error output from
|
||||
that many runs back from the current run.
|
||||
|
||||
"""
|
||||
if not run:
|
||||
run = len(self._stderr)
|
||||
@@ -516,10 +519,12 @@ class TestCmd:
|
||||
return self._stderr[run]
|
||||
|
||||
def stdout(self, run=None):
|
||||
"""Returns the standard output from the specified run number. If there
|
||||
is no specified run number, then returns the standard output of the last
|
||||
run. If the run number is less than zero, then returns the standard
|
||||
output from that many runs back from the current run.
|
||||
"""
|
||||
Returns the standard output from the specified run number. If there
|
||||
is no specified run number, then returns the standard output of the
|
||||
last run. If the run number is less than zero, then returns the
|
||||
standard output from that many runs back from the current run.
|
||||
|
||||
"""
|
||||
if not run:
|
||||
run = len(self._stdout)
|
||||
@@ -531,15 +536,17 @@ class TestCmd:
|
||||
return self._stdout[run]
|
||||
|
||||
def subdir(self, *subdirs):
|
||||
"""Create new subdirectories under the temporary working directory, one
|
||||
"""
|
||||
Create new subdirectories under the temporary working directory, one
|
||||
for each argument. An argument may be a list, in which case the list
|
||||
elements are concatenated using the os.path.join() method.
|
||||
Subdirectories multiple levels deep must be created using a separate
|
||||
argument for each level:
|
||||
|
||||
test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
|
||||
test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
|
||||
|
||||
Returns the number of subdirectories actually created.
|
||||
|
||||
"""
|
||||
count = 0
|
||||
for sub in subdirs:
|
||||
@@ -553,14 +560,16 @@ class TestCmd:
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
count = count + 1
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def unlink (self, file):
|
||||
"""Unlinks the specified file name. The file name may be a list, in
|
||||
"""
|
||||
Unlinks the specified file name. The file name may be a list, in
|
||||
which case the elements are concatenated using the os.path.join()
|
||||
method. The file is assumed to be under the temporary working directory
|
||||
unless it is an absolute path name.
|
||||
|
||||
"""
|
||||
if type(file) is ListType:
|
||||
file = apply(os.path.join, tuple(file))
|
||||
@@ -574,14 +583,15 @@ class TestCmd:
|
||||
self.verbose = verbose
|
||||
|
||||
def workdir_set(self, path):
|
||||
"""Creates a temporary working directory with the specified path name.
|
||||
If the path is a null string (''), a unique directory name is created.
|
||||
"""
|
||||
Creates a temporary working directory with the specified path name.
|
||||
If the path is a null string (''), a unique directory name is created.
|
||||
|
||||
"""
|
||||
if os.path.isabs(path):
|
||||
self.workdir = path
|
||||
else:
|
||||
if (path != None):
|
||||
if path != None:
|
||||
if path == '':
|
||||
path = tempfile.mktemp()
|
||||
if path != None:
|
||||
@@ -592,8 +602,8 @@ class TestCmd:
|
||||
_Cleanup.index(self)
|
||||
except ValueError:
|
||||
_Cleanup.append(self)
|
||||
# We'd like to set self.workdir like this:
|
||||
# self.workdir = path
|
||||
# We would like to set self.workdir like this:
|
||||
# self.workdir = path
|
||||
# But symlinks in the path will report things differently from
|
||||
# os.getcwd(), so chdir there and back to fetch the canonical
|
||||
# path.
|
||||
@@ -605,31 +615,31 @@ class TestCmd:
|
||||
self.workdir = None
|
||||
|
||||
def workpath(self, *args):
|
||||
"""Returns the absolute path name to a subdirectory or file within the
|
||||
"""
|
||||
Returns the absolute path name to a subdirectory or file within the
|
||||
current temporary working directory. Concatenates the temporary working
|
||||
directory name with the specified arguments using the os.path.join()
|
||||
method.
|
||||
|
||||
"""
|
||||
return apply(os.path.join, (self.workdir,) + tuple(args))
|
||||
|
||||
def writable(self, top, write):
|
||||
"""Make the specified directory tree writable (write == 1) or not
|
||||
(write == None).
|
||||
"""
|
||||
Make the specified directory tree writable (write == 1) or not
|
||||
(write == None).
|
||||
|
||||
"""
|
||||
def _walk_chmod(arg, dirname, names):
|
||||
st = os.stat(dirname)
|
||||
os.chmod(dirname, arg(st[stat.ST_MODE]))
|
||||
for name in names:
|
||||
n = os.path.join(dirname, name)
|
||||
st = os.stat(n)
|
||||
os.chmod(n, arg(st[stat.ST_MODE]))
|
||||
fullname = os.path.join(dirname, name)
|
||||
st = os.stat(fullname)
|
||||
os.chmod(fullname, arg(st[stat.ST_MODE]))
|
||||
|
||||
def _mode_writable(mode):
|
||||
return stat.S_IMODE(mode|0200)
|
||||
|
||||
def _mode_non_writable(mode):
|
||||
return stat.S_IMODE(mode&~0200)
|
||||
_mode_writable = lambda mode: stat.S_IMODE(mode|0200)
|
||||
_mode_non_writable = lambda mode: stat.S_IMODE(mode&~0200)
|
||||
|
||||
if write:
|
||||
f = _mode_writable
|
||||
@@ -641,12 +651,14 @@ class TestCmd:
|
||||
pass # Ignore any problems changing modes.
|
||||
|
||||
def write(self, file, content, mode='wb'):
|
||||
"""Writes the specified content text (second argument) to the specified
|
||||
"""
|
||||
Writes the specified content text (second argument) to the specified
|
||||
file name (first argument). The file name may be a list, in which case
|
||||
the elements are concatenated using the os.path.join() method. The file
|
||||
is created under the temporary working directory. Any subdirectories in
|
||||
the path must already exist. The I/O mode for the file may be specified;
|
||||
it must begin with a 'w'. The default is 'wb' (binary write).
|
||||
|
||||
"""
|
||||
if type(file) is ListType:
|
||||
file = apply(os.path.join, tuple(file))
|
||||
|
||||
@@ -19,8 +19,8 @@ toolset = BoostBuild.get_toolset()
|
||||
|
||||
# Clear environment for testing.
|
||||
#
|
||||
for s in ('BOOST_ROOT', 'BOOST_BUILD_PATH', 'JAM_TOOLSET', 'BCCROOT', 'MSVCDir',
|
||||
'MSVC', 'MSVCNT', 'MINGW', 'watcom' ):
|
||||
for s in ('BOOST_ROOT', 'BOOST_BUILD_PATH', 'JAM_TOOLSET', 'BCCROOT',
|
||||
'MSVCDir', 'MSVC', 'MSVCNT', 'MINGW', 'watcom'):
|
||||
try:
|
||||
del os.environ[s]
|
||||
except:
|
||||
|
||||
Reference in New Issue
Block a user