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