| 254 | #define CASE( c, caseInsensitive ) ( caseInsensitive ? std::tolower( c ) : ( c ) ) |
| 255 | |
| 256 | bool String::globMatch( std::string_view text, std::string_view glob, bool caseInsensitive ) { |
| 257 | size_t i = 0; |
| 258 | size_t j = 0; |
| 259 | size_t n = text.size(); |
| 260 | size_t m = glob.size(); |
| 261 | size_t text1_backup = std::string_view::npos; |
| 262 | size_t glob1_backup = std::string_view::npos; |
| 263 | size_t text2_backup = std::string_view::npos; |
| 264 | size_t glob2_backup = std::string_view::npos; |
| 265 | bool nodot = !DOTGLOB; |
| 266 | // match pathname if glob contains a / otherwise match the basename |
| 267 | if ( j + 1 < m && glob[j] == '/' ) { |
| 268 | // if pathname starts with ./ then ignore these pairs |
| 269 | while ( i + 1 < n && text[i] == '.' && text[i + 1] == PATHSEP ) |
| 270 | i += 2; |
| 271 | // if pathname starts with a / then ignore it |
| 272 | if ( i < n && text[i] == PATHSEP ) |
| 273 | i++; |
| 274 | j++; |
| 275 | } else if ( glob.find( '/' ) == std::string_view::npos ) { |
| 276 | size_t sep = text.rfind( PATHSEP ); |
| 277 | if ( sep != std::string_view::npos ) |
| 278 | i = sep + 1; |
| 279 | } |
| 280 | while ( i < n ) { |
| 281 | if ( j < m ) { |
| 282 | switch ( glob[j] ) { |
| 283 | case '*': |
| 284 | // match anything except . after / |
| 285 | if ( nodot && text[i] == '.' ) |
| 286 | break; |
| 287 | if ( ++j < m && glob[j] == '*' ) { |
| 288 | // trailing ** match everything after / |
| 289 | if ( ++j >= m ) |
| 290 | return true; |
| 291 | // ** followed by a / match zero or more directories |
| 292 | if ( glob[j] != '/' ) |
| 293 | return false; |
| 294 | // new **-loop, discard *-loop |
| 295 | text1_backup = std::string_view::npos; |
| 296 | glob1_backup = std::string_view::npos; |
| 297 | text2_backup = i; |
| 298 | glob2_backup = ++j; |
| 299 | continue; |
| 300 | } |
| 301 | // trailing * matches everything except / |
| 302 | text1_backup = i; |
| 303 | glob1_backup = j; |
| 304 | continue; |
| 305 | case '?': |
| 306 | // match anything except . after / |
| 307 | if ( nodot && text[i] == '.' ) |
| 308 | break; |
| 309 | // match any character except / |
| 310 | if ( text[i] == PATHSEP ) |
| 311 | break; |
| 312 | i++; |
| 313 | j++; |