hirchert@ncsa.uiuc.edu (Kurt Hirchert) (02/20/91)
In article <1991Feb16.202213.10167@ariel.unm.edu> scavo@cie.uoregon.edu (Tom Scavo) writes: >So how do I fix these nonstandard routines without having >to resort to local character variables (which would put an >unnecessary limit on the length of each argument)? (long FORTRAN 77 example appeared in original article) Typically, you do it by replacing assignment statements that attempt to do the move as one step with loops that do the move in smaller steps. It is permissible for the same string to appear on both sides of an assignment statement as long as the ranges do not overlap, so you can move in chunks no longer than the offset between the starting and ending positions. If the offset is small, this can reduce to a series of very small moves that may be inefficient on some machines, so you may prefer to copy larger chunks to a local buffer and then back to the target position. As long as you do this in a loop, the size of the local buffer in no way limits the size of strings you can handle. The subroutine mvleft below illustrates the use of both approaches. In your example, you could replace st(j+1:j+m) = st(i+1:n) and st = st(n-m+1:n) with call mvleft(st,i+1,m,i-j) and call mvleft(st,n-m+1,m,n-m) in order to get the same functionality implemented in conformance with the FORTRAN 77 standard. [P.S. The restriction against overlapping strings in an assignment statement was eliminated in Fortran 90. This change may cause the code generated for a subroutine like mvleft to be less efficient (because the compiler may be unable to recognize that all assignments from st to st in mvleft are made under circumstances where there is no overlap), but you also wouldn't need mvleft, because your original assignment statement would be standard conforming.] subroutine mvleft(st,istart,len,left) * move the len character substring of st starting at position * istart to a position left positions to the left. (if left * is negative, move the string to the right.) * the following parameter controls the size of the local copy buffer parameter (lenb = 16) * the following parameter specifies the length of strings where it * becomes faster to copy strings to and from the local copy buffer * than to do multiple direct copies of this length within st. this * value should always be less than or equal to lenb/2, since two * copies are involved in using the local copy buffer. parameter (lcopy = 4) character*(*) st character*(lenb) buf * check for no movement case if (left.eq.0) return * check if there is no overlap - if, so use straight assignment if (abs(left).le.len) then st(istart-left:istart+len-1-left) = st(istart:istart+len-1) return endif * check if nonoverlapped portion is too short to be efficient if (abs(left) .le. lcopy) go to 100 * do copy in chunks no larger than the nonoverlapped portion i = mod(len,abs(left)) if (left .gt. 0) then if (i .ne. 0) & st(istart-left:istart+i-1-left) = & st(istart:istart+i-1) jstart = istart+i jend = istart+len-1 else if (i .ne. 0) & st(istart+len-i-left:istart+len-1-left) = & st(istart+len-i:istart+len-1) jstart = istart+len-i+left jend = istart endif do 10 i=jstart,jend,left 10 st(i-left:i+iabs(left)-1-left) = st(i:i+iabs(left)-1) return * do copy in chunks the size of the local copy buffer 100 i = mod(len,lenb) if (left .gt. 0) then if (i .ne. 0) then buf(1:i) = st(istart:istart+i-1) st(istart-left:istart+i-1-left) = buf(1:i) endif jstart = istart+i jend = istart+len-1 jinc = lenb else if (i .ne. 0) then buf = st(istart+len-i:istart+len-1) st(istart+len-i-left:istart+len-1-left) = buf endif jstart = istart+len-i-lenb jend = istart jinc = -lenb endif do 20 i=jstart,jend,jinc buf = st(i:i+lenb-1) 20 st(i-left:i+lenb-1-left) = buf end -- Kurt W. Hirchert hirchert@ncsa.uiuc.edu National Center for Supercomputing Applications