@@ -62,7 +62,8 @@ contains |
| 62 | 62 | ! After --, everything is a file/pattern argument |
| 63 | 63 | if (end_of_options) then |
| 64 | 64 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then |
| 65 | | - call append_pattern(patterns, trim(arg)) |
| 65 | + ! Use exact length from get_command_argument to preserve whitespace patterns |
| 66 | + call append_pattern(patterns, arg(1:arg_len)) |
| 66 | 67 | has_explicit_pattern = .true. |
| 67 | 68 | else |
| 68 | 69 | call append_file(files, trim(arg)) |
@@ -96,7 +97,8 @@ contains |
| 96 | 97 | else |
| 97 | 98 | ! Non-option argument |
| 98 | 99 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then |
| 99 | | - call append_pattern(patterns, trim(arg)) |
| 100 | + ! Use exact length from get_command_argument to preserve whitespace patterns |
| 101 | + call append_pattern(patterns, arg(1:arg_len)) |
| 100 | 102 | has_explicit_pattern = .true. |
| 101 | 103 | else |
| 102 | 104 | call append_file(files, trim(arg)) |
@@ -687,41 +689,87 @@ contains |
| 687 | 689 | end subroutine handle_option_argument |
| 688 | 690 | |
| 689 | 691 | subroutine read_patterns_from_file(patterns, filename, ierr) |
| 692 | + !> Read patterns from file, preserving exact line lengths (including whitespace-only lines) |
| 690 | 693 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) |
| 691 | 694 | character(len=*), intent(in) :: filename |
| 692 | 695 | integer, intent(out) :: ierr |
| 693 | 696 | |
| 694 | | - integer :: unit_num, ios |
| 697 | + integer :: unit_num, ios, line_len |
| 695 | 698 | character(len=max_pattern_len) :: line |
| 699 | + character(len=1) :: ch |
| 696 | 700 | |
| 697 | 701 | ierr = 0 |
| 698 | | - open(newunit=unit_num, file=filename, status='old', action='read', iostat=ios) |
| 702 | + ! Use stream access to read exact line lengths (preserving whitespace patterns) |
| 703 | + open(newunit=unit_num, file=filename, status='old', action='read', & |
| 704 | + access='stream', form='formatted', iostat=ios) |
| 699 | 705 | if (ios /= 0) then |
| 700 | 706 | write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory' |
| 701 | 707 | ierr = 2 |
| 702 | 708 | return |
| 703 | 709 | end if |
| 704 | 710 | |
| 711 | + line_len = 0 |
| 712 | + line = '' |
| 713 | + |
| 705 | 714 | do |
| 706 | | - read(unit_num, '(A)', iostat=ios) line |
| 707 | | - if (ios /= 0) exit |
| 708 | | - call append_pattern(patterns, trim(line)) |
| 715 | + read(unit_num, '(A1)', iostat=ios, advance='no') ch |
| 716 | + if (ios /= 0) then |
| 717 | + ! EOF or error - save current line if non-empty |
| 718 | + if (line_len > 0) then |
| 719 | + call append_pattern(patterns, line(1:line_len)) |
| 720 | + end if |
| 721 | + exit |
| 722 | + end if |
| 723 | + |
| 724 | + if (ch == char(10)) then |
| 725 | + ! Newline - save pattern with exact length (even if zero for empty lines) |
| 726 | + if (line_len > 0) then |
| 727 | + call append_pattern(patterns, line(1:line_len)) |
| 728 | + else |
| 729 | + ! Empty line - skip (grep ignores empty pattern lines) |
| 730 | + end if |
| 731 | + line_len = 0 |
| 732 | + line = '' |
| 733 | + else if (ch == char(13)) then |
| 734 | + ! Carriage return - ignore (handle Windows line endings) |
| 735 | + else |
| 736 | + ! Regular character - add to line |
| 737 | + if (line_len < max_pattern_len) then |
| 738 | + line_len = line_len + 1 |
| 739 | + line(line_len:line_len) = ch |
| 740 | + end if |
| 741 | + end if |
| 709 | 742 | end do |
| 710 | 743 | |
| 711 | 744 | close(unit_num) |
| 712 | 745 | end subroutine read_patterns_from_file |
| 713 | 746 | |
| 714 | 747 | subroutine append_pattern(patterns, pattern) |
| 748 | + !> Append a pattern to the patterns array, preserving its exact length |
| 749 | + !> Uses null terminator to mark the true end of the pattern |
| 715 | 750 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) |
| 716 | 751 | character(len=*), intent(in) :: pattern |
| 717 | 752 | |
| 718 | 753 | character(len=max_pattern_len), allocatable :: temp(:) |
| 719 | | - integer :: n |
| 754 | + integer :: n, plen |
| 720 | 755 | |
| 721 | 756 | n = size(patterns) |
| 722 | 757 | allocate(temp(n + 1)) |
| 723 | 758 | if (n > 0) temp(1:n) = patterns |
| 724 | | - temp(n + 1) = pattern |
| 759 | + |
| 760 | + ! Store pattern with null terminator to preserve exact length |
| 761 | + plen = len(pattern) |
| 762 | + if (plen > 0 .and. plen < max_pattern_len) then |
| 763 | + temp(n + 1) = pattern |
| 764 | + temp(n + 1)(plen + 1:plen + 1) = char(0) ! Null terminator |
| 765 | + else if (plen == 0) then |
| 766 | + ! Empty pattern - store just null terminator |
| 767 | + temp(n + 1) = char(0) |
| 768 | + else |
| 769 | + ! Pattern too long - truncate |
| 770 | + temp(n + 1) = pattern(1:max_pattern_len) |
| 771 | + end if |
| 772 | + |
| 725 | 773 | call move_alloc(temp, patterns) |
| 726 | 774 | end subroutine append_pattern |
| 727 | 775 | |