$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r75808 - trunk/tools/build/v2/engine
From: steven_at_[hidden]
Date: 2011-12-04 21:12:57
Author: steven_watanabe
Date: 2011-12-04 21:12:55 EST (Sun, 04 Dec 2011)
New Revision: 75808
URL: http://svn.boost.org/trac/boost/changeset/75808
Log:
Convert short paths to long paths on NT.
Text files modified: 
   trunk/tools/build/v2/engine/filent.c   |     1                                         
   trunk/tools/build/v2/engine/pathsys.h  |     1                                         
   trunk/tools/build/v2/engine/pathunix.c |   270 +++++++++++++++++++++++---------------- 
   3 files changed, 160 insertions(+), 112 deletions(-)
Modified: trunk/tools/build/v2/engine/filent.c
==============================================================================
--- trunk/tools/build/v2/engine/filent.c	(original)
+++ trunk/tools/build/v2/engine/filent.c	2011-12-04 21:12:55 EST (Sun, 04 Dec 2011)
@@ -169,6 +169,7 @@
             path_build( &f, filename, 0 );
 
             filename_obj = object_new( filename->value );
+            path_add_key( filename_obj );
             files = list_new( files, filename_obj );
             ff = file_info( filename_obj );
             ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
Modified: trunk/tools/build/v2/engine/pathsys.h
==============================================================================
--- trunk/tools/build/v2/engine/pathsys.h	(original)
+++ trunk/tools/build/v2/engine/pathsys.h	2011-12-04 21:12:55 EST (Sun, 04 Dec 2011)
@@ -65,6 +65,7 @@
     same key.
  */
 OBJECT * path_as_key( OBJECT * path );
+void path_add_key( OBJECT * path );
 
 #ifdef USE_PATHUNIX
 /** Returns a static pointer to the system dependent path to the temporary
Modified: trunk/tools/build/v2/engine/pathunix.c
==============================================================================
--- trunk/tools/build/v2/engine/pathunix.c	(original)
+++ trunk/tools/build/v2/engine/pathunix.c	2011-12-04 21:12:55 EST (Sun, 04 Dec 2011)
@@ -18,6 +18,7 @@
 # include "filesys.h"
 # include <time.h>
 # include <stdlib.h>
+# include <assert.h>
 # ifndef OS_NT
 # include <unistd.h>
 # endif
@@ -273,131 +274,90 @@
 
 #ifdef NT
 #include <windows.h>
-#include <tchar.h>
 
 /* The definition of this in winnt.h is not ANSI-C compatible. */
 #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 );
 
-DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
-                          cchBuffer)
+void ShortPathToLongPath( char * short_path, string * out )
 {
-    LONG i=0;
-    TCHAR path[_MAX_PATH]={0};
-    TCHAR ret[_MAX_PATH]={0};
-    LONG pos=0, prev_pos=0;
-    LONG len=_tcslen(lpszShortPath);
-
-    /* Is the string valid? */
-    if (!lpszShortPath) {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    /* Is the path valid? */
-    if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
-        return 0;
-
-    /* Convert "/" to "\" */
-    for (i=0;i<len;++i) {
-        if (lpszShortPath[i]==_T('/'))
-            path[i]=_T('\\');
-        else
-            path[i]=lpszShortPath[i];
+    const char * new_element;
+    unsigned long saved_size;
+    char * p;
+
+    if ( short_path[0] == '\0' )
+    {
+        return;
     }
 
-    /* UNC path? */
-    if (path[0]==_T('\\') && path[1]==_T('\\')) {
-        pos=2;
-        for (i=0;i<2;++i) {
-            while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
-                ++pos;
-            ++pos;
-        }
-        _tcsncpy(ret,path,pos-1);
-    } /* Drive letter? */
-    else if (path[1]==_T(':')) {
-        if (path[2]==_T('\\'))
-            pos=3;
-        if (len==3) {
-            if (cchBuffer>3)
-                _tcscpy(lpszLongPath,lpszShortPath);
-            return len;
-        }
-        _tcsncpy(ret,path,2);
-        ret[0] = toupper(ret[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, ':' );
+        string_push_back( out, '\\' );
+        return;
     }
+    
+    /* '/' already handled. */
+    if ( ( p = strrchr( short_path, '\\' ) ) )
+    {
+        char saved;
+        new_element = p + 1;
 
-    /* Expand the path for each subpath, and strip trailing backslashes */
-    for (prev_pos = pos-1;pos<=len;++pos) {
-        if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
-                                    path[pos-1]!=_T('\\'))) {
-            WIN32_FIND_DATA fd;
-            HANDLE hf=0;
-            TCHAR c=path[pos];
-            char* new_element;
-            path[pos]=_T('\0');
-
-            /* the path[prev_pos+1]... path[pos] range is the part of
-               path we're handling right now. We need to find long
-               name for that element and add it. */
-            new_element = path + prev_pos + 1;
-
-            /* First add separator, but only if there's something in result already. */
-            if (ret[0] != _T('\0'))
-            {
-                _tcscat(ret,_T("\\"));
-            }
-
-            /* If it's ".." element, we need to append it, not
-               the name in parent that FindFirstFile will return.
-               Same goes for "." */
-
-            if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
-                new_element[0] == _T('.') && new_element[1] == _T('.')
-                && new_element[2] == _T('\0'))
-            {
-                _tcscat(ret, new_element);
-            }
-            else
-            {
-                hf=FindFirstFile(path, &fd);
-                if (hf==INVALID_HANDLE_VALUE)
-                    return 0;
-
-                _tcscat(ret,fd.cFileName);
-                FindClose(hf);
-            }
+        /* special case \ */
+        if ( p == short_path )
+            ++p;
+        
+        /* special case D:\ */
+        if ( p == short_path + 2  && short_path[1] == ':' )
+            ++p;
 
-            path[pos]=c;
+        saved = *p;
+        *p = '\0';
+        path_write_key( short_path, out );
+        *p = saved;
+    }
+    else
+    {
+        new_element = short_path;
+    }
 
-            prev_pos = pos;
-        }
+    if ( out->size && out->value[ out->size - 1 ] != '\\' )
+    {
+        string_push_back( out, '\\' );
     }
+    
+    saved_size = out->size;
+    string_append( out, new_element );
 
-    len=_tcslen(ret)+1;
-    if (cchBuffer>=len)
-        _tcscpy(lpszLongPath,ret);
+    if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
+        new_element[0] == '.' && new_element[1] == '.'
+        && new_element[2] == '\0' ) )
+    {
+        WIN32_FIND_DATA fd;
+        HANDLE hf = 0;
+        hf = FindFirstFile( out->value, &fd );
 
-    return len;
+        /* If the file exists, replace the name. */
+        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 )
 {
-    char buffer2[_MAX_PATH];
-    int ret = ShortPathToLongPath( object_str( short_path ), buffer2, _MAX_PATH );
-
-    if (ret)
-        return object_new( buffer2 );
-    else
-        return object_copy( short_path );
+    return path_as_key( short_path );
 }
 
-#endif
-
-#ifdef NT
-
 struct path_key_entry
 {
     OBJECT * path;
@@ -406,6 +366,78 @@
 
 static struct hash * path_key_cache;
 
+static void path_write_key( char * path_, string * out )
+{
+    struct path_key_entry e, *result = &e;
+    OBJECT * path = object_new( path_ );
+
+    /* This is only called by path_as_key, which initializes the cache. */
+    assert( path_key_cache );
+
+    result->path = path;
+    if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
+    {
+        /* path_ is already normalized. */
+        ShortPathToLongPath( path_, out );
+        result->key = object_new( out->value );
+    }
+    else
+    {
+        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 ] == '\\' )
+    {
+        string_pop_back( path );
+    }
+}
+
+void path_add_key( OBJECT * path )
+{
+    struct path_key_entry e, *result = &e;
+
+    if ( ! path_key_cache )
+        path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
+
+    result->path = path;
+    if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
+    {
+        string buf[1];
+        OBJECT * normalized;
+        struct path_key_entry ne, *nresult = ≠
+        string_copy( buf, object_str( path ) );
+        normalize_path( buf );
+        normalized = object_new( buf->value );
+        string_free( buf );
+        nresult->path = normalized;
+        if ( hashenter( path_key_cache, (HASHDATA * *)&nresult ) || nresult == result )
+        {
+            nresult->path = object_copy( normalized );
+            nresult->key = object_copy( path );
+        }
+        object_free( normalized );
+        if ( nresult != result )
+        {
+            result->path = object_copy( path );
+            result->key = object_copy( nresult->key );
+        }
+    }
+}
+
 OBJECT * path_as_key( OBJECT * path )
 {
     struct path_key_entry e, *result = &e;
@@ -417,21 +449,31 @@
     if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
     {
         string buf[1];
-        char * s;
+        OBJECT * normalized;
+        struct path_key_entry ne, *nresult = ≠
         string_copy( buf, object_str( path ) );
-        for ( s = buf->value; s < buf->value + buf->size; ++s )
+        normalize_path( buf );
+        normalized = object_new( buf->value );
+        nresult->path = normalized;
+        if ( hashenter( path_key_cache, (HASHDATA * *)&nresult ) || nresult == result )
         {
-            if ( *s == '/' )
-                *s = '\\';
-            else
-                *s = tolower( *s );
+            string long_path[1];
+            string_new( long_path );
+            ShortPathToLongPath( buf->value, long_path );
+            nresult->path = object_copy( normalized );
+            nresult->key = object_new( long_path->value );
+            string_free( long_path );
         }
-        result->path = object_copy( path );
-        result->key = object_new( buf->value );
         string_free( buf );
+        object_free( normalized );
+        if ( nresult != result )
+        {
+            result->path = object_copy( path );
+            result->key = object_copy( nresult->key );
+        }
     }
 
-    return result->key;
+    return object_copy( result->key );
 }
 
 static void free_path_key_entry( void * xentry, void * data )
@@ -452,6 +494,10 @@
 
 #else
 
+void path_add_key( OBJECT * path )
+{
+}
+
 OBJECT * path_as_key( OBJECT * path )
 {
     return object_copy( path );