379 lines
7.8 KiB
Fortran
379 lines
7.8 KiB
Fortran
!! string handling
|
|
!!
|
|
subroutine STR_TRIM(RETSTR, STR, RETLEN) !!
|
|
!!
|
|
!! if RETSTR=STR then RETSTR is not touched
|
|
!!
|
|
!! Arguments:
|
|
character*(*) STR, RETSTR !! in,out
|
|
integer RETLEN !! out
|
|
integer i
|
|
|
|
i=len(str)
|
|
if (str(1:1) .gt. ' ') then
|
|
10 if (str(i:i) .le. ' ') then
|
|
i=i-1
|
|
goto 10
|
|
endif
|
|
else
|
|
20 if (str(i:i) .le. ' ') then
|
|
if (i .gt. 1) then
|
|
i=i-1
|
|
goto 20
|
|
endif
|
|
endif
|
|
endif
|
|
retlen=min(len(retstr),i)
|
|
if (retstr .ne. str) then ! avoid copy to retstr if equal
|
|
retstr=str(1:i)
|
|
endif
|
|
end
|
|
|
|
!!
|
|
subroutine STR_UPCASE(RETSTR, STR) !!
|
|
!!
|
|
!! Arguments:
|
|
character STR*(*), RETSTR*(*) !! in,out
|
|
integer i, ch
|
|
|
|
retstr=str
|
|
do i=1,len(retstr)
|
|
ch=ichar(retstr(i:i))
|
|
if (ch .ge. ichar('a') .and. ch .le. ichar('z')) then
|
|
retstr(i:i)=char(ch-(ichar('a')-ichar('A')))
|
|
endif
|
|
enddo
|
|
end
|
|
|
|
!!
|
|
subroutine STR_LOWCASE(RETSTR, STR) !!
|
|
!!
|
|
!! Arguments:
|
|
character STR*(*), RETSTR*(*) !! in,out
|
|
integer i, ch
|
|
|
|
retstr=str
|
|
do i=1,len(retstr)
|
|
ch=ichar(retstr(i:i))
|
|
if (ch .ge. ichar('A') .and. ch .le. ichar('Z')) then
|
|
retstr(i:i)=char(ch+(ichar('a')-ichar('A')))
|
|
endif
|
|
enddo
|
|
end
|
|
|
|
!!
|
|
subroutine STR_APPEND(str, length, add) !!
|
|
!!
|
|
implicit none
|
|
|
|
character*(*) str, add !!
|
|
integer length !!
|
|
|
|
if (len(add)+length .gt. len(str)) then
|
|
if (length .lt. len(str)) then
|
|
str(length+1:)=add
|
|
length=len(str)
|
|
endif
|
|
else
|
|
str(length+1:length+len(add))=add
|
|
length=length+len(add)
|
|
endif
|
|
end
|
|
|
|
!!
|
|
integer function STR_CMP(str1, str2) !!
|
|
!!
|
|
!! if strings are equal: return 0
|
|
!! else return position of first different character
|
|
|
|
character str1*(*), str2*(*) !!
|
|
|
|
integer i
|
|
|
|
do i=0,min(len(str1),len(str2))-1
|
|
if (str1(i+1:i+1) .ne. str2(i+1:i+1)) then
|
|
str_cmp=i+1
|
|
return
|
|
endif
|
|
enddo
|
|
do i=len(str1),len(str2)-1
|
|
if (str2(i+1:i+1) .ne. ' ') then
|
|
str_cmp=i+1
|
|
return
|
|
endif
|
|
enddo
|
|
do i=len(str2),len(str1)-1
|
|
if (str1(i+1:i+1) .ne. ' ') then
|
|
str_cmp=i+1
|
|
return
|
|
endif
|
|
enddo
|
|
str_cmp=0
|
|
return
|
|
end
|
|
|
|
!!
|
|
subroutine STR_FIRST_NONBLANK(STR, POS) !!
|
|
!!
|
|
!! Arguments:
|
|
character*(*) STR !! in
|
|
integer POS !! out
|
|
integer i
|
|
|
|
do i=1,len(str)
|
|
if (str(i:i) .gt. ' ') then
|
|
pos=i
|
|
return
|
|
endif
|
|
enddo
|
|
pos=0
|
|
end
|
|
|
|
!!
|
|
subroutine STR_SPLIT(STR, DELIM, START, ENDE) !!
|
|
!!
|
|
!! split string into sequences separated by DELIM
|
|
!! for the first sequence set ENDE=0 and START=0 (or START=n for other start position n+1)
|
|
!! result: end of list: ENDE=-1
|
|
!! empty sequence: START=ENDE+1
|
|
!! normal sequence: STR(START:ENDE) without delimiter
|
|
!!
|
|
!! if ENDE has not a legal value, nothing happens
|
|
|
|
character STR*(*), DELIM*(*) !! (in) string, delimiter
|
|
integer START, ENDE !! (in/out) start/end position
|
|
|
|
integer i
|
|
|
|
if (ende .lt. 0 .or. ende .ge. len(str) .or. start .lt. 0) then
|
|
ende=-1
|
|
RETURN
|
|
endif
|
|
if (ende .ne. 0) start=ende+len(delim)
|
|
if (start .ge. len(str)) then
|
|
if (start .gt. len(str)) then
|
|
ende=-1
|
|
RETURN
|
|
endif
|
|
i=0
|
|
else
|
|
i=index(str(start+1:), delim)
|
|
endif
|
|
if (i .eq. 0) then
|
|
ende=len(str)
|
|
else
|
|
ende=start+i-1
|
|
endif
|
|
start=start+1
|
|
end
|
|
|
|
!!
|
|
subroutine STR_GET_ELEM(STR, POS, ELEM) !!
|
|
!!
|
|
!! reads next element ELEM from string STR(POS:). Elements are separated by
|
|
!! spaces combined with one control-char (assume tab) or one comma.
|
|
!! return ' ' when STR(POS:) contains only whitespace or when pos is to high
|
|
!!
|
|
character STR*(*) !! (in) input string
|
|
character ELEM*(*) !! (out) element read
|
|
integer POS !! (in/out) read position
|
|
|
|
integer start
|
|
|
|
|
|
1 if (pos .gt. len(str)) then
|
|
elem=' '
|
|
RETURN
|
|
endif
|
|
if (str(pos:pos) .eq. ' ') then
|
|
pos=pos+1
|
|
goto 1
|
|
endif
|
|
start=pos
|
|
2 if (str(pos:pos) .gt. ' ' .and. str(pos:pos) .ne. ',') then
|
|
pos=pos+1
|
|
if (pos .le. len(str)) then
|
|
goto 2
|
|
endif
|
|
pos=pos-1
|
|
endif
|
|
if (str(pos:pos) .eq. ',' .or. str(pos:pos) .lt. ' ') then
|
|
if (start .eq. pos) then
|
|
elem=str(start:pos)
|
|
else
|
|
elem=str(start:pos-1)
|
|
endif
|
|
pos=pos+1
|
|
RETURN
|
|
endif
|
|
elem=str(start:pos-1)
|
|
if (str(pos:) .eq. ' ') RETURN
|
|
3 if (str(pos:pos) .eq. ' ') then
|
|
pos=pos+1
|
|
if (pos .gt. len(str)) stop 'STR_GET_ELEM: assertion failed'
|
|
goto 3
|
|
endif
|
|
if (str(pos:pos) .eq. ',' .or. str(pos:pos) .lt. ' ') then
|
|
pos=pos+1
|
|
endif
|
|
end
|
|
|
|
!!
|
|
integer function STR_FIND_ELEM(STR, ELEM) !!
|
|
!!
|
|
!! find column index of element ELEM (case insensitive)
|
|
!! only the first 64 chars of each element are checked
|
|
!! 0 is returned when not found
|
|
!!
|
|
character STR*(*), ELEM*(*)
|
|
character ups*64, upe*64
|
|
integer pos, idx
|
|
|
|
pos=1
|
|
call str_upcase(upe, elem)
|
|
idx=0
|
|
|
|
call str_get_elem(str, pos, ups)
|
|
do while (ups .ne. ' ')
|
|
idx=idx+1
|
|
call str_upcase(ups, ups)
|
|
if (ups .eq. upe) then
|
|
str_find_elem=idx
|
|
RETURN
|
|
endif
|
|
call str_get_elem(str, pos, ups)
|
|
enddo
|
|
str_find_elem=0
|
|
RETURN
|
|
end
|
|
|
|
!!
|
|
subroutine STR_SUBSTITUTE(RESULT, STR, OLD, NEW) !!
|
|
!!
|
|
!! replace all occurences of substring OLD in STR by NEW
|
|
!! special case: if NEW=CHAR(0) then a null length string is replaced
|
|
!!
|
|
character RESULT*(*), STR*(*) !! (out), (in) strings (must either be equal or not overlap)
|
|
character OLD*(*), NEW*(*) !! substrings (in)
|
|
|
|
integer i,j,k
|
|
|
|
i=0
|
|
j=index(str, old)-1
|
|
if (len(new) .eq. 1 .and. new(1:1) .eq. char(0)) then
|
|
k=0
|
|
do while (j .ge. 0)
|
|
if (j .gt. 0) result(k+1:k+j)=str(i+1:i+j)
|
|
i=i+j+len(old)
|
|
k=k+j
|
|
if (i .ge. len(str)) then
|
|
if (k .lt. len(result)) result(k+1:)=' '
|
|
RETURN
|
|
endif
|
|
j=index(str(i+1:), old)-1
|
|
enddo
|
|
if (k .lt. len(result)) result(k+1:)=str(i+1:)
|
|
elseif (len(old) .ge. len(new)) then
|
|
k=0
|
|
do while (j .ge. 0)
|
|
if (j .gt. 0) result(k+1:k+j)=str(i+1:i+j)
|
|
i=i+j+len(old)
|
|
k=k+j
|
|
result(k+1:k+len(new))=new
|
|
k=k+len(new)
|
|
if (i .ge. len(str)) then
|
|
if (k .lt. len(result)) result(k+1:)=' '
|
|
RETURN
|
|
endif
|
|
j=index(str(i+1:), old)-1
|
|
enddo
|
|
if (k .lt. len(result)) result(k+1:)=str(i+1:)
|
|
else
|
|
result=str
|
|
do while (j .ne. 0)
|
|
i=i+j
|
|
result(i+1:)=new//result(i+len(old)+1:)
|
|
i=i+len(new)
|
|
if (i .ge. len(str)) RETURN
|
|
j=index(str(i+1:), old)-1
|
|
enddo
|
|
endif
|
|
end
|
|
|
|
subroutine STR_CRC(CRC,BUF) !!
|
|
!!
|
|
!! Computes a 16-bit Cyclic Redundancy Check for an character string BUF.
|
|
!! Before the first call CRC should be intitalized (i.e. to 0) -
|
|
!! between subsequent call it should left untouched.
|
|
|
|
integer CRC !! (in/out) CRC code
|
|
character BUF*(*) !! characters
|
|
|
|
|
|
integer init,ireg,i,j,icrctb(0:255),ichr,ib1,ib2,ib3
|
|
character*1 creg(4)
|
|
save icrctb,init,ib1,ib2,ib3
|
|
equivalence (creg,ireg) ! used to get at the 4 bytes in an integer.
|
|
data init /0/
|
|
|
|
integer crc1, crc2
|
|
|
|
if (init.eq.0) then ! initialize tables?
|
|
init=1
|
|
ireg=256*(256*ichar('3')+ichar('2'))+ichar('1')
|
|
do j=1,4 ! figure out which component of creg addresses which byte of ireg.
|
|
if (creg(j).eq.'1') ib1=j
|
|
if (creg(j).eq.'2') ib2=j
|
|
if (creg(j).eq.'3') ib3=j
|
|
enddo
|
|
do j=0,255 ! create CRCs of all characters.
|
|
ireg=j*256
|
|
|
|
do i=1,8 ! Here is where 8 one-bit shifts, and some XORs with the generator polynomial, are done.
|
|
ichr=ichar(creg(ib2))
|
|
ireg=ireg+ireg
|
|
creg(ib3)=char(0)
|
|
if(ichr.gt.127)ireg=ieor(ireg,4129)
|
|
enddo
|
|
|
|
icrctb(j)=ireg
|
|
enddo
|
|
endif
|
|
ireg=crc
|
|
crc1=ichar(creg(ib1))
|
|
crc2=ichar(creg(ib2))
|
|
|
|
do j=1,len(buf) ! Main loop over the characters
|
|
ireg=icrctb(ieor(ichar(buf(j:j)),crc2))
|
|
crc2=ieor(ichar(creg(ib2)),crc1)
|
|
crc1=ichar(creg(ib1))
|
|
enddo
|
|
creg(ib1)=char(crc1)
|
|
creg(ib2)=char(crc2)
|
|
crc=ireg
|
|
return
|
|
end
|
|
|
|
!!
|
|
subroutine STR_CRC_COMP(CRC, CHR) !!
|
|
!!
|
|
!! encode CRC (16 bit) as 3 characters in CHR
|
|
!!
|
|
integer CRC !! (in)
|
|
character CHR*3 !! (out)
|
|
|
|
integer n,j
|
|
character*41 cs/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$+-&_'/
|
|
|
|
if (crc .lt. 0 .or. crc .gt. 65535) stop 'STR_CRC_COMP: illegal CRC'
|
|
n=crc
|
|
j=mod(n,41)
|
|
chr(1:1)=cs(j+1:j+1)
|
|
n=n/41
|
|
j=mod(n,41)
|
|
chr(2:2)=cs(j+1:j+1)
|
|
j=n/41
|
|
chr(3:3)=cs(j+1:j+1)
|
|
end
|
|
|