@@ -35,6 +35,7 @@ program ferp |
| 35 | integer :: num_exclude_patterns, num_include_patterns | 35 | integer :: num_exclude_patterns, num_include_patterns |
| 36 | logical :: any_match, file_match | 36 | logical :: any_match, file_match |
| 37 | logical :: found_early ! For quiet mode early termination in parallel | 37 | logical :: found_early ! For quiet mode early termination in parallel |
| | 38 | + logical :: has_error ! Track if any errors occurred (for exit code 2) |
| 38 | | 39 | |
| 39 | ! Parse command-line arguments | 40 | ! Parse command-line arguments |
| 40 | call parse_arguments(opts, patterns, files, ierr) | 41 | call parse_arguments(opts, patterns, files, ierr) |
@@ -114,6 +115,7 @@ program ferp |
| 114 | | 115 | |
| 115 | any_match = .false. | 116 | any_match = .false. |
| 116 | found_early = .false. | 117 | found_early = .false. |
| | 118 | + has_error = .false. |
| 117 | | 119 | |
| 118 | ! Process input sources | 120 | ! Process input sources |
| 119 | if (size(files) == 0) then | 121 | if (size(files) == 0) then |
@@ -128,7 +130,7 @@ program ferp |
| 128 | ! Process each file with OpenMP parallelization (release builds) | 130 | ! Process each file with OpenMP parallelization (release builds) |
| 129 | ! Thread-safe: all buffers are now dynamically allocated per-thread | 131 | ! Thread-safe: all buffers are now dynamically allocated per-thread |
| 130 | !$omp parallel do default(shared) private(src, file_match) & | 132 | !$omp parallel do default(shared) private(src, file_match) & |
| 131 | - !$omp& reduction(.or.:any_match) schedule(dynamic) | 133 | + !$omp& reduction(.or.:any_match,has_error) schedule(dynamic) |
| 132 | do i = 1, size(files) | 134 | do i = 1, size(files) |
| 133 | ! Early termination check for quiet mode | 135 | ! Early termination check for quiet mode |
| 134 | if (opts%quiet .and. found_early) cycle | 136 | if (opts%quiet .and. found_early) cycle |
@@ -143,7 +145,14 @@ program ferp |
| 143 | ! This path is rare - usually -r is specified explicitly | 145 | ! This path is rare - usually -r is specified explicitly |
| 144 | cycle | 146 | cycle |
| 145 | case default ! DIR_READ | 147 | case default ! DIR_READ |
| 146 | - ! Will try to read directory as file (usually fails) | 148 | + ! Print error message and skip (like grep) |
| | 149 | + if (.not. opts%no_messages) then |
| | 150 | + !$omp critical(error_output) |
| | 151 | + write(error_unit, '(A)') 'ferp: ' // trim(files(i)) // ': Is a directory' |
| | 152 | + !$omp end critical(error_output) |
| | 153 | + end if |
| | 154 | + has_error = .true. |
| | 155 | + cycle |
| 147 | end select | 156 | end select |
| 148 | end if | 157 | end if |
| 149 | | 158 | |
@@ -178,6 +187,9 @@ program ferp |
| 178 | if (opts%quiet) found_early = .true. | 187 | if (opts%quiet) found_early = .true. |
| 179 | end if | 188 | end if |
| 180 | call src%close() | 189 | call src%close() |
| | 190 | + else |
| | 191 | + ! File open failed - set error flag |
| | 192 | + has_error = .true. |
| 181 | end if | 193 | end if |
| 182 | end do | 194 | end do |
| 183 | !$omp end parallel do | 195 | !$omp end parallel do |
@@ -188,7 +200,10 @@ program ferp |
| 188 | | 200 | |
| 189 | ! Exit with appropriate code | 201 | ! Exit with appropriate code |
| 190 | ! 0 = match found, 1 = no match, 2 = error | 202 | ! 0 = match found, 1 = no match, 2 = error |
| 191 | - if (any_match) then | 203 | + ! Note: grep returns 2 if there's any error, even with matches |
| | 204 | + if (has_error) then |
| | 205 | + call c_exit(2_c_int) |
| | 206 | + else if (any_match) then |
| 192 | call c_exit(0_c_int) | 207 | call c_exit(0_c_int) |
| 193 | else | 208 | else |
| 194 | call c_exit(1_c_int) | 209 | call c_exit(1_c_int) |