MODULE Strings !! !! string handling CONTAINS !! subroutine STR_TRIM(RETSTR, STR, RETLEN) !! !! !! if RETSTR=STR then RETSTR is not touched !! 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=i if (retstr .ne. str) then ! avoid copy to retstr if equal retstr=str(1:i) endif end subroutine !! subroutine STR_UPCASE(RETSTR, STR) !! !! 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 !! subroutine STR_LOWCASE(RETSTR, STR) !! !! 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 !! subroutine STR_APPEND(STR, LENGTH, ADD) !! !! !! append ADD to STR(1:LENGTH) !! when STR too short, it is truncated !! character*(*) str !! (in/out) character*(*) add !! (in) integer length !! (in/out) 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 subroutine !! integer function STR_CMP(str1, str2) !! !! !! if strings are equal: return 0 !! else return position of first different character !! character STR1*(*), STR2*(*) !! (in) strings to comapre 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 function !! 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 !! 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 !! subroutine STR_SPLIT(STR, DELIM, START, END) !! !! !! split string into sequences separated by DELIM !! for the first sequence set END=0 and START=0 (or START=n for other start position n+1) !! result: end of list: END=0, START=0 !! empty sequence: START=END+1 !! normal sequence: STR(START:END) without delimiter !! character STR*(*), DELIM*(*) !! (in) string, delimiter integer START, END !! (in/out) start/end position integer i if (end .eq. len(str)) then start=0 end=0 RETURN endif if (end .ne. 0) start=end+len(delim) i=index(str(start+1:), delim) if (i .eq. 0) then end=len(str) else end=start+i-1 endif start=start+1 end subroutine !! subroutine STR_FMT_REAL(RESULT, RESLEN, X, WIDTH, FIXLEN, DIGITS, TRUNC) !! !! !! Convert X to RESULT !! !! The number is converted using Fortran format F.. !! If the number is too large or the number of significant digits is to !! low, the number digits after the decimal point is changed or, if this is !! is not possible, an E-format is choosen. If WIDTH is lower than 6, the !! result length will be larger in some cases. !! !! Default format (WIDTH < 0, FIXLEN < -1, DIGITS < 0) !! !! Arguments character*(*) RESULT !! integer RESLEN !! length of result real X !! number to be converted integer WIDTH !! minimum width integer FIXLEN !! minimum digits after comma integer DIGITS !! minimum significant digits integer TRUNC !! TRUNC=1,3: omit trailing zeros !! TRUNC=0,1: decimal point always shown parameter bufmax=32 integer wid, fix, dig, trc character*(bufmax) fixbuf, expbuf ! internal buffers integer exponent real mantissa integer f0, fl, e0, el ! start and end of used buffer F/E integer fdig, edig ! digits after decimal point F/E format integer overhd ! overhead integer p ! position of decimal point integer digf ! number of digits-1 shown (F-Format) integer le, l trc=trunc if (mod(trc,2) .eq. 1) then ! defaults wid=1 fix=0 dig=4 if (width .ge. 0) wid=width else wid=min(8,len(result)) if (width .ge. 0) wid=width fix=max(0,wid/2-1) dig=1 endif if (fixlen .ge. 0) fix=fixlen if (digits .ge. 0) dig=digits wid=min(bufmax, wid, len(result)) dig=min(bufmax, dig) if (x .eq. 0) then exponent=0 mantissa=0 else exponent=int(log10(abs(x))+100)-100 mantissa=x/10.0**exponent endif edig=min(max(wid-4,dig-1),len(result)-4) fdig=min(max(fix,dig-1-exponent),len(result)-1) ! F-Format 11 f0=0 fl=bufmax+1 ! in case of write error digf=-1 if (fdig .lt. -exponent) goto 14 write(fixbuf, 101, err=14) x 101 format (F.) ! reduce f0=bufmax-fdig if (exponent .gt. 0) f0=f0-exponent do while(f0 .gt. 0 .and. fixbuf(f0:f0) .ne. ' ') f0=f0-1 enddo fl=bufmax-1 do while(fixbuf(fl+1:fl+1) .eq. ' ') fl=fl-1 enddo overhd=fl+1-f0-len(result) do while (fixbuf(fl+1:fl+1) .eq. '0' .and. (overhd .gt. 0 .or. mod(trc,2) .eq. 1)) fl=fl-1 overhd=overhd-1 enddo if (fixbuf(fl+1:fl+1) .eq. '.' .and. trc .ge. 2) then overhd=overhd-1 else fl=fl+1 endif if (overhd .gt. 0) then 12 if (fdig .ge. overhd) then fdig=fdig-overhd goto 11 ! try again with less digits endif fl=bufmax+1 endif digf=fdig+exponent ! E-Format mantissa 14 if (x .eq. 0 .or. edig .lt. 0) goto 13 15 write(expbuf(1:bufmax-4), 102, err=19) mantissa 102 format (F.) if (exponent .gt. -10) then if (exponent .lt. 10 .and. exponent .ge. 0) then le=2 else le=3 endif else le=4 endif ! reduce e0=bufmax-6-edig if (e0 .gt. 0) then if (expbuf(e0:e0) .eq. '1') then ! 9.9 was rounded to 10 exponent=exponent+1 mantissa=mantissa/10.0 goto 15 endif if (expbuf(e0:e0) .eq. '-') e0=e0-1 endif el=bufmax-5 do while(expbuf(el+1:el+1) .eq. ' ') el=el-1 enddo overhd=el+le+1-e0-len(result) do while (expbuf(el+1:el+1) .eq. '0' .and. (overhd .gt. 0 .or. trc)) el=el-1 overhd=overhd-1 enddo if (expbuf(el+1:el+1) .eq. '.' .and. trc .ge. 2) then overhd=overhd-1 else el=el+1 endif if (overhd .gt. 0) then if (edig .ge. overhd) then edig=edig-overhd goto 14 ! try again with less digits endif el=bufmax+1 else write(expbuf(el+1:el+le), 103) exponent 103 format('E',I) el=el+le endif ! Compare l=fl-f0 if (l .gt. wid .and. & & (edig .gt. digf .or. & & edig .eq. digf .and. l .gt. el-e0 .or. & & l .gt. len(result))) then ! E-format is better fixbuf=expbuf f0=e0 fl=el p=bufmax-4-edig else p=bufmax-fdig if (fix .eq. 0 .and. trc .ge. 2) p=p-1 ! Decimal point not needed if fix=0 endif 13 l=fl-f0 if (l .gt. len(result)) then goto 19 elseif (p-f0 .gt. wid-fix .or. l .ge. wid) then ! Left just result=fixbuf(f0+1:fl) elseif (fl-p .gt. fix) then ! Right just result=fixbuf(fl-wid+1:fl) l=wid else ! Decimal just result=fixbuf(p+fix-wid+1:fl) l=fl+wid-p-fix endif reslen=min(l, len(result)) return 19 result='******' reslen=len(result) end subroutine subroutine STR_CRC(CRC,BUF) !! !! !! Computes a 16-bit Cyclic Redundancy Check for an character string BUF. !! In the first call CRC should be intitalized - !! between subsequent call it should be 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 !! 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 subroutine end module