diff options
Diffstat (limited to 'tools/build/v2/engine/pathunix.c')
-rw-r--r-- | tools/build/v2/engine/pathunix.c | 338 |
1 files changed, 234 insertions, 104 deletions
diff --git a/tools/build/v2/engine/pathunix.c b/tools/build/v2/engine/pathunix.c index 2daad14b72..a8428df8d6 100644 --- a/tools/build/v2/engine/pathunix.c +++ b/tools/build/v2/engine/pathunix.c @@ -14,10 +14,11 @@ # include "jam.h" # include "pathsys.h" # include "strings.h" -# include "newstr.h" +# include "object.h" # include "filesys.h" # include <time.h> # include <stdlib.h> +# include <assert.h> # ifndef OS_NT # include <unistd.h> # endif @@ -56,11 +57,11 @@ * path_parse() - split a file name into dir/base/suffix/member */ -void path_parse( char * file, PATHNAME * f ) +void path_parse( const char * file, PATHNAME * f ) { - char * p; - char * q; - char * end; + const char * p; + const char * q; + const char * end; memset( (char *)f, 0, sizeof( *f ) ); @@ -273,124 +274,250 @@ path_parent( PATHNAME *f ) #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; + const char * new_element; + unsigned long saved_size; + char * p; + + if ( short_path[0] == '\0' ) + { + return; + } + + 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' ) ) ) + { + 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; + + /* special case \ */ + if ( p == short_path ) + ++p; + + /* special case D:\ */ + if ( p == short_path + 2 && short_path[1] == ':' ) + ++p; + + saved = *p; + *p = '\0'; + path_write_key( short_path, 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' ) ) + { + WIN32_FIND_DATA fd; + HANDLE hf = 0; + hf = FindFirstFile( out->value, &fd ); + + /* If the file exists, replace the name. */ + if ( hf != INVALID_HANDLE_VALUE ) + { + string_truncate( out, saved_size ); + string_append( out, fd.cFileName ); + FindClose( hf ); + } } +} - /* Is the path valid? */ - if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES) - return 0; +OBJECT * short_path_to_long_path( OBJECT * short_path ) +{ + return path_as_key( short_path ); +} - /* Convert "/" to "\" */ - for (i=0;i<len;++i) { - if (lpszShortPath[i]==_T('/')) - path[i]=_T('\\'); +struct path_key_entry +{ + OBJECT * path; + OBJECT * key; +}; + +static struct hash * path_key_cache; + +static void path_write_key( char * path_, string * out ) +{ + struct path_key_entry * result; + OBJECT * path = object_new( path_ ); + int found; + + /* This is only called by path_as_key, which initializes the cache. */ + assert( path_key_cache ); + + result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found ); + if ( !found ) + { + /* path_ is already normalized. */ + result->path = path; + 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 - path[i]=lpszShortPath[i]; + *s = tolower( *s ); + } + /* Strip trailing "/" */ + if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' ) + { + string_pop_back( path ); } +} - /* 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; +void path_add_key( OBJECT * path ) +{ + struct path_key_entry * result; + int found; + + if ( ! path_key_cache ) + path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" ); + + result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found ); + if ( !found ) + { + string buf[1]; + OBJECT * normalized; + struct 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 ); + if ( !found || nresult == result ) + { + nresult->path = object_copy( normalized ); + nresult->key = object_copy( path ); } - _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; + object_free( normalized ); + if ( nresult != result ) + { + result->path = object_copy( path ); + result->key = object_copy( nresult->key ); } - _tcsncpy(ret,path,2); } +} + +OBJECT * path_as_key( OBJECT * path ) +{ + struct path_key_entry * result; + int found; + + if ( ! path_key_cache ) + path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" ); - /* 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); - } - - path[pos]=c; - - prev_pos = pos; + result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found ); + if ( !found ) + { + string buf[1]; + OBJECT * normalized; + struct 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 ); + if ( !found || nresult == result ) + { + string long_path[1]; + nresult->path = normalized; + 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 ); } + string_free( buf ); + object_free( normalized ); + if ( nresult != result ) + { + result->path = object_copy( path ); + result->key = object_copy( nresult->key ); + } + } + + return object_copy( result->key ); +} + +static void free_path_key_entry( void * xentry, void * data ) +{ + struct path_key_entry * entry = (struct path_key_entry *)xentry; + object_free( entry->path ); + object_free( entry->key ); +} + +void path_done( void ) +{ + if ( path_key_cache ) + { + hashenumerate( path_key_cache, &free_path_key_entry, (void *)0 ); + hashdone( path_key_cache ); } +} - len=_tcslen(ret)+1; - if (cchBuffer>=len) - _tcscpy(lpszLongPath,ret); +#else - return len; +void path_add_key( OBJECT * path ) +{ } -char* short_path_to_long_path(char* short_path) +OBJECT * path_as_key( OBJECT * path ) { - char buffer2[_MAX_PATH]; - int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH); + return object_copy( path ); +} - if (ret) - return newstr(buffer2); - else - return newstr(short_path); +void path_done( void ) +{ } #endif @@ -424,7 +551,7 @@ const char * path_tmpdir() return path_tmpdir_result; } -const char * path_tmpnam(void) +OBJECT * path_tmpnam(void) { char name_buffer[64]; # ifdef OS_NT @@ -436,18 +563,21 @@ const char * path_tmpnam(void) if (0 == c1) c1 = time(0)&0xffff; c1 += 1; sprintf(name_buffer,"jam%lx%lx.000",c0,c1); - return newstr(name_buffer); + return object_new(name_buffer); } -const char * path_tmpfile(void) +OBJECT * path_tmpfile(void) { - const char * result = 0; + OBJECT * result = 0; + OBJECT * tmpnam; string file_path; string_copy(&file_path,path_tmpdir()); string_push_back(&file_path,PATH_DELIM); - string_append(&file_path,path_tmpnam()); - result = newstr(file_path.value); + tmpnam = path_tmpnam(); + string_append(&file_path,object_str(tmpnam)); + object_free(tmpnam); + result = object_new(file_path.value); string_free(&file_path); return result; |