31
31
32
32
class Dir
33
33
module Glob
34
- no_meta_chars = '[^*?\\[\\]{}\\\\]'
34
+ no_meta_chars = /[^*?\[ \] {}\\ ]/
35
+ no_meta_chars_unescaped = /(?:#{ no_meta_chars } |\\ \\ |\\ \* |\\ \? |\\ \[ |\\ \] |\\ \{ |\\ \} )/
35
36
NO_GLOB_META_CHARS = /\A #{ no_meta_chars } +\z /
36
- TRAILING_BRACES = /\A (#{ no_meta_chars } +)(?:\{ (#{ no_meta_chars } *)\} )?\z /
37
+ NO_GLOB_META_CHARS_UNESCAPED = /\A #{ no_meta_chars_unescaped } +\z /
38
+ TRAILING_BRACES = /\A (#{ no_meta_chars_unescaped } +)(?:\{ (#{ no_meta_chars_unescaped } *)\} )?\z /
37
39
38
40
class Node
39
41
def initialize ( nxt , flags )
40
- @flags = flags
42
+ @flags = flags | File :: FNM_EXTGLOB
41
43
@next = nxt
42
44
@separator = nil
43
45
end
@@ -349,6 +351,10 @@ def process_entry(entry, entry_type, matches, parent, glob_base_dir)
349
351
end
350
352
end
351
353
354
+ def self . unescape ( pattern )
355
+ pattern . gsub ( /\\ (.)/ , '\\1' )
356
+ end
357
+
352
358
def self . path_split ( str )
353
359
start = 0
354
360
ret = [ ]
@@ -383,7 +389,10 @@ def self.path_split(str)
383
389
end
384
390
385
391
def self . single_compile ( glob , flags = 0 )
386
- if glob . getbyte ( -1 ) != 47 && NO_GLOB_META_CHARS . match? ( glob ) # byte value 47 = ?/
392
+ escape = ( flags & File ::FNM_NOESCAPE ) == 0
393
+ if escape && glob . getbyte ( -1 ) != 47 && NO_GLOB_META_CHARS_UNESCAPED . match? ( glob ) # byte value 47 = ?/
394
+ return ConstantEntry . new nil , flags , unescape ( glob )
395
+ elsif !escape && glob . getbyte ( -1 ) != 47 && NO_GLOB_META_CHARS . match? ( glob ) # byte value 47 = ?/
387
396
return ConstantEntry . new nil , flags , glob
388
397
end
389
398
@@ -393,8 +402,10 @@ def self.single_compile(glob, flags=0)
393
402
last = DirectoriesOnly . new nil , flags
394
403
else
395
404
file = parts . pop
396
- if NO_GLOB_META_CHARS . match? ( file )
405
+ if ! escape && NO_GLOB_META_CHARS . match? ( file )
397
406
last = ConstantEntry . new nil , flags , file
407
+ elsif escape && NO_GLOB_META_CHARS_UNESCAPED . match? ( file )
408
+ last = ConstantEntry . new nil , flags , unescape ( file )
398
409
elsif file == '*'
399
410
last = AllNameEntryMatch . new nil , flags , file
400
411
elsif file && file [ 0 ] == '*' && NO_GLOB_META_CHARS . match? ( file [ 1 ..] )
@@ -414,14 +425,25 @@ def self.single_compile(glob, flags=0)
414
425
else
415
426
last = RecursiveDirectories . new last , flags
416
427
end
417
- elsif NO_GLOB_META_CHARS . match? ( dir )
428
+ elsif ! escape && NO_GLOB_META_CHARS . match? ( dir )
418
429
while NO_GLOB_META_CHARS . match? ( parts [ -2 ] )
419
430
next_sep = parts . pop
420
431
next_sect = parts . pop
421
432
422
433
dir = next_sect << next_sep << dir
423
434
end
424
435
436
+ last = ConstantDirectory . new last , flags , dir
437
+ elsif escape && NO_GLOB_META_CHARS_UNESCAPED . match? ( dir )
438
+
439
+ dir = unescape ( dir )
440
+ while NO_GLOB_META_CHARS_UNESCAPED . match? ( parts [ -2 ] )
441
+ next_sep = parts . pop
442
+ next_sect = unescape ( parts . pop )
443
+
444
+ dir = next_sect << next_sep << dir
445
+ end
446
+
425
447
last = ConstantDirectory . new last , flags , dir
426
448
elsif !dir . empty?
427
449
last = DirectoryMatch . new last , flags , dir
@@ -466,9 +488,10 @@ def self.glob(base_dir, pattern, flags, matches)
466
488
# only as a suffix.
467
489
468
490
if braces = m [ 2 ]
469
- stem = m [ 1 ]
491
+ stem = unescape ( m [ 1 ] )
470
492
471
493
braces . split ( ',' ) . each do |s |
494
+ s = unescape ( s )
472
495
path = "#{ stem } #{ s } "
473
496
if Truffle ::FileOperations . exist? path_join ( base_dir , path )
474
497
matches << path
@@ -480,6 +503,7 @@ def self.glob(base_dir, pattern, flags, matches)
480
503
matches << stem if Truffle ::FileOperations . exist? path_join ( base_dir , stem )
481
504
end
482
505
else
506
+ pattern = unescape ( pattern )
483
507
matches << pattern if Truffle ::FileOperations . exist? ( path_join ( base_dir , pattern ) )
484
508
end
485
509
0 commit comments