fortrangoingonforty/ferp / 3df9d92

Browse files

Store patterns with null terminators for exact length tracking

Append null terminators when storing patterns to preserve their exact
length. This enables correct handling of whitespace-only patterns that
would otherwise be space-padded in Fortran's fixed-length strings.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
3df9d92b5a436d7f916657b5ee3fe0d4fda7d76b
Parents
b43bcce
Tree
132ef5e

1 changed file

StatusFile+-
M src/ferp_cli.f90 57 9
src/ferp_cli.f90modified
@@ -62,7 +62,8 @@ contains
62
       ! After --, everything is a file/pattern argument
62
       ! After --, everything is a file/pattern argument
63
       if (end_of_options) then
63
       if (end_of_options) then
64
         if (.not. has_explicit_pattern .and. size(patterns) == 0) then
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
           has_explicit_pattern = .true.
67
           has_explicit_pattern = .true.
67
         else
68
         else
68
           call append_file(files, trim(arg))
69
           call append_file(files, trim(arg))
@@ -96,7 +97,8 @@ contains
96
       else
97
       else
97
         ! Non-option argument
98
         ! Non-option argument
98
         if (.not. has_explicit_pattern .and. size(patterns) == 0) then
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
           has_explicit_pattern = .true.
102
           has_explicit_pattern = .true.
101
         else
103
         else
102
           call append_file(files, trim(arg))
104
           call append_file(files, trim(arg))
@@ -687,41 +689,87 @@ contains
687
   end subroutine handle_option_argument
689
   end subroutine handle_option_argument
688
 
690
 
689
   subroutine read_patterns_from_file(patterns, filename, ierr)
691
   subroutine read_patterns_from_file(patterns, filename, ierr)
692
+    !> Read patterns from file, preserving exact line lengths (including whitespace-only lines)
690
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
693
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
691
     character(len=*), intent(in) :: filename
694
     character(len=*), intent(in) :: filename
692
     integer, intent(out) :: ierr
695
     integer, intent(out) :: ierr
693
 
696
 
694
-    integer :: unit_num, ios
697
+    integer :: unit_num, ios, line_len
695
     character(len=max_pattern_len) :: line
698
     character(len=max_pattern_len) :: line
699
+    character(len=1) :: ch
696
 
700
 
697
     ierr = 0
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
     if (ios /= 0) then
705
     if (ios /= 0) then
700
       write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory'
706
       write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory'
701
       ierr = 2
707
       ierr = 2
702
       return
708
       return
703
     end if
709
     end if
704
 
710
 
711
+    line_len = 0
712
+    line = ''
713
+
705
     do
714
     do
706
-      read(unit_num, '(A)', iostat=ios) line
715
+      read(unit_num, '(A1)', iostat=ios, advance='no') ch
707
-      if (ios /= 0) exit
716
+      if (ios /= 0) then
708
-      call append_pattern(patterns, trim(line))
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
     end do
742
     end do
710
 
743
 
711
     close(unit_num)
744
     close(unit_num)
712
   end subroutine read_patterns_from_file
745
   end subroutine read_patterns_from_file
713
 
746
 
714
   subroutine append_pattern(patterns, pattern)
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
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
750
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
716
     character(len=*), intent(in) :: pattern
751
     character(len=*), intent(in) :: pattern
717
 
752
 
718
     character(len=max_pattern_len), allocatable :: temp(:)
753
     character(len=max_pattern_len), allocatable :: temp(:)
719
-    integer :: n
754
+    integer :: n, plen
720
 
755
 
721
     n = size(patterns)
756
     n = size(patterns)
722
     allocate(temp(n + 1))
757
     allocate(temp(n + 1))
723
     if (n > 0) temp(1:n) = patterns
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
     call move_alloc(temp, patterns)
773
     call move_alloc(temp, patterns)
726
   end subroutine append_pattern
774
   end subroutine append_pattern
727
 
775