txt2f90.f90 source
module m_
use, intrinsic :: iso_fortran_env, only: stderr=>error_unit, stdout=>output_unit, stdin=>input_unit
implicit none
contains
subroutine fileread(filename,pageout)
class(*),intent(in) :: filename
character(len=:),allocatable,intent(out) :: pageout(:)
character(len=1),allocatable :: text(:)
call filebyte(filename,text)
if(.not.allocated(text))then
select type(filename)
type is (character(len=*)); write(*,*)'*fileread* failed to load file '//filename
type is (integer); write(*,'(a,i0)')'*fileread* failed to load file unit ',filename
end select
else
pageout=page(text)
deallocate(text)
endif
contains
function page(array) result (table)
character(len=1),intent(in) :: array(:)
character(len=:),allocatable :: table(:)
integer :: i
integer :: linelength
integer :: length
integer :: lines
integer :: linecount
integer :: position
integer :: sz
character(len=1),parameter :: nl = char(10)
character(len=1),parameter :: cr = char(13)
lines = 0
linelength = 0
length = 0
sz=size(array)
do i = 1,sz
if( array(i) == nl )then
linelength = max(linelength,length)
lines = lines + 1
length = 0
else
length = length + 1
endif
enddo
if( sz > 0 )then
if( array(sz) /= nl )then
lines = lines+1
endif
endif
if(allocated(table))deallocate(table)
allocate(character(len=linelength) :: table(lines))
table(:) = ' '
linecount = 1
position = 1
do i = 1,sz
if( array(i) == nl )then
linecount=linecount+1
position=1
elseif( array(i) == cr )then
elseif( linelength /= 0 )then
table(linecount)(position:position) = array(i)
position = position+1
endif
enddo
end function page
end subroutine fileread
subroutine filebyte(filename,text,length,lines)
implicit none
class(*),intent(in) :: filename
character(len=1),allocatable,intent(out) :: text(:)
integer,intent(out),optional :: length
integer,intent(out),optional :: lines
integer :: nchars=0
integer :: igetunit
integer :: ios=0
integer :: length_local
integer :: lines_local
integer :: i
integer :: icount
character(len=256) :: message
character(len=4096) :: label
character(len=:),allocatable :: line
length_local=0
lines_local=0
message=''
select type(filename)
type is (character(len=*))
if(filename /= '-') then
open(newunit=igetunit, file=trim(filename), action="read", iomsg=message,&
&form="unformatted", access="stream",status='old',iostat=ios)
label=filename
else
call copystdin()
endif
type is (integer)
if(filename /= stdin) then
rewind(unit=filename,iostat=ios,iomsg=message)
igetunit=filename
else
call copystdin()
endif
write(label,'("unit ",i0)')filename
end select
if(ios == 0)then
inquire(unit=igetunit, size=nchars)
if(nchars <= 0)then
write(stderr,'(a)') '*filebyte* empty file '//trim(label)
return
endif
if(allocated(text))deallocate(text)
allocate ( text(nchars) )
read(igetunit,iostat=ios,iomsg=message) text
if(ios /= 0)then
write(stderr,'(a)') '*filebyte* bad read of '//trim(label)//':'//trim(message)
endif
else
write(stderr,'(a)') '*filebyte* '//message
allocate ( text(0) )
endif
close(iostat=ios,unit=igetunit)
if(present(lines).or.present(length))then
icount=0
do i=1,nchars
if(text(i) == new_line('A'))then
lines_local=lines_local+1
length_local=max(length_local,icount)
icount=0
endif
icount=icount+1
enddo
if(nchars /= 0)then
if(text(nchars) /= new_line('A'))then
lines_local=lines_local+1
length_local=max(length_local,icount)
endif
endif
if(present(lines))lines=lines_local
if(present(length))length=length_local
endif
contains
subroutine copystdin()
integer :: iostat
open(newunit=igetunit, iomsg=message,&
&form="unformatted", access="stream",status='scratch',iostat=iostat)
open(unit=stdin,pad='yes')
infinite: do while (getline(line,iostat=iostat)==0)
write(igetunit)line//new_line('a')
enddo infinite
rewind(igetunit,iostat=iostat,iomsg=message)
end subroutine copystdin
end subroutine filebyte
function stretch(line,length) result(strout)
character(len=*),intent(in) :: line
integer,intent(in) :: length
character(len=:),allocatable :: strout
strout=pad(line,length)
end function stretch
function replace(targetline,old,new,ierr) result (newline)
character(len=*),intent(in) :: targetline
character(len=*),intent(in) :: old
character(len=*),intent(in) :: new
integer,intent(out),optional :: ierr
character(len=:),allocatable :: newline
character(len=:),allocatable :: new_local, old_local, old_local_for_comparison
integer :: icount,ichange,ier2
integer :: original_input_length
integer :: len_old, len_new
integer :: ladd
integer :: right_margin
integer :: ind
integer :: ic
integer :: ichr
integer :: range_local(2)
character(len=:),allocatable :: targetline_for_comparison
character(len=:),allocatable :: targetline_local
original_input_length=len_trim(targetline)
old_local=old
new_local=new
range_local(1)=1
range_local(2)=original_input_length
targetline_for_comparison=targetline
old_local_for_comparison=old_local
targetline_local=targetline
icount=0
ichange=0
len_old=len(old_local)
len_new=len(new_local)
right_margin=len(targetline)
newline=''
if(len_old == 0)then
ichr=len_new + original_input_length
if(len_new > 0)then
newline=new_local(:len_new)//targetline_local(1:original_input_length)
else
newline=targetline_local(1:original_input_length)
endif
ichange=1
if(present(ierr))ierr=ichange
return
endif
ichr=1
ic=1
loop: do
ind=index(targetline_for_comparison(ic:),old_local_for_comparison(:len_old))+ic-1
if(ind == ic-1.or.ind > right_margin)then
exit loop
endif
icount=icount+1
if(ind > ic)then
ladd=ind-ic
newline=newline(:ichr-1)//targetline_local(ic:ind-1)
ichr=ichr+ladd
endif
if(icount >= range_local(1).and.icount <= range_local(2))then
ichange=ichange+1
if(len_new /= 0)then
newline=newline(:ichr-1)//new_local(:len_new)
ichr=ichr+len_new
endif
else
if(len_old /= 0)then
newline=newline(:ichr-1)//old_local(:len_old)
ichr=ichr+len_old
endif
endif
ic=ind+len_old
enddo loop
select case (ichange)
case (0)
newline=targetline_local
case default
if(ic <= len(targetline))then
newline=newline(:ichr-1)//targetline_local(ic:max(ic,original_input_length))
endif
end select
if(present(ierr))ierr=ichange
end function replace
function pad(line,length) result(strout)
character(len=*),intent(in) :: line
integer,intent(in) :: length
character(len=:),allocatable :: strout
allocate(character(len=max(length,len(line))) :: strout)
strout(:)=line
end function pad
function getline(line,lun,iostat) result(ier)
implicit none
character(len=:),allocatable,intent(out) :: line
integer,intent(in),optional :: lun
integer,intent(out),optional :: iostat
integer :: ier
character(len=4096) :: message
integer,parameter :: buflen=1024
character(len=:),allocatable :: line_local
character(len=buflen) :: buffer
integer :: isize
integer :: lun_local
line_local=''
ier=0
if(present(lun))then
lun_local=lun
else
lun_local=stdin
endif
infinite: do
read(lun_local,pad='yes',iostat=ier,fmt='(a)',advance='no', &
& size=isize,iomsg=message) buffer
if(isize > 0)line_local=line_local//buffer(:isize)
if(is_iostat_eor(ier))then
ier=0
exit infinite
elseif(ier /= 0)then
line=trim(message)
exit infinite
endif
enddo infinite
line=line_local
if(present(iostat))iostat=ier
end function getline
end module m_
program txt2f90
use, intrinsic :: iso_fortran_env, only: stderr=>error_unit, stdout=>output_unit, stdin=>input_unit
use m_
implicit none
integer :: argument_length, istat
character(len=:), allocatable :: textblock(:)
character(len=:),allocatable :: subname
call get_command_argument(number=1,length=argument_length)
if(allocated(subname))deallocate(subname)
allocate(character(len=argument_length) :: subname)
call get_command_argument(1,subname,status=istat)
if(istat.ne.0.or.len(subname).eq.0) subname='_text'
call fileread(stdin,textblock)
if (size(textblock) > 0)then
call codeit()
endif
contains
subroutine codeit()
integer :: width
integer :: i
integer :: ilength
character(len=:), allocatable :: buff
width = 0
do i = min(1, size(textblock)), size(textblock)
width = max(width, len_trim(textblock(i)))
end do
write (stdout, '(a)') 'subroutine txt2f90'//subname//'()'
write (stdout, '(a)') 'integer :: i'
write (stdout, '(a)') 'character(len=:),allocatable :: txt2f90_text(:)'
write (stdout, '(a,i0,a)') 'txt2f90_text'//'=[ CHARACTER(LEN=', width, ') :: &'
do i = min(1, size(textblock)), size(textblock)
buff = trim(textblock(i))
buff = replace(buff,"'","''")
write (stdout, '("''",a,"'',&")') stretch(buff, width)
end do
write (stdout, '(a)') "'']"
write (stdout, '(a)') "write(*,'(a)') (trim(txt2f90_text(i)), i=1, size(txt2f90_text))"
write (stdout, '(a)') "end subroutine txt2f90"//subname
end subroutine codeit
end program txt2f90