| 86 | */ |
| 87 | |
| 88 | static int canonicWindowsPath( char const * const path, int const path_length, |
| 89 | string * const out ) |
| 90 | { |
| 91 | char const * last_element; |
| 92 | unsigned long saved_size; |
| 93 | char const * p; |
| 94 | int missing_parent; |
| 95 | |
| 96 | /* This is only called via path_key(), which initializes the cache. */ |
| 97 | assert( path_key_cache ); |
| 98 | |
| 99 | if ( !path_length ) |
| 100 | return 1; |
| 101 | |
| 102 | if ( path_length == 1 && path[ 0 ] == '\\' ) |
| 103 | { |
| 104 | string_push_back( out, '\\' ); |
| 105 | return 1; |
| 106 | } |
| 107 | |
| 108 | if ( path[ 1 ] == ':' && |
| 109 | ( path_length == 2 || |
| 110 | ( path_length == 3 && path[ 2 ] == '\\' ) ) ) |
| 111 | { |
| 112 | string_push_back( out, toupper( path[ 0 ] ) ); |
| 113 | string_push_back( out, ':' ); |
| 114 | string_push_back( out, '\\' ); |
| 115 | return 1; |
| 116 | } |
| 117 | |
| 118 | /* Find last '\\'. */ |
| 119 | for ( p = path + path_length - 1; p >= path && *p != '\\'; --p ); |
| 120 | last_element = p + 1; |
| 121 | |
| 122 | /* Special case '\' && 'D:\' - include trailing '\'. */ |
| 123 | if ( p == path || |
| 124 | p == path + 2 && path[ 1 ] == ':' ) |
| 125 | ++p; |
| 126 | |
| 127 | missing_parent = 0; |
| 128 | |
| 129 | if ( p >= path ) |
| 130 | { |
| 131 | char const * const dir = path; |
| 132 | int const dir_length = p - path; |
| 133 | OBJECT * const dir_obj = object_new_range( dir, dir_length ); |
| 134 | int found; |
| 135 | path_key_entry * const result = (path_key_entry *)hash_insert( |
| 136 | path_key_cache, dir_obj, &found ); |
| 137 | if ( !found ) |
| 138 | { |
| 139 | result->path = dir_obj; |
| 140 | if ( canonicWindowsPath( dir, dir_length, out ) ) |
| 141 | result->exists = 1; |
| 142 | else |
| 143 | result->exists = 0; |
| 144 | result->key = object_new( out->value ); |
| 145 | } |
no test coverage detected