Skip to content

Commit 5c908fc

Browse files
authored
Expand tabs in source file parsing (#521)
1 parent 04da9a1 commit 5c908fc

File tree

3 files changed

+136
-6
lines changed

3 files changed

+136
-6
lines changed

src/fpm_filesystem.F90

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ module fpm_filesystem
66
OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, &
77
OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD
88
use fpm_environment, only: separator, get_env
9-
use fpm_strings, only: f_string, replace, string_t, split
9+
use fpm_strings, only: f_string, replace, string_t, split, notabs
1010
use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer
1111
use fpm_error, only : fpm_stop
1212
implicit none
1313
private
14-
public :: basename, canon_path, dirname, is_dir, join_path, number_of_rows, read_lines, list_files, env_variable, &
14+
public :: basename, canon_path, dirname, is_dir, join_path, number_of_rows, list_files, env_variable, &
1515
mkdir, exists, get_temp_filename, windows_path, unix_path, getline, delete_file
1616
public :: fileopen, fileclose, filewrite, warnwrite, parent_dir
17+
public :: read_lines, read_lines_expanded
1718
public :: which
1819

1920
integer, parameter :: LINE_BUFFER_LEN = 1000
@@ -316,6 +317,23 @@ integer function number_of_rows(s) result(nrows)
316317
rewind(s)
317318
end function number_of_rows
318319

320+
!> read lines into an array of TYPE(STRING_T) variables expanding tabs
321+
function read_lines_expanded(fh) result(lines)
322+
integer, intent(in) :: fh
323+
type(string_t), allocatable :: lines(:)
324+
325+
integer :: i
326+
integer :: ilen
327+
character(LINE_BUFFER_LEN) :: line_buffer_read, line_buffer_expanded
328+
329+
allocate(lines(number_of_rows(fh)))
330+
do i = 1, size(lines)
331+
read(fh, '(A)') line_buffer_read
332+
call notabs(line_buffer_read, line_buffer_expanded, ilen)
333+
lines(i)%s = trim(line_buffer_expanded)
334+
end do
335+
336+
end function read_lines_expanded
319337

320338
!> read lines into an array of TYPE(STRING_T) variables
321339
function read_lines(fh) result(lines)

src/fpm_source_parsing.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module fpm_source_parsing
2222
FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, &
2323
FPM_UNIT_CSOURCE, FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, &
2424
FPM_SCOPE_LIB, FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST
25-
use fpm_filesystem, only: read_lines
25+
use fpm_filesystem, only: read_lines, read_lines_expanded
2626
implicit none
2727

2828
private
@@ -84,7 +84,7 @@ function parse_f_source(f_filename,error) result(f_source)
8484
f_source%file_name = f_filename
8585

8686
open(newunit=fh,file=f_filename,status='old')
87-
file_lines = read_lines(fh)
87+
file_lines = read_lines_expanded(fh)
8888
close(fh)
8989

9090
! for efficiency in parsing make a lowercase left-adjusted copy of the file

src/fpm_strings.f90

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,19 @@
2222
!! - [[GLOB]] function compares text strings, one of which can have wildcards ('*' or '?').
2323
!! - [[IS_FORTRAN_NAME]] determine whether a string is an acceptable Fortran entity name
2424
!! - [[TO_FORTRAN_NAME]] replace allowed special but unusuable characters in names with underscore
25-
!!### Miscellaneous
25+
!!### Whitespace
26+
!! - [[NOTABS]] Expand tab characters assuming a tab space every eight characters
2627
!! - [[LEN_TRIM]] Determine total trimmed length of **STRING_T** array
28+
!!### Miscellaneous
2729
!! - [[FNV_1A]] Hash a **CHARACTER(*)** string of default kind or a **TYPE(STRING_T)** array
2830
!! - [[REPLACE]] Returns string with characters in charset replaced with target_char.
2931
!! - [[RESIZE]] increase the size of a **TYPE(STRING_T)** array by N elements
3032
!!
31-
3233
module fpm_strings
3334
use iso_fortran_env, only: int64
35+
use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, &
36+
& stdout=>output_unit, &
37+
& stderr=>error_unit
3438
use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer, c_size_t
3539
implicit none
3640

@@ -39,6 +43,7 @@ module fpm_strings
3943
public :: to_fortran_name, is_fortran_name
4044
public :: string_array_contains, string_cat, len_trim, operator(.in.), fnv_1a
4145
public :: replace, resize, str, join, glob
46+
public :: notabs
4247

4348
type string_t
4449
character(len=:), allocatable :: s
@@ -986,5 +991,112 @@ function is_fortran_name(line) result (lout)
986991
lout = .false.
987992
endif
988993
end function is_fortran_name
994+
!>
995+
!!### NAME
996+
!! notabs(3f) - [fpm_strings:NONALPHA] expand tab characters
997+
!! (LICENSE:PD)
998+
!!
999+
!!### SYNOPSIS
1000+
!!
1001+
!! subroutine notabs(INSTR,OUTSTR,ILEN)
1002+
!!
1003+
!! character(len=*),intent=(in) :: INSTR
1004+
!! character(len=*),intent=(out) :: OUTSTR
1005+
!! integer,intent=(out) :: ILEN
1006+
!!
1007+
!!### DESCRIPTION
1008+
!! NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining
1009+
!! columns. It assumes a tab is set every 8 characters. Trailing spaces
1010+
!! are removed.
1011+
!!
1012+
!! In addition, trailing carriage returns and line feeds are removed
1013+
!! (they are usually a problem created by going to and from MSWindows).
1014+
!!
1015+
!! What are some reasons for removing tab characters from an input line?
1016+
!! Some Fortran compilers have problems with tabs, as tabs are not
1017+
!! part of the Fortran character set. Some editors and printers will
1018+
!! have problems with tabs. It is often useful to expand tabs in input
1019+
!! files to simplify further processing such as tokenizing an input line.
1020+
!!
1021+
!!### OPTIONS
1022+
!! instr Input line to remove tabs from
1023+
!!
1024+
!!### RESULTS
1025+
!! outstr Output string with tabs expanded. Assumed to be of sufficient
1026+
!! length
1027+
!! ilen Significant length of returned string
1028+
!!
1029+
!!### EXAMPLES
1030+
!!
1031+
!! Sample program:
1032+
!!
1033+
!! program demo_notabs
1034+
!!
1035+
!! ! test filter to remove tabs and trailing white space from input
1036+
!! ! on files up to 1024 characters wide
1037+
!! use fpm_strings, only : notabs
1038+
!! character(len=1024) :: in,out
1039+
!! integer :: ios,iout
1040+
!! do
1041+
!! read(*,'(A)',iostat=ios)in
1042+
!! if(ios /= 0) exit
1043+
!! call notabs(in,out,iout)
1044+
!! write(*,'(a)')out(:iout)
1045+
!! enddo
1046+
!! end program demo_notabs
1047+
!!
1048+
!!### SEE ALSO
1049+
!! GNU/Unix commands expand(1) and unexpand(1)
1050+
!!
1051+
!!### AUTHOR
1052+
!! John S. Urban
1053+
!!
1054+
!!### LICENSE
1055+
!! Public Domain
1056+
elemental impure subroutine notabs(instr,outstr,ilen)
1057+
1058+
! ident_31="@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars"
1059+
1060+
character(len=*),intent(in) :: instr ! input line to scan for tab characters
1061+
character(len=*),intent(out) :: outstr ! tab-expanded version of INSTR produced
1062+
integer,intent(out) :: ilen ! column position of last character put into output string
1063+
! that is, ILEN holds the position of the last non-blank character in OUTSTR
1064+
1065+
integer,parameter :: tabsize=8 ! assume a tab stop is set every 8th column
1066+
integer :: ipos ! position in OUTSTR to put next character of INSTR
1067+
integer :: lenin ! length of input string trimmed of trailing spaces
1068+
integer :: lenout ! number of characters output string can hold
1069+
integer :: istep ! counter that advances thru input string INSTR one character at a time
1070+
character(len=1) :: c ! character in input line being processed
1071+
integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested
1072+
1073+
ipos=1 ! where to put next character in output string OUTSTR
1074+
lenin=len_trim(instr( 1:len(instr) )) ! length of INSTR trimmed of trailing spaces
1075+
lenout=len(outstr) ! number of characters output string OUTSTR can hold
1076+
outstr=" " ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters
1077+
1078+
SCAN_LINE: do istep=1,lenin ! look through input string one character at a time
1079+
c=instr(istep:istep) ! get next character
1080+
iade=ichar(c) ! get ADE of the character
1081+
EXPAND_TABS : select case (iade) ! take different actions depending on which character was found
1082+
case(9) ! test if character is a tab and move pointer out to appropriate column
1083+
ipos = ipos + (tabsize - (mod(ipos-1,tabsize)))
1084+
case(10,13) ! convert carriage-return and new-line to space ,typically to handle DOS-format files
1085+
ipos=ipos+1
1086+
case default ! c is anything else other than a tab,newline,or return insert it in output string
1087+
if(ipos > lenout)then
1088+
write(stderr,*)"*notabs* output string overflow"
1089+
exit
1090+
else
1091+
outstr(ipos:ipos)=c
1092+
ipos=ipos+1
1093+
endif
1094+
end select EXPAND_TABS
1095+
enddo SCAN_LINE
1096+
1097+
ipos=min(ipos,lenout) ! tabs or newline or return characters or last character might have gone too far
1098+
ilen=len_trim(outstr(:ipos)) ! trim trailing spaces
1099+
1100+
end subroutine notabs
9891101

9901102
end module fpm_strings

0 commit comments

Comments
 (0)