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
6262
       ! After --, everything is a file/pattern argument
6363
       if (end_of_options) then
6464
         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))
6667
           has_explicit_pattern = .true.
6768
         else
6869
           call append_file(files, trim(arg))
@@ -96,7 +97,8 @@ contains
9697
       else
9798
         ! Non-option argument
9899
         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))
100102
           has_explicit_pattern = .true.
101103
         else
102104
           call append_file(files, trim(arg))
@@ -687,41 +689,87 @@ contains
687689
   end subroutine handle_option_argument
688690
 
689691
   subroutine read_patterns_from_file(patterns, filename, ierr)
692
+    !> Read patterns from file, preserving exact line lengths (including whitespace-only lines)
690693
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
691694
     character(len=*), intent(in) :: filename
692695
     integer, intent(out) :: ierr
693696
 
694
-    integer :: unit_num, ios
697
+    integer :: unit_num, ios, line_len
695698
     character(len=max_pattern_len) :: line
699
+    character(len=1) :: ch
696700
 
697701
     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)
699705
     if (ios /= 0) then
700706
       write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory'
701707
       ierr = 2
702708
       return
703709
     end if
704710
 
711
+    line_len = 0
712
+    line = ''
713
+
705714
     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
709742
     end do
710743
 
711744
     close(unit_num)
712745
   end subroutine read_patterns_from_file
713746
 
714747
   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
715750
     character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:)
716751
     character(len=*), intent(in) :: pattern
717752
 
718753
     character(len=max_pattern_len), allocatable :: temp(:)
719
-    integer :: n
754
+    integer :: n, plen
720755
 
721756
     n = size(patterns)
722757
     allocate(temp(n + 1))
723758
     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
+
725773
     call move_alloc(temp, patterns)
726774
   end subroutine append_pattern
727775