$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r79429 - trunk/tools/build/v2/engine
From: jurko.gospodnetic_at_[hidden]
Date: 2012-07-11 17:42:52
Author: jurko
Date: 2012-07-11 17:42:51 EDT (Wed, 11 Jul 2012)
New Revision: 79429
URL: http://svn.boost.org/trac/boost/changeset/79429
Log:
Booat Jam code cleanup - synchronized filent.c & fileunix.c OS specific implementation modules. Extracted shared functionality to filesys.c. Updated related descriptive function & module comments. Added missing copyright comment for the filesys.c module.
Text files modified: 
   trunk/tools/build/v2/engine/filent.c   |   318 ++++++++++++++++----------------------- 
   trunk/tools/build/v2/engine/filesys.c  |   255 +++++++++++++++++++++++++++++--         
   trunk/tools/build/v2/engine/filesys.h  |    37 +--                                     
   trunk/tools/build/v2/engine/fileunix.c |   173 +++++++--------------                   
   4 files changed, 442 insertions(+), 341 deletions(-)
Modified: trunk/tools/build/v2/engine/filent.c
==============================================================================
--- trunk/tools/build/v2/engine/filent.c	(original)
+++ trunk/tools/build/v2/engine/filent.c	2012-07-11 17:42:51 EDT (Wed, 11 Jul 2012)
@@ -15,21 +15,17 @@
  * filent.c - scan directories and archives on NT
  *
  * External routines:
- *  file_dirscan() - scan a directory for files
- *  file_time() - get timestamp of file, if not done by file_dirscan()
  *  file_archscan() - scan an archive for files
+ *  file_mkdir()    - create a directory
  *
- * 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.
+ * External routines called only via routines in filesys.c:
+ *  file_collect_dir_content_() - collects directory content information
+ *  file_dirscan_()             - OS specific file_dirscan() implementation
+ *  file_query_()               - query information about a path from the OS
  */
 
 #include "jam.h"
-
 #ifdef OS_NT
-
 #include "filesys.h"
 
 #include "object.h"
@@ -45,144 +41,138 @@
 # define _finddata_t ffblk
 #endif
 
+#include <assert.h>
 #include <ctype.h>
 #include <direct.h>
 #include <io.h>
-#include <sys/stat.h>
 
 #include <windows.h>
 
 
 /*
- * file_dirscan() - scan a directory for files
+ * file_collect_dir_content_() - collects directory content information
  */
 
-void file_dirscan( OBJECT * dir, scanback func, void * closure )
+int file_collect_dir_content_( file_info_t * const d )
 {
-    PROFILE_ENTER( FILE_DIRSCAN );
-
-    /* First enter the directory itself. */
+    PATHNAME f;
+    string filespec[ 1 ];
+    string filename[ 1 ];
+    struct _finddata_t finfo[ 1 ];
+    LIST * files = L0;
+    int d_length;
+
+    assert( d );
+    assert( d->is_dir );
+    assert( list_empty( d->files ) );
+
+    d_length = strlen( object_str( d->name ) );
+
+    memset( (char *)&f, '\0', sizeof( f ) );
+    f.f_dir.ptr = object_str( d->name );
+    f.f_dir.len = d_length;
+
+    /* Prepare file search specification for the findfirst() API. */
+    if ( !d_length )
+        string_copy( filespec, ".\\*" );
+    else
+    {
+        /* 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 const trailingChar = object_str( d->name )[ d_length - 1 ] ;
+        string_copy( filespec, object_str( d->name ) );
+        if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
+            string_append( filespec, "\\" );
+        string_append( filespec, "*" );
+    }
 
-    file_info_t * const d = file_query( dir );
-    if ( !d || !d->is_dir )
+    #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
+    if ( findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
     {
-        PROFILE_EXIT( FILE_DIRSCAN );
-        return;
+        string_free( filespec );
+        return -1;
     }
 
-    /* If we do not have the directory's contents information - collect it. */
-    if ( list_empty( d->files ) )
+    string_new( filename );
+    do
     {
-        PATHNAME f;
-        string filespec[ 1 ];
-        string filename[ 1 ];
-        struct _finddata_t finfo[ 1 ];
-        LIST * files = L0;
-        OBJECT * const long_dir = short_path_to_long_path( dir );
-        int const d_length = strlen( object_str( long_dir ) );
-
-        memset( (char *)&f, '\0', sizeof( f ) );
-        f.f_dir.ptr = object_str( long_dir );
-        f.f_dir.len = d_length;
-
-        /* Prepare file search specification for the findfirst() API. */
-        if ( !d_length )
-            string_copy( filespec, ".\\*" );
-        else
+        f.f_base.ptr = finfo->ff_name;
+        f.f_base.len = strlen( finfo->ff_name );
+        string_truncate( filename, 0 );
+        path_build( &f, filename );
+
+        files = list_push_back( files, object_new( filename->value ) );
         {
-            /* 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 const trailingChar = object_str( long_dir )[ d_length - 1 ] ;
-            string_copy( filespec, object_str( long_dir ) );
-            if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
-                string_append( filespec, "\\" );
-            string_append( filespec, "*" );
+            file_info_t * const ff = file_info( filename->value );
+            ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
+            ff->is_dir = !ff->is_file;
+            ff->size = finfo->ff_fsize;
+            ff->time = ( finfo->ff_ftime << 16 ) | finfo->ff_ftime;
         }
-
-        if ( DEBUG_BINDSCAN )
-            printf( "scan directory %s\n", long_dir );
-
-        #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
-        if ( findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
+    }
+    while ( !findnext( finfo ) );
+    #else
+    {
+        long const handle = _findfirst( filespec->value, finfo );
+        if ( handle < 0L )
         {
             string_free( filespec );
-            object_free( long_dir );
-            PROFILE_EXIT( FILE_DIRSCAN );
-            return;
+            return -1;
         }
 
         string_new( filename );
         do
         {
-            f.f_base.ptr = finfo->ff_name;
-            f.f_base.len = strlen( finfo->ff_name );
+            OBJECT * filename_obj;
+
+            f.f_base.ptr = finfo->name;
+            f.f_base.len = strlen( finfo->name );
             string_truncate( filename, 0 );
-            path_build( &f, filename );
+            path_build( &f, filename, 0 );
 
-            files = list_push_back( files, object_new( filename->value ) );
+            filename_obj = object_new( filename->value );
+            path_key__register_long_path( filename_obj );
+            files = list_push_back( files, filename_obj );
             {
-                file_info_t * const ff = file_info( filename->value );
-                ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
+                file_info_t * const ff = file_info( filename_obj );
+                ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
                 ff->is_dir = !ff->is_file;
-                ff->size = finfo->ff_fsize;
-                ff->time = ( finfo->ff_ftime << 16 ) | finfo->ff_ftime;
+                ff->size = finfo->size;
+                ff->time = finfo->time_write;
             }
         }
-        while ( !findnext( finfo ) );
-        #else
-        {
-            long const handle = _findfirst( filespec->value, finfo );
-            if ( handle < 0L )
-            {
-                string_free( filespec );
-                object_free( long_dir );
-                PROFILE_EXIT( FILE_DIRSCAN );
-                return;
-            }
+        while ( !_findnext( handle, finfo ) );
 
-            string_new( filename );
-            do
-            {
-                OBJECT * filename_obj;
+        _findclose( handle );
+    }
+    #endif
+    string_free( filename );
+    string_free( filespec );
 
-                f.f_base.ptr = finfo->name;
-                f.f_base.len = strlen( finfo->name );
-                string_truncate( filename, 0 );
-                path_build( &f, filename, 0 );
-
-                filename_obj = object_new( filename->value );
-                path_key__register_long_path( filename_obj );
-                files = list_push_back( files, filename_obj );
-                {
-                    file_info_t * const ff = file_info( filename_obj );
-                    ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
-                    ff->is_dir = !ff->is_file;
-                    ff->size = finfo->size;
-                    ff->time = finfo->time_write;
-                }
-            }
-            while ( !_findnext( handle, finfo ) );
+    d->files = files;
+    return 0;
+}
 
-            _findclose( handle );
-        }
-        #endif
-        string_free( filename );
-        string_free( filespec );
-        object_free( long_dir );
 
-        d->files = files;
-    }
+/*
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ */
+
+void file_dirscan_( file_info_t * const d, scanback func, void * closure )
+{
+    assert( d );
+    assert( d->is_dir );
 
     /* Special case \ or d:\ : enter it */
     {
-        unsigned long const len = strlen( object_str( d->name ) );
-        if ( len == 1 && object_str( d->name )[ 0 ] == '\\' )
+        char const * const name = object_str( d->name );
+        if ( name[ 0 ] == '\\' && !name[ 1 ] )
         {
             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
         }
-        else if ( len == 3 && object_str( d->name )[ 1 ] == ':' )
+        else if ( name[ 0 ] && name[ 1 ] == ':' && name[ 2 ] && !name[ 3 ] )
         {
             /* We have just entered a 3-letter drive name spelling (with a
              * trailing slash), into the hash table. Now enter its two-letter
@@ -196,90 +186,44 @@
              * There will be no trailing slash in $(p), but there will be one in
              * $(p2). But, that seems rather fragile.
              */
-            char const * const str = object_str( d->name );
-            OBJECT * const dir_no_slash = object_new_range( str, 2 );
+            OBJECT * const dir_no_slash = object_new_range( name, 2 );
             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
             (*func)( closure, dir_no_slash, 1 /* stat()'ed */, d->time );
             object_free( dir_no_slash );
         }
     }
-
-    /* Now enter the directory contents. */
-    {
-        LISTITER iter = list_begin( d->files );
-        LISTITER const end = list_end( d->files );
-        for ( ; iter != end; iter = list_next( iter ) )
-        {
-            file_info_t const * const ff = file_info( list_item( iter ) );
-            (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
-        }
-    }
-
-    PROFILE_EXIT( FILE_DIRSCAN );
-}
-
-
-file_info_t * file_query( OBJECT * filename )
-{
-    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( 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()
+ * file_mkdir() - create a directory
  */
 
-int file_time( OBJECT * filename, time_t * time )
+int file_mkdir( char const * const path )
 {
-    file_info_t const * const ff = file_query( filename );
-    if ( !ff ) return -1;
-    *time = ff->time;
-    return 0;
+    return _mkdir( path );
 }
 
 
-int file_is_file( OBJECT * filename )
-{
-    file_info_t const * const ff = file_query( filename );
-    return ff ? ff->is_file : -1;
-}
-
+/*
+ * file_query_() - query information about a path from the OS
+ */
 
-int file_mkdir( char const * pathname )
+int file_query_( file_info_t * const info )
 {
-    return _mkdir( pathname );
+    /* Note that the POSIX stat() function implementation 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-paced 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.
+     */
+    return file_query_posix_( info );
 }
 
 
@@ -289,7 +233,7 @@
 
 /* Straight from SunOS */
 
-#define ARMAG   "!<arch>\n"
+#define ARMAG  "!<arch>\n"
 #define SARMAG  8
 
 #define ARFMAG  "`\n"
@@ -304,8 +248,8 @@
     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( char const * archive, scanback func, void * closure )
 {
@@ -336,8 +280,6 @@
         long lar_size;
         char * name = 0;
         char * endname;
-        char * c;
-        OBJECT * member;
 
         sscanf( ar_hdr.ar_date, "%ld", &lar_date );
         sscanf( ar_hdr.ar_size, "%ld", &lar_size );
@@ -382,16 +324,20 @@
         *++endname = 0;
 
         /* strip leading directory names, an NT specialty */
-
-        if ( c = strrchr( name, '/' ) )
-            name = c + 1;
-        if ( c = strrchr( name, '\\' ) )
-            name = c + 1;
+        {
+            char * c;
+            if ( c = strrchr( name, '/' ) )
+                name = c + 1;
+            if ( c = strrchr( name, '\\' ) )
+                name = c + 1;
+        }
 
         sprintf( buf, "%s(%.*s)", archive, endname - name, name );
-        member = object_new( buf );
-        (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
-        object_free( member );
+        {
+            OBJECT * const member = object_new( buf );
+            (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+            object_free( member );
+        }
 
         offset += SARHDR + lar_size;
         lseek( fd, offset, 0 );
Modified: trunk/tools/build/v2/engine/filesys.c
==============================================================================
--- trunk/tools/build/v2/engine/filesys.c	(original)
+++ trunk/tools/build/v2/engine/filesys.c	2012-07-11 17:42:51 EDT (Wed, 11 Jul 2012)
@@ -1,3 +1,32 @@
+/*
+ *  Copyright 2001-2004 David Abrahams.
+ *  Copyright 2005 Rene Rivera.
+ *  Distributed under the Boost Software License, Version 1.0.
+ *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+/*
+ * filesys.c - OS independant file system manipulation support
+ *
+ * External routines:
+ *  file_build1()        - construct a path string based on PATHNAME information
+ *  file_dirscan()       - scan a directory for files
+ *  file_done()          - module cleanup called on shutdown
+ *  file_info()          - return cached information about a path
+ *  file_is_file()       - return whether a name identifies an existing file
+ *  file_query()         - get cached information about a path, query the OS if
+ *                         needed
+ *  file_remove_atexit() - schedule a path to be removed on program exit
+ *  file_time()          - get a file timestamp
+ *
+ * External routines - utilites for OS specific module implementations:
+ *  file_query_posix_()  - query information about a path using POSIX stat()
+ *
+ * Internal routines:
+ *  file_dirscan_impl()  - no-profiling worker for file_dirscan()
+ */
+
+
 #include "jam.h"
 #include "filesys.h"
 
@@ -6,6 +35,29 @@
 #include "pathsys.h"
 #include "strings.h"
 
+#include <assert.h>
+#include <sys/stat.h>
+
+
+/* Internal OS specific implementation details - have names ending with an
+ * underscore and are expected to be implemented in an OS specific fileXXX.c
+ * module.
+ */
+void file_dirscan_( file_info_t * const dir, scanback func, void * closure );
+int file_collect_dir_content_( file_info_t * const dir );
+int file_query_( file_info_t * const info );
+
+static void file_dirscan_impl( OBJECT * dir, scanback func, void * closure );
+static void free_file_info( void * xfile, void * data );
+static void remove_files_atexit( void );
+
+
+static struct hash * filecache_hash;
+
+
+/*
+ * file_build1() - construct a path string based on PATHNAME information
+ */
 
 void file_build1( PATHNAME * f, string * file )
 {
@@ -36,7 +88,40 @@
 }
 
 
-static struct hash * filecache_hash = 0;
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
+{
+    PROFILE_ENTER( FILE_DIRSCAN );
+    file_dirscan_impl( dir, func, closure );
+    PROFILE_EXIT( FILE_DIRSCAN );
+}
+
+
+/*
+ * file_done() - module cleanup called on shutdown
+ */
+
+void file_done()
+{
+    remove_files_atexit();
+    if ( filecache_hash )
+    {
+        hashenumerate( filecache_hash, free_file_info, (void *)0 );
+        hashdone( filecache_hash );
+    }
+}
+
+
+/*
+ * file_info() - return cached information about a path
+ *
+ * Returns a default initialized structure containing only the path's normalized
+ * name in case this is the first time this file system entity has been
+ * referenced.
+ */
 
 file_info_t * file_info( OBJECT * filename )
 {
@@ -64,39 +149,173 @@
 }
 
 
-static LIST * files_to_remove = L0;
+/*
+ * file_is_file() - return whether a name identifies an existing file
+ */
 
-static void remove_files_atexit( void )
+int file_is_file( OBJECT * filename )
 {
-    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;
+    file_info_t const * const ff = file_query( filename );
+    return ff ? ff->is_file : -1;
 }
 
 
-static void free_file_info( void * xfile, void * data )
+/*
+ * file_time() - get a file timestamp
+ */
+
+int file_time( OBJECT * filename, time_t * time )
 {
-    file_info_t * const file = (file_info_t *)xfile;
-    object_free( file->name );
-    list_free( file->files );
+    file_info_t const * const ff = file_query( filename );
+    if ( !ff ) return -1;
+    *time = ff->time;
+    return 0;
 }
 
 
-void file_done()
+/*
+ * file_query() - get cached information about a path, query the OS if needed
+ *
+ * Returns 0 in case querying the OS about the given path fails, e.g. because
+ * the path does not reference an existing file system object.
+ */
+
+file_info_t * file_query( OBJECT * path )
 {
-    remove_files_atexit();
-    if ( filecache_hash )
+    /* FIXME: Add tracking for disappearing files (i.e. those that can not be
+     * detected by stat() even though they had been detected successfully
+     * before) and see how they should be handled in the rest of Boost Jam code.
+     * Possibly allow Jamfiles to specify some files as 'volatile' which would
+     * make Boost Jam avoid caching information about those files and instead
+     * ask the OS about them every time.
+     *
+     * FIXME: Consider returning a clear file_info() result here if
+     * file_query_() fails. Should simplify the caller side error checking and
+     * the caller still can and needs to detect whether the file has not been
+     * successfully detected by the OS, i.e. whether the file_query() call
+     * failed.
+     */
+    file_info_t * const ff = file_info( path );
+    if ( !ff->time )
     {
-        hashenumerate( filecache_hash, free_file_info, (void *)0 );
-        hashdone( filecache_hash );
+        if ( file_query_( ff ) < 0 )
+            return 0;
+
+        /* Set the path's timestamp to 1 in case it is 0 or undetected to avoid
+         * confusion with non-existing paths.
+         */
+        if ( !ff->time ) ff->time = 1;
     }
+    return ff;
 }
 
 
+/*
+ * file_query_posix_() - query information about a path using POSIX stat()
+ *
+ * Fallback file_query_() implementation for OS specific modules.
+ */
+
+int file_query_posix_( file_info_t * const info )
+{
+    struct stat statbuf;
+    char const * const pathstr = object_str( info->name );
+    char const * const pathspec = *pathstr ? pathstr : ".";
+
+    assert( !info->time );
+
+    if ( stat( pathspec, &statbuf ) < 0 )
+        return -1;
+
+    info->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
+    info->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
+    info->size = statbuf.st_size;
+    info->time = statbuf.st_mtime;
+    return 0;
+}
+
+
+/*
+ * file_remove_atexit() - schedule a path to be removed on program exit
+ */
+
+static LIST * files_to_remove = L0;
+
 void file_remove_atexit( OBJECT * const path )
 {
     files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
 }
+
+
+/*
+ * file_dirscan_impl() - no-profiling worker for file_dirscan()
+ */
+
+static void file_dirscan_impl( OBJECT * dir, scanback func, void * closure )
+{
+    file_info_t * const d = file_query( dir );
+    if ( !d || !d->is_dir )
+        return;
+
+    /* Lazy collect the directory content information. */
+    if ( list_empty( d->files ) )
+    {
+        if ( DEBUG_BINDSCAN )
+            printf( "scan directory %s\n", object_str( d->name ) );
+        if ( file_collect_dir_content_( d ) < 0 )
+            return;
+    }
+
+    /* OS specific part of the file_dirscan operation. */
+    file_dirscan_( d, func, closure );
+
+    /* Report the collected directory content. */
+    {
+        LISTITER iter = list_begin( d->files );
+        LISTITER const end = list_end( d->files );
+        for ( ; iter != end; iter = list_next( iter ) )
+        {
+            OBJECT * const filename = list_item( iter );
+            file_info_t const * const ffq = file_query( filename );
+            /* The only way a file_query() call can fail is if its internal OS
+             * file information gathering API (e.g. stat()) failed. If that
+             * happens we should treat the file as if it no longer exists. We
+             * then request the raw cached file_info_t structure for that file
+             * and use the file name from there.
+             */
+            file_info_t const * const ff = ffq ? ffq : file_info( filename );
+            /* Using a file name read from a file_info_t structure allows OS
+             * specific implementations to store some kind of a normalized file
+             * name there. Using such a normalized file name then allows us to
+             * correctly recognize different file paths actually identifying the
+             * same file. For instance, an implementation may:
+             *  - convert all file names internally to lower case on a case
+             *    insensitive file system
+             *  - convert the NTFS paths to their long path variants as that
+             *    file system each file system entity may have a long and a
+             *    short path variant thus allowing for many different path
+             *    strings identifying the same file.
+             */
+            (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
+        }
+    }
+}
+
+
+static void free_file_info( void * xfile, void * data )
+{
+    file_info_t * const file = (file_info_t *)xfile;
+    object_free( file->name );
+    list_free( file->files );
+}
+
+
+static void remove_files_atexit( void )
+{
+    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;
+}
Modified: trunk/tools/build/v2/engine/filesys.h
==============================================================================
--- trunk/tools/build/v2/engine/filesys.h	(original)
+++ trunk/tools/build/v2/engine/filesys.h	2012-07-11 17:42:51 EDT (Wed, 11 Jul 2012)
@@ -23,17 +23,6 @@
 #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( char const * arch, scanback func, void * closure );
-
-int file_time( OBJECT * filename, time_t * time );
-
-void file_build1( PATHNAME * f, string * file ) ;
-int file_is_file( OBJECT * filename );
-int file_mkdir( char const * pathname );
-
 typedef struct file_info_t
 {
     OBJECT * name;
@@ -44,20 +33,22 @@
     LIST * files;
 } file_info_t;
 
+typedef void (*scanback)( void * closure, OBJECT * path, int found, time_t t );
 
-/* Returns a pointer to information about file 'filename', creating it as
- * necessary. If created, the structure will be default initialized.
- */
-file_info_t * file_info( OBJECT * filename );
-
-/* Returns information about a file, queries the OS if needed. Will return 0 if
- * the file does not exist.
- */
-file_info_t * file_query( OBJECT * filename );
 
-void file_done();
-
-/* Marks a path/file to be removed when JAM exits. */
+void file_archscan( char const * arch, scanback func, void * closure );
+void file_build1( PATHNAME * f, string * file ) ;
+void file_dirscan( OBJECT * dir, scanback func, void * closure );
+file_info_t * file_info( OBJECT * path );
+int file_is_file( OBJECT * path );
+int file_mkdir( char const * const path );
+file_info_t * file_query( OBJECT * path );
 void file_remove_atexit( OBJECT * const path );
+int file_time( OBJECT * path, time_t * time );
+
+/* Internal utility worker functions. */
+int file_query_posix_( file_info_t * const info );
+
+void file_done();
 
 #endif
Modified: trunk/tools/build/v2/engine/fileunix.c
==============================================================================
--- trunk/tools/build/v2/engine/fileunix.c	(original)
+++ trunk/tools/build/v2/engine/fileunix.c	2012-07-11 17:42:51 EDT (Wed, 11 Jul 2012)
@@ -15,15 +15,13 @@
  * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
  *
  * External routines:
- *  file_dirscan() - scan a directory for files
- *  file_time() - get timestamp of file, if not done by file_dirscan()
  *  file_archscan() - scan an archive for files
+ *  file_mkdir()    - create a directory
  *
- * 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.
+ * External routines called only via routines in filesys.c:
+ *  file_collect_dir_content_() - collects directory content information
+ *  file_dirscan_()             - OS specific file_dirscan() implementation
+ *  file_query_()               - query information about a path from the OS
  */
 
 #include "jam.h"
@@ -34,8 +32,8 @@
 #include "pathsys.h"
 #include "strings.h"
 
+#include <assert.h>
 #include <stdio.h>
-#include <sys/stat.h>
 
 #if defined( sun ) || defined( __sun ) || defined( linux )
 # include <unistd.h>  /* needed for read and close prototype */
@@ -48,11 +46,6 @@
 # define PORTAR 1
 #endif
 
-#ifdef __EMX__
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
 #if defined( OS_RHAPSODY ) || defined( OS_MACOSX ) || defined( OS_NEXT )
 # include <sys/dir.h>
 # include <unistd.h>  /* need unistd for rhapsody's proper lseek */
@@ -103,136 +96,88 @@
 
 
 /*
- * file_dirscan() - scan a directory for files.
+ * file_collect_dir_content_() - collects directory content information
  */
 
-void file_dirscan( OBJECT * dir, scanback func, void * closure )
+int file_collect_dir_content_( file_info_t * const d )
 {
-    PROFILE_ENTER( FILE_DIRSCAN );
-
-    file_info_t * const d = file_query( dir );
-    if ( !d || !d->is_dir )
-    {
-        PROFILE_EXIT( FILE_DIRSCAN );
-        return;
-    }
+    LIST * files = L0;
+    PATHNAME f;
+    DIR * dd;
+    STRUCT_DIRENT * dirent;
+    string filename[ 1 ];
+    char const * dirstr;
 
-    /* If we do not have the directory's contents information - collect it. */
-    if ( list_empty( d->files ) )
-    {
-        LIST * files = L0;
-        PATHNAME f;
-        DIR * dd;
-        STRUCT_DIRENT * dirent;
-        string filename[ 1 ];
-        char const * dirstr = object_str( dir );
-
-        /* First enter the directory itself. */
-        memset( (char *)&f, '\0', sizeof( f ) );
-        f.f_dir.ptr = dirstr;
-        f.f_dir.len = strlen( dirstr );
+    assert( d );
+    assert( d->is_dir );
+    assert( list_empty( d->files ) );
 
-        if ( !*dirstr ) dirstr = ".";
+    dirstr = object_str( d->name );
 
-        if ( !( dd = opendir( dirstr ) ) )
-        {
-            PROFILE_EXIT( FILE_DIRSCAN );
-            return;
-        }
+    memset( (char *)&f, '\0', sizeof( f ) );
+    f.f_dir.ptr = dirstr;
+    f.f_dir.len = strlen( dirstr );
 
-        if ( DEBUG_BINDSCAN )
-            printf( "scan directory %s\n", dirstr );
+    if ( !*dirstr ) dirstr = ".";
 
-        string_new( filename );
-        while ( ( dirent = readdir( dd ) ) )
-        {
-            OBJECT * filename_obj;
-            f.f_base.ptr = dirent->d_name
-            #ifdef old_sinix
-                - 2  /* Broken structure definition on sinix. */
-            #endif
-                ;
-            f.f_base.len = strlen( f.f_base.ptr );
-
-            string_truncate( filename, 0 );
-            path_build( &f, filename, 0 );
-
-            filename_obj = object_new( filename->value );
-            files = list_push_back( files, filename_obj );
-            file_query( filename_obj );
-        }
-        string_free( filename );
+    if ( !( dd = opendir( dirstr ) ) )
+        return -1;
 
-        closedir( dd );
+    string_new( filename );
+    while ( ( dirent = readdir( dd ) ) )
+    {
+        f.f_base.ptr = dirent->d_name
+        #ifdef old_sinix
+            - 2  /* Broken structure definition on sinix. */
+        #endif
+            ;
+        f.f_base.len = strlen( f.f_base.ptr );
 
-        d->files = files;
+        string_truncate( filename, 0 );
+        path_build( &f, filename, 0 );
+        files = list_push_back( files, object_new( filename->value ) );
     }
+    string_free( filename );
 
-    /* Special case / : enter it */
-    if ( !strcmp( object_str( d->name ), "/" ) )
-        (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+    closedir( dd );
 
-    /* Now enter the directory contents. */
-    {
-        LISTITER iter = list_begin( d->files );
-        LISTITER const end = list_end( d->files );
-        for ( ; iter != end; iter = list_next( iter ) )
-        {
-            file_info_t const * const ff = file_info( list_item( iter ) );
-            (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
-        }
-    }
-
-    PROFILE_EXIT( FILE_DIRSCAN );
+    d->files = files;
+    return 0;
 }
 
 
-file_info_t * file_query( OBJECT * filename )
+/*
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ */
+
+void file_dirscan_( file_info_t * const d, scanback func, void * closure )
 {
-    file_info_t * const ff = file_info( filename );
-    if ( !ff->time )
-    {
-        struct stat statbuf;
+    assert( d );
+    assert( d->is_dir );
 
-        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;
+    /* Special case / : enter it */
+    if ( !strcmp( object_str( d->name ), "/" ) )
+        (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
 }
 
 
 /*
- * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_mkdir() - create a directory
  */
 
-int file_time( OBJECT * filename, time_t * time )
+int file_mkdir( char const * const pathname )
 {
-    file_info_t const * const ff = file_query( filename );
-    if ( !ff ) return -1;
-    *time = ff->time;
-    return 0;
+    return mkdir( pathname, 0766 );
 }
 
 
-int file_is_file( OBJECT * filename )
-{
-    file_info_t const * const ff = file_query( filename );
-    return ff ? ff->is_file : -1;
-}
-
+/*
+ * file_query_() - query information about a path from the OS
+ */
 
-int file_mkdir( char const * pathname )
+int file_query_( file_info_t * const info )
 {
-    return mkdir( pathname, 0766 );
+    return file_query_posix_( info );
 }
 
 
@@ -446,7 +391,7 @@
     int fd;
     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 ||