@@ -3533,20 +3533,20 @@ contains |
| 3533 | 3533 | ! When pattern is non-empty, filter with grep to avoid buffer overflow on large directories |
| 3534 | 3534 | ! Use tr to convert newlines to spaces for easier parsing |
| 3535 | 3535 | ! Filter with grep when pattern exists to limit output size |
| 3536 | + ! No tr needed — execute_and_capture_tabs converts newlines to tabs |
| 3536 | 3537 | if (pattern_len > 0) then |
| 3537 | 3538 | ls_command = 'ls -1aF "' // trim(expanded_dir) // '/" 2>/dev/null | grep -i "^' // & |
| 3538 | | - trim(pattern) // '" | tr ' // "'" // char(92) // 'n' // "' ' '" |
| 3539 | + trim(pattern) // '"' |
| 3539 | 3540 | else |
| 3540 | | - ls_command = 'ls -1aF "' // trim(expanded_dir) // '/" 2>/dev/null | tr ' // & |
| 3541 | | - "'" // char(92) // 'n' // "' ' '" |
| 3541 | + ls_command = 'ls -1aF "' // trim(expanded_dir) // '/" 2>/dev/null' |
| 3542 | 3542 | end if |
| 3543 | 3543 | |
| 3544 | 3544 | ! Debug output |
| 3545 | 3545 | if (debug_enabled) then |
| 3546 | 3546 | end if |
| 3547 | 3547 | |
| 3548 | | - ! Get output from command (allocatable result) |
| 3549 | | - ls_output_alloc = execute_and_capture(ls_command) |
| 3548 | + ! Get output from command — use tab-delimited capture to preserve spaces in filenames |
| 3549 | + ls_output_alloc = execute_and_capture_tabs(ls_command) |
| 3550 | 3550 | |
| 3551 | 3551 | ! Copy to fixed buffer (avoids flang-new issues with allocatable strings) |
| 3552 | 3552 | ls_output = ls_output_alloc(:min(len(ls_output), len(ls_output_alloc))) |
@@ -3554,8 +3554,8 @@ contains |
| 3554 | 3554 | ! Clean up allocatable |
| 3555 | 3555 | if (allocated(ls_output_alloc)) deallocate(ls_output_alloc) |
| 3556 | 3556 | |
| 3557 | | - ! Parse ls output into individual entries |
| 3558 | | - call parse_ls_output(ls_output, entries, num_entries) |
| 3557 | + ! Parse ls output — tab-delimited to preserve spaces in filenames |
| 3558 | + call parse_ls_output(ls_output, entries, num_entries, use_tab_delim=.true.) |
| 3559 | 3559 | |
| 3560 | 3560 | ! Debug output |
| 3561 | 3561 | if (debug_enabled) then |
@@ -3658,12 +3658,19 @@ contains |
| 3658 | 3658 | end function |
| 3659 | 3659 | |
| 3660 | 3660 | ! Parse ls output into individual entries |
| 3661 | | - subroutine parse_ls_output(output, entries, num_entries) |
| 3661 | + subroutine parse_ls_output(output, entries, num_entries, use_tab_delim) |
| 3662 | 3662 | character(len=*), intent(in) :: output |
| 3663 | 3663 | character(len=MAX_LINE_LEN), allocatable, intent(out) :: entries(:) |
| 3664 | 3664 | integer, intent(out) :: num_entries |
| 3665 | + logical, intent(in), optional :: use_tab_delim |
| 3665 | 3666 | |
| 3666 | 3667 | integer :: pos, start, output_len, count_pass |
| 3668 | + logical :: tab_mode |
| 3669 | + character :: delim |
| 3670 | + |
| 3671 | + tab_mode = .false. |
| 3672 | + if (present(use_tab_delim)) tab_mode = use_tab_delim |
| 3673 | + delim = merge(char(9), ' ', tab_mode) |
| 3667 | 3674 | |
| 3668 | 3675 | output_len = len_trim(output) |
| 3669 | 3676 | |
@@ -3671,8 +3678,9 @@ contains |
| 3671 | 3678 | num_entries = 0 |
| 3672 | 3679 | pos = 1 |
| 3673 | 3680 | do while (pos <= output_len) |
| 3674 | | - ! Skip whitespace |
| 3675 | | - do while (pos <= output_len .and. (output(pos:pos) == ' ' .or. output(pos:pos) == char(9))) |
| 3681 | + ! Skip delimiter characters |
| 3682 | + do while (pos <= output_len .and. (output(pos:pos) == delim .or. & |
| 3683 | + (.not. tab_mode .and. output(pos:pos) == char(9)))) |
| 3676 | 3684 | pos = pos + 1 |
| 3677 | 3685 | end do |
| 3678 | 3686 | |
@@ -3680,8 +3688,8 @@ contains |
| 3680 | 3688 | |
| 3681 | 3689 | start = pos |
| 3682 | 3690 | |
| 3683 | | - ! Find end of entry (space-separated, since execute_and_capture converts newlines to spaces) |
| 3684 | | - do while (pos <= output_len .and. output(pos:pos) /= ' ') |
| 3691 | + ! Find end of entry |
| 3692 | + do while (pos <= output_len .and. output(pos:pos) /= delim) |
| 3685 | 3693 | pos = pos + 1 |
| 3686 | 3694 | end do |
| 3687 | 3695 | |
@@ -3700,8 +3708,9 @@ contains |
| 3700 | 3708 | count_pass = 0 |
| 3701 | 3709 | pos = 1 |
| 3702 | 3710 | do while (pos <= output_len .and. count_pass < num_entries) |
| 3703 | | - ! Skip whitespace |
| 3704 | | - do while (pos <= output_len .and. (output(pos:pos) == ' ' .or. output(pos:pos) == char(9))) |
| 3711 | + ! Skip delimiter characters |
| 3712 | + do while (pos <= output_len .and. (output(pos:pos) == delim .or. & |
| 3713 | + (.not. tab_mode .and. output(pos:pos) == char(9)))) |
| 3705 | 3714 | pos = pos + 1 |
| 3706 | 3715 | end do |
| 3707 | 3716 | |
@@ -3710,7 +3719,7 @@ contains |
| 3710 | 3719 | start = pos |
| 3711 | 3720 | |
| 3712 | 3721 | ! Find end of entry |
| 3713 | | - do while (pos <= output_len .and. output(pos:pos) /= ' ') |
| 3722 | + do while (pos <= output_len .and. output(pos:pos) /= delim) |
| 3714 | 3723 | pos = pos + 1 |
| 3715 | 3724 | end do |
| 3716 | 3725 | |