function a_to_i4 ( ch ) !*****************************************************************************80 ! !! a_to_i4() returns the index of an alphabetic character. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Example: ! ! CH A_TO_I4 ! ! 'A' 1 ! 'B' 2 ! ... ! 'Z' 26 ! 'a' 27 ! 'b' 28 ! ... ! 'z' 52 ! '$' 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 February 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a character. ! ! Output: ! ! integer A_TO_I4, is the alphabetic index of the ! character, between 1 and 26 if the character is a capital letter, ! between 27 and 52 if it is lower case, and 0 otherwise. ! implicit none integer a_to_i4 integer, parameter :: cap_shift = 64 character ch integer, parameter :: low_shift = 96 if ( lle ( 'A', ch ) .and. lle ( ch, 'Z' ) ) then a_to_i4 = iachar ( ch ) - cap_shift else if ( lle ( 'a', ch ) .and. lle ( ch, 'z' ) ) then a_to_i4 = iachar ( ch ) - low_shift + 26 else a_to_i4 = 0 end if return end subroutine b4_ieee_to_r4 ( word, r ) !*****************************************************************************80 ! !! b4_ieee_to_r4() converts a 4 byte IEEE word into an R4. ! ! Discussion: ! ! An "R4" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! This routine does not seem to work reliably for unnormalized data. ! ! The word containing the real value may be interpreted as: ! ! /SEEEEEEE/EFFFFFFF/FFFFFFFF/FFFFFFFF/ ! ! /33222222/22222222/22222100/00000000/ ! /10987654/32109876/54321098/76543210/ <-- Bit numbering ! ! where ! ! S is the sign bit, ! E are the exponent bits, ! F are the mantissa bits. ! ! The mantissa is usually "normalized"; that is, there is an implicit ! leading 1 which is not stored. However, if the exponent is set to ! its minimum value, this is no longer true. ! ! The exponent is "biased". That is, you must subtract a bias value ! from the exponent to get the true value. ! ! If we read the three fields as integers S, E and F, then the ! value of the resulting real number R can be determined by: ! ! * if E = 255 ! if F is nonzero, then R = NaN; ! if F is zero and S is 1, R = -Inf; ! if F is zero and S is 0, R = +Inf; ! * else if 0 < E then R = (-1)^(S) * 2^(E-127) * (1 + (F/2^24)) ! * else if E = 0 ! if F is nonzero, R = (-1)^(S) * 2^(E-126) * (F/2^24) ! if F is zero and S is 1, R = -0; ! if F is zero and S is 0, R = +0; ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 November 2001 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! IEEE Standards Committee 754, ! IEEE Standard for Binary Floating Point Arithmetic, ! ANSI/IEEE Standard 754-1985, ! SIGPLAN Notices, ! Volume 22, Number 2, 1987, pages 9-25. ! ! Input: ! ! integer WORD, the word to be decoded. ! ! Output: ! ! real ( kind = rk ) R, the value of the real number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer e integer f integer i real ( kind = rk ) r integer s integer word ! ! Read the fields. ! s = 0 call mvbits ( word, 31, 1, s, 0 ) e = 0 call mvbits ( word, 23, 8, e, 0 ) f = 0 call mvbits ( word, 0, 23, f, 0 ) ! ! Don't bother trying to return NaN or Inf just yet. ! if ( e == 255 ) then r = 0.0E+00 else if ( 0 < e ) then r = ( -1.0E+00 )**s * 2.0E+00**(e-127-23) * real ( 8388608 + f, kind = rk ) else if ( e == 0 ) then r = ( -1.0E+00 )**s * 2.0E+00**(-126) * real ( f, kind = rk ) do i = 1, 23 r = r / 2.0E+00 end do end if return end subroutine b4_ieee_to_sef ( word, s, e, f ) !*****************************************************************************80 ! !! b4_ieee_to_sef() converts an IEEE real word to S * 2^E * F format. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer WORD, a word containing an IEEE real number. ! ! Output: ! ! integer S, the sign bit: ! 0, if R is nonnegative; ! 1, if R is negative. ! ! integer E, the exponent base 2. ! ! integer F, the mantissa. ! implicit none integer e integer e2 integer f integer s integer word s = 0 call mvbits ( word, 31, 1, s, 0 ) e2 = 0 call mvbits ( word, 23, 8, e2, 0 ) if ( e2 == 255 ) then e = 128 call mvbits ( word, 0, 23, f, 0 ) if ( f == 0 ) then f = 0 else f = 2**23 - 1 end if else if ( 0 < e2 ) then e = e2 - 127 - 23 f = 2**23 call mvbits ( word, 0, 23, f, 0 ) do while ( mod ( f, 2 ) == 0 ) f = f / 2 e = e + 1 end do else if ( e2 == 0 ) then e = e2 - 127 - 23 f = 0 call mvbits ( word, 0, 23, f, 0 ) if ( f == 0 ) then e = 0 else do while ( 0 < f .and. mod ( f, 2 ) == 0 ) f = f / 2 e = e + 1 end do end if end if return end subroutine base_to_i4 ( s, base, i ) !*****************************************************************************80 ! !! base_to_i4() returns the value of an I4 represented in some base. ! ! Discussion: ! ! BASE = 1 is allowed, in which case we allow the digits '1' and '0', ! and we simply count the '1' digits for the result. ! ! Negative bases between -16 and -2 are allowed. ! ! The base -1 is allowed, and essentially does a parity check on ! a string of 1's. ! ! Example: ! ! Input Output ! ------------- ------ ! S BASE I ! ------ ----- ------ ! '101' 2 5 ! '-1000' 3 -27 ! '100' 4 16 ! '111111' 2 63 ! '111111' -2 21 ! '111111' 1 6 ! '111111' -1 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. The elements of S are ! blanks, a plus or minus sign, and digits. Normally, the digits ! are representations of integers between 0 and |BASE-1|. In the ! special case of base 1 or base -1, we allow both 0 and 1 as digits. ! ! integer BASE, the base in which the representation ! is given. Normally, 2 <= BASE <= 16. However, there are two exceptions. ! ! Output: ! ! integer I, the integer. ! implicit none integer base character c integer i integer ichr integer idig integer isgn character ( len = * ) s integer s_length integer state i = 0 s_length = len_trim ( s ) if ( base == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BASE_TO_I4 - Serious error!' write ( *, '(a)' ) ' The input base is zero.' i = -1 return end if if ( 16 < abs ( base ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BASE_TO_I4 - Serious error!' write ( *, '(a)' ) ' The input base is greater than 16!' i = -1 return end if state = 0 isgn = 1 ichr = 1 do while ( ichr <= s_length ) c = s(ichr:ichr) ! ! Blank. ! if ( c == ' ' ) then if ( state == 2 ) then exit end if ! ! Sign, + or -. ! else if ( c == '-' ) then if ( state /= 0 ) then exit end if state = 1 isgn = -1 else if ( c == '+' ) then if ( state /= 0 ) then exit end if state = 1 else ! ! Digit? ! call hex_digit_to_i4 ( c, idig ) if ( abs ( base ) == 1 .and. ( idig == 0 .or. idig == 1 ) ) then i = base * i + idig state = 2 else if ( 0 <= idig .and. idig < abs ( base ) ) then i = base * i + idig state = 2 else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BASE_TO_I4 - Serious error!' write ( *, '(a)' ) ' Illegal digit = "' // c // '"' write ( *, '(a)' ) ' Conversion halted prematurely!' return end if end if ichr = ichr + 1 end do ! ! Once we're done reading information, we expect to be in state 2. ! if ( state /= 2 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BASE_TO_I4 - Serious error!' write ( *, '(a)' ) ' Unable to decipher input!' return end if ! ! Account for the sign. ! i = isgn * i return end subroutine binary_to_i4 ( s, i ) !*****************************************************************************80 ! !! binary_to_i4() converts a binary representation into an I4. ! ! Example: ! ! S I ! ! '101' 5 ! '-1000' -8 ! '1' 1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the binary representation. ! ! Output: ! ! integer I, the I4 whose representation was input. ! implicit none character c integer i integer ichr integer isgn character ( len = * ) s integer s_length integer state s_length = len_trim ( s ) i = 0 ichr = 1 state = 0 isgn = 1 do while ( ichr <= s_length ) c = s(ichr:ichr) ! ! Blank. ! if ( c == ' ' ) then if ( state == 2 ) then state = 3 end if ! ! Sign, + or -. ! else if ( c == '-' ) then if ( state == 0 ) then state = 1 isgn = -1 else state = -1 end if else if ( c == '+' ) then if ( state == 0 ) then state = 1 else state = -1 end if ! ! Digit, 0 or 1. ! else if ( c == '1' ) then i = 2 * i i = i + 1 state = 2 else if ( c == '0' ) then i = 2 * i state = 2 ! ! Illegal or unknown sign. ! else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_I4 - Serious error!' write ( *, '(a)' ) ' Illegal digit = "' // c // '"' write ( *, '(a)' ) ' Conversion halted prematurely!' return end if if ( state == -1 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_I4 - Serious error!' write ( *, '(a)' ) ' Unable to decipher input!' return end if if ( 3 <= state ) then exit end if ichr = ichr + 1 end do ! ! Apply the sign. ! i = isgn * i return end subroutine binary_to_r4 ( s, r ) !*****************************************************************************80 ! !! binary_to_r4() converts a binary representation into an R4. ! ! Discussion: ! ! An "R4" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! Example: ! ! S R ! ! -1010.11 -10.75 ! 0.011011 0.4218750 ! 0.01010101010101010101010 0.3333333 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the binary representation. ! ! Output: ! ! real ( kind = rk ) R, the real number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character c integer ichr integer intval integer isgn integer power real ( kind = rk ) r character ( len = * ) s integer s_length integer state s_length = len_trim ( s ) intval = 0 ichr = 1 state = 0 isgn = 1 r = 0.0E+00 power = 0 do while ( ichr <= s_length ) c = s(ichr:ichr) ! ! Blank. ! if ( c == ' ' ) then if ( state == 4 ) then state = 5 end if ! ! Sign, + or -. ! else if ( c == '-' ) then if ( state == 0 ) then state = 1 isgn = -1 else state = -1 end if else if ( c == '+' ) then if ( state == 0 ) then state = 1 else state = -1 end if ! ! Digit, 0 or 1. ! else if ( c == '1' ) then intval = 2 * intval + 1 if ( state == 0 .or. state == 1 ) then state = 2 else if ( state == 3 ) then state = 4 end if if ( state == 4 ) then power = power + 1 end if else if ( c == '0' ) then intval = 2 * intval if ( state == 0 .or. state == 1 ) then state = 2 else if ( state == 3 ) then state = 4 end if if ( state == 4 ) then power = power + 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( state <= 2 ) then state = 3 else state = -1 end if ! ! Illegal or unknown sign. ! else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_R4 - Serious error!' write ( *, '(a)' ) ' Illegal character = "' // c // '"' write ( *, '(a)' ) ' Conversion halted prematurely!' stop 1 end if if ( state == -1 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_R4 - Serious error!' write ( *, '(a)' ) ' Unable to decipher input!' stop 1 end if if ( 5 <= state ) then exit end if ichr = ichr + 1 end do ! ! Apply the sign and the scale factor. ! r = real ( isgn * intval, kind = rk ) / 2.0E+00 ** power return end subroutine binary_to_r8 ( s, r ) !*****************************************************************************80 ! !! binary_to_r8() converts a binary representation into an R8. ! ! Discussion: ! ! An "R8" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! Example: ! ! S R ! ! -1010.11 -10.75 ! 0.011011 0.4218750 ! 0.01010101010101010101010 0.3333333 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the binary representation. ! ! Output: ! ! real ( kind = rk ) R, the real number. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) character c integer ichr integer intval integer isgn integer power real ( kind = rk ) r character ( len = * ) s integer s_length integer state s_length = len_trim ( s ) intval = 0 ichr = 1 state = 0 isgn = 1 r = 0.0D+00 power = 0 do while ( ichr <= s_length ) c = s(ichr:ichr) ! ! Blank. ! if ( c == ' ' ) then if ( state == 4 ) then state = 5 end if ! ! Sign, + or -. ! else if ( c == '-' ) then if ( state == 0 ) then state = 1 isgn = -1 else state = -1 end if else if ( c == '+' ) then if ( state == 0 ) then state = 1 else state = -1 end if ! ! Digit, 0 or 1. ! else if ( c == '1' ) then intval = 2 * intval + 1 if ( state == 0 .or. state == 1 ) then state = 2 else if ( state == 3 ) then state = 4 end if if ( state == 4 ) then power = power + 1 end if else if ( c == '0' ) then intval = 2 * intval if ( state == 0 .or. state == 1 ) then state = 2 else if ( state == 3 ) then state = 4 end if if ( state == 4 ) then power = power + 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( state <= 2 ) then state = 3 else state = -1 end if ! ! Illegal or unknown sign. ! else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_R8 - Serious error!' write ( *, '(a)' ) ' Illegal character = "' // c // '"' write ( *, '(a)' ) ' Conversion halted prematurely!' stop 1 end if if ( state == -1 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'BINARY_TO_R8 - Serious error!' write ( *, '(a)' ) ' Unable to decipher input!' stop 1 end if if ( 5 <= state ) then exit end if ichr = ichr + 1 end do ! ! Apply the sign and the scale factor. ! r = real ( isgn * intval, kind = rk ) / 2.0D+00 ** power return end subroutine ch_cap ( ch ) !*****************************************************************************80 ! !! ch_cap() capitalizes a single character. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, ! which guarantee the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 19 July 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to capitalize. ! ! Output: ! ! character CH, the capitalized character. ! implicit none character ch integer itemp itemp = iachar ( ch ) if ( 97 <= itemp .and. itemp <= 122 ) then ch = achar ( itemp - 32 ) end if return end subroutine ch_count_chvec_add ( n, chvec, count ) !*****************************************************************************80 ! !! ch_count_chvec_add() adds a character vector to a character count. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in the vector. ! ! character CHVEC(N), a vector of characters. ! ! integer COUNT(0:255), the character counts. ! ! Output: ! ! integer COUNT(0:255), the updated character counts. ! implicit none integer n integer count(0:255) character chvec(n) integer i integer j do i = 1, n j = iachar ( chvec(i) ) count(j) = count(j) + 1 end do return end subroutine ch_count_file_add ( file_name, count ) !*****************************************************************************80 ! !! ch_count_file_add() adds characters in a file to a character count. ! ! Discussion: ! ! Each line is counted up to the last nonblank. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) FILE_NAME, the name of the file to examine. ! ! Output: ! ! integer COUNT(0:255), the character counts. ! implicit none integer count(0:255) character ( len = * ) file_name integer ios integer iunit character ( len = 255 ) line ! ! Open the file. ! call get_unit ( iunit ) open ( unit = iunit, file = file_name, status = 'old', iostat = ios ) if ( ios /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CH_COUNT_FILE_ADD - Fatal error!' write ( *, '(a)' ) ' Could not open the file:' write ( *, '(a)' ) ' ' // trim ( file_name ) return end if do read ( iunit, '(a)', iostat = ios ) line if ( ios /= 0 ) then exit end if call ch_count_s_add ( trim ( line ), count ) end do close ( unit = iunit ) return end subroutine ch_count_histogram_print ( count, title ) !*****************************************************************************80 ! !! ch_count_histogram_print() prints a histogram of a set of character counts. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer COUNT(0:255), the character counts. ! ! character ( len = * ) TITLE, a title to be printed. ! implicit none character c character ( len = 4 ) ch4(0:255) integer count(0:255) integer i integer ihi integer ilo integer percent integer row character ( len = 4 ) s(0:255) character ( len = * ) title integer total total = sum ( count ) do i = 0, 255 c = achar ( i ) call ch_to_sym ( c, ch4(i) ) end do do i = 0, 255 if ( total == 0 ) then percent = 0 else percent = nint ( real ( 100 * count(i) ) / real ( total ) ) end if if ( percent == 0 ) then s(i) = ' .' else write ( s(i), '(i4)' ) percent end if end do if ( 0 < len_trim ( title ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) end if write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Character Histogram (Percentages).' write ( *, '(a)' ) ' ' do row = 1, 16 ilo = ( row - 1 ) * 16 ihi = row * 16 - 1 write ( *, '(2x,i3,a4,i3,3x,16a4)' ) ilo, ' to ', ihi, ch4(ilo:ihi) write ( *, '(12x,16a4)' ) s(ilo:ihi) end do return end subroutine ch_count_init ( count ) !*****************************************************************************80 ! !! ch_count_init() initializes a character count. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Output: ! ! integer COUNT(0:255), the character counts. ! implicit none integer count(0:255) count(0:255) = 0 return end subroutine ch_count_print ( count, title ) !*****************************************************************************80 ! !! ch_count_print() prints a set of character counts. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer COUNT(0:255), the character counts. ! ! character ( len = * ) TITLE, a title to be printed. ! implicit none character c character ( len = 4 ) ch4(0:255) integer count(0:255) integer i real percent character ( len = * ) title integer total total = sum ( count ) do i = 0, 255 c = achar ( i ) call ch_to_sym ( c, ch4(i) ) end do if ( 0 < len_trim ( title ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) end if write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Char Count Percentages.' write ( *, '(a)' ) ' ' do i = 0, 255 if ( 0 < count(i) ) then if ( total == 0 ) then percent = 0.0E+00 else percent = real ( 100 * count(i) ) / real ( total ) end if write ( *, '(2x,a4,2x,i8,2x,f6.3)' ) ch4(i), count(i), percent end if end do return end subroutine ch_count_s_add ( s, count ) !*****************************************************************************80 ! !! ch_count_s_add() adds a character string to a character histogram. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string to be examined. ! ! integer COUNT(0:255), the character counts. ! ! Output: ! ! integer COUNT(0:255), the updated character counts. ! implicit none integer count(0:255) integer i integer j character ( len = * ) s do i = 1, len ( s ) j = iachar ( s(i:i) ) count(j) = count(j) + 1 end do return end function ch_eqi ( c1, c2 ) !*****************************************************************************80 ! !! ch_eqi() is a case insensitive comparison of two characters for equality. ! ! Discussion: ! ! CH_EQI ( 'A', 'a' ) is TRUE. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character C1, C2, the characters to compare. ! ! Output: ! ! logical CH_EQI, the result of the comparison. ! implicit none character c1 character c1_cap character c2 character c2_cap logical ch_eqi c1_cap = c1 c2_cap = c2 call ch_cap ( c1_cap ) call ch_cap ( c2_cap ) if ( c1_cap == c2_cap ) then ch_eqi = .true. else ch_eqi = .false. end if return end subroutine ch_extract ( s, ch ) !*****************************************************************************80 ! !! ch_extract() extracts the next nonblank character from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! Output: ! ! character ( len = * ) S, the string. The ! first nonblank character has been removed, and the string ! has been shifted left. ! ! character CH, the leading character of the string. ! implicit none character ch integer get character ( len = * ) s integer s_len s_len = len_trim ( s ) ch = ' ' get = 1 do while ( get <= s_len ) if ( s(get:get) /= ' ' ) then ch = s(get:get) call s_shift_left ( s, get ) exit end if get = get + 1 end do return end subroutine ch_fake_use ( ch ) !*****************************************************************************80 ! !! ch_fake_use() pretends to use a variable. ! ! Discussion: ! ! Some compilers will issue a warning if a variable is unused. ! Sometimes there's a good reason to include a variable in a program, ! but not to use it. Calling this function with that variable as ! the argument will shut the compiler up. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 June 2020 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the variable to be "used". ! implicit none character ch logical, parameter :: printit = .false. if ( ch == '?' ) then if ( printit ) then write ( *, '(a)' ) '' write ( *, '(a)' ) 'ch_fake_use:' write ( *, '(a)' ) ' Another question mark!' end if end if return end function ch_index_first ( s, ch ) !*****************************************************************************80 ! !! ch_index_first() returns the first occurrence of a character in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character CH, the character to be searched for. ! ! Output: ! ! integer CH_INDEX_FIRST, the location of the first ! occurrence of the character in the string, or -1 if it does not occur. ! implicit none character ch integer ch_index_first integer i character ( len = * ) s integer s_length ch_index_first = - 1 s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == ch ) then ch_index_first = i return end if end do return end function ch_index_last ( s, ch ) !*****************************************************************************80 ! !! ch_index_last() is the last occurrence of a character in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 03 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character CH, the character to be searched for. ! ! Output: ! ! integer CH_INDEX_LAST, the location of the last ! occurrence of the character in the string, or -1 if it does not occur. ! implicit none character ch integer ch_index_last integer i character ( len = * ) s integer s_length ch_index_last = -1 s_length = len_trim ( s ) do i = s_length, 1, -1 if ( s(i:i) == ch ) then ch_index_last = i return end if end do return end function ch_indexi ( s, ch ) !*****************************************************************************80 ! !! ch_indexi(): (case insensitive) first occurrence of a character in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 03 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character CH, the character to be searched for. ! ! Output: ! ! integer CH_INDEXI, the location of the first ! occurrence of the character (upper or lowercase), or -1 if it does ! not occur. ! implicit none character ch logical ch_eqi integer ch_indexi integer i character ( len = * ) s integer s_length ch_indexi = -1 s_length = len_trim ( s ) do i = 1, s_length if ( ch_eqi ( s(i:i), ch ) ) then ch_indexi = i return end if end do return end function ch_is_alpha ( ch ) !*****************************************************************************80 ! !! ch_is_alpha() is TRUE if CH is an alphabetic character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a character to check. ! ! Output: ! ! logical CH_IS_ALPHA is TRUE if CH is an alphabetic character. ! implicit none character ch logical ch_is_alpha if ( ( lle ( 'a', ch ) .and. lle ( ch, 'z' ) ) .or. & ( lle ( 'A', ch ) .and. lle ( ch, 'Z' ) ) ) then ch_is_alpha = .true. else ch_is_alpha = .false. end if return end function ch_is_alphanumeric ( ch ) !*****************************************************************************80 ! !! ch_is_alphanumeric() is TRUE if CH is alphanumeric. ! ! Discussion: ! ! Alphanumeric characters are 'A' through 'Z', 'a' through 'z' and ! '0' through '9'. ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be checked. ! ! Output: ! ! logical CH_IS_ALPHANUMERIC, is TRUE if the character ! is alphabetic or numeric. ! implicit none character ch logical ch_is_alphanumeric integer i i = iachar ( ch ) if ( ( 65 <= i .and. i <= 90 ) .or. & ( 97 <= i .and. i <= 122 ) .or. & ( 48 <= i .and. i <= 57 ) ) then ch_is_alphanumeric = .true. else ch_is_alphanumeric = .false. end if return end function ch_is_control ( ch ) !*****************************************************************************80 ! !! ch_is_control() is TRUE if a character is a control character. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! A "control character" has ASCII code <= 31 or 127 <= ASCII code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be tested. ! ! Output: ! ! logical CH_IS_CONTROL, TRUE if the character is ! a control character, and FALSE otherwise. ! implicit none character ch logical ch_is_control if ( iachar ( ch ) <= 31 .or. 127 <= iachar ( ch ) ) then ch_is_control = .true. else ch_is_control = .false. end if return end function ch_is_digit ( ch ) !*****************************************************************************80 ! !! ch_is_digit() is TRUE if a character is a decimal digit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be analyzed. ! ! Output: ! ! logical CH_IS_DIGIT, is TRUE if the character is a digit. ! implicit none character ch logical ch_is_digit if ( lle ( '0', ch ) .and. lle ( ch, '9' ) ) then ch_is_digit = .true. else ch_is_digit = .false. end if return end function ch_is_format_code ( ch ) !*****************************************************************************80 ! !! ch_is_format_code() is TRUE if a character is a FORTRAN format code. ! ! Discussion: ! ! The format codes accepted here are not the only legal format ! codes in FORTRAN90. However, they are more than sufficient ! for my needs! ! ! Table: ! ! A Character ! B Binary digits ! D Real number, exponential representation ! E Real number, exponential representation ! F Real number, fixed point ! G General format ! I Integer ! L Logical variable ! O Octal digits ! Z Hexadecimal digits ! * Free format ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 November 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be analyzed. ! ! Output: ! ! logical CH_IS_FORMAT_CODE, is TRUE if the character ! is a FORTRAN format code. ! implicit none character ch logical ch_eqi logical ch_is_format_code ch_is_format_code = .true. if ( ch_eqi ( ch, 'A' ) ) then return else if ( ch_eqi ( ch, 'B' ) ) then return else if ( ch_eqi ( ch, 'D' ) ) then return else if ( ch_eqi ( ch, 'E' ) ) then return else if ( ch_eqi ( ch, 'F' ) ) then return else if ( ch_eqi ( ch, 'G' ) ) then return else if ( ch_eqi ( ch, 'I' ) ) then return else if ( ch_eqi ( ch, 'L' ) ) then return else if ( ch_eqi ( ch, 'O' ) ) then return else if ( ch_eqi ( ch, 'Z' ) ) then return else if ( ch == '*' ) then return end if ch_is_format_code = .false. return end function ch_is_isbn_digit ( ch ) !*****************************************************************************80 ! !! ch_is_isbn_digit() is TRUE if a character is an ISBN digit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be analyzed. ! ! Output: ! ! logical CH_IS_ISBN_DIGIT, is TRUE if the character ! is an ISBN digit. ! implicit none character ch logical ch_is_isbn_digit logical value if ( lle ( '0', ch ) .and. lle ( ch, '9' ) ) then value = .true. else if ( ch == 'x' .or. ch == 'X' ) then value = .true. else value = .false. end if ch_is_isbn_digit = value return end function ch_is_lower ( ch ) !*****************************************************************************80 ! !! ch_is_lower() is TRUE if a character is a lower case letter. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 May 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be analyzed. ! ! Output: ! ! logical CH_IS_LOWER, is TRUE if the character is a ! lower case letter. ! implicit none character ch logical ch_is_lower if ( lle ( 'a', ch ) .and. lle ( ch, 'z' ) ) then ch_is_lower = .true. else ch_is_lower = .false. end if return end function ch_is_printable ( ch ) !*****************************************************************************80 ! !! ch_is_printable() is TRUE if C is printable. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 03 July 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a character to check. ! ! Output: ! ! logical CH_IS_PRINTABLE is TRUE if C is a printable ! character. ! implicit none character ch logical ch_is_printable integer i i = iachar ( ch ) if ( 32 <= i .and. i <= 126 ) then ch_is_printable = .true. else ch_is_printable = .false. end if return end function ch_is_space ( ch ) !*****************************************************************************80 ! !! ch_is_space() is TRUE if a character is a whitespace character. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! A whitespace character is a space, a form feed, a newline, ! a carriage return, a tab, or a vertical tab. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 October 2004 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a character to check. ! ! Output: ! ! logical CH_IS_SPACE is TRUE if the character is a ! whitespace character. ! implicit none character ch logical ch_is_space if ( ch == ' ' ) then ch_is_space = .true. else if ( ch == achar ( 12 ) ) then ch_is_space = .true. else if ( ch == achar ( 10 ) ) then ch_is_space = .true. else if ( ch == achar ( 13 ) ) then ch_is_space = .true. else if ( ch == achar ( 9 ) ) then ch_is_space = .true. else if ( ch == achar ( 11 ) ) then ch_is_space = .true. else ch_is_space = .false. end if return end function ch_is_upper ( ch ) !*****************************************************************************80 ! !! ch_is_upper() is TRUE if CH is an upper case letter. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 May 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be analyzed. ! ! Output: ! ! logical CH_IS_UPPER, is TRUE if CH is an upper ! case letter. ! implicit none character ch logical ch_is_upper if ( lle ( 'A', ch ) .and. lle ( ch, 'Z' ) ) then ch_is_upper = .true. else ch_is_upper = .false. end if return end subroutine ch_low ( ch ) !*****************************************************************************80 ! !! ch_low() lowercases a single character. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, ! which guarantee the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 May 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be lowercased. ! ! Output: ! ! character CH, the lowercased character. ! implicit none character ch integer i i = iachar ( ch ) if ( 65 <= i .and. i <= 90 ) then ch = achar ( i + 32 ) end if return end subroutine ch_next ( s, ch, done ) !*****************************************************************************80 ! !! ch_next() reads the next character from a string, ignoring blanks and commas. ! ! Example: ! ! Input: ! ! S = ' A B, C DE F' ! ! Output: ! ! 'A', 'B', 'C', 'D', 'E', 'F', and then blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string of characters. Blanks and ! commas are considered insignificant. ! ! logical DONE. ! On input with a fresh value of S, the user should set ! DONE to TRUE. ! ! Output: ! ! character CH. If DONE is FALSE, then the ! "next" character. If DONE is TRUE, then a blank. ! ! logical DONE. ! The routine sets DONE to FALSE if another character ! was read, or TRUE if no more characters could be read. ! implicit none character ch logical done integer i integer, save :: next = 1 character ( len = * ) s integer s_length if ( done ) then next = 1 done = .false. end if s_length = len_trim ( s ) do i = next, s_length if ( s(i:i) /= ' ' .and. s(i:i) /= ',' ) then ch = s(i:i) next = i + 1 return end if end do done = .true. next = 1 ch = ' ' return end function ch_not_control ( ch ) !*****************************************************************************80 ! !! ch_not_control() = CH is NOT a control character. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 January 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH is the character to be tested. ! ! Output: ! ! logical CH_NOT_CONTROL, TRUE if CH is not a control ! character, and FALSE otherwise. ! implicit none character ch logical ch_not_control if ( iachar ( ch ) <= 31 .or. 128 <= iachar ( ch ) ) then ch_not_control = .true. else ch_not_control = .false. end if return end function ch_roman_to_i4 ( ch ) !*****************************************************************************80 ! !! ch_roman_to_i4() converts a single Roman digit to an I4. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 09 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a Roman digit. ! ! Output: ! ! integer CH_ROMAN_TO_I4, the value of the Roman ! numeral. If the Roman numeral was not recognized, 0 is returned. ! implicit none character ch integer ch_roman_to_i4 integer i if ( ch == 'M' .or. ch == 'm' ) then i = 1000 else if ( ch == 'D' .or. ch == 'd' ) then i = 500 else if ( ch == 'C' .or. ch == 'c' ) then i = 100 else if ( ch == 'L' .or. ch == 'l' ) then i = 50 else if ( ch == 'X' .or. ch == 'x' ) then i = 10 else if ( ch == 'V' .or. ch == 'v' ) then i = 5 else if ( ch == 'I' .or. ch == 'i' .or. & ch == 'J' .or. ch == 'j' ) then i = 1 else i = 0 end if ch_roman_to_i4 = i return end function ch_scrabble ( tile ) !*****************************************************************************80 ! !! ch_scrabble() returns the character on a given Scrabble tile. ! ! Discussion: ! ! The tiles are numbered 1 to 100, and are labeled 'A' through 'Z', ! plus two blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer TILE, the index of the desired Scrabble tile. ! ! Output: ! ! character CH_SCRABBLE, the character on the given tile. ! implicit none character ch_scrabble character, dimension ( 1 : 100 ) :: scrabble = (/ & 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', & 'B', 'C', 'C', 'D', 'D', 'D', 'D', 'E', 'E', 'E', & 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'F', & 'F', 'G', 'G', 'G', 'H', 'H', 'I', 'I', 'I', 'I', & 'I', 'I', 'I', 'I', 'I', 'J', 'K', 'L', 'L', 'L', & 'L', 'M', 'M', 'N', 'N', 'N', 'N', 'N', 'N', 'O', & 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'P', 'P', 'Q', & 'R', 'R', 'R', 'R', 'R', 'R', 'S', 'S', 'S', 'S', & 'T', 'T', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', & 'V', 'V', 'W', 'W', 'X', 'X', 'Y', 'Z', ' ', ' ' /) integer tile if ( 1 <= tile .and. tile <= 100 ) then ch_scrabble = scrabble(tile) else ch_scrabble = '?' end if return end function ch_scrabble_frequency ( ch ) !*****************************************************************************80 ! !! ch_scrabble_frequency() returns the Scrabble frequency of a character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character. ! ! Output: ! ! integer CH_SCRABBLE_FREQUENCY, the frequency of ! the character. ! implicit none character ch integer ch_scrabble_frequency integer ch_to_scrabble integer, dimension ( 27 ) :: frequency = (/ & 9, 2, 2, 4, 12, & 2, 3, 2, 9, 1, & 1, 4, 2, 6, 8, & 2, 1, 6, 4, 6, & 4, 2, 2, 1, 2, & 1, 2 /) integer ic ! ! Convert character to a Scrabble character index. ! ic = ch_to_scrabble ( ch ) if ( 1 <= ic .and. ic <= 27 ) then ch_scrabble_frequency = frequency(ic) else ch_scrabble_frequency = 0 end if return end function ch_scrabble_points ( ch ) !*****************************************************************************80 ! !! ch_scrabble_points() returns the Scrabble point value of a character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character. ! ! Output: ! ! integer CH_SCRABBLE_POINTS, the point value of ! the character. ! implicit none character ch integer ch_scrabble_points integer ch_to_scrabble integer ic integer, dimension ( 27 ) :: points = (/ & 1, 3, 3, 2, 1, & 4, 2, 4, 1, 8, & 5, 1, 3, 1, 1, & 3, 10, 1, 1, 1, & 1, 4, 4, 8, 4, & 10, 0 /) ! ! Convert character to a Scrabble character index. ! ic = ch_to_scrabble ( ch ) if ( 1 <= ic .and. ic <= 27 ) then ch_scrabble_points = points(ic) else ch_scrabble_points = 0 end if return end function ch_scrabble_select ( ) !*****************************************************************************80 ! !! ch_scrabble_select() selects a character with the Scrabble probability. ! ! Discussion: ! ! There are 100 Scrabble tiles, including two blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2006 ! ! Author: ! ! John Burkardt ! ! Output: ! ! character CH_SCRABBLE_SELECT, the character on a randomly ! chosen Scrabble tile. ! implicit none character ch_scrabble character ch_scrabble_select integer i4_uniform_ab integer tile ! ! Choose a tile between 1 and 100. ! tile = i4_uniform_ab ( 1, 100 ) ! ! Retrieve the character on that tile. ! ch_scrabble_select = ch_scrabble ( tile ) return end subroutine ch_swap ( ch1, ch2 ) !*****************************************************************************80 ! !! ch_swap() swaps two characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 July 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH1, CH2, two characters. ! ! Output: ! ! character CH1, CH2, the values have been interchanged. ! implicit none character ch1 character ch2 character ch3 ch3 = ch1 ch1 = ch2 ch2 = ch3 return end subroutine ch_to_amino_name ( ch, amino_name ) !*****************************************************************************80 ! !! ch_to_amino_name() converts a character to an amino acid name. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 June 2000 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Carl Branden, John Tooze, ! Introduction to Protein Structure, ! Garland Publishing, 1991. ! ! Input: ! ! character CH, the one letter code for an amino acid. ! Lower and upper case letters are treated the same. ! ! Output: ! ! character ( len = * ) AMINO_NAME, the full name of the ! corresponding amino acid. The longest name is 27 characters. ! If the input code is not recognized, then AMINO_NAME will be set to '???'. ! implicit none integer, parameter :: n = 23 character ( len = * ) amino_name character ( len = 27 ), dimension ( n ) :: amino_table = (/ & 'Alanine ', & 'Aspartic acid or Asparagine', & 'Cysteine ', & 'Aspartic acid ', & 'Glutamic acid ', & 'Phenylalanine ', & 'Glycine ', & 'Histidine ', & 'Isoleucine ', & 'Lysine ', & 'Leucine ', & 'Methionine ', & 'Asparagine ', & 'Proline ', & 'Glutamine ', & 'Arginine ', & 'Serine ', & 'Threonine ', & 'Valine ', & 'Tryptophan ', & 'Undetermined amino acid ', & 'Tyrosine ', & 'Glutamic acid or Glutamine ' /) character ch logical ch_eqi character, dimension ( n ) :: ch_table = (/ & 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', & 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', & 'X', 'Y', 'Z' /) integer i do i = 1, n if ( ch_eqi ( ch, ch_table(i) ) ) then amino_name = amino_table(i) return end if end do amino_name = '???' return end subroutine ch_to_braille ( ch, ncol, braille ) !*****************************************************************************80 ! !! ch_to_braille() converts an ASCII character to a Braille character string. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 August 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the ASCII character. ! ! Output: ! ! integer NCOL, the number of columns used to represent ! the character. ! ! character ( len = 6 ) BRAILLE(3), contains, in rows 1 ! through 3 and character columns 1 through NCOL, either a '*' or a ' '. ! implicit none integer, parameter :: num_symbol = 37 character ( len = 6 ) braille(3) character ch logical ch_is_digit logical ch_is_upper integer iascii integer ic_to_ibraille integer ibraille integer ncol ! ! space Aa1 Bb2 Cc3 Dd4 ! Ee5 Ff6 Gg7 Hh8 Ii9 ! Jj0 Kk Ll Mm Nn ! Oo Pp Qq Rr Ss ! Tt Uu Vv Ww Xx ! Yy Zz & , ; ! : . ! () "? ! ' - ! character ( len = 6 ), parameter, dimension ( num_symbol ) :: symbol = (/ & ' ', '* ', '* * ', '** ', '** * ', & '* * ', '*** ', '**** ', '* ** ', ' ** ', & ' *** ', '* * ', '* * * ', '** * ', '** ** ', & '* ** ', '*** * ', '***** ', '* *** ', ' ** * ', & ' **** ', '* **', '* * **', ' *** *', '** **', & '** ***', '* ***', '*** **', ' * ', ' * * ', & ' ** ', ' ** *', ' *** ', ' ****', ' * **', & ' * ', ' **' /) ncol = 0 braille(1)(1:6) = ' ' braille(2)(1:6) = ' ' braille(3)(1:6) = ' ' ! ! A space is treated specially. ! if ( ch == ' ' ) then braille(1)(1:2) = ' ' braille(2)(1:2) = ' ' braille(3)(1:2) = ' ' ncol = 2 return end if ! ! Get the ASCII numeric code of the character. ! iascii = iachar ( ch ) ! ! Get the index of the Braille equivalent. ! ibraille = ic_to_ibraille ( iascii ) if ( 0 <= ibraille ) then ! ! Upper case characters are preceded by a special mark. ! if ( ch_is_upper ( ch ) ) then braille(1)(1:3) = ' ' braille(2)(1:3) = ' ' braille(3)(1:3) = ' * ' ncol = 3 ! ! Digits are preceded by a special mark. ! else if ( ch_is_digit ( ch ) ) then braille(1)(1:3) = ' * ' braille(2)(1:3) = ' * ' braille(3)(1:3) = '** ' ncol = 3 end if braille(1)(ncol+1:ncol+2) = symbol(ibraille)(1:2) braille(2)(ncol+1:ncol+2) = symbol(ibraille)(3:4) braille(3)(ncol+1:ncol+2) = symbol(ibraille)(5:6) ncol = ncol + 2 ! ! Add a trailing "half space". ! braille(1)(ncol+1:ncol+1) = ' ' braille(2)(ncol+1:ncol+1) = ' ' braille(3)(ncol+1:ncol+1) = ' ' ncol = ncol + 1 end if return end subroutine ch_to_ch3_amino ( ch, ch3 ) !*****************************************************************************80 ! !! ch_to_ch3_amino() converts a 1 character to a 3 character code for amino acids. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 November 1999 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Carl Branden, John Tooze, ! Introduction to Protein Structure, ! Garland Publishing, 1991. ! ! Input: ! ! character CH, the one letter code for an amino acid. ! Lower and upper case letters are treated the same. ! ! Output: ! ! character ( len = 3 ) CH3, the three letter code for the ! amino acid. If the input code is not recognized, then CH3 will be '???'. ! implicit none integer, parameter :: n = 23 character ch logical ch_eqi character, parameter, dimension ( n ) :: ch_table = (/ & 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', & 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', & 'X', 'Y', 'Z' /) character ( len = 3 ) ch3 character ( len = 3 ), parameter, dimension ( n ) :: ch3_table = (/ & 'Ala', 'Asx', 'Cys', 'Asp', 'Glu', 'Phe', 'Gly', 'His', 'Ise', 'Lys', & 'Leu', 'Met', 'Asn', 'Pro', 'Gln', 'Arg', 'Ser', 'Thr', 'Val', 'Trp', & 'X ', 'Tyr', 'Glx' /) integer i do i = 1, n if ( ch_eqi ( ch, ch_table(i) ) ) then ch3 = ch3_table(i) return end if end do ch3 = '???' return end subroutine ch_to_digit ( ch, digit ) !*****************************************************************************80 ! !! ch_to_digit() returns the value of a base 10 digit. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Example: ! ! CH DIGIT ! --- ----- ! '0' 0 ! '1' 1 ! ... ... ! '9' 9 ! 'X' -1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the decimal digit, '0' through '9' are legal. ! ! Output: ! ! integer DIGIT, the corresponding value. ! If CH was 'illegal', then DIGIT is -1. ! implicit none character ch integer digit if ( lle ( '0', ch ) .and. lle ( ch, '9' ) ) then digit = iachar ( ch ) - 48 else digit = - 1 end if return end subroutine ch_to_digit_bin ( ch, digit ) !*****************************************************************************80 ! !! ch_to_digit_bin() returns the value of a binary digit. ! ! Discussion: ! ! This routine handles other traditional binary pairs of "digits" ! besides '0' and '1'. ! ! Example: ! ! CH DIGIT ! --- ----- ! '0' 0 ! '1' 1 ! 'T' 1 ! 'F' 0 ! 'Y' 1 ! 'N' 0 ! '+' 1 ! '-' 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the binary digit. ! ! Output: ! ! integer DIGIT, the corresponding value. ! If CH was 'illegal', then DIGIT is -1. ! implicit none character ch integer digit if ( ch == '0' .or. & ch == 'F' .or. & ch == 'f' .or. & ch == '-' .or. & ch == 'N' .or. & ch == 'n' ) then digit = 0 else if ( ch == '1' .or. & ch == 'T' .or. & ch == 't' .or. & ch == '+' .or. & ch == 'Y' .or. & ch == 'y' ) then digit = 1 else digit = -1 end if return end subroutine ch_to_digit_oct ( ch, i ) !*****************************************************************************80 ! !! ch_to_digit_oct() returns the value of an octal digit. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the octal digit, '0' through '7'. ! ! Output: ! ! integer I, the corresponding value, or ! -1 if CH was illegal. ! implicit none character ch integer i i = iachar ( ch ) if ( lle ( '0', ch ) .and. lle ( ch, '7' ) ) then i = i - 48 else if ( ch == ' ' ) then i = 0 else i = -1 end if return end function ch_to_ebcdic ( ch ) !*****************************************************************************80 ! !! ch_to_ebcdic() converts a character to EBCDIC. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantee the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the ASCII character. ! ! Output: ! ! character CH_TO_EBCDIC, the corresponding EBCDIC character, or a ! blank character if no correspondence holds. ! implicit none character ch character ch_to_ebcdic integer i integer ic_to_iebcdic i = ic_to_iebcdic ( iachar ( ch ) ) if ( i /= -1 ) then ch_to_ebcdic = achar ( i ) else ch_to_ebcdic = ' ' end if return end subroutine ch_to_military ( ch, military ) !*****************************************************************************80 ! !! ch_to_military() converts an ASCII character to a Military code word. ! ! Example: ! ! 'A' 'Alpha' ! 'B' 'Bravo' ! 'Z' 'Zulu' ! 'a' 'alpha' ! '7' '7' ! '%' '%' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the ASCII character. ! ! Output: ! ! character ( len = 8 ) MILITARY, the military code word. ! If CH is not an alphabetic letter, then MILITARY is simply set equal to CH. ! implicit none integer a_to_i4 character ch character ( len = 8 ), parameter, dimension ( 26 ) :: code = (/ & 'alpha ', 'bravo ', 'charlie ', 'delta ', 'echo ', & 'foxtrot ', 'golf ', 'hotel ', 'india ', 'juliet ', & 'kilo ', 'lima ', 'mike ', 'november', 'oscar ', & 'papa ', 'quebec ', 'romeo ', 'sierra ', 'tango ', & 'uniform ', 'victor ', 'whiskey ', 'x-ray ', 'yankee ', & 'zulu ' /) integer i character ( len = * ) military if ( 'A' <= ch .and. ch <= 'Z' ) then i = a_to_i4 ( ch ) military = code(i) call ch_cap ( military(1:1) ) else if ( 'a' <= ch .and. ch <= 'z' ) then i = a_to_i4 ( ch ) - 26 military = code(i) else military = ch end if return end subroutine ch_to_morse ( ch, morse ) !*****************************************************************************80 ! !! ch_to_morse() converts an ASCII character to a Morse character string. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 September 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the ASCII character. ! ! Output: ! ! character ( len = 6 ) MORSE, the Morse character string. ! implicit none integer, parameter :: num_symbol = 45 character ch integer iascii integer ic_to_imorse integer imorse character ( len = 6 ) morse character ( len = 6 ), parameter, dimension ( num_symbol ) :: msymbol = (/ & ' ', '.- ', '-... ', '-.-. ', '-.. ', & '. ', '..-. ', '--. ', '.... ', '.. ', & '.--- ', '-.- ', '.-.. ', '-- ', '-. ', & '--- ', '.--. ', '--.- ', '.-. ', '... ', & '- ', '..- ', '...- ', '.-- ', '-..- ', & '-.-- ', '--.. ', '.---- ', '..--- ', '...-- ', & '....- ', '..... ', '-.... ', '--... ', '---.. ', & '----. ', '----- ', '.-.-.-', '--..--', '---...', & '..--..', '.----.', '-....-', '-..-. ', '.-..-.' /) iascii = iachar ( ch ) imorse = ic_to_imorse ( iascii ) if ( imorse == -1 ) then morse = ' ' else morse = msymbol ( imorse ) end if return end function ch_to_rot13 ( ch ) !*****************************************************************************80 ! !! ch_to_rot13() converts a character to its ROT13 equivalent. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantees the ASCII collating sequence. ! ! Two applications of CH_TO_ROT13 to a character will return the original. ! ! As a further scrambling, digits are similarly rotated using ! a "ROT5" scheme. ! ! Example: ! ! Input: Output: ! ! a n ! C P ! J W ! 1 6 ! 5 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be converted. ! ! Output: ! ! character CH_TO_ROT13, the ROT13 equivalent of the character. ! implicit none character ch character ch_to_rot13 integer itemp itemp = iachar ( ch ) ! ! [0:4] -> [5:9] ! if ( 48 <= itemp .and. itemp <= 52 ) then itemp = itemp + 5 ! ! [5:9] -> [0:4] ! else if ( 53 <= itemp .and. itemp <= 57 ) then itemp = itemp - 5 ! ! [A:M] -> [N:Z] ! else if ( 65 <= itemp .and. itemp <= 77 ) then itemp = itemp + 13 ! ! [N:Z] -> [A:M] ! else if ( 78 <= itemp .and. itemp <= 90 ) then itemp = itemp - 13 ! ! [a:m] -> [n:z] ! else if ( 97 <= itemp .and. itemp <= 109 ) then itemp = itemp + 13 ! ! [n:z] -> [a:m] ! else if ( 110 <= itemp .and. itemp <= 122 ) then itemp = itemp - 13 end if ch_to_rot13 = achar ( itemp ) return end function ch_to_scrabble ( ch ) !*****************************************************************************80 ! !! ch_to_scrabble() returns the Scrabble index of a character. ! ! Discussion: ! ! 'A' through 'Z' have indices 1 through 26, and blank is index 27. ! Case is ignored. All other characters return index -1. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character. ! ! Output: ! ! integer CH_TO_SCRABBLE, the Scrabble index of ! the character. ! implicit none integer a_to_i4 character ch character ch_copy integer ch_to_scrabble integer ic if ( ch == ' ' ) then ch_to_scrabble = 27 return end if ch_copy = ch call ch_cap ( ch_copy ) ic = a_to_i4 ( ch_copy ) if ( 1 <= ic .and. ic <= 26 ) then ch_to_scrabble = ic else ch_to_scrabble = -1 end if return end subroutine ch_to_soundex ( ch, soundex ) !*****************************************************************************80 ! !! ch_to_soundex() converts an ASCII character to a Soundex character. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantees the ASCII collating sequence. ! ! The soundex code is used to replace words by a code of up to four ! digits. Similar sounding words will often have identical soundex ! codes. ! ! Soundex Letters ! ------- --------------- ! 0 A E I O U Y H W ! 1 B B P V ! 2 C G J K Q S X Z ! 3 D T ! 4 L ! 5 M N ! 6 R ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 January 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the ASCII character. ! ! Output: ! ! character SOUNDEX, the Soundex character, which is ! '0', '1', '2', '3', '4', '5', '6', or ' '. ! implicit none character ch integer iascii integer ic_to_isoundex integer isoundex character soundex iascii = iachar ( ch ) isoundex = ic_to_isoundex ( iascii ) if ( isoundex == -1 ) then soundex = ' ' else soundex = achar ( isoundex ) end if return end subroutine ch_to_sym ( ch, sym ) !*****************************************************************************80 ! !! ch_to_sym() returns a printable symbol for any ASCII character. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the character to be represented. ! ! Output: ! ! character ( len = 4 ) SYM, is the printable symbol for CHR. ! implicit none character ch integer i integer put character ( len = 4 ) sym i = iachar ( ch ) sym = ' ' put = 0 ! ! Characters 128-255 are symbolized with a ! prefix. ! Then shift them down by 128. ! Now all values of I are between 0 and 127. ! if ( 128 <= i ) then i = mod ( i, 128 ) put = put + 1 sym(put:put) = '!' end if ! ! Characters 0-31 are symbolized with a ^ prefix. ! Shift them up by 64. Now all values of I are between 32 and 127. ! if ( i <= 31 ) then i = i + 64 put = put + 1 sym(put:put) = '^' end if ! ! Character 32 becomes SP. ! Characters 32 through 126 are themselves. ! Character 127 is DEL. ! if ( i == 32 ) then put = put + 1 sym(put:put+1) = 'SP' else if ( i <= 126 ) then put = put + 1 sym(put:put) = achar ( i ) else if ( i == 127 ) then put = put + 1 sym(put:put+2) = 'DEL' end if return end function ch_uniform ( clo, chi ) !*****************************************************************************80 ! !! ch_uniform() returns a random character in a given range. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, ! which guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 January 2012 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CLO, CHI, the minimum and maximum acceptable characters. ! ! Output: ! ! character CH_UNIFORM, the randomly chosen character. ! implicit none character ch_uniform character chi character clo integer i integer i4_uniform_ab integer ihi integer ilo ilo = iachar ( clo ) ihi = iachar ( chi ) i = i4_uniform_ab ( ilo, ihi ) ch_uniform = achar ( i ) return end subroutine ch3_to_ch_amino ( ch3, ch ) !*****************************************************************************80 ! !! ch3_to_ch_amino() converts a 3 character to a 1 character code for amino acids. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 November 1999 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Carl Branden, John Tooze, ! Introduction to Protein Structure, ! Garland Publishing, 1991. ! ! Input: ! ! character ( len = 3 ) CH3, presumably the 3 letter code for an ! amino acid. Lower and upper case letters are treated the same. ! ! Output: ! ! character CH, the one letter code for the amino acid. ! If the input code is not recognized, then CH will be '?'. ! implicit none integer, parameter :: n = 23 character ch character, parameter, dimension ( n ) :: ch_table = (/ & 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', & 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', & 'X', 'Y', 'Z' /) character ( len = 3 ) ch3 character ( len = 3 ), parameter, dimension ( n ) :: ch3_table = (/ & 'Ala', 'Asx', 'Cys', 'Asp', 'Glu', 'Phe', 'Gly', 'His', 'Ise', 'Lys', & 'Leu', 'Met', 'Asn', 'Pro', 'Gln', 'Arg', 'Ser', 'Thr', 'Val', 'Trp', & 'X ', 'Tyr', 'Glx' /) integer i logical s_eqi do i = 1, n if ( s_eqi ( ch3, ch3_table(i) ) ) then ch = ch_table(i) return end if end do ch = '?' return end subroutine ch4_to_i4 ( ch4, i4 ) !*****************************************************************************80 ! !! ch4_to_i4() converts a four character string to an I4. ! ! Example: ! ! Adam 1097097581 ! Bill 1114205292 ! Crow 1131573111 ! Dave 1147237989 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 May 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 4 ) CH4, the character value. ! ! Output: ! ! integer I4, a corresponding value. ! implicit none character c1 character c2 character c3 character c4 character ( len = 4 ) ch4 integer i4 integer j1 integer j2 integer j3 integer j4 read ( ch4, '(4a1)' ) c1, c2, c3, c4 j1 = iachar ( c1 ) j2 = iachar ( c2 ) j3 = iachar ( c3 ) j4 = iachar ( c4 ) call mvbits ( j1, 0, 8, i4, 0 ) call mvbits ( j2, 0, 8, i4, 8 ) call mvbits ( j3, 0, 8, i4, 16 ) call mvbits ( j4, 0, 8, i4, 24 ) return end subroutine ch4_to_r4 ( ch4, r4 ) !*****************************************************************************80 ! !! ch4_to_r4() converts a 4 character string to an R4. ! ! Discussion: ! ! The MVBITS routine requires the two word arguments to be of the ! same arithmetic type, so we first need to use the TRANSFER ! function so that the data inside an integer word can be copied ! verbatin into a real. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 May 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 4 ) CH4, the character value. ! ! Output: ! ! real ( kind = rk ) R4, a corresponding real value. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character c1 character c2 character c3 character c4 character ( len = 4 ) ch4 integer i4 integer j real ( kind = rk ) r4 read ( ch4, '(4a1)' ) c1, c2, c3, c4 j = iachar ( c1 ) call mvbits ( j, 0, 8, i4, 0 ) j = iachar ( c2 ) call mvbits ( j, 0, 8, i4, 8 ) j = iachar ( c3 ) call mvbits ( j, 0, 8, i4, 16 ) j = iachar ( c4 ) call mvbits ( j, 0, 8, i4, 24 ) r4 = transfer ( i4, r4 ) return end subroutine ch4vec_to_i4vec ( n, s, i4vec ) !*****************************************************************************80 ! !! ch4vec_to_i4vec() converts an string of characters into an array of integers. ! ! Discussion: ! ! This routine can be useful when trying to write character data to an ! unformatted direct access file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of sets of 4 characters ! in the string. ! ! character ( len = 4*N ) S, the string of characters. ! Each set of 4 characters is assumed to represent an integer. ! ! Output: ! ! integer I4VEC(N), the integers encoded in the string. ! implicit none integer n integer i integer i4vec(n) integer j character ( len = 4 * n ) s do i = 1, n j = 4 * ( i - 1 ) + 1 call ch4_to_i4 ( s(j:j+3), i4vec(i) ) end do return end subroutine chr4_to_8 ( s1, s2 ) !*****************************************************************************80 ! !! chr4_to_8() replaces pairs of hexadecimal digits by a character. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be decoded. ! ! Output: ! ! character ( len = * ) S2, the output string. ! implicit none integer i integer i1 integer j1 integer k1 integer nchar2 integer nroom character ( len = * ) s1 integer s1_length character ( len = * ) s2 ! ! Set S1_LENGTH to the number of characters to be copied. ! nchar2 = 0 s1_length = len ( s1 ) if ( mod ( s1_length, 2 ) == 1 ) then s1_length = s1_length - 1 end if if ( s1_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHR4_TO_8 - Serious error!' write ( *, '(a)' ) ' The input string has nonpositive length!' return end if ! ! Make sure we have enough room. ! nroom = len ( s2 ) if ( 2 * nroom < s1_length ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHR4_TO_8 - Warning!' write ( *, '(a)' ) ' Not enough room in the output string.' write ( *, '(a,i8)' ) ' Positions available = ', nroom write ( *, '(a,i8)' ) ' Positions needed = ', s1_length / 2 write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The program will drop excess characters.' s1_length = 2 * nroom end if do i = 1, s1_length, 2 call hex_digit_to_i4 ( s1(i:i), j1 ) call hex_digit_to_i4 ( s1(i+1:i+1), k1 ) ! ! Make sure that the values of J1 and K1 are legal. If not, ! set I1 so that it returns a blank character. ! if ( ( 0 <= j1 .and. j1 <= 15) .and. ( 0 <= k1 .and. k1 <= 15) ) then i1 = 16 * j1 + k1 else i1 = 0 end if nchar2 = nchar2 + 1 s2(nchar2:nchar2) = achar ( i1 ) end do return end subroutine chr8_to_4 ( s1, s2 ) !*****************************************************************************80 ! !! chr8_to_4() replaces characters by a pair of hexadecimal digits. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Unprintable characters (0 through 31, or 127 through 255) ! can be displayed. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be replaced. ! ! Output: ! ! character ( len = * ) S2, the output string. ! implicit none character c integer i integer i1 integer j integer j1 integer k1 integer nroom character ( len = * ) s1 integer s1_length character ( len = * ) s2 ! ! Set S1_LENGTH to the number of characters to be copied. ! s1_length = len ( s1 ) if ( s1_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHR8_TO_4 - Serious error!' write ( *, '(a)' ) ' The input string has nonpositive length!' return end if ! ! Make sure we have enough room. ! nroom = len ( s2 ) if ( nroom < 2 * s1_length ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHR8_TO_4 - Warning!' write ( *, '(a)' ) ' The output string isn''t long enough to hold' write ( *, '(a)' ) ' all the information!' write ( *, '(a,i8)' ) ' Positions available: ', nroom write ( *, '(a,i8)' ) ' Positions needed: ', 2 * s1_length write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' We will do a partial conversion.' s1_length = nroom / 2 end if j = 0 do i = 1, s1_length c = s1(i:i) i1 = iachar ( c ) ! ! Compute J1 and K1 so that I1 = J1*16+K1. ! j1 = i1 / 16 k1 = i1 - 16 * j1 j = j + 1 call i4_to_hex_digit ( j1, s2(j:j) ) j = j + 1 call i4_to_hex_digit ( k1, s2(j:j) ) end do return end subroutine chra_to_s ( s1, s2 ) !*****************************************************************************80 ! !! chra_to_s() replaces control characters by printable symbols. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Table: ! ! IACHAR(c) Symbol ! -------- ------ ! 0 ^@ ! 1 ^A ! ... ... ! 31 ^_ ! 32 (space) ! ... ... ! 126 ~ ! 127 DEL ! 128 !^@ ! ... ... ! 159 !^_ ! 160 !(space) ! ... ... ! 254 !~ ! 255 !DEL ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be operated on. ! ! Output: ! ! character ( len = * ) S2, a copy of S1, except that each ! control character has been replaced by a symbol. ! implicit none logical ch_is_control integer get integer put integer lsym character ( len = * ) s1 integer s1_length character ( len = * ) s2 character ( len = 4 ) sym s1_length = len_trim ( s1 ) s2 = ' ' put = 1 do get = 1, s1_length if ( ch_is_control ( s1(get:get) ) ) then call ch_to_sym ( s1(get:get), sym ) lsym = len_trim ( sym ) s2(put:put+lsym-1) = sym(1:lsym) put = put + lsym else s2(put:put) = s1(get:get) put = put + 1 end if end do return end subroutine chrasc ( iascii, nascii, string ) !*****************************************************************************80 ! !! chrasc() converts a vector of ASCII codes into character strings. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! The length of the strings is determined via the ! LEN function. The entries in IASCII are converted and ! stored into the characters of STRING(1), and when that is ! full, into STRING(2) and so on until all the entries have ! been converted. ! ! If any entry of IASCII is less than 0, or greater than ! 255, it is handled as though it were 0. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IASCII(NASCII), a vector presumed to ! contain entries between 0 and 255, the ASCII codes of ! individual characters. ! ! integer NASCII, the number of ASCII codes input. ! ! Output: ! ! character ( len = * ) STRING(*). STRING is assumed to be ! a vector of sufficient size to contain the information ! input in IASCII. ! implicit none integer i integer iascii(*) integer ihi integer itemp integer ix integer j integer nascii integer nchar character ( len = * ) string(*) nchar = len ( string(1) ) ix = 0 ihi = ( (nascii-1) / nchar ) + 1 do i = 1, ihi do j = 1, nchar ix = ix + 1 if ( nascii <= ix ) then return end if itemp = iascii ( ix ) if ( itemp < 0 .or. 255 < itemp ) then itemp = 0 end if string(i)(j:j) = achar ( itemp ) end do end do return end subroutine chrass ( s, lhs, rhs ) !*****************************************************************************80 ! !! chrass() "understands" an assignment statement of the form LHS = RHS. ! ! Discussion: ! ! CHRASS returns a string containing the left hand side, and another ! string containing the right hand side. ! ! Leading and trailing spaces are removed from the right hand side ! and the left hand side. ! ! Normally, LHS will be the name of a variable, which is ! assumed to be whatever appears before the first equals ! sign in the string. ! ! If the input line was blank, then LHS will equal ' '. ! ! If the input line contains an equal sign, but nothing ! before the equals sign except blanks, then LHS will be ' '. ! ! If the input line does not contain an "=" sign, then ! NAME will contain the text of the whole line. ! ! If an error occurred while trying to process the ! input line, NAME will contain the text of the line.. ! ! If the line began with "#", then NAME will contain the ! text of the line. ! ! If the line equals "end-of-input", then NAME will contain ! the text of the line. ! ! RHS is whatever appears on the right hand side of the ! first equals sign in the string. ! ! If S is blank, then RHS is ' '. ! ! If the string contains no equals sign, then RHS is ' '. ! ! If the string contains nothing to the right of the first equals ! sign, but blanks, then RHS is ' '. ! ! Example: ! ! S Rhs Lhs ! ! 'a = 1.0' 'a' '1.0' ! 'n = -17' 'n' '-17' ! 'scale = +5.3E-2' 'scale' '+5.3E-2' ! 'filename = myprog.f' 'filename' 'myprog.f' ! '= A pot of gold' ' ' 'A pot of gold' ! 'Fred' 'Fred' ' ' ! '= Bob' ' ' 'Bob' ! '1=2, 2=3, 3=4' '1' '2, 2=3, 3=4' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the assignment statement to be broken up. ! ! Output: ! ! character ( len = * ) LHS, the left hand side of the assignment statement. ! ! character ( len = * ) RHS, the right hand side of the assignment statement. ! implicit none integer first integer iequal character ( len = * ) lhs character ( len = * ) rhs character ( len = * ) s integer s_first_nonblank integer s_length ! ! Set default values ! lhs = ' ' rhs = ' ' ! ! Find the last nonblank. ! s_length = len_trim ( s ) if ( s_length <= 0 ) then return end if ! ! Look for the first equals sign. ! iequal = index ( s, '=' ) ! ! If no equals sign, then LHS = S and return. ! if ( iequal == 0 ) then first = s_first_nonblank ( s ) lhs = s(first:s_length) return end if ! ! Otherwise, copy LHS = S(1:IEQUAL-1), RHS = S(IEQUAL+1:). ! lhs = s(1:iequal-1) if ( iequal + 1 <= s_length ) then rhs = s(iequal+1:) end if ! ! Now shift the strings to the left. ! lhs = adjustl ( lhs ) rhs = adjustl ( rhs ) return end subroutine chrctf ( s, itop, ibot, ierror, length ) !*****************************************************************************80 ! !! chrctf() reads an integer or rational fraction from a string. ! ! Discussion: ! ! The integer may be in real format, for example '2.25'. The routine ! returns ITOP and IBOT. If the input number is an integer, ITOP ! equals that integer, and IBOT is 1. But in the case of 2.25, ! the program would return ITOP = 225, IBOT = 100. ! ! Legal input is: ! ! blanks, ! initial sign, ! blanks, ! integer part, ! decimal point, ! fraction part, ! 'E' or 'e' or 'D' or 'd', exponent marker, ! exponent sign, ! exponent integer part, ! blanks, ! final comma or semicolon. ! ! with most quantities optional. ! ! Example: ! ! S ITOP IBOT ! ! '1' 1 1 ! ' 1 ' 1 1 ! '1A' 1 1 ! '12,34,56' 12 1 ! ' 34 7' 34 1 ! '-1E2ABCD' -100 1 ! '-1X2ABCD' -1 1 ! ' 2E-1' 2 10 ! '23.45' 2345 100 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate when no more characters ! can be read to form a legal integer. Blanks, commas, ! or other nonnumeric data will, in particular, cause ! the conversion to halt. ! ! Output: ! ! integer ITOP, the integer read from the string, ! assuming that no negative exponents or fractional parts ! were used. Otherwise, the 'integer' is ITOP/IBOT. ! ! integer IBOT, the integer divisor required to ! represent numbers which are in real format or have a ! negative exponent. ! ! integer IERROR, error flag. ! 0 if no errors, ! Value of IHAVE when error occurred otherwise. ! ! integer LENGTH, the number of characters read from ! the string to form the number. ! implicit none character c logical ch_eqi integer ibot integer ierror integer ihave integer isgn integer iterm integer itop integer jsgn integer jtop integer length integer ndig character ( len = * ) s integer s_length s_length = len_trim ( s ) ierror = 0 length = -1 isgn = 1 itop = 0 ibot = 1 jsgn = 1 jtop = 0 ihave = 1 iterm = 0 do while ( length < s_length ) length = length + 1 c = s(length+1:length+1) ! ! Blank. ! if ( c == ' ' ) then if ( ihave == 2 ) then else if ( ihave == 6 .or. ihave == 7 ) then iterm = 1 else if ( 1 < ihave ) then ihave = 11 end if ! ! Comma. ! else if ( c == ',' .or. c == ';' ) then if ( ihave /= 1 ) then iterm = 1 ihave = 12 length = length + 1 end if ! ! Minus sign. ! else if ( c == '-' ) then if ( ihave == 1 ) then ihave = 2 isgn = -1 else if ( ihave == 6 ) then ihave = 7 jsgn = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 1 ) then ihave = 2 else if ( ihave == 6 ) then ihave = 7 else iterm = 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( ihave < 4 ) then ihave = 4 else iterm = 1 end if ! ! Exponent marker. ! else if ( ch_eqi ( c, 'E' ) .or. ch_eqi ( c, 'D' ) ) then if ( ihave < 6 ) then ihave = 6 else iterm = 1 end if ! ! Digit. ! else if ( lle ( '0', c ) .and. lle ( c, '9' ) .and. ihave < 11 ) then if ( ihave <= 2 ) then ihave = 3 else if ( ihave == 4 ) then ihave = 5 else if ( ihave == 6 .or. ihave == 7 ) then ihave = 8 end if call ch_to_digit ( c, ndig ) if ( ihave == 3 ) then itop = 10 * itop + ndig else if ( ihave == 5 ) then itop = 10 * itop + ndig ibot = 10 * ibot else if ( ihave == 8 ) then jtop = 10 * jtop + ndig end if ! ! Anything else is regarded as a terminator. ! else iterm = 1 end if if ( iterm == 1 ) then exit end if end do if ( iterm /= 1 .and. length + 1 == s_length ) then length = s_length end if ! ! Number seems to have terminated. Have we got a legal number? ! if ( ihave == 1 .or. ihave == 2 .or. ihave == 6 .or. ihave == 7 ) then ierror = ihave write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHRCTF - Serious error!' write ( *, '(a)' ) ' Illegal input:' // trim ( s ) return end if ! ! Number seems OK. Form it. ! if ( jsgn == 1 ) then itop = itop * 10**jtop else ibot = ibot * 10**jtop end if itop = isgn * itop return end subroutine chrctg ( s, itop, ibot, ierror, length ) !*****************************************************************************80 ! !! chrctg() reads an integer, decimal fraction or a ratio from a string. ! ! Discussion: ! ! CHRCTG returns an equivalent ratio (ITOP/IBOT). ! ! If the input number is an integer, ITOP equals that integer, and ! IBOT is 1. But in the case of 2.25, the program would return ! ITOP = 225, IBOT = 100. ! ! A ratio is either ! a number ! or ! a number, "/", a number. ! ! A "number" is defined as: ! ! blanks, ! initial sign, ! integer part, ! decimal point, ! fraction part, ! E, ! exponent sign, ! exponent integer part, ! blanks, ! final comma or semicolon, ! ! Examples of a number: ! ! 15, 15.0, -14E-7, E2, -12.73E-98, etc. ! ! Examples of a ratio: ! ! 15, 1/7, -3/4.9, E2/-12.73 ! ! Example: ! ! S ITOP IBOT ! ! '1' 1 1 ! ' 1 ' 1 1 ! '1A' 1 1 ! '12,34,56' 12 1 ! ' 34 7' 34 1 ! '-1E2ABCD' -100 1 ! '-1X2ABCD' -1 1 ! ' 2E-1' 2 10 ! '23.45' 2345 100 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate when no more characters ! can be read to form a legal integer. Blanks, commas, ! or other nonnumeric data will, in particular, cause ! the conversion to halt. ! ! Output: ! ! integer ITOP, the integer read from the string, ! assuming that no negative exponents or fractional parts ! were used. Otherwise, the 'integer' is ITOP/IBOT. ! ! integer IBOT, the integer divisor required to ! represent numbers which are in decimal format or have a ! negative exponent. ! ! integer IERROR, error flag. ! 0 if no errors, ! Value of IHAVE in CHRCTF when error occurred otherwise. ! ! integer LENGTH, the number of characters read. ! implicit none integer i integer i4_gcd integer ibot integer ibotb integer ierror integer itemp integer itop integer itopb integer length integer length2 character ( len = * ) s integer s_length itop = 0 ibot = 1 length = 0 call chrctf ( s, itop, ibot, ierror, length ) if ( ierror /= 0) then return end if ! ! The number is represented as a fraction. ! If the next nonblank character is "/", then read another number. ! s_length = len_trim ( s ) do i = length + 1, s_length - 1 if ( s(i:i) == '/' ) then call chrctf ( s(i+1:), itopb, ibotb, ierror, length2 ) if ( ierror /= 0 ) then return end if itop = itop * ibotb ibot = ibot * itopb itemp = i4_gcd ( itop, ibot ) itop = itop / itemp ibot = ibot / itemp length = i + length2 return else if ( s(i:i) /= ' ' ) then return end if end do return end subroutine chrcti2 ( s, intval, ierror, length ) !*****************************************************************************80 ! !! chrcti2() finds and reads an integer from a string. ! ! Discussion: ! ! The routine is given a string which may contain one or more integers. ! Starting at the first character position, it looks for the first ! substring that could represent an integer. If it finds such a string, ! it returns the integer's value, and the position of the last character ! read. ! ! Example: ! ! S INTVAL LENGTH ! ! 'Apollo 13' 13 9 ! ' 1 ' 1 6 ! '1A' 1 1 ! '12,34,56' 12 2 ! 'A1A2A3' 1 2 ! '-1E2ABCD' -1 2 ! '-X20ABCD' 20 4 ! '23.45' 23 2 ! ' N = 34, $' 34 7 ! 'Oops!' 0 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 September 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be read. ! Reading will begin at position 1 and terminate at the end of the ! string, or when no more characters can be read to form a legal integer. ! Blanks, commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! integer INTVAL, the integer read from the string, ! or 0 if there was an error. ! ! integer IERROR, 0 an integer was found, ! 1 if no integer found. ! ! integer LENGTH, the number of characters read. ! implicit none character c integer i integer idig integer ierror integer ihave integer intval integer isgn integer iterm integer length character ( len = * ) s integer s_length s_length = len_trim ( s ) ierror = 0 i = 0 isgn = 1 intval = 0 ihave = 0 iterm = 0 ! ! Examine the next character. ! do while ( iterm /= 1 ) i = i + 1 if ( s_length < i ) then iterm = 1 else c = s(i:i) ! ! Minus sign. ! if ( c == '-' ) then if ( ihave == 0 ) then ihave = 1 isgn = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 0 ) then ihave = 1 else iterm = 1 end if ! ! Digit. ! else if ( lle ( '0', c ) .and. lle ( c, '9' ) ) then ihave = 2 call ch_to_digit ( c, idig ) intval = 10 * intval + idig ! ! Blank or TAB. ! else if ( ihave == 2 ) then iterm = 1 else ihave = 0 end if end if end if end do if ( ihave == 2 ) then length = i - 1 intval = isgn * intval else ierror = 0 length = 0 intval = 0 end if return end subroutine chrctp ( s, cval, ierror, length ) !*****************************************************************************80 ! !! chrctp() reads a parenthesized complex number from a string. ! ! Discussion: ! ! The routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the number. ! ! Legal input is: ! ! 1 blanks, ! ! 2 left parenthesis, REQUIRED ! ! 3 blanks ! 4 '+' or '-' sign, ! 5 blanks ! 6 integer part, ! 7 decimal point, ! 8 fraction part, ! 9 'E' or 'e' or 'D' or 'd', exponent marker, ! 10 exponent sign, ! 11 exponent integer part, ! 12 exponent decimal point, ! 13 exponent fraction part, ! 14 blanks, ! ! 15 comma, REQUIRED ! ! 16 blanks ! 17 '+' or '-' sign, ! 18 blanks ! 19 integer part, ! 20 decimal point, ! 21 fraction part, ! 22 'E' or 'e' or 'D' or 'd', exponent marker, ! 23 exponent sign, ! 24 exponent integer part, ! 25 exponent decimal point, ! 26 exponent fraction part, ! 27 blanks, ! ! 28 right parenthesis, REQUIRED ! ! Example: ! ! S CVAL IERROR LENGTH ! ! '(1, 1)' 1 + 1 i 0 5 ! '( 20 , 99 )' 20+99i 0 11 ! '(-1.2E+2, +30E-2)' -120+0.3i 0 17 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read to form a legal real. Blanks, ! commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! complex ( kind = rk ) CVAL, the value read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! 1, the string was empty. ! 2, Did not find left parenthesis. ! 3, Could not read A correctly. ! 4, Did not find the comma. ! 5, Could not read B correctly. ! 6, Did not find right parenthesis. ! ! integer LENGTH, the number of characters read. ! implicit none integer, parameter :: ck = kind ( ( 1.0E+00, 1.0E+00 ) ) integer, parameter :: rk = kind ( 1.0E+00 ) real ( kind = rk ) aval real ( kind = rk ) bval character c complex ( kind = ck ) cval integer ichr integer ierror integer length character ( len = * ) s ! ! Initialize the return arguments. ! ierror = 0 aval = 0 bval = 0 cval = cmplx ( aval, bval, kind = ck ) length = 0 ! ! Get the length of the line, and if it's zero, return. ! if ( len_trim ( s ) <= 0 ) then ierror = 1 return end if ! ! Is the next character a left parenthesis, like it must be? ! call nexchr ( s, ichr, c ) if ( c /= '(' ) then ierror = 2 return end if length = ichr ! ! Is the next character a comma? Then a = 0. ! call nexchr ( s(length+1:), ichr, c ) if ( c == ',' ) then aval = 0 length = length + ichr ! ! Read the A value. ! else call s_to_r4 ( s(length+1:), aval, ierror, ichr ) if ( ierror /= 0 ) then ierror = 3 length = 0 return end if length = length + ichr ! ! Expect to read the comma ! if ( s(length:length) /= ',' ) then ierror = 4 length = 0 return end if end if ! ! Is the next character a left parenthesis? Then b = 0. ! call nexchr ( s(length+1:), ichr, c ) if ( c == ')' ) then bval = 0 length = length + ichr ! ! Read the B value. ! else call s_to_r4 ( s(length+1:), bval, ierror, ichr ) if ( ierror /= 0 ) then ierror = 5 length = 0 return end if length = length + ichr ! ! Expect to read the right parenthesis. ! call nexchr ( s(length+1:), ichr, c ) if ( c /= ')' ) then ierror = 6 length = 0 return end if end if length = length + ichr cval = cmplx ( aval, bval, kind = ck ) return end subroutine chrs_to_a ( s1, s2 ) !*****************************************************************************80 ! !! chrs_to_a() replaces all control symbols by control characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1 is the string to be operated on. ! ! Output: ! ! character ( len = * ) S2 is a copy of S1, except that each ! control symbol has been replaced by a control character. ! implicit none character c integer ihi integer ilo integer put integer nchar2 character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len_trim ( s1 ) nchar2 = len ( s2 ) ihi = 0 put = 0 do if ( s1_length <= ihi ) then return end if ilo = ihi + 1 call sym_to_ch ( s1(ilo:), c, ihi ) put = put + 1 if ( nchar2 < put ) then exit end if s2(put:put) = c end do return end subroutine chvec_permute ( n, a, p ) !*****************************************************************************80 ! !! chvec_permute() permutes a character vector in place. ! ! Discussion: ! ! This routine permutes an array of character "objects", but the same ! logic can be used to permute an array of objects of any arithmetic ! type, or an array of objects of any complexity. The only temporary ! storage required is enough to store a single object. The number ! of data movements made is N + the number of cycles of order 2 or more, ! which is never more than N + N/2. ! ! Example: ! ! Input: ! ! N = 5 ! P = ( 2, 4, 5, 1, 3 ) ! A = ( 'B', 'D', 'E', 'A', 'C' ) ! ! Output: ! ! A = ( 'A', 'B', 'C', 'D', 'E' ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of objects. ! ! character A(N), the array to be permuted. ! ! integer P(N), the permutation. P(I) = J means ! that the I-th element of the output array should be the J-th ! element of the input array. P must be a legal permutation ! of the integers from 1 to N, otherwise the algorithm will ! fail catastrophically. ! ! Output: ! ! character A(N), the array to be permuted. ! implicit none integer n character a(n) character a_temp integer ierror integer get integer put integer istart integer p(n) call perm_check ( n, p, ierror ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHVEC_PERMUTE - Fatal error!' write ( *, '(a)' ) ' The input array does not represent' write ( *, '(a)' ) ' a proper permutation. In particular, the' write ( *, '(a,i8)' ) ' array is missing the value ', ierror stop 1 end if ! ! Search for the next element of the permutation that has not been used. ! do istart = 1, n if ( p(istart) < 0 ) then cycle else if ( p(istart) == istart ) then p(istart) = -p(istart) cycle else a_temp = a(istart) get = istart ! ! Copy the new value into the vacated entry. ! do put = get get = p(get) p(put) = -p(put) if ( get < 1 .or. n < get ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CHVEC_PERMUTE - Fatal error!' write ( *, '(a)' ) ' "get" character is out of bounds.' stop 1 end if if ( get == istart ) then a(put) = a_temp exit end if a(put) = a(get) end do end if end do ! ! Restore the signs of the entries. ! p(1:n) = - p(1:n) return end subroutine chvec_print ( n, a, title ) !*****************************************************************************80 ! !! chvec_print() prints a character vector. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of components of the vector. ! ! character A(N), the vector to be printed. ! ! character ( len = * ) TITLE, a title. ! implicit none integer n character a(n) logical ch_is_printable integer i integer ihi integer ilo integer j character ( len = 255 ) string character ( len = * ) title write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' ' do ilo = 1, n, 80 ihi = min ( ilo + 79, n ) string = ' ' do i = ilo, ihi j = i + 1 - ilo if ( ch_is_printable ( a(i) ) ) then string(j:j) = a(i) end if end do write ( *, '(a)' ) trim ( string ) end do return end subroutine chvec_reverse ( n, x ) !*****************************************************************************80 ! !! chvec_reverse() reverses the elements of a character vector. ! ! Example: ! ! Input: ! ! N = 4, X = ( 'L', 'I', 'V', 'E' ). ! ! Output: ! ! X = ( 'E', 'V', 'I', 'L' ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 July 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in the array. ! ! character X(N), the array to be reversed. ! ! Output: ! ! character X(N), the array to be reversed. ! implicit none integer n character cval integer i character x(n) do i = 1, n/2 cval = x(i) x(i) = x(n+1-i) x(n+1-i) = cval end do return end subroutine chvec_to_s ( n, chvec, s ) !*****************************************************************************80 ! !! chvec_to_s() converts a character vector to a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 March 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of characters to convert. ! ! character CHVEC(N), a vector of characters. ! ! Output: ! ! character ( len = * ) S, a string of characters. ! implicit none integer n character chvec(n) integer i character ( len = * ) s do i = 1, min ( n, len ( s ) ) s(i:i) = chvec(i) end do return end subroutine chvec2_print ( m, a, n, b, title ) !*****************************************************************************80 ! !! chvec2_print() prints two vectors of characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 09 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer M, the length of the first sequence. ! ! character A(M), the first sequence. ! ! integer N, the length of the second sequence. ! ! character B(N), the second sequence. ! ! character ( len = * ), a title. ! implicit none integer m integer n character a(m) character ai character b(n) character bi integer i character ( len = * ) title write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' ' do i = 1, max ( m, n ) if ( i <= m ) then ai = a(i) else ai = ' ' end if if ( i <= n ) then bi = b(i) else bi = ' ' end if write ( *, '(i3,2x,a1,2x,a1)' ) i, ai, bi end do return end subroutine comma ( s ) !*****************************************************************************80 ! !! comma() moves commas left through blanks in a string. ! ! Example: ! ! Input: Output: ! ----- ------ ! "To Henry , our dog" "To Henry, our dog" ! " , , ," ",,, " ! " 14.0 ," " 14.0, " ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string in which the ! commas are to be shifted left through blanks. ! ! Output: ! ! character ( len = * ) S, the shifted string. ! implicit none integer iblank integer icomma character ( len = * ) s icomma = len_trim ( s ) do while ( 1 < icomma ) if ( s(icomma:icomma) == ',' ) then iblank = icomma do while ( 1 < iblank ) if ( s(iblank-1:iblank-1) /= ' ' ) then exit end if iblank = iblank - 1 end do if ( icomma /= iblank ) then s(icomma:icomma) = ' ' s(iblank:iblank) = ',' end if end if icomma = icomma - 1 end do return end subroutine dec_to_s_left ( ival, jval, s ) !*****************************************************************************80 ! !! dec_to_s_left() returns a left-justified representation of IVAL * 10^JVAL. ! ! Example: ! ! IVAL JVAL S ! ---- ---- ------ ! 0 0 0 ! 21 3 21000 ! -3 0 -3 ! 147 -2 14.7 ! 16 -5 0.00016 ! 34 30 Inf ! 123 -21 0.0000000000000000012 ! 34 -30 0.0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 13 September 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IVAL, JVAL, integers which represent ! the decimal. ! ! Output: ! ! character ( len = * ) S, the representation of the value. ! The string is 'Inf' or '0.0' if the value was too large ! or small to represent with a fixed point format. ! implicit none character ( len = 22 ) chrrep integer i integer get1 integer get2 integer put1 integer put2 integer ival integer jval integer ndigit integer nleft character ( len = * ) s integer s_length s = ' ' if ( ival == 0 ) then s = '0' return end if s_length = len ( s ) ! ! Store a representation of IVAL in CHRREP. ! write ( chrrep, '(i22)' ) ival call s_blank_delete ( chrrep ) ndigit = len_trim ( chrrep ) ! ! Inf if JVAL is positive, and S_LENGTH < NDIGIT + JVAL. ! if ( 0 < jval ) then if ( s_length < ndigit + jval ) then s = 'Inf' return end if end if ! ! Underflow if JVAL is negative, and S_LENGTH < 3 + NDIGIT - JVAL. ! if ( jval < 0 ) then if ( 0 < ival ) then if ( s_length < 3 - ndigit - jval ) then s = '0.0' return end if else if ( s_length < 5 - ndigit - jval ) then s = '0.0' return end if end if end if ! ! If JVAL is nonnegative, insert trailing zeros. ! if ( 0 <= jval ) then s(1:ndigit) = chrrep(1:ndigit) do i = ndigit + 1, ndigit + jval s(i:i) = '0' end do else if ( jval < 0 ) then put2 = 0 get2 = 0 ! ! Sign. ! if ( ival < 0 ) then put1 = 1 put2 = 1 get2 = 1 s(put1:put2) = '-' ndigit = ndigit - 1 end if ! ! Digits of the integral part. ! if ( 0 < ndigit + jval ) then put1 = put2 + 1 put2 = put1 + ndigit + jval -1 get1 = get2 + 1 get2 = get1 + ndigit+jval - 1 s(put1:put2) = chrrep(get1:get2) else put1 = put2 + 1 put2 = put1 s(put1:put2) = '0' end if ! ! Decimal point. ! put1 = put2 + 1 put2 = put1 s(put1:put2) = '.' ! ! Leading zeroes. ! do i = 1, - jval - ndigit put1 = put2 + 1 put2 = put1 s(put1:put2) = '0' end do nleft = min ( -jval, ndigit ) nleft = min ( nleft, s_length - put2 ) put1 = put2 + 1 put2 = put1 + nleft - 1 get1 = get2 + 1 get2 = get1 + nleft - 1 s(put1:put2) = chrrep(get1:get2) end if return end subroutine dec_to_s_right ( ival, jval, s ) !*****************************************************************************80 ! !! DEC_TO_S_RIGHT returns a right justified representation of IVAL * 10**JVAL. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IVAL, JVAL, the integers which represent the ! decimal fraction. ! ! Output: ! ! character ( len = * ) S, a right justified string ! containing the representation of the decimal fraction. ! implicit none integer ival integer jval character ( len = * ) s call dec_to_s_left ( ival, jval, s ) call s_adjustr ( s ) return end subroutine digit_bin_to_ch ( i, ch ) !*****************************************************************************80 ! !! DIGIT_BIN_TO_CH returns the character representation of a binary digit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the integer, between 0 and 1. ! ! Output: ! ! character CH, the character representation of the integer. ! implicit none character ch integer i if ( i == 0 ) then ch = '0' else if ( i == 1 ) then ch = '1' else ch = '*' end if return end subroutine digit_inc ( ch ) !*****************************************************************************80 ! !! digit_inc() increments a decimal digit. ! ! Example: ! ! Input Output ! ----- ------ ! '0' '1' ! '1' '2' ! ... ! '8' '9' ! '9' '0' ! 'A' 'A' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, a digit to be incremented. ! ! Output: ! ! character CH, the incremented digit. ! implicit none character ch integer digit call ch_to_digit ( ch, digit ) if ( digit == -1 ) then return end if digit = digit + 1 if ( digit == 10 ) then digit = 0 end if call digit_to_ch ( digit, ch ) return end subroutine digit_oct_to_ch ( i, ch ) !*****************************************************************************80 ! !! DIGIT_OCT_TO_CH returns the character representation of an octal digit. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the integer, between 0 and 7. ! ! Output: ! ! character CH, the character representation of the integer. ! character ch integer i if ( 0 <= i .and. i <= 7 ) then ch = achar ( i + 48 ) else ch = '*' end if return end subroutine digit_to_ch ( digit, ch ) !*****************************************************************************80 ! !! digit_to_ch() returns the character representation of a decimal digit. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Example: ! ! DIGIT CH ! ----- --- ! 0 '0' ! 1 '1' ! ... ... ! 9 '9' ! 17 '*' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer DIGIT, the digit value between 0 and 9. ! ! Output: ! ! character CH, the corresponding character. ! implicit none character ch integer digit if ( 0 <= digit .and. digit <= 9 ) then ch = achar ( digit + 48 ) else ch = '*' end if return end function ebcdic_to_ch ( e ) !*****************************************************************************80 ! !! EBCDIC_TO_CH converts an EBCDIC character to ASCII. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character E, the EBCDIC character. ! ! Output: ! ! character EBCDIC_TO_CH, the corresponding ASCII ! character, or a blank character if no correspondence holds. ! implicit none character e character ebcdic_to_ch integer i integer iebcdic_to_ic i = iebcdic_to_ic ( iachar ( e ) ) if ( i /= -1 ) then ebcdic_to_ch = achar ( i ) else ebcdic_to_ch = ' ' end if return end subroutine ebcdic_to_s ( s ) !*****************************************************************************80 ! !! EBCDIC_TO_S converts a string of EBCDIC characters to ASCII. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the EBCDIC string. ! ! Output: ! ! character ( len = * ) S, the ASCII version of the string. ! implicit none character ebcdic_to_ch integer i character ( len = * ) s integer s_length s_length = len ( s ) do i = 1, s_length s(i:i) = ebcdic_to_ch ( s(i:i) ) end do return end subroutine fillch ( s1, field, s2 ) !*****************************************************************************80 ! !! FILLCH writes a string into a subfield of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string which is presumed ! to contain, somewhere, a substring that is to be filled in. ! The substring might be '?', for instance. ! ! character ( len = * ) FIELD, a substring to be searched for in ! S, which denotes the spot where the value should be placed. ! Trailing blanks are ignored. ! ! character ( len = * ) S2, the character string to be written ! into the subfield. Trailing blanks are ignored. ! ! Output: ! ! character ( len = * ) S1, the substring has been overwritten. ! implicit none character ( len = * ) field integer i integer lenc integer s_indexi character ( len = * ) s1 character ( len = * ) s2 i = s_indexi ( s1, field ) if ( i /= 0 ) then lenc = len_trim ( field ) call s_chop ( s1, i, i+lenc-1 ) lenc = len_trim ( s2 ) call s_s_insert ( s1, i, s2(1:lenc) ) end if return end subroutine fillin ( s, field, ival ) !*****************************************************************************80 ! !! FILLIN writes an integer into a subfield of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string which is presumed ! to contain, somewhere, a substring that is to be filled in. ! The substring might be '?', for instance. ! ! character ( len = * ) FIELD, a substring to be searched for in ! S, which denotes the spot where the value should be placed. ! Trailing blanks are ignored. ! ! integer IVAL, the value to be written ! into the subfield. ! ! Output: ! ! character ( len = * ) S, the substring has been overwritten. ! implicit none character ( len = * ) field integer i integer ival integer lenc integer s_indexi character ( len = * ) s character ( len = 14 ) sval i = s_indexi ( s, field ) if ( i /= 0 ) then lenc = len_trim ( field ) call s_chop ( s, i, i+lenc-1 ) call i4_to_s_left ( ival, sval ) lenc = len_trim ( sval ) call s_s_insert ( s, i, sval(1:lenc) ) end if return end subroutine fillrl ( s, field, r ) !*****************************************************************************80 ! !! FILLRL writes a real into a subfield of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string which is presumed ! to contain, somewhere, a substring that is to be filled in. ! The substring might be '?', for instance. ! ! character ( len = * ) FIELD, a substring to be searched for in ! S, which denotes the spot where the value should be placed. ! Trailing blanks are ignored. ! ! real ( kind = rk ) R, the value to be written into the subfield. ! ! Output: ! ! character ( len = * ) S, the substring has been overwritten by the value. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character ( len = * ) field integer i integer lenc real ( kind = rk ) r character ( len = * ) s integer s_indexi character ( len = 10 ) sval i = s_indexi ( s, field ) if ( i /= 0 ) then lenc = len_trim ( field ) call s_chop ( s, i, i+lenc-1 ) call r4_to_s_right ( r, sval ) call s_blank_delete ( sval ) lenc = len_trim ( sval ) call s_s_insert ( s, i, sval(1:lenc) ) end if return end subroutine flt_to_s ( mant, iexp, ndig, s ) !*****************************************************************************80 ! !! FLT_TO_S returns a representation of MANT * 10**IEXP. ! ! Example: ! ! MANT IEXP S ! ! 1 2 100 ! 101 -1 10.1 ! 23 -3 0.023 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer MANT, the mantissa of the representation. ! This is an integer whose magnitude is between 0 and ! 10**NDIG, that is, 0 <= MANT < 10**NDIG. ! ! integer IEXP, the exponent of 10 that multiplies MULT. ! ! integer NDIG, the number of digits of accuracy ! in the representation. ! ! Output: ! ! character ( len = * ) S, the representation of the quantity. ! implicit none integer iexp integer jexp integer mant integer ndig character ( len = * ) s ! ! Get the length of the string, and set it all to blanks. ! s = ' ' ! ! If the mantissa is zero, the number is zero, and we have ! a special case: S = '0'. ! if ( mant == 0 ) then s = '0' return else if ( 0 < mant ) then s(1:2) = ' ' else if ( mant < 0 ) then s(1:2) = '- ' end if ! ! Now write the mantissa into S in positions 3 to NDIG+2. ! call i4_to_s_left ( abs ( mant ), s(3:ndig+2) ) ! ! Insert a decimal place after the first digit. ! s(2:2) = s(3:3) s(3:3) = '.' ! ! Place the "e" representing the exponent. ! s(ndig+3:ndig+3) = 'e' ! ! Write the exponent. ! jexp = 0 do while ( 10**jexp <= abs ( mant ) ) jexp = jexp + 1 end do jexp = jexp + iexp - 1 call i4_to_s_zero ( jexp, s(ndig+4:ndig+6) ) ! ! Remove all blanks, effectively shifting the string left too. ! call s_blank_delete ( s ) return end subroutine forcom ( s, fortran, comment ) !*****************************************************************************80 ! !! FORCOM splits a FORTRAN line into "fortran" and "comment". ! ! Discussion: ! ! The "comment" portion is everything following the first occurrence ! of an exclamation mark (and includes the exclamation mark). ! ! The "fortran" portion is everything before the first exclamation ! mark. ! ! Either or both the data and comment portions may be blank. ! ! Example: ! ! S FORTRAN COMMENT ! ! ' x = 1952 ! Wow' ' x = 1952' '! Wow' ! ' continue' ' continue' ' ' ! '! Hey, Abbott!' ' ' '! Hey, Abbott!' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be analyzed. ! ! Output: ! ! character ( len = * ) FORTRAN, the initial portion of the string, ! containing a FORTRAN statement. ! ! character COMMENT, the final portion of the string, ! containing a comment. ! implicit none character ( len = * ) comment character ( len = * ) fortran integer i character ( len = * ) s i = index ( s, '!' ) if ( i == 0 ) then fortran = s comment = ' ' else if ( i == 1 ) then fortran = ' ' comment = s else fortran = s ( 1:i-1) comment = s ( i: ) end if return end subroutine get_unit ( iunit ) !*****************************************************************************80 ! !! GET_UNIT returns a free FORTRAN unit number. ! ! Discussion: ! ! A "free" FORTRAN unit number is an integer between 1 and 99 which ! is not currently associated with an I/O device. A free FORTRAN unit ! number is needed in order to open a file with the OPEN command. ! ! If IUNIT = 0, then no free FORTRAN unit could be found, although ! all 99 units were checked (except for units 5 and 6). ! ! Otherwise, IUNIT is an integer between 1 and 99, representing a ! free FORTRAN unit. Note that GET_UNIT assumes that units 5 and 6 ! are special, and will never return those values. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 March 1999 ! ! Author: ! ! John Burkardt ! ! Output: ! ! integer IUNIT, the unit number. ! implicit none integer i integer ios integer iunit logical lopen iunit = 0 do i = 1, 99 if ( i /= 5 .and. i /= 6 ) then inquire ( unit = i, opened = lopen, iostat = ios ) if ( ios == 0 ) then if ( .not. lopen ) then iunit = i return end if end if end if end do return end subroutine hex_digit_to_i4 ( ch, i ) !*****************************************************************************80 ! !! HEX_DIGIT_TO_I4 converts a hexadecimal digit to an I4. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 August 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character CH, the hexadecimal digit, '0' ! through '9', or 'A' through 'F', or also 'a' through 'f' ! are allowed. ! ! Output: ! ! integer I, the corresponding integer, or -1 if ! CH was illegal. ! implicit none character ch integer i i = iachar ( ch ) if ( lle ( '0', ch ) .and. lle ( ch, '9' ) ) then i = i - 48 else if ( 65 <= i .and. i <= 70 ) then i = i - 55 else if ( 97 <= i .and. i <= 102 ) then i = i - 87 else if ( ch == ' ' ) then i = 0 else i = -1 end if return end subroutine hex_to_binary_digits ( hex_digit, binary_digits ) !*****************************************************************************80 ! !! HEX_TO_BINARY_DIGITS converts a hexadecimal digit to 4 binary digits. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 August 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character HEX_DIGIT, the hexadecimal digit. ! ! Output: ! ! character ( len = 4 ) BINARY_DIGITS, the binary digits. ! implicit none character ( len = 4 ) binary_digits character hex_digit if ( hex_digit == '0' ) then binary_digits = '0000' else if ( hex_digit == '1' ) then binary_digits = '0001' else if ( hex_digit == '2' ) then binary_digits = '0010' else if ( hex_digit == '3' ) then binary_digits = '0011' else if ( hex_digit == '4' ) then binary_digits = '0100' else if ( hex_digit == '5' ) then binary_digits = '0101' else if ( hex_digit == '6' ) then binary_digits = '0110' else if ( hex_digit == '7' ) then binary_digits = '0111' else if ( hex_digit == '8' ) then binary_digits = '1000' else if ( hex_digit == '9' ) then binary_digits = '1001' else if ( hex_digit == 'A' .or. hex_digit == 'a' ) then binary_digits = '1010' else if ( hex_digit == 'B' .or. hex_digit == 'b' ) then binary_digits = '1011' else if ( hex_digit == 'C' .or. hex_digit == 'c' ) then binary_digits = '1100' else if ( hex_digit == 'D' .or. hex_digit == 'd' ) then binary_digits = '1101' else if ( hex_digit == 'E' .or. hex_digit == 'e' ) then binary_digits = '1110' else if ( hex_digit == 'F' .or. hex_digit == 'f' ) then binary_digits = '1111' else binary_digits = ' ' end if return end subroutine hex_to_i4 ( s, i4 ) !*****************************************************************************80 ! !! HEX_TO_I4 converts a hexadecimal string to an I4. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string of hexadecimal digits. ! ! Output: ! ! integer I4, the corresponding I4. ! implicit none integer first integer idig integer i4 integer isgn integer j character ( len = * ) s integer s_length s_length = len_trim ( s ) ! ! Determine if there is a plus or minus sign. ! isgn = 1 first = s_length + 1 do j = 1, s_length if ( s(j:j) == '-' ) then isgn = -1 else if ( s(j:j) == '+' ) then isgn = + 1 else if ( s(j:j) /= ' ' ) then first = j exit end if end do ! ! Read the numeric portion of the string. ! i4 = 0 do j = first, s_length call hex_digit_to_i4 ( s(j:j), idig ) i4 = i4 * 16 + idig end do i4 = isgn * i4 return end subroutine hex_to_s ( hex, s ) !*****************************************************************************80 ! !! HEX_TO_S converts a hexadecimal string into characters. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Example: ! ! Input: ! ! '414243' ! ! Output: ! ! 'ABC'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) HEX, a string of pairs of hexadecimal values. ! ! Output: ! ! character ( len = * ) S, the corresponding character string. ! implicit none character ( len = * ) hex integer i integer intval integer j integer ndo integer nhex character ( len = * ) s integer s_length s_length = len ( s ) nhex = len_trim ( hex ) ndo = min ( nhex / 2, s_length ) s = ' ' do i = 1, ndo j = 2 * i - 1 call hex_to_i4 ( hex(j:j+1), intval ) s(i:i) = achar ( intval ) end do return end subroutine i2_byte_swap ( iword, bytes ) !*****************************************************************************80 ! !! I2_BYTE_SWAP swaps bytes in an 8-byte word. ! ! Discussion: ! ! This routine uses the MVBITS routines to carry out the swaps. The ! relationship between the bits in the word (0 through 63) and the ! bytes (1 through 8) is machine dependent. That is, byte 1 may ! comprise bits 0 through 7, or bits 56 through 63. So some ! experimentation may be necessary the first time this routine ! is used. ! ! This routine was originally written simply to take the drudgery ! out of swapping bytes in a VAX word that was to be read by ! another machine. ! ! The statement ! ! call i2_byte_swap ( IWORD, (/ 1, 2, 3, 4, 5, 6, 7, 8 /) ) ! ! will do nothing to IWORD, and ! ! call i2_byte_swap ( IWORD, (/ 8, 7, 6, 5, 4, 3, 2, 1 /) ) ! ! will reverse the bytes in IWORD, and ! ! call i2_byte_swap ( IWORD, (/ 2, 2, 2, 2, 2, 2, 2, 2 /) ) ! ! will replace IWORD with a word containing byte(2) repeated 8 times. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IWORD, the word whose bits are to be swapped. ! ! integer BYTES(8), indicates which byte in the input ! word should overwrite each byte of the output word. ! ! Output: ! ! integer IWORD, the word after bit swapping. ! implicit none integer, parameter :: bytes_num = 8 integer bytes(bytes_num) integer i integer iword integer jword jword = iword do i = 1, bytes_num if ( bytes(i) < 1 .or. bytes_num < bytes(i) ) then cycle end if if ( bytes(i) == i ) then cycle end if call mvbits ( jword, (bytes(i)-1)*8, 8, iword, 0 ) end do return end subroutine i4_byte_swap ( iword, bytes ) !*****************************************************************************80 ! !! I4_BYTE_SWAP swaps bytes in a 4-byte word. ! ! Discussion: ! ! This routine uses the MVBITS routines to carry out the swaps. The ! relationship between the bits in the word (0 through 31) and the ! bytes (1 through 4) is machine dependent. That is, byte 1 may ! comprise bits 0 through 7, or bits 24 through 31. So some ! experimentation may be necessary the first time this routine ! is used. ! ! This routine was originally written simply to take the drudgery ! out of swapping bytes in a VAX word that was to be read by ! another machine. ! ! The statement ! ! call i4_byte_swap ( IWORD, (/ 1, 2, 3, 4 /) ) ! ! will do nothing to IWORD, and ! ! call i4_byte_swap ( IWORD, (/ 4, 3, 2, 1 /) ) ! ! will reverse the bytes in IWORD, and ! ! call i4_byte_swap ( IWORD, (/ 2, 2, 2, 2 /) ) ! ! will replace IWORD with a word containing byte(2) repeated 4 times. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IWORD, the word whose bits are to be swapped. ! ! integer BYTES(4), indicates which byte in the ! input word should overwrite each byte of the output word. ! ! Output: ! ! integer IWORD, the word after bit swapping. ! implicit none integer, parameter :: NUM_BYTES = 4 integer, parameter :: bit_length = 8 integer bytes(NUM_BYTES) integer from_pos integer i integer iword integer jword integer to_pos jword = iword do i = 1, NUM_BYTES if ( bytes(i) < 1 .or. NUM_BYTES < bytes(i) ) then cycle end if if ( bytes(i) == i ) then cycle end if from_pos = 8 * ( bytes(i) - 1 ) to_pos = 8 * ( i - 1 ) call mvbits ( jword, from_pos, bit_length, iword, to_pos ) end do return end subroutine i4_extract ( s, i, ierror ) !*****************************************************************************80 ! !! I4_EXTRACT "extracts" an I4 from the beginning of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S; on a string from ! whose beginning an integer is to be extracted. ! ! Output: ! ! character ( len = * ) S; the integer, if found, has been removed. ! ! integer I. If IERROR is 0, then I contains the ! next integer read from S; otherwise I is 0. ! ! integer IERROR. ! 0, no error. ! nonzero, an integer could not be extracted from the beginning of the ! string. I is 0 and S is unchanged. ! implicit none integer i integer ierror integer length character ( len = * ) s i = 0 call s_to_i4 ( s, i, ierror, length ) if ( ierror /= 0 .or. length == 0 ) then ierror = 1 i = 0 else call s_shift_left ( s, length ) end if return end function i4_gcd ( i, j ) !*****************************************************************************80 ! !! I4_GCD finds the greatest common divisor of I and J. ! ! Discussion: ! ! Note that only the absolute values of I and J are ! considered, so that the result is always nonnegative. ! ! If I or J is 0, I4_GCD is returned as max ( 1, abs ( I ), abs ( J ) ). ! ! If I and J have no common factor, I4_GCD is returned as 1. ! ! Otherwise, using the Euclidean algorithm, I_GCD is the ! largest common factor of I and J. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 03 March 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, J, two numbers whose greatest common ! divisor is desired. ! ! Output: ! ! integer I4_GCD, the greatest common divisor of ! I and J. ! implicit none integer i integer i4_gcd integer ip integer iq integer ir integer j i4_gcd = 1 ! ! Return immediately if either I or J is zero. ! if ( i == 0 ) then i4_gcd = max ( 1, abs ( j ) ) return else if ( j == 0 ) then i4_gcd = max ( 1, abs ( i ) ) return end if ! ! Set IP to the larger of I and J, IQ to the smaller. ! This way, we can alter IP and IQ as we go. ! ip = max ( abs ( i ), abs ( j ) ) iq = min ( abs ( i ), abs ( j ) ) ! ! Carry out the Euclidean algorithm. ! do ir = mod ( ip, iq ) if ( ir == 0 ) then exit end if ip = iq iq = ir end do i4_gcd = iq return end function i4_huge ( ) !*****************************************************************************80 ! !! I4_HUGE returns a "huge" I4. ! ! Discussion: ! ! On an IEEE 32 bit machine, I4_HUGE should be 2**31 - 1, and its ! bit pattern should be ! ! 01111111111111111111111111111111 ! ! In this case, its numerical value is 2147483647. ! ! Using the Dec/Compaq/HP Alpha FORTRAN compiler FORT, I could ! use I4_HUGE() and HUGE interchangeably. ! ! Explanation: because under G95 the default integer type is 64 bits! ! So HUGE ( 1 ) = a very very huge integer indeed, whereas ! I4_HUGE ( ) = the same old 32 bit big value. ! ! An I4 is an integer value. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 January 2007 ! ! Author: ! ! John Burkardt ! ! Output: ! ! integer I4_HUGE, a "huge" I4. ! implicit none integer i4_huge i4_huge = 2147483647 return end subroutine i4_input ( string, value, ierror ) !*****************************************************************************80 ! !! i4_input() prints a prompt string and reads an I4 from the user. ! ! Discussion: ! ! If the input line starts with a comment character ('#') or is ! blank, the routine ignores that line, and tries to read the next one. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) STRING, the prompt string. ! ! Output: ! ! integer VALUE, the value input by the user. ! ! integer IERROR, an error flag, which is zero ! if no error occurred. ! implicit none integer ierror integer last character ( len = 255 ) line character ( len = * ) string integer value ierror = 0 value = huge ( value ) ! ! Write the prompt. ! write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( string ) do read ( *, '(a)', iostat = ierror ) line if ( ierror /= 0 ) then return end if ! ! If the line begins with a comment character, go back and read the next line. ! if ( line(1:1) == '#' ) then cycle end if if ( len_trim ( line ) == 0 ) then cycle end if ! ! Extract integer information from the string. ! call s_to_i4 ( line, value, ierror, last ) if ( ierror /= 0 ) then value = huge ( value ) return end if exit end do return end function i4_length ( i4 ) !*****************************************************************************80 ! !! I4_LENGTH computes the number of characters needed to print an I4. ! ! Example: ! ! I4 I4_LENGTH ! ! 0 1 ! 1 1 ! -1 2 ! 1952 4 ! 123456 6 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the integer whose length is desired. ! ! Output: ! ! integer I4_LENGTH, the number of characters required ! to print the integer. ! implicit none integer i4 integer i4_copy integer i4_length if ( i4 < 0 ) then i4_length = 1 else if ( i4 == 0 ) then i4_length = 1 return else if ( 0 < i4 ) then i4_length = 0 end if i4_copy = abs ( i4 ) do while ( i4_copy /= 0 ) i4_length = i4_length + 1 i4_copy = i4_copy / 10 end do return end function i4_modp ( i, j ) !*****************************************************************************80 ! !! I4_MODP returns the nonnegative remainder of I4 division. ! ! Discussion: ! ! If ! NREM = I4_MODP ( I, J ) ! NMULT = ( I - NREM ) / J ! then ! I = J * NMULT + NREM ! where NREM is always nonnegative. ! ! The MOD function computes a result with the same sign as the ! quantity being divided. Thus, suppose you had an angle A, ! and you wanted to ensure that it was between 0 and 360. ! Then mod(A,360) would do, if A was positive, but if A ! was negative, your result would be between -360 and 0. ! ! On the other hand, I4_MODP(A,360) is between 0 and 360, always. ! ! An I4 is an integer value. ! ! Example: ! ! I J MOD I4_MODP Factorization ! ! 107 50 7 7 107 = 2 * 50 + 7 ! 107 -50 7 7 107 = -2 * -50 + 7 ! -107 50 -7 43 -107 = -3 * 50 + 43 ! -107 -50 -7 43 -107 = 3 * -50 + 43 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 March 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the number to be divided. ! ! integer J, the number that divides I. ! ! Output: ! ! integer I4_MODP, the nonnegative remainder when I is ! divided by J. ! implicit none integer i integer i4_modp integer j integer value if ( j == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_MODP - Fatal error!' write ( *, '(a,i8)' ) ' Illegal divisor J = ', j stop 1 end if value = mod ( i, j ) if ( value < 0 ) then value = value + abs ( j ) end if i4_modp = value return end subroutine i4_next ( s, ival, done ) !*****************************************************************************80 ! !! I4_NEXT "reads" I4's from a string, one at a time. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string, presumably containing ! integers. These may be separated by spaces or commas. ! ! logical DONE. ! On input with a fresh string, the user should set DONE to TRUE. ! ! Output: ! ! integer IVAL. If DONE is FALSE, then IVAL contains ! the "next" integer read. If DONE is TRUE, then IVAL is zero. ! ! logical DONE, the routine sets DONE to FALSE ! if another integer was read, or TRUE if no more integers could be read. ! implicit none logical done integer ierror integer ival integer length integer, save :: next = 1 character ( len = * ) s ival = 0 if ( done ) then next = 1 done = .false. end if if ( len ( s ) < next ) then done = .true. return end if call s_to_i4 ( s(next:), ival, ierror, length ) if ( ierror /= 0 .or. length == 0 ) then done = .true. next = 1 else done = .false. next = next + length end if return end subroutine i4_next_read ( s, intval, ierror ) !*****************************************************************************80 ! !! I4_NEXT_READ finds and reads the next I4 in a string. ! ! Discussion: ! ! This routine can be used to extract, one at a time, the integers in ! a string. ! ! Example: ! ! Input: ! ! S = 'Data set #12 extends from (5,-43) and is worth $4.56' ! IERROR = -1 ! ! Output: ! ! (on successive calls) ! ! INTVAL IERROR ! ------ ------ ! 1 0 ! 2 0 ! 5 0 ! -43 0 ! 4 0 ! 56 0 ! 0 1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 August 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! integer IERROR: On the first call for a given string, set IERROR = -1. ! ! Output: ! ! integer INTVAL, the next integer in the string, or 0 ! if no integer could be found. ! ! integer IERROR: the routine will return IERROR = 0 if another ! integer was found, or 1 if no more integers were found. ! implicit none integer ierror integer intval integer, save :: istart = 1 integer length character ( len = * ) s if ( ierror == -1 ) then istart = 1 end if ierror = 0 intval = 0 if ( len_trim ( s ) < istart ) then ierror = 1 return end if call chrcti2 ( s(istart:), intval, ierror, length ) if ( ierror == 0 .and. 0 < length ) then istart = istart + length else ierror = 1 end if return end subroutine i4_range_input ( string, value1, value2, ierror ) !*****************************************************************************80 ! !! i4_range_input() reads a pair of I4's from the user, representing a range. ! ! Discussion: ! ! If the input line starts with a comment character ('#') or is blank, ! the routine ignores that line, and tries to read the next one. ! ! The pair of integers may be separated by spaces or a comma or both. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) STRING, the prompt string. ! ! Output: ! ! integer VALUE1, VALUE2, the values entered by the user. ! ! integer IERROR, an error flag, which is zero ! if no error occurred. ! implicit none character, parameter :: comma = ',' integer ierror integer last integer last2 character ( len = 255 ) line character, parameter :: space = ' ' character ( len = * ) string integer value1 integer value2 ierror = 0 value1 = huge ( value1 ) value2 = huge ( value2 ) ! ! Write the prompt. ! write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( string ) do read ( *, '(a)', iostat = ierror ) line if ( ierror /= 0 ) then return end if ! ! If the line begins with a comment character, go back and read the next line. ! if ( line(1:1) == '#' ) then cycle end if if ( len_trim ( line ) == 0 ) then cycle end if ! ! Replace commas by spaces. ! call s_replace_ch ( line, comma, space ) ! ! Extract integer information from the string. ! call s_to_i4 ( line, value1, ierror, last ) if ( ierror /= 0 ) then value1 = huge ( value1 ) return end if call s_to_i4 ( line(last+1:), value2, ierror, last2 ) if ( ierror /= 0 ) then value2 = huge ( value2 ) return end if exit end do return end subroutine i4_swap ( i, j ) !*****************************************************************************80 ! !! I4_SWAP swaps two I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 November 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, J, two values. ! ! Output: ! ! integer I, J, the values have been interchanged. ! implicit none integer i integer j integer k k = i i = j j = k return end function i4_to_a ( i ) !*****************************************************************************80 ! !! I4_TO_A returns the I-th alphabetic character. ! ! Discussion: ! ! Instead of CHAR, we now use the ACHAR function, which ! guarantees the ASCII collating sequence. ! ! Example: ! ! I I4_TO_A ! ! -8 ' ' ! 0 ' ' ! 1 'A' ! 2 'B' ! .. ! 26 'Z' ! 27 'a' ! 52 'z' ! 53 ' ' ! 99 ' ' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 February 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the index of the letter to be returned. ! 0 is a space; ! 1 through 26 requests 'A' through 'Z', (ASCII 65:90); ! 27 through 52 requests 'a' through 'z', (ASCII 97:122); ! ! Output: ! ! character I4_TO_A, the requested alphabetic letter. ! implicit none integer, parameter :: cap_shift = 64 integer i character i4_to_a integer, parameter :: low_shift = 96 if ( i <= 0 ) then i4_to_a = ' ' else if ( 1 <= i .and. i <= 26 ) then i4_to_a = achar ( cap_shift + i ) else if ( 27 <= i .and. i <= 52 ) then i4_to_a = achar ( low_shift + i - 26 ) else if ( 53 <= i ) then i4_to_a = ' ' end if return end subroutine i4_to_amino_code ( i, ch ) !*****************************************************************************80 ! !! I4_TO_AMINO_CODE converts an integer to an amino code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 June 2000 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Carl Branden, John Tooze, ! Introduction to Protein Structure, ! Garland Publishing, 1991. ! ! Input: ! ! integer I, the index of an amino acid, between 1 ! and 23. ! ! Output: ! ! character CH, the one letter code for an amino acid. ! implicit none integer, parameter :: n = 23 character ch character, dimension ( n ) :: ch_table = (/ & 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', & 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', & 'X', 'Y', 'Z' /) integer i if ( 1 <= i .and. i <= 23 ) then ch = ch_table(i) else ch = '?' end if return end subroutine i4_to_base ( i4, base, s ) !*****************************************************************************80 ! !! I4_TO_BASE represents an integer in any base up to 16. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! Input Output ! ------------- -------- ! INTVAL BASE S ! ! 5 -1 '101010101' ! 5 1 '11111' ! 5 2 '101' ! 5 3 '12' ! 5 4 '11' ! -5 5 '-10' ! 5 6 '5' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the integer whose representation ! is desired. ! ! integer BASE, the base in which the representation is ! given. BASE must be greater than 0 and no greater than 16. ! ! Output: ! ! character ( len = * ) S, the string. ! implicit none integer base integer i integer i4 integer icopy integer idig integer jdig character ( len = * ) s integer s_length s = ' ' s_length = len ( s ) ! ! Check the base. ! if ( base < -1 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BASE - Serious error!' write ( *, '(a)' ) ' The input base is less than -1!' return end if if ( base == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BASE - Serious error!' write ( *, '(a)' ) ' The input base is zero.' return end if if ( 16 < base ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BASE - Serious error!' write ( *, '(a)' ) ' The input base is greater than 16!' return end if ! ! Special treatment for base 1 and -1. ! if ( base == 1 ) then call i4_to_unary ( i4, s ) return else if ( base == -1 ) then call i4_to_nunary ( i4, s ) return end if ! ! Do repeated mod's ! jdig = 0 icopy = abs ( i4 ) do if ( ( 0 <= i4 .and. s_length <= jdig ) .or. & ( i4 < 0 .and. s_length - 1 <= jdig ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BASE - Fatal error!' do i = 1, s_length s(i:i) = '*' end do return end if jdig = jdig + 1 idig = mod ( icopy, base ) icopy = ( icopy - idig ) / base call i4_to_hex_digit ( idig, s(s_length+1-jdig:s_length+1-jdig) ) if ( icopy == 0 ) then exit end if end do ! ! Take care of the minus sign. ! if ( i4 < 0 ) then jdig = jdig + 1 s(s_length+1-jdig:s_length+1-jdig) = '-' end if return end subroutine i4_to_binary ( i, s ) !*****************************************************************************80 ! !! I4_TO_BINARY produces the binary representation of an I4. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! I S ! -- ------ ! 1 '1' ! 2 '10' ! 3 '11' ! 4 '100' ! -9 '-1001' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 17 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, an integer to be represented. ! ! Output: ! ! character ( len = * ) S, the binary representation. ! implicit none integer i integer i_copy integer j character ( len = * ) s i_copy = abs ( i ) s = ' ' j = len ( s ) do while ( 0 < j ) if ( mod ( i_copy, 2 ) == 1 ) then s(j:j) = '1' else s(j:j) = '0' end if i_copy = i_copy / 2 if ( i_copy == 0 ) then exit end if j = j - 1 end do if ( i_copy /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BINARY - Serious error!' write ( *, '(a)' ) ' Not enough room in the string to represent the value.' end if if ( i < 0 ) then if ( 1 < j ) then j = j - 1 s(j:j) = '-' else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_BINARY - Serious error!' write ( *, '(a)' ) ' No room to prefix minus sign!' end if end if return end function i4_to_binhex ( i ) !*****************************************************************************80 ! !! I4_TO_BINHEX returns the I-th character in the BINHEX encoding. ! ! Example: ! ! I I4_TO_BINHEX ! ! 1 '!' ! 2 '"' ! 3 '#' ! .. ! 64 'r' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 January 2013 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the index of the character. ! 1 <= I <= 64. ! ! Output: ! ! character I4_TO_BINHEX, the requested character. ! implicit none integer i character i4_to_binhex character ( len = 64 ), parameter :: string = & '!"#$%&''()*+,-012345689@ABCDEFGHIJKLMNPQRSTVWXYZ[`abcdefhijklmpqr' if ( 1 <= i .and. i <= 64 ) then i4_to_binhex = string(i:i) else i4_to_binhex = ' ' end if return end subroutine i4_to_ch4 ( i4, ch4 ) !*****************************************************************************80 ! !! I4_TO_CH4 converts an I4 to a 4 character string. ! ! Discussion: ! ! An I4 is an integer. ! ! While most integers will be converted to unprintable strings, ! here are a few nice ones: ! ! 1097097581 Adam ! 1114205292 Bill ! 1131573111 Crow ! 1147237989 Dave ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 May 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the value. ! ! Output: ! ! character ( len = 4 ) CH4, a corresponding character value. ! implicit none character ( len = 4 ) ch4 integer i4 integer j1 integer j2 integer j3 integer j4 j1 = ibits ( i4, 0, 8 ) j2 = ibits ( i4, 8, 8 ) j3 = ibits ( i4, 16, 8 ) j4 = ibits ( i4, 24, 8 ) ch4 = achar ( j1 ) // achar ( j2 ) // achar ( j3 ) // achar ( j4 ) return end subroutine i4_to_hex ( i4, s ) !*****************************************************************************80 ! !! I4_TO_HEX produces the hexadecimal representation of an I4. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! I4 S ! --- --- ! 0 '0' ! 9 '9' ! 10 'A' ! 15 'F' ! 16 '10' ! 100 '64' ! -12 '-C' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the integer to be represented. ! ! Output: ! ! character ( len = * ) S, the hexadecimal representation. ! implicit none integer i4 integer i1 integer ichr integer intcpy integer isgn character ( len = * ) s integer s_length s_length = len ( s ) intcpy = i4 isgn = 1 if ( intcpy < 0 ) then isgn = -1 intcpy = - intcpy end if s = ' ' ! ! Point to the position just after the end of the string. ! ichr = s_length + 1 ! ! Moving left, fill in the next digit of the string. ! do ichr = ichr - 1 if ( ichr <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_HEX - Serious error!' write ( *, '(a)' ) ' Ran out of room in the string!' return end if i1 = mod ( intcpy, 16 ) intcpy = intcpy / 16 call i4_to_hex_digit ( i1, s(ichr:ichr) ) if ( intcpy == 0 ) then if ( isgn == -1 ) then if ( 1 < ichr ) then ichr = ichr - 1 s(ichr:ichr) = '-' else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_HEX - Serious error!' write ( *, '(a)' ) ' No room to prefix minus sign!' end if end if return end if end do return end subroutine i4_to_hex_digit ( i, ch ) !*****************************************************************************80 ! !! I4_TO_HEX_DIGIT converts a (small) I4 to a hexadecimal digit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 August 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the integer, between 0 and 15. ! ! Output: ! ! character CH, the hexadecimal digit corresponding to the integer. ! implicit none character ch integer i if ( 0 <= i .and. i <= 9 ) then ch = achar ( i + 48 ) else if ( 10 <= i .and. i <= 15 ) then ch = achar ( i + 55 ) else ch = '*' end if return end function i4_to_isbn_digit ( i ) !*****************************************************************************80 ! !! I4_TO_ISBN_DIGIT converts an I4 to an ISBN digit. ! ! Discussion: ! ! Only the integers 0 through 10 can be input. The representation ! of 10 is 'X'. ! ! An I4 is an integer value. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, an integer between 0 and 10. ! ! Output: ! ! character I4_TO_ISBN_DIGIT, the ISBN character code of the integer. ! If I is illegal, the value is set to '?'. ! implicit none integer i character i4_to_isbn_digit character value if ( i == 0 ) then value = '0' else if ( i == 1 ) then value = '1' else if ( i == 2 ) then value = '2' else if ( i == 3 ) then value = '3' else if ( i == 4 ) then value = '4' else if ( i == 5 ) then value = '5' else if ( i == 6 ) then value = '6' else if ( i == 7 ) then value = '7' else if ( i == 8 ) then value = '8' else if ( i == 9 ) then value = '9' else if ( i == 10 ) then value = 'X' else value = '?' end if i4_to_isbn_digit = value return end subroutine i4_to_month_abb ( m, month_abb ) !*****************************************************************************80 ! !! I4_TO_MONTH_ABB returns the 3 character abbreviation of a given month. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 11 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer M, the index of the month, which should ! be between 1 and 12. ! ! Output: ! ! character ( len = 3 ) MONTH_ABB, the month abbreviation ! implicit none character ( len = 3 ), parameter, dimension(12) :: abb = (/ & 'Jan', 'Feb', 'Mar', 'Apr', & 'May', 'Jun', 'Jul', 'Aug', & 'Sep', 'Oct', 'Nov', 'Dec' /) integer m character ( len = 3 ) month_abb if ( m < 1 .or. 12 < m ) then month_abb = '???' else month_abb = abb(m) end if return end subroutine i4_to_month_name ( m, month_name ) !*****************************************************************************80 ! !! I4_TO_MONTH_NAME returns the name of a given month. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 April 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer M, the index of the month, which should ! be between 1 and 12. ! ! Output: ! ! character ( len = * ) MONTH_NAME, a string containing as much ! of the month's name as will fit. To get the typical 3-letter abbreviations ! for the months, simply declare ! character ( len = 3 ) MONTH_NAME ! or pass in MONTH_NAME(1:3). ! implicit none integer i integer m character ( len = * ) month_name character ( len = 9 ), parameter, dimension(12) :: name = (/ & 'January ', 'February ', 'March ', 'April ', & 'May ', 'June ', 'July ', 'August ', & 'September', 'October ', 'November ', 'December ' /) if ( m < 1 .or. 12 < m ) then do i = 1, len ( month_name ) month_name(i:i) = '?' end do else month_name = name(m) end if return end subroutine i4_to_nunary ( intval, s ) !*****************************************************************************80 ! !! I4_TO_NUNARY produces the "base -1" representation of an I4. ! ! Discussion: ! ! An I4 is an integer. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer INTVAL, an integer to be represented. ! ! Output: ! ! character ( len = * ) S, the negative unary representation. ! implicit none integer i integer intval character ( len = * ) s s = ' ' if ( intval < 0 ) then do i = 1, abs ( intval ) s(2*i-1:2*i) = '10' end do else if ( intval == 0 ) then s = '0' else if ( 0 < intval ) then s(1:1) = '1' do i = 2, intval s(2*i-2:2*i-1) = '01' end do end if s = adjustr ( s ) return end subroutine i4_to_oct ( i4, s ) !*****************************************************************************80 ! !! I4_TO_OCT produces the octal representation of an integer. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! I4 S ! ! 0 '0' ! 9 '11' ! 10 '12' ! 15 '17' ! 16 '20' ! 100 '144' ! -12 '-14' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the integer to be represented. ! ! Output: ! ! character ( len = * ) S, the octal representation. ! implicit none integer i4 integer i1 integer ichr integer intcpy integer isgn character ( len = * ) s integer s_length s_length = len ( s ) intcpy = i4 isgn = 1 if ( intcpy < 0 ) then isgn = - 1 intcpy = -intcpy end if s = ' ' ! ! Point to the position just after the end of the string. ! ichr = s_length + 1 ! ! Moving left, fill in the next digit of the string. ! do ichr = ichr - 1 if ( ichr <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_OCT - Fatal error!' write ( *, '(a)' ) ' Ran out of room in the string!' stop 1 end if i1 = mod ( intcpy, 8 ) intcpy = intcpy / 8 call digit_oct_to_ch ( i1, s(ichr:ichr) ) if ( intcpy == 0 ) then if ( isgn == -1 ) then if ( 1 < ichr ) then ichr = ichr - 1 s(ichr:ichr) = '-' else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4_TO_OCT - Fatal error!' write ( *, '(a)' ) ' No room to prefix minus sign!' stop 1 end if end if return end if end do return end subroutine i4_to_s_left ( i4, s ) !*****************************************************************************80 ! !! I4_TO_S_LEFT converts an I4 to a left-justified string. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! Assume that S is 6 characters long: ! ! I4 S ! ! 1 1 ! -1 -1 ! 0 0 ! 1952 1952 ! 123456 123456 ! 1234567 ****** <-- Not enough room! ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, an integer to be converted. ! ! Output: ! ! character ( len = * ) S, the representation of the integer. ! The integer will be left-justified. If there is not enough space, ! the string will be filled with stars. ! implicit none character c integer i integer i4 integer idig integer ihi integer ilo integer ipos integer ival character ( len = * ) s s = ' ' ilo = 1 ihi = len ( s ) if ( ihi <= 0 ) then return end if ! ! Make a copy of the integer. ! ival = i4 ! ! Handle the negative sign. ! if ( ival < 0 ) then if ( ihi <= 1 ) then s(1:1) = '*' return end if ival = -ival s(1:1) = '-' ilo = 2 end if ! ! The absolute value of the integer goes into S(ILO:IHI). ! ipos = ihi ! ! Find the last digit of IVAL, strip it off, and stick it into the string. ! do idig = mod ( ival, 10 ) ival = ival / 10 if ( ipos < ilo ) then do i = 1, ihi s(i:i) = '*' end do return end if call digit_to_ch ( idig, c ) s(ipos:ipos) = c ipos = ipos - 1 if ( ival == 0 ) then exit end if end do ! ! Shift the string to the left. ! s(ilo:ilo+ihi-ipos-1) = s(ipos+1:ihi) s(ilo+ihi-ipos:ihi) = ' ' return end subroutine i4_to_s_right ( intval, s ) !*****************************************************************************80 ! !! I4_TO_S_RIGHT converts an I4 to a right justified string. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! Assume that S is 6 characters long: ! ! INTVAL S ! ! 1 1 ! -1 -1 ! 0 0 ! 1952 1952 ! 123456 123456 ! 1234567 ****** <-- Not enough room! ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer INTVAL, an integer to be converted. ! ! Output: ! ! character ( len = * ) S, the representation of the integer. ! The integer will be right-justified. If there is not enough space, ! the string will be filled with stars. ! implicit none character c integer i integer idig integer ihi integer ilo integer intval integer ipos integer ival character ( len = * ) s s = ' ' ilo = 1 ihi = len ( s ) if ( ihi <= 0 ) then return end if ! ! Make a copy of the integer. ! ival = intval ! ! Handle the negative sign. ! if ( ival < 0 ) then if ( ihi <= 1 ) then s(1:1) = '*' return end if ival = -ival s(1:1) = '-' ilo = 2 end if ! ! The absolute value of the integer goes into S(ILO:IHI). ! ipos = ihi ! ! Find the last digit of IVAL, strip it off, and stick it into the string. ! do idig = mod ( ival, 10 ) ival = ival / 10 if ( ipos < ilo ) then do i = 1, ihi s(i:i) = '*' end do return end if call digit_to_ch ( idig, c ) s(ipos:ipos) = c ipos = ipos - 1 if ( ival == 0 ) then exit end if end do ! ! Shift the minus sign, if any. ! if ( s(1:1) == '-' ) then if ( ipos /= 1 ) then s(1:1) = ' ' s(ipos:ipos) = '-' end if end if return end subroutine i4_to_s_right_comma ( i4, s ) !*****************************************************************************80 ! !! I4_TO_S_RIGHT_COMMA converts an I4 to a right justified string with commas. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! Assume that S is 10 characters long: ! ! I4 S ! ! 1 1 ! -1 -1 ! 0 0 ! 1952 1,952 ! 123456 123,456 ! 1234567 1,234,567 ! 12345678 12,345,678 ! 123456789 ********** <-- Not enough room! ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 April 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, an integer to be converted. ! ! Output: ! ! character ( len = * ) S, the representation of the integer. ! The integer will be right-justified. Commas will be used to separate ! sets of three digits. If there is not enough space, the string will ! be filled with stars. ! implicit none character c integer digit integer digit_num integer hi integer i integer i4 integer lo integer pos character ( len = * ) s integer value s = ' ' lo = 1 hi = len ( s ) if ( hi <= 0 ) then return end if ! ! Make a copy of the integer. ! value = i4 ! ! Handle the negative sign. ! if ( value < 0 ) then if ( hi <= 1 ) then s(1:1) = '*' return end if value = -value s(1:1) = '-' lo = 2 end if ! ! The absolute value of the integer goes into S(LO:HI). ! pos = hi ! ! Find the last digit of VALUE, strip it off, and stick it into the string. ! digit_num = 0 do digit = mod ( value, 10 ) value = value / 10 digit_num = digit_num + 1 if ( pos < lo ) then do i = 1, hi s(i:i) = '*' end do return end if ! ! Insert a comma? ! if ( 1 < digit_num .and. mod ( digit_num, 3 ) == 1 ) then if ( pos < lo ) then do i = 1, hi s(i:i) = '*' end do return end if s(pos:pos) = ',' pos = pos - 1 end if call digit_to_ch ( digit, c ) s(pos:pos) = c pos = pos - 1 if ( value == 0 ) then exit end if end do ! ! Shift the minus sign, if any. ! if ( s(1:1) == '-' ) then if ( pos /= 1 ) then s(1:1) = ' ' s(pos:pos) = '-' end if end if return end subroutine i4_to_s_roman ( intval, s ) !*****************************************************************************80 ! !! I4_TO_S_ROMAN converts an I4 to a string of Roman numerals. ! ! Discussion: ! ! An I4 is an integer. ! ! To generate numbers greater than 4999, the numeral 'V' had a bar ! above it, representing a value of 5000, a barred 'X' represented ! 10,000 and so on. ! ! In the subtractive representation of 4 by 'IV', 9 by 'IX' and so on, ! 'I' can only subtract from 'V' or 'X', ! 'X' can only subtract from 'L' or 'C', ! 'C' can only subtract from 'D' or 'M'. ! Under these rules, 1999 cannot be written IMM! ! ! Example: ! ! INTVAL S ! ! -2 -II <-- Not a Roman numeral ! -1 -I <-- Not a Roman numeral ! 0 0 <-- Not a Roman numeral ! 1 I ! 2 II ! 3 III ! 4 IV ! 5 V ! 10 X ! 20 XX ! 30 XXX ! 40 XL ! 50 L ! 60 LX ! 70 LXX ! 80 LXXX ! 90 XC ! 100 C ! 500 D ! 1000 M ! 4999 MMMMCMLXLIX ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 09 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer INTVAL, an integer to be converted. If the ! integer has absolute value greater than 4999, the string '?' will be ! returned. If the integer is 0, then the string '0' will be returned. If ! the integer is negative, then a minus sign will precede it, even ! though this has nothing to do with Roman numerals. ! ! Output: ! ! character ( len = * ) S, the representation of the integer ! as a Roman numeral. ! implicit none integer icopy integer intval character ( len = * ) s s = ' ' icopy = intval if ( 4999 < abs ( icopy ) ) then s = '?' return end if if ( icopy == 0 ) then s = '0' return end if if ( icopy <= 0 ) then s = '-' icopy = -icopy end if do while ( 0 < icopy ) if ( 1000 <= icopy ) then call s_cat ( s, 'M', s ) icopy = icopy - 1000 else if ( 900 <= icopy ) then call s_cat ( s, 'CM', s ) icopy = icopy - 900 else if ( 500 <= icopy ) then call s_cat ( s, 'D', s ) icopy = icopy - 500 else if ( 400 <= icopy ) then call s_cat ( s, 'CD', s ) icopy = icopy - 400 else if ( 100 <= icopy ) then call s_cat ( s, 'C', s ) icopy = icopy - 100 else if ( 90 <= icopy ) then call s_cat ( s, 'XC', s ) icopy = icopy - 90 else if ( 50 <= icopy ) then call s_cat ( s, 'L', s ) icopy = icopy - 50 else if ( 40 <= icopy ) then call s_cat ( s, 'XL', s ) icopy = icopy - 40 else if ( 10 <= icopy ) then call s_cat ( s, 'X', s ) icopy = icopy - 10 else if ( 9 <= icopy ) then call s_cat ( s, 'IX', s ) icopy = icopy - 9 else if ( 5 <= icopy ) then call s_cat ( s, 'V', s ) icopy = icopy - 5 else if ( 4 <= icopy ) then call s_cat ( s, 'IV', s ) icopy = icopy - 4 else call s_cat ( s, 'I', s ) icopy = icopy - 1 end if end do return end subroutine i4_to_s_zero ( intval, s ) !*****************************************************************************80 ! !! I4_TO_S_ZERO converts an I4 to a string, with zero padding. ! ! Discussion: ! ! An I4 is an integer. ! ! Example: ! ! Assume that S is 6 characters long: ! ! INTVAL S ! ! 1 000001 ! -1 -00001 ! 0 000000 ! 1952 001952 ! 123456 123456 ! 1234567 ****** <-- Not enough room! ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer INTVAL, an integer to be converted. ! ! Output: ! ! character ( len = * ) S, the representation of the integer. ! The integer will be right justified, and zero padded. ! If there is not enough space, the string will be filled with stars. ! implicit none character c integer i integer idig integer ihi integer ilo integer intval integer ipos integer ival character ( len = * ) s s = ' ' ilo = 1 ihi = len ( s ) if ( ihi <= 0 ) then return end if ! ! Make a copy of the integer. ! ival = intval ! ! Handle the negative sign. ! if ( ival < 0 ) then if ( ihi <= 1 ) then s(1:1) = '*' return end if ival = -ival s(1:1) = '-' ilo = 2 end if ! ! Working from right to left, strip off the digits of the integer ! and place them into S(ILO:IHI). ! ipos = ihi do while ( ival /= 0 .or. ipos == ihi ) idig = mod ( ival, 10 ) ival = ival / 10 if ( ipos < ilo ) then do i = 1, ihi s(i:i) = '*' end do return end if call digit_to_ch ( idig, c ) s(ipos:ipos) = c ipos = ipos - 1 end do ! ! Fill the empties with zeroes. ! do i = ilo, ipos s(i:i) = '0' end do return end function i4_to_s32 ( i4 ) !*****************************************************************************80 ! !! I4_TO_S32 converts an I4 to an S32. ! ! Discussion: ! ! An I4 is an integer. ! ! An S32 is a character ( len = 32 ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, the integer to be coded. ! ! Output: ! ! character ( len = 32 ) I4_TO_S32, the character variable that ! corresponds to the integer. ! implicit none integer i integer i4 integer i4_copy character ( len = 32 ) i4_to_s32 character ( len = 32 ) s32 i4_copy = abs ( i4 ) ! ! Binary digits: ! do i = 32, 2, -1 if ( mod ( i4_copy, 2 ) == 1 ) then s32(i:i) = '1' else s32(i:i) = '0' end if i4_copy = i4_copy / 2 end do ! ! Sign bit ! s32(1:1) = '0' ! ! If original number was negative, then reverse all bits. ! if ( i4 < 0 ) then do i = 1, 32 if ( s32(i:i) == '0' ) then s32(i:i) = '1' else s32(i:i) = '0' end if end do end if i4_to_s32 = s32 return end subroutine i4_to_unary ( i4, s ) !*****************************************************************************80 ! !! I4_TO_UNARY produces the "base 1" representation of an I4. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I4, an integer to be represented. ! ! Output: ! ! character ( len = * ) S, the unary representation. ! implicit none integer i integer i4 character ( len = * ) s integer s_length s_length = len ( s ) s = ' ' if ( i4 < 0 ) then if ( s_length < i4 + 1 ) then s = '?' return end if s(1:1) = '-' do i = 2, abs ( i4 ) + 1 s(i:i) = '1' end do else if ( i4 == 0 ) then s = '0' else if ( 0 < i4 ) then if ( s_length < i4 ) then s = '?' return end if do i = 1, i4 s(i:i) = '1' end do end if s = adjustr ( s ) return end function i4_to_uudecode ( i ) !*****************************************************************************80 ! !! I4_TO_UUDECODE returns the I-th character in the UUDECODE encoding. ! ! Example: ! ! I I4_TO_UUDECODE ! ! 1 '`' ! 2 '!' ! 3 '"' ! .. ! 64 '_' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the index of the character. ! 1 <= I <= 64. ! ! Output: ! ! character I4_TO_UUDECODE, the requested character. ! implicit none integer i character i4_to_uudecode character ( len = 64 ), parameter :: string = & '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' if ( 1 <= i .and. i <= 64 ) then i4_to_uudecode = string(i:i) else i4_to_uudecode = ' ' end if return end function i4_to_xxdecode ( i ) !*****************************************************************************80 ! !! I4_TO_XXDECODE returns the I-th character in the XXDECODE encoding. ! ! Example: ! ! I I4_TO_UUDECODE ! ! 1 '+' ! 2 '-' ! 3 '0' ! .. ! 64 'z' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, the index of the character. ! 1 <= I <= 64. ! ! Output: ! ! character I4_TO_XXDECODE, the requested character. ! implicit none integer i character i4_to_xxdecode character ( len = 64 ), parameter :: string = & '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' if ( 1 <= i .and. i <= 64 ) then i4_to_xxdecode = string(i:i) else i4_to_xxdecode = ' ' end if return end function i4_uniform_ab ( a, b ) !*****************************************************************************80 ! !! i4_uniform_ab() returns a scaled pseudorandom I4. ! ! Discussion: ! ! An I4 is an integer value. ! ! The pseudorandom number will be scaled to be uniformly distributed ! between A and B. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Paul Bratley, Bennett Fox, Linus Schrage, ! A Guide to Simulation, ! Springer Verlag, pages 201-202, 1983. ! ! Pierre L'Ecuyer, ! Random Number Generation, ! in Handbook of Simulation, ! edited by Jerry Banks, ! Wiley Interscience, page 95, 1998. ! ! Bennett Fox, ! Algorithm 647: ! Implementation and Relative Efficiency of Quasirandom ! Sequence Generators, ! ACM Transactions on Mathematical Software, ! Volume 12, Number 4, pages 362-376, 1986. ! ! Peter Lewis, Allen Goodman, James Miller ! A Pseudo-Random Number Generator for the System/360, ! IBM Systems Journal, ! Volume 8, pages 136-143, 1969. ! ! Input: ! ! integer A, B, the limits of the interval. ! ! Output: ! ! integer I4_UNIFORM_AB, a number between A and B. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer a integer b integer i4_uniform_ab real ( kind = rk ) r integer value call random_number ( harvest = r ) ! ! Scale R to lie between A-0.5 and B+0.5. ! r = ( 1.0D+00 - r ) * ( real ( min ( a, b ), kind = rk ) - 0.5D+00 ) & + r * ( real ( max ( a, b ), kind = rk ) + 0.5D+00 ) ! ! Use rounding to convert R to an integer between A and B. ! value = nint ( r ) value = max ( value, min ( a, b ) ) value = min ( value, max ( a, b ) ) i4_uniform_ab = value return end subroutine i4vec_indicator ( n, a ) !*****************************************************************************80 ! !! I4VEC_INDICATOR sets an I4VEC to the indicator vector. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 09 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of elements of A. ! ! Output: ! ! integer A(N), the array to be initialized. ! implicit none integer n integer a(n) integer i do i = 1, n a(i) = i end do return end subroutine i4vec_print ( n, a, title ) !*****************************************************************************80 ! !! I4VEC_PRINT prints an I4VEC. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of components of the vector. ! ! integer A(N), the vector to be printed. ! ! character ( len = * ) TITLE, a title. ! implicit none integer n integer a(n) integer big integer i character ( len = * ) title write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) big = maxval ( abs ( a(1:n) ) ) write ( *, '(a)' ) ' ' if ( big < 1000 ) then do i = 1, n write ( *, '(i8,1x,i4)' ) i, a(i) end do else if ( big < 1000000 ) then do i = 1, n write ( *, '(i8,1x,i7)' ) i, a(i) end do else do i = 1, n write ( *, '(i8,i11)' ) i, a(i) end do end if return end subroutine i4vec_to_ch4vec ( n, i4vec, s ) !*****************************************************************************80 ! !! I4VEC_TO_CH4VEC converts an I4VEC into a string. ! ! Discussion: ! ! This routine can be useful when trying to read character data from an ! unformatted direct access file, for instance. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of integers. ! ! integer I4VEC(N), the integers. ! ! Output: ! ! character ( len = * ) S, a string of 4 * N characters ! representing the integer information. ! implicit none integer n integer i integer i4vec(n) integer j integer len_s character ( len = * ) s len_s = len ( s ) if ( len_s < 4 * n ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4VEC_TO_CH4VEC - Fatal error!' write ( *, '(a)' ) ' String S is too small for the data.' stop 1 end if s(1:4*n) = ' ' do i = 1, n j = 4 * ( i - 1 ) + 1 call i4_to_ch4 ( i4vec(i), s(j:j+3) ) end do return end function ic_to_ibraille ( ic ) !*****************************************************************************80 ! !! IC_TO_IBRAILLE converts an ASCII integer code to a Braille code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IC, the integer code for the ASCII character. ! ! Output: ! ! integer IC_TO_IBRAILLE, the integer code for ! the Braille character, or -1 if no corresponding code is available. ! implicit none integer ic integer ic_to_ibraille integer, parameter, dimension ( 0:255 ) :: junk = (/ & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & 1, 33, 35, -1, -1, -1, 28, 36, 34, 34, -1, -1, 29, 37, 32, -1, & 11, 02, 04, 05, 06, 07, 08, 09, 10, -1, 31, 30, -1, -1, -1, 35, & -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, & 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, & -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, & 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /) if ( 0 <= ic .and. ic <= 255 ) then ic_to_ibraille = junk(ic) else ic_to_ibraille = -1 end if return end function ic_to_iebcdic ( ic ) !*****************************************************************************80 ! !! IC_TO_IEBCDIC converts an ASCII character code to an EBCDIC code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IC, the integer code for the ASCII character. ! ! Output: ! ! integer IC_TO_IEBCDIC, the integer code for the ! EBCDIC character, or -1 if no corresponding EBCDIC code is available. ! implicit none integer ic integer ic_to_iebcdic integer, parameter, dimension ( 0:255 ) :: junk = (/ & 0, 1, 2, 3, 56, 45, 46, 47, 22, 5, 37, 11, 12, 13, 60, 61, & 16, 17, 18, -1, -1, -1, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, & 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, -1, 97, & 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, & 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, & 215,216,217,226,227,228,229,230,231,232,233, -1, -1, -1, -1,109, & -1,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, & 151,152,153,162,163,164,165,166,167,168,169, -1, 79, -1, -1, 7, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /) if ( 0 <= ic .and. ic <= 255 ) then ic_to_iebcdic = junk(ic) else ic_to_iebcdic = -1 end if return end function ic_to_imorse ( ic ) !*****************************************************************************80 ! !! IC_TO_IMORSE converts an ASCII integer code to a Morse integer code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IC, the integer code for the ASCII character. ! ! Output: ! ! integer IC_TO_IMORSE, the integer code for the ! Morse character, or -1 if no corresponding Morse code is available. ! implicit none integer ic integer ic_to_imorse integer, parameter, dimension ( 0:255 ) :: junk = (/ & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & 1, -1, 45, -1, -1, -1, -1, 42, -1, -1, -1, -1, 39, 43, 38, 44, & 37, 28, 29, 30, 31, 32, 33, 34, 35, 36, 40, -1, -1, -1, -1, 41, & -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, & 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, & -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, & 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /) if ( 0 <= ic .and. ic <= 255 ) then ic_to_imorse = junk(ic) else ic_to_imorse = -1 end if return end function ic_to_isoundex ( ic ) !*****************************************************************************80 ! !! IC_TO_ISOUNDEX converts an ASCII integer code to a Soundex integer code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IC, the integer code for the ASCII character. ! ! Output: ! ! integer IC_TO_ISOUNDEX, the integer code for the ! Soundex character, or -1 if no corresponding Soundex code is available. ! implicit none integer ic integer ic_to_isoundex integer, parameter, dimension ( 0:255 ) :: junk = (/ & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, 48, 49, 50, 51, 48, 49, 50, 48, 48, 50, 50, 52, 53, 53, 48, & 49, 50, 54, 50, 51, 48, 49, 48, 50, 48, 50, -1, -1, -1, -1, -1, & -1, 48, 49, 50, 51, 48, 49, 50, 48, 48, 50, 50, 52, 53, 53, 48, & 49, 50, 54, 50, 51, 48, 49, 48, 50, 48, 50, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /) if ( 0 <= ic .and. ic <= 255 ) then ic_to_isoundex = junk(ic) else ic_to_isoundex = -1 end if return end function iebcdic_to_ic ( iebcdic ) !*****************************************************************************80 ! !! IEBCDIC_TO_IC converts an EBCDIC character code to ASCII. ! ! Discussion: ! ! What this actually means is the following: ! ! If the letter "A" is entered into a file on an EBCDIC machine, ! it is coded internally as character 193. Should this character ! be read on an ASCII machine, it will not be displayed as "A", ! but rather as an unprintable character! But passing 193 in to ! IEBCDIC_TO_IC, out will come 65, the ASCII code for "A". Thus, the ! correct character to display on an ASCII machine is ! ! ACHAR ( IACHAR ( IEBCDIC_TO_IC ( EBCDIC Character ) ) ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 March 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IEBCDIC, the integer code for the EBCDIC ! character. ! ! Output: ! ! integer IEBCDIC_TO_IC, the integer code for the ! ASCII character, or -1 if no corresponding ASCII code is available. ! implicit none integer iebcdic integer iebcdic_to_ic integer, parameter, dimension ( 0:255 ) :: junk = (/ & 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, & 16, 17, 18, -1, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, & -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, & -1, -1, 22, -1, -1, -1, -1, -1, 4, -1, -1, -1, 14, 15, -1, 26, & 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, 40, 43,124, & 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, -1, & 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, 35, 64, 39, 61, 34, & -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, & -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, & -1, -1,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, & -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, & -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, & -1, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, & -1, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, & 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /) if ( 0 <= iebcdic .and. iebcdic <= 255 ) then iebcdic_to_ic = junk(iebcdic) else iebcdic_to_ic = -1 end if return end function isbn_digit_to_i4 ( c ) !*****************************************************************************80 ! !! ISBN_DIGIT_TO_I4 converts an ISBN digit to an I4. ! ! Discussion: ! ! The characters '0' through '9' stand for themselves, but ! the character 'X' or 'x' stands for 10. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character C, the ISBN character code to be converted. ! ! Output: ! ! integer ISBN_DIGIT_TO_I4, the numeric value of the ! character code, between 0 and 10. This value is returned as -1 if C is ! not a valid character code. ! implicit none character c integer isbn_digit_to_i4 integer value if ( c == '0' ) then value = 0 else if ( c == '1' ) then value = 1 else if ( c == '2' ) then value = 2 else if ( c == '3' ) then value = 3 else if ( c == '4' ) then value = 4 else if ( c == '5' ) then value = 5 else if ( c == '6' ) then value = 6 else if ( c == '7' ) then value = 7 else if ( c == '8' ) then value = 8 else if ( c == '9' ) then value = 9 else if ( c == 'X' .or. c == 'x' ) then value = 10 else value = -1 end if isbn_digit_to_i4 = value return end function istrcmp ( s1, s2 ) !*****************************************************************************80 ! !! ISTRCMP compares two strings, returning +1, 0, or -1. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to be compared. ! ! Output: ! ! integer ISTRCMP: ! -1 if S1 < S2, ! 0 if S1 = S2 ! +1 if S2 < S1. ! implicit none integer istrcmp integer nchar1 integer nchar2 integer s_length character ( len = * ) s1 character ( len = * ) s2 nchar1 = len ( s1 ) nchar2 = len ( s2 ) s_length = min ( nchar1, nchar2 ) if ( llt ( s1(1:s_length), s2(1:s_length) ) ) then istrcmp = -1 else if ( llt ( s2(1:s_length), s1(1:s_length) ) ) then istrcmp = 1 else if ( s1(1:s_length) == s2(1:s_length) ) then if ( nchar1 == nchar2 ) then istrcmp = 0 else if ( nchar1 < nchar2 ) then istrcmp = -1 else istrcmp = 1 end if end if return end function istrncmp ( s1, s2, nchar ) !*****************************************************************************80 ! !! ISTRNCMP compares the start of two strings, returning +1, 0, or -1. ! ! Discussion: ! ! If either string is shorter than NCHAR characters, then it is ! treated as though it were padded with blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to be compared. ! ! integer NCHAR, the number of characters to be compared. ! ! Output: ! ! integer ISTRNCMP: ! +1 if S1(1:NCHAR) is lexically greater than S2(1:NCHAR), ! 0 if they are equal, and ! -1 if S1(1:NCHAR) is lexically less than S2(1:NCHAR). ! implicit none character c1 character c2 integer i integer istrncmp integer nchar integer nchar1 integer nchar2 character ( len = * ) s1 character ( len = * ) s2 ! ! Figure out the maximum number of characters we will examine, ! which is the minimum of NCHAR and the lengths of the two ! strings. ! istrncmp = 0 nchar1 = len ( s1 ) nchar2 = len ( s2 ) do i = 1, nchar if ( i <= nchar1 ) then c1 = s1(i:i) else c1 = ' ' end if if ( i <= nchar2 ) then c2 = s2(i:i) else c2 = ' ' end if if ( llt ( c1, c2 ) ) then istrncmp = -1 return else if ( lgt ( c1, c2 ) ) then istrncmp = 1 return end if end do return end function len_nonnull ( s ) !*****************************************************************************80 ! !! LEN_NONNULL returns the length of a string up to the last non-null character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to measure. ! ! Output: ! ! integer LEN_NONNULL, the length of the string, ! up to the last non-null character. ! implicit none integer i integer len_nonnull integer len_s character, parameter :: NULL = achar ( 0 ) character ( len = * ) s len_s = len ( s ) do i = len_s, 1, -1 if ( s(i:i) /= NULL ) then len_nonnull = i return end if end do len_nonnull = 0 return end function malphnum2 ( s ) !*****************************************************************************80 ! !! MALPHNUM2 is TRUE if a string contains only alphanumerics and underscores. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Alphanumeric characters are 'A' through 'Z', 'a' through 'z', ! '0' through '9' and the underscore character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical MALPHNUM2, is TRUE if the string contains only ! alphabetic characters, numerals, and underscores. ! implicit none integer i integer itemp logical malphnum2 character ( len = * ) s malphnum2 = .false. do i = 1, len ( s ) if ( s(i:i) /= '_' ) then itemp = iachar ( s(i:i) ) if ( .not. ( 65 <= itemp .and. itemp <= 90 ) ) then if ( .not. ( 97 <= itemp .and. itemp <= 122 ) ) then if ( .not. ( 48 <= itemp .and. itemp <= 57 ) ) then return end if end if end if end if end do malphnum2 = .true. return end subroutine military_to_ch ( military, ch ) !*****************************************************************************80 ! !! MILITARY_TO_CH converts a Military code word to an ASCII character. ! ! Example: ! ! 'Alpha' 'A' ! 'Bravo' 'B' ! 'Zulu' 'Z' ! 'alpha' 'a' ! '7' '7' ! '%' '%' ! 'Adam' 'A' ! 'Anthrax' 'A' ! 'amoeba' 'a' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 December 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 8 ) MILITARY, the military code word. ! ! Output: ! ! character CH, the ASCII character. If MILITARY was not ! a recognized military code word, then CH is set to MILITARY(1:1). ! implicit none integer a_to_i4 character ch character ( len = 8 ), dimension ( 26 ) :: code = (/ & 'alpha ', 'bravo ', 'charlie ', 'delta ', 'echo ', & 'foxtrot ', 'golf ', 'hotel ', 'india ', 'juliet ', & 'kilo ', 'lima ', 'mike ', 'november', 'oscar ', & 'papa ', 'quebec ', 'romeo ', 'sierra ', 'tango ', & 'uniform ', 'victor ', 'whiskey ', 'x-ray ', 'yankee ', & 'zulu ' /) integer i character ( len = * ) military logical s_eqi ch = military(1:1) i = a_to_i4 ( ch ) if ( 1 <= i .and. i <= 26 ) then if ( s_eqi ( military, code(i) ) ) then ch = military(1:1) end if else if ( 27 <= i .and. i <= 52 ) then if ( s_eqi ( military, code(i-26) ) ) then ch = military(1:1) end if end if return end subroutine month_name_to_i4 ( month_name, month ) !*****************************************************************************80 ! !! MONTH_NAME_TO_I4 returns the month number of a given month ! ! Discussion: ! ! Capitalization is ignored. The month name has to match up to ! the unique beginning of a month name, and the rest is ignored. ! Here are the limits: ! ! JAnuary ! February ! MARch ! APril ! MAY ! JUNe ! JULy ! AUgust ! September ! October ! November ! December ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) MONTH_NAME, a string containing a month ! name or abbreviation. ! ! Output: ! ! integer MONTH, the number of the month, ! or -1 if the name could not be recognized. ! implicit none integer month character ( len = * ) month_name character ( len = 3 ) string string = month_name call s_cap ( string ) if ( string(1:2) == 'JA' ) then month = 1 else if ( string(1:1) == 'F' ) then month = 2 else if ( string(1:3) == 'MAR' ) then month = 3 else if ( string(1:2) == 'AP' ) then month = 4 else if ( string(1:3) == 'MAY' ) then month = 5 else if ( string(1:3) == 'JUN' ) then month = 6 else if ( string(1:3) == 'JUL' ) then month = 7 else if ( string(1:2) == 'AU' ) then month = 8 else if ( string(1:1) == 'S' ) then month = 9 else if ( string(1:1) == 'O' ) then month = 10 else if ( string(1:1) == 'N' ) then month = 11 else if ( string(1:1) == 'D' ) then month = 12 else month = -1 end if return end subroutine namefl ( s ) !*****************************************************************************80 ! !! NAMEFL replaces "lastname, firstname" by "firstname lastname". ! ! Discussion: ! ! As part of the process, all commas and double blanks are ! removed, and the first character of the output string is ! never a blank, unless the input S was entirely blank. ! ! Any commas in the input string are deleted. ! ! This routine cannot handle more than 255 characters in S. ! ! Example: ! ! Input Output ! ! Brown, Charlie Charlie Brown ! Cher Cher ! Howell, James Thurston James Thurston Howell ! Shakespeare Joe Bob Joe Bob Shakespeare ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a series of words separated by spaces. ! ! Output: ! ! character ( len = * ) S, the first word has been moved ! to the end of S, and any trailing comma removed. implicit none character ( len = 255 ) s2 integer i character ( len = * ) s integer s_length s2 = ' ' ! ! Remove all commas. ! s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == ',') then s(i:i) = ' ' end if end do ! ! Remove double blanks. ! This also guarantees the string is flush left. ! call s_blanks_delete ( s ) ! ! Get length of string. ! s_length = len_trim ( s ) if ( s_length <= 2 ) then return end if if ( 255 < s_length ) then s_length = len_trim ( s(1:255) ) end if ! ! Find the first blank in the string. ! do i = 2, s_length - 1 if ( s(i:i) == ' ' ) then s2(1:s_length-i) = s(i+1:s_length) s2(s_length-i+1:s_length-i+1) = ' ' s2(s_length-i+2:s_length) = s(1:i-1) s = s2(1:s_length) end if end do return end subroutine namelf ( s ) !*****************************************************************************80 ! !! NAMELF replaces "firstname lastname" by "lastname, firstname". ! ! Discussion: ! ! A one-word name is left unchanged. ! ! Example: ! ! Input: Output: ! ! Charlie Brown Brown, Charlie ! Cher Cher ! James Thurston Howell Howell, James Thurston ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S. ! S contains a series of words separated by spaces. ! ! Output: ! ! character ( len = * ) S: ! On if S contained a single word, it is ! unchanged. Otherwise, the last word has been moved ! to the beginning of S, and followed by a comma. ! ! As part of this process, all double blanks are removed ! from S, and the output S never begins with ! a blank (unless the input S was entirely blank). ! ! Moreover, any commas in the input string are deleted. ! ! This routine cannot handle more than 255 characters ! in S. If S is longer than that, only the ! first 255 characters will be considered. ! implicit none character ( len = 255 ) s2 integer i character ( len = * ) s integer s_length s2 = ' ' ! ! Remove all commas. ! s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == ',' ) then s(i:i) = ' ' end if end do ! ! Remove all double blanks, and make string flush left. ! call s_blanks_delete ( s ) ! ! Get length of string. ! s_length = len_trim ( s ) if ( s_length <= 2 ) then return end if if ( 255 < s_length ) then s_length = len_trim ( s(1:255) ) end if ! ! Find the last blank in the string. ! do i = s_length, 2, -1 if ( s(i:i) == ' ' ) then s2(1:s_length-i) = s(i+1:s_length) s2(s_length-i+1:s_length-i+2) = ', ' s2(s_length-i+3:s_length+1) = s(1:i-1) s = s2(1:s_length+1) end if end do return end subroutine namels ( name, ierror, rhs, value ) !*****************************************************************************80 ! !! NAMELS reads a NAMELIST line, returning the variable name and value. ! ! Discussion: ! ! NAMELS is a simple program, and can only handle simple input. ! In particular, it cannot handle: ! ! multiple assignments on one line, ! a single assignment extended over multiple lines, ! assignments to character or complex variables, ! assignments to arrays. ! ! Typical input would be of the form: ! ! name = value ! ! including, for instance: ! ! a = 1.0 ! n = -17 ! scale = +5.3E-2 ! ! Spaces are ignored, and case is not important. Integral values ! will be returned as real, but this is never a ! problem as long as the integers are "small". ! ! If a line begins with the character "#", it is assumed to be ! a comment, and is ignored. IERROR is returned as 6. ! ! If a line begins with the characters "end-of-input", it is ! assumed to be an "end-of-input" marker, and IERROR is returned ! as 7. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Output: ! ! character ( len = * ) NAME. ! NAME contains the left hand side of the assignment statement. ! Normally, this will be the name of a variable. ! If the input line was blank, then NAME will equal ' '. ! If an error occurred while trying to process the ! input line, NAME will contain the text of the line. ! If the line began with "#", then NAME will contain the ! text of the line. ! If the line equals "end-of-input", then NAME will contain ! the text of the line. ! ! integer IERROR. ! 0, no errors were detected. ! 1, the line was blank. ! 2, the line did not contain an "=" sign. ! 3, the line did not contain a variable name to the ! left of the "=" sign. ! 4, the right hand side of the assignment did not make ! sense. ! 5, end of input. ! 6, the line began with "#", signifying a comment. ! The text of the line is returned in NAME. ! 7, the line began with "end-of-input". ! ! character ( len = * ) RHS. ! RHS contains the right hand side of the assignment statement. ! ! real ( kind = rk ) VALUE. ! VALUE contains the right hand side of the assignment statement. ! Normally, this will be a real value. ! But if the input line was blank, or if an error occurred ! while trying to process the input line, or if input ! terminated, then VALUE will simply be set to 0. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer iequal integer ierror integer ios integer length character ( len = 255 ) line character ( len = * ) name integer pos character ( len = * ) rhs logical s_eqi real ( kind = rk ) value ! ! Set default values ! ierror = 0 name = ' ' rhs = ' ' value = 0 ! ! Read a line ! read ( *, '(a)', iostat = ios ) line if ( ios /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'NAMELS - Reached end of input.' ierror = 5 return end if ! ! Empty lines are OK ! if ( len_trim ( line ) <= 0 ) then ierror = 1 return end if ! ! Check for comment. ! if ( line(1:1) == '#' ) then ierror = 6 name = line return end if ! ! Check for "end-of-line". ! if ( s_eqi ( line, 'END-OF-INPUT' ) ) then ierror = 7 name = line return end if ! ! Does the line contain an = sign? ! if ( index ( line, '=' ) <= 0 ) then ierror = 2 value = 0 name = line return end if ! ! Find the name of the variable to be assigned. ! iequal = index ( name, '=' ) if ( 0 < iequal ) then rhs = line(iequal+1:) else rhs = line end if call s_before_ss_copy ( line, '=', name ) call s_blank_delete ( name ) if ( len_trim ( name ) <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'NAMELS - Warning!' write ( *, '(a)' ) ' The following input line was ignored, because' write ( *, '(a)' ) ' there was no variable name on the left hand' write ( *, '(a)' ) ' side of the assignment statement:' write ( *, '(a)' ) line write ( *, '(a)' ) ' ' ierror = 3 return end if ! ! Read the value, as a real number. ! pos = index ( line, '=' ) call s_to_r4 ( line(pos+1:), value, ierror, length ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'NAMELS - Warning!' write ( *, '(a)' ) ' The following input line was ignored, because' write ( *, '(a)' ) ' the right hand side of the assignment ' write ( *, '(a)' ) ' statement did not seem to make sense:' write ( *, '(a)' ) line write ( *, '(a)' ) ' ' ierror = 4 end if return end subroutine nexchr ( s, i, c ) !*****************************************************************************80 ! !! NEXCHR returns the next nonblank character from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! integer I. If I is 0, then there were no ! nonblank characters in the string. Otherwise I is ! the index of the first nonblank character in the string. ! ! character C, the first nonblank character in the string. ! implicit none character c integer i character ( len = * ) s integer s_first_nonblank i = s_first_nonblank ( s ) if ( 0 < i ) then c = s(i:i) else c = ' ' end if return end subroutine nexstr ( s, nsub, isub, sub ) !*****************************************************************************80 ! !! NEXSTR returns the next nonblank characters from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! integer NSUB, the number of nonblank characters ! desired. ! ! Output: ! ! integer ISUB, the index of the NSUB-th nonblank ! character. However, if ISUB is 0, there were NO nonblank ! characters. And if there are less than NSUB nonblank characters ! ISUB is the location of the last one of them. ! ! character ( len = NSUB ) SUB, the first NSUB nonblanks. ! implicit none integer nsub integer i integer isub integer jsub integer s_first_nonblank character ( len = * ) s character ( len = nsub ) sub sub = ' ' isub = 0 do i = 1, nsub jsub = s_first_nonblank ( s(isub+1:) ) if ( jsub <= 0 ) then return end if isub = isub + jsub sub(i:i) = s(isub:isub) end do return end subroutine number_inc ( s ) !*****************************************************************************80 ! !! NUMBER_INC increments the integer represented by a string. ! ! Example: ! ! Input Output ! ----- ------ ! '17' '18' ! 'cat3' 'cat4' ! '2for9' '3for0' ! '99thump' '00thump' ! ! Discussion: ! ! If the string contains characters that are not digits, they will ! simply be ignored. If the integer is all 9's on then ! the output will be all 0's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 January 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string representing an integer. ! ! Output: ! ! character ( len = * ) S, a string representing the incremented integer. ! implicit none logical ch_is_digit integer i character ( len = * ) s do i = len ( s ), 1, -1 if ( ch_is_digit ( s(i:i) ) ) then call digit_inc ( s(i:i) ) if ( s(i:i) /= '0' ) then return end if end if end do return end subroutine oct_to_i4 ( s, intval ) !*****************************************************************************80 ! !! OCT_TO_I4 converts an octal string to an I4. ! ! Warning: ! ! If too many digits are strung together, the computation will overflow. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string of digits. ! ! Output: ! ! integer INTVAL, the corresponding value. ! implicit none integer first integer i integer idig integer intval integer isgn character ( len = * ) s integer s_length s_length = len_trim ( s ) ! ! Determine if there is a plus or minus sign. ! isgn = 1 first = s_length do i = 1, s_length - 1 if ( s(i:i) == '-' ) then isgn = -1 else if ( s(i:i) == '+' ) then isgn = + 1 else if ( s(i:i) /= ' ' ) then first = i exit end if end do ! ! Read the numeric portion of the string. ! intval = 0 do i = first, s_length call ch_to_digit_oct ( s(i:i), idig ) intval = intval * 8 + idig end do intval = isgn * intval return end subroutine perm_check ( n, p, ierror ) !*****************************************************************************80 ! !! PERM_CHECK checks that a vector represents a permutation. ! ! Discussion: ! ! The routine verifies that each of the integers from 1 ! to N occurs among the N entries of the permutation. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 August 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries. ! ! integer P(N), the permutation, in standard index form. ! ! Output: ! ! integer IERROR, error flag. ! 0, the array does represent a permutation. ! nonzero, the array does not represent a permutation. The smallest ! missing value is equal to IERROR. ! implicit none integer n integer ierror integer ifind integer iseek integer p(n) ierror = 0 do iseek = 1, n ierror = iseek do ifind = 1, n if ( p(ifind) == iseek ) then ierror = 0 exit end if end do if ( ierror /= 0 ) then return end if end do return end subroutine perm_inverse3 ( n, perm, perm_inv ) !*****************************************************************************80 ! !! PERM_INVERSE3 produces the inverse of a given permutation. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 October 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of items permuted. ! ! integer PERM(N), a permutation. ! ! Output: ! ! integer PERM_INV(N), the inverse permutation. ! implicit none integer n integer i integer perm(n) integer perm_inv(n) do i = 1, n perm_inv(perm(i)) = i end do return end subroutine perm_uniform ( n, p ) !*****************************************************************************80 ! !! perm_uniform() selects a random permutation of N objects. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 April 2003 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Albert Nijenhuis, Herbert Wilf, ! Combinatorial Algorithms for Computers and Calculators, ! Academic Press, 1978, second edition, ! ISBN 0-12-519260-6, ! LC: QA164.N54. ! ! Input: ! ! integer N, the number of objects to be permuted. ! ! Output: ! ! integer P(N), the permutation. P(I) is the "new" ! location of the object originally at I. ! implicit none integer n integer i integer i4_uniform_ab integer j integer p(n) call i4vec_indicator ( n, p ) do i = 1, n j = i4_uniform_ab ( i, n ) call i4_swap ( p(i), p(j) ) end do return end subroutine r4_to_b4_ieee ( r, word ) !*****************************************************************************80 ! !! R4_TO_B4_IEEE converts an R4 to a 4 byte IEEE word. ! ! Discussion: ! ! This routine does not seem to working reliably for unnormalized data. ! ! Example: ! ! 0 00000000 00000000000000000000000 = 0 ! 1 00000000 00000000000000000000000 = -0 ! ! 0 11111111 00000000000000000000000 = Infinity ! 1 11111111 00000000000000000000000 = -Infinity ! ! 0 11111111 00000100000000000000000 = NaN ! 1 11111111 00100010001001010101010 = NaN ! ! 0 01111110 00000000000000000000000 = +1 * 2**(126-127) * 1.0 = 0.5 ! 0 01111111 00000000000000000000000 = +1 * 2**(127-127) * 1.0 = 1 ! 0 10000000 00000000000000000000000 = +1 * 2**(128-127) * 1.0 = 2 ! 0 10000001 00000000000000000000000 = +1 * 2**(129-127) * 1.0 = 4 ! ! 0 10000001 10100000000000000000000 = +1 * 2**(129-127) * 1.101 = 6.5 ! 1 10000001 10100000000000000000000 = -1 * 2**(129-127) * 1.101 = -6.5 ! ! 0 00000001 00000000000000000000000 = +1 * 2**( 1-127) * 1.0 = 2**(-126) ! 0 00000000 10000000000000000000000 = +1 * 2**( 0-126) * 0.1 = 2**(-127) ! 0 00000000 00000000000000000000001 = +1 * 2**( 0-126) * ! 0.00000000000000000000001 = ! 2**(-149) (Smallest positive value) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 11 November 2001 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! IEEE Standards Committee 754, ! IEEE Standard for Binary Floating Point Arithmetic, ! ANSI/IEEE Standard 754-1985, ! SIGPLAN Notices, ! Volume 22, Number 2, 1987, pages 9-25. ! ! Input: ! ! real ( kind = rk ) R, the real number to be converted. ! ! Output: ! ! integer WORD, the IEEE representation of the number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer e integer f real ( kind = rk ) r real ( kind = rk ) r_copy integer s integer word r_copy = r ! ! Determine S, the sign bit. ! if ( 0.0E+00 <= r_copy ) then s = 0 else s = 1 r_copy = -r_copy end if ! ! Determine E, the exponent. ! (FOR NOW, IGNORE UNNORMALIZED NUMBERS) ! e = 0 if ( r == 0.0E+00 ) then else do while ( 2.0E+00 <= r_copy ) e = e + 1 r_copy = r_copy / 2.0E+00 end do do while ( r_copy < 1.0E+00 .and. -127 < e ) e = e - 1 r_copy = r_copy * 2.0E+00 end do e = e + 127 end if ! ! Determine F, the fraction. ! if ( r == 0.0E+00 ) then f = 0 else if ( 0 < e) then r_copy = r_copy - 1.0E+00 f = int ( r_copy * 2.0E+00**23 ) else if ( e == 0 ) then f = int ( r_copy * 2.0E+00**23 ) end if ! ! Set the bits corresponding to S, E, F. ! call mvbits ( s, 0, 1, word, 31 ) call mvbits ( e, 0, 8, word, 23 ) call mvbits ( f, 0, 23, word, 0 ) return end subroutine r4_to_binary ( r, s ) !*****************************************************************************80 ! !! R4_TO_BINARY represents an R4 as a string of binary digits. ! ! Discussion: ! ! No check is made to ensure that the string is long enough. ! ! The binary digits are a faithful representation of the real ! number in base 2. ! ! Example: ! ! R S ! ! -10.75000 -1010.11 ! 0.4218750 0.011011 ! 0.3333333 0.01010101010101010101010 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 August 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R, the real number. ! ! Output: ! ! character ( len = * ) S, the binary representation. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer i integer iexp integer ilo real ( kind = rk ) r real ( kind = rk ) rcopy character ( len = * ) s integer s_length s_length = len ( s ) if ( s_length < 1 ) then return end if rcopy = r s = ' ' if ( rcopy == 0.0E+00 ) then s = '0' return end if ilo = 0 if ( rcopy < 0.0E+00 ) then ilo = 1 s(ilo:ilo) = '-' rcopy = -rcopy end if ! ! Figure out the divisor. ! iexp = 0 do while ( 1.0E+00 <= rcopy ) rcopy = rcopy / 2.0E+00 iexp = iexp + 1 end do do while ( rcopy < 0.5E+00 ) rcopy = rcopy * 2.0E+00 iexp = iexp - 1 end do ! ! Now 0.5 <= RCOPY < 1. ! ! If IEXP < 0, print leading zeroes. ! if ( iexp == 0 ) then ilo = ilo + 1 s(ilo:ilo) = '0' else if ( iexp < 0 ) then ilo = ilo + 1 s(ilo:ilo) = '0' ilo = ilo + 1 s(ilo:ilo) = '.' do i = 1, -iexp ilo = ilo + 1 s(ilo:ilo) = '0' end do end if ! ! Now repeatedly double RCOPY. ! Every time you exceed 1, that's a '1' digit. ! iexp = iexp + 1 do rcopy = 2.0E+00 * rcopy iexp = iexp - 1 if ( iexp == 0 ) then ilo = ilo + 1 s(ilo:ilo) = '.' if ( s_length <= ilo ) then return end if end if ilo = ilo + 1 if ( 1.0E+00 <= rcopy ) then rcopy = rcopy - 1.0E+00 s(ilo:ilo) = '1' else s(ilo:ilo) = '0' end if if ( s_length <= ilo ) then return end if if ( rcopy == 0.0E+00 ) then exit end if end do return end subroutine r4_to_ch4 ( r4, ch4 ) !*****************************************************************************80 ! !! R4_TO_CH4 converts an R4 to a 4 character string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 May 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real value. ! ! Output: ! ! character ( len = 4 ) CH4, a corresponding character value. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character ( len = 4 ) ch4 integer i4 integer j1 integer j2 integer j3 integer j4 real ( kind = rk ) r4 i4 = transfer ( r4, i4 ) j1 = ibits ( i4, 0, 8 ) j2 = ibits ( i4, 8, 8 ) j3 = ibits ( i4, 16, 8 ) j4 = ibits ( i4, 24, 8 ) ch4 = achar ( j1 ) // achar ( j2 ) // achar ( j3 ) // achar ( j4 ) return end subroutine r4_to_flt ( r4, isgn, mant, iexp, ndig ) !*****************************************************************************80 ! !! R4_TO_FLT computes the scientific representation of an R4. ! ! Discussion: ! ! The routine is given a real number R and computes a sign ISGN, ! an integer mantissa MANT and an integer exponent IEXP so ! that ! ! R4 = ISGN * MANT * 10 ^ IEXP ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real number whose scientific ! representation is desired. ! ! integer NDIG, the number of decimal digits. ! ! Output: ! ! integer ISGN, the sign of the number: ! -1, if R4 is negative. ! 0, if R4 is zero. ! 1, if R4 is positive. ! ! integer MANT, the mantissa of the representation. ! This is an integer between 0 and 10**NDIG, that is, ! 0 <= MANT < 10^NDIG. ! ! integer IEXP, the exponent of 10 that multiplies MULT. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer i integer idig integer iexp integer isgn integer mant integer ndig real ( kind = rk ) rmant real ( kind = rk ) r4 mant = 0 iexp = 0 isgn = 0 ! ! Find the first digit. ! That is, write the value in the form RMANT * 10**IEXP ! where 1/10 < RMANT <= 1. ! if ( r4 == 0.0E+00 ) then return else if ( r4 < 0.0E+00 ) then isgn = -1 rmant = abs ( r4 ) else isgn = 1 rmant = r4 end if do while ( 1.0E+00 < rmant ) rmant = rmant / 10.0E+00 iexp = iexp + 1 end do do while ( rmant <= 0.1E+00 ) rmant = rmant * 10.0E+00 iexp = iexp - 1 end do ! ! Now read off NDIG digits of RMANT. ! do i = 1, ndig rmant = rmant * 10.0E+00 idig = int ( rmant ) rmant = rmant - idig mant = 10 * mant + idig iexp = iexp - 1 end do ! ! Now do rounding. ! idig = int ( rmant * 10.0E+00 ) mant = 10 * mant + idig mant = nint ( real ( mant, kind = rk ) / 10.0E+00 ) ! ! Now chop off trailing zeroes. ! do while ( mod ( mant, 10 ) == 0 ) mant = mant / 10 iexp = iexp + 1 end do return end subroutine r4_to_s_left ( r4, s ) !*****************************************************************************80 ! !! R4_TO_S_LEFT writes an R4 into a left justified character string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real number to be written into the string. ! ! Output: ! ! character ( len = * ) S, the string into which ! the real number is to be written. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) real ( kind = rk ) r4 character ( len = * ) s character ( len = 14 ) s2 if ( real ( int ( r4 ), kind = rk ) == r4 ) then write ( s2, '(i14)' ) int ( r4 ) else if ( abs ( r4 ) < 999999.5E+00 ) then write ( s2, '(f14.6)' ) r4 else write ( s2, '(g14.6)' ) r4 end if s = adjustl ( s2 ) return end subroutine r4_to_s_right ( r4, s ) !*****************************************************************************80 ! !! R4_TO_S_RIGHT writes an R4 into a right justified character string. ! ! Discussion: ! ! Thanks to Bill Richmond for pointing out a programming error ! that stored the data in S2, and then failed to copy it to the ! output quantity S. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 September 2004 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real number to be written into the string. ! ! Output: ! ! character ( len = * ) S, the string into which ! the real number is to be written. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) real ( kind = rk ) r4 character ( len = * ) s character ( len = 14 ) s2 if ( real ( int ( r4 ), kind = rk ) == r4 ) then write ( s2, '(i14)' ) int ( r4 ) else if ( abs ( r4 ) < 999999.5E+00 ) then write ( s2, '(f14.6)' ) r4 else write ( s2, '(g14.6)' ) r4 end if s = ' ' s(1:14) = s2(1:14) call s_adjustr ( s ) return end function r4_to_s32 ( r4 ) !*****************************************************************************80 ! !! R4_TO_S32 encodes an R4 as 32 characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real number to be coded. ! ! Output: ! ! character ( len = 32 ) R4_TO_S32, the character variable that ! corresponds to the real number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character ( len = 32 ) chr32 integer i integer iexp integer ii integer j real ( kind = rk ) r4 character ( len = 32 ) r4_to_s32 real ( kind = rk ) rcopy rcopy = r4 ! ! Sign bit ! if ( rcopy < 0.0E+00 ) then chr32(1:1) = '1' else chr32(1:1) = '0' end if rcopy = abs ( rcopy ) ! ! Exponent: 'excess 128' format, legal values of IEXP are 1 to 255. ! if ( rcopy == 0.0E+00 ) then iexp = 0 else iexp = 128 if ( rcopy < 1.0E+00 ) then do while ( 1 < iexp ) rcopy = 2.0E+00 * rcopy iexp = iexp - 1 end do else if ( 2.0E+00 <= rcopy ) then do while ( iexp < 255 ) rcopy = 0.5E+00 * rcopy iexp = iexp + 1 end do end if end if ! ! Write characters 2 through 9 that represent exponent. ! do i = 1, 8 ii = 10 - i j = mod ( iexp, 2 ) iexp = iexp / 2 if ( j == 0 ) then chr32(ii:ii) = '0' else chr32(ii:ii) = '1' end if end do ! ! Write mantissa in positions 10 through 32. ! Note that, unless exponent equals 0, the most significant bit is ! assumed to be 1 and hence is not stored. ! if ( rcopy /= 0.0E+00 ) then rcopy = rcopy - 1.0E+00 end if do i = 10, 32 rcopy = 2.0E+00 * rcopy if ( 1.0E+00 <= rcopy ) then chr32(i:i) = '1' rcopy = rcopy - 1.0E+00 else chr32(i:i) = '0' end if end do r4_to_s32 = chr32 return end subroutine r4_to_sef ( r4, s, e, f ) !*****************************************************************************80 ! !! R4_TO_SEF represents an R4 as R = S * 2**E * F. ! ! Discussion: ! ! Assuming no arithmetic problems, in fact, this equality should be ! exact, that is, S, E and F should exactly express the value ! as stored on the computer. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 November 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R4, the real number. ! ! Output: ! ! integer S, the sign bit: ! 0, if R is nonnegative; ! 1, if R is negative. ! ! integer E, the exponent base 2. ! ! integer F, the mantissa. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer e integer f real ( kind = rk ) r4 real ( kind = rk ) r4_copy integer s if ( r4 == 0.0E+00 ) then s = 0 e = 0 f = 0 return end if r4_copy = r4 ! ! Set S. ! if ( 0.0E+00 <= r4_copy ) then s = 0 else s = 1 r4_copy = -r4_copy end if ! ! Extracting the exponent leaves 0.5 <= R4_COPY < 1.0. ! e = 0 do while ( r4_copy < 0.5E+00 ) r4_copy = r4_copy * 2.0E+00 e = e - 1 end do do while ( 1.0E+00 <= r4_copy ) r4_copy = r4_copy / 2.0E+00 e = e + 1 end do ! ! Get the binary mantissa, adjusting the exponent as you go. ! f = 0 e = e + 1 do f = 2 * f e = e - 1 if ( 1.0E+00 <= r4_copy ) then f = f + 1 r4_copy = r4_copy - 1.0E+00 end if if ( r4_copy == 0.0E+00 ) then exit end if r4_copy = 2.0E+00 * r4_copy end do return end subroutine r8_extract ( s, r8, ierror ) !*****************************************************************************80 ! !! r8_extract() "extracts" an R8 from the beginning of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S; a string from ! whose beginning a real is to be extracted. ! ! Output: ! ! character ( len = * ) S: the real, if found, has been removed ! from the string. ! ! real ( kind = rk ) R8. If IERROR is 0, then R4 contains the ! next real read from the string; otherwise R4 is 0. ! ! integer IERROR. ! 0, no error. ! nonzero, a real could not be extracted from the beginning of the ! string. R4 is 0.0 and S is unchanged. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer ierror integer length real ( kind = rk ) r8 character ( len = * ) s r8 = 0.0D+00 call s_to_r8_old ( s, r8, ierror, length ) if ( ierror /= 0 .or. length == 0 ) then ierror = 1 r8 = 0.0D+00 else call s_shift_left ( s, length ) end if return end subroutine r8_input ( string, value, ierror ) !*****************************************************************************80 ! !! R8_INPUT prints a prompt string and reads an R8 from the user. ! ! Discussion: ! ! An R8 is a real ( kind = rk ) value. ! ! If the input line starts with a comment character ('#') or is blank, ! the routine ignores that line, and tries to read the next one. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 March 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) STRING, the prompt string. ! ! Output: ! ! real ( kind = rk ) VALUE, the value input by the user. ! ! integer IERROR, an error flag, which is zero ! if no error occurred. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer ierror integer length character ( len = 255 ) line character ( len = * ) string real ( kind = rk ) value ierror = 0 value = huge ( value ) ! ! Write the prompt. ! write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( string ) do read ( *, '(a)', iostat = ierror ) line if ( ierror /= 0 ) then return end if ! ! If the line begins with a comment character, go back and read the next line. ! if ( line(1:1) == '#' ) then cycle end if if ( len_trim ( line ) == 0 ) then cycle end if ! ! Extract numeric information from the string. ! call s_to_r8_old ( line, value, ierror, length ) if ( ierror /= 0 ) then value = huge ( value ) return end if exit end do return end subroutine r8_next ( s, r, done ) !*****************************************************************************80 ! !! R8_NEXT "reads" R8's from a string, one at a time. ! ! Discussion: ! ! An R8 is a real ( kind = rk ) value. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string, presumably containing real ! numbers. These may be separated by spaces or commas. ! ! logical DONE. ! On input with a fresh string, the user should set DONE to TRUE. ! ! Output: ! ! real ( kind = rk ) R. If DONE is FALSE, then R contains the ! "next" real value read from the string. If DONE is TRUE, then ! R is zero. ! ! logical DONE: the routine sets DONE to FALSE if another real ! value was read, or TRUE if no more reals could be read. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) logical done integer ierror integer length integer, save :: next = 1 real ( kind = rk ) r character ( len = * ) s r = 0.0D+00 if ( done ) then next = 1 done = .false. end if if ( len ( s ) < next ) then done = .true. return end if call s_to_r8_old ( s(next:), r, ierror, length ) if ( ierror /= 0 ) then done = .true. next = 1 else if ( length == 0 ) then done = .true. next = 1 else done = .false. next = next + length end if return end subroutine r8_to_binary ( r, s ) !*****************************************************************************80 ! !! R8_TO_BINARY represents an R8 as a string of binary digits. ! ! Discussion: ! ! No check is made to ensure that the string is long enough. ! ! The binary digits are a faithful representation of the real ! number in base 2. ! ! Example: ! ! R S ! ! -10.75000 -1010.11 ! 0.4218750 0.011011 ! 0.3333333 0.01010101010101010101010 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R, the real number. ! ! Output: ! ! character ( len = * ) S, the binary representation. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer i integer iexp integer ilo real ( kind = rk ) r real ( kind = rk ) rcopy character ( len = * ) s integer s_length s_length = len ( s ) if ( s_length < 1 ) then return end if rcopy = r s = ' ' if ( rcopy == 0.0D+00 ) then s = '0' return end if ilo = 0 if ( rcopy < 0.0D+00 ) then ilo = 1 s(ilo:ilo) = '-' rcopy = -rcopy end if ! ! Figure out the divisor. ! iexp = 0 do while ( 1.0D+00 <= rcopy ) rcopy = rcopy / 2.0D+00 iexp = iexp + 1 end do do while ( rcopy < 0.5D+00 ) rcopy = rcopy * 2.0D+00 iexp = iexp - 1 end do ! ! Now 0.5 <= RCOPY < 1. ! ! If IEXP < 0, print leading zeroes. ! if ( iexp == 0 ) then ilo = ilo + 1 s(ilo:ilo) = '0' else if ( iexp < 0 ) then ilo = ilo + 1 s(ilo:ilo) = '0' ilo = ilo + 1 s(ilo:ilo) = '.' do i = 1, -iexp ilo = ilo + 1 s(ilo:ilo) = '0' end do end if ! ! Now repeatedly double RCOPY. ! Every time you exceed 1, that's a '1' digit. ! iexp = iexp + 1 do rcopy = 2.0D+00 * rcopy iexp = iexp - 1 if ( iexp == 0 ) then ilo = ilo + 1 s(ilo:ilo) = '.' if ( s_length <= ilo ) then return end if end if ilo = ilo + 1 if ( 1.0D+00 <= rcopy ) then rcopy = rcopy - 1.0D+00 s(ilo:ilo) = '1' else s(ilo:ilo) = '0' end if if ( s_length <= ilo ) then return end if if ( rcopy == 0.0D+00 ) then exit end if end do return end subroutine r8_to_s_left ( r8, s ) !*****************************************************************************80 ! !! R8_TO_S_LEFT writes an R8 into a left justified string. ! ! Discussion: ! ! An R8 is a real ( kind = rk ) value. ! ! A 'G14.6' format is used with a WRITE statement. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 January 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) R8, the number to be written into the string. ! ! Output: ! ! character ( len = * ) S, the string into which ! the real number is to be written. If the string is less than 14 ! characters long, it will will be returned as a series of asterisks. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer i real ( kind = rk ) r8 character ( len = * ) s integer s_length character ( len = 14 ) s2 s_length = len ( s ) if ( s_length < 14 ) then do i = 1, s_length s(i:i) = '*' end do else if ( r8 == 0.0D+00 ) then s(1:14) = ' 0.0 ' else write ( s2, '(g14.6)' ) r8 s(1:14) = s2 end if ! ! Shift the string left. ! s = adjustl ( s ) return end subroutine r8_to_s_right ( d, s ) !*****************************************************************************80 ! !! R8_TO_S_LEFT writes an R8 into a right justified string. ! ! Discussion: ! ! An R8 is a real ( kind = rk ) value. ! ! A 'G14.6' format is used with a WRITE statement. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 January 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! real ( kind = rk ) D, the number to be written into the string. ! ! Output: ! ! character ( len = * ) S, the string into which ! the real number is to be written. If the string is less than 14 ! characters long, it will will be returned as a series of asterisks. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) real ( kind = rk ) d integer i character ( len = * ) s integer s_length character ( len = 14 ) s2 s_length = len ( s ) if ( s_length < 14 ) then do i = 1, s_length s(i:i) = '*' end do else if ( d == 0.0D+00 ) then s(1:14) = ' 0.0 ' else write ( s2, '(g14.6)' ) d s(1:14) = s2 end if ! ! Shift the string right. ! call s_adjustr ( s ) return end subroutine r8vec_to_s ( n, x, s ) !*****************************************************************************80 ! !! R8VEC_TO_S "writes" an R8VEC into a string. ! ! Discussion: ! ! An R8VEC is a vector of "real ( kind = rk )" values. ! ! The values will be separated by commas and a single space. ! If the string is too short, then data will be lost. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the dimension of X. ! ! real ( kind = rk ) X(N), a vector to be written to a string. ! ! Output: ! ! character ( len = * ) S, a string to which the real vector ! has been written. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer i character ( len = * ) s character ( len = 14 ) s2 real ( kind = rk ) x(n) do i = 1, n if ( x(i) == 0.0D+00 ) then s2 = '0' else if ( 1.0D+10 <= abs ( x(i) ) ) then write ( s2, '(g14.6)' ) x(i) call s_trim_zeros ( s2 ) else if ( real ( int ( x(i) ), kind = rk ) == x(i) ) then write ( s2, '(i12)' ) int ( x(i) ) else write ( s2, '(g14.6)' ) x(i) call s_trim_zeros ( s2 ) end if if ( i == 1 ) then s = adjustl ( s2 ) else s = trim ( s ) // ', ' // adjustl ( s2 ) end if end do return end subroutine ranger ( s, maxval, nval, ival ) !*****************************************************************************80 ! !! RANGER "understands" a range defined by a string like '4:8'. ! ! Discussion: ! ! The range can be much more complicated, as in ! ! '4:8 10 2 14:20' ! ! or (commas are optional) ! ! '4:8,10, 2 , 14:20' ! ! RANGER will return the values ! ! 4, 5, 6, 7, 8, 10, 2, 14, 15, 16, 17, 18, 19, 20 ! ! 0 and negative integers are acceptable. So are pairs ! of values that are equal, as in '4:4', which just represents ! 4, and pairs that represent descending sequences, as ! in '4:-2'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, contains a string of integers, ! representing themselves, and pairs of integers representing ! themselves and all integers between them. ! ! integer MAXVAL, the dimension of the IVAL vector, ! which represents the maximum number of integers that may ! be read from the string. ! ! Output: ! ! integer NVAL, the number of integers read from ! the string. ! ! integer IVAL(MAXVAL). The first NVAL entries of ! IVAL contain the integers read from the string. ! implicit none integer maxval integer i integer ierror integer ilo integer inc integer intval integer ival(maxval) integer length integer lens integer next integer nval character ( len = * ) s nval = 0 ! ! Replace all commas by blanks. ! call s_ch_blank ( s, ',' ) ! ! Replace multiple consecutive blanks by one blank. ! call s_blanks_delete ( s ) ! ! Get the length of the string to the last nonblank. ! lens = len_trim ( s ) ! ! Set a pointer to the next location to be examined. ! next = 1 do while ( next <= lens ) ! ! Find the next integer in the string. ! call s_to_i4 ( s(next:), intval, ierror, length ) if ( ierror /= 0 ) then return end if ! ! Move the pointer. ! next = next + length ! ! If there's room, add the value to the list. ! if ( maxval <= nval ) then return end if nval = nval + 1 ival(nval) = intval ! ! Have we reached the end of the string? ! if ( lens < next ) then return end if ! ! Skip past the next character if it is a space. ! if ( s(next:next) == ' ' ) then next = next + 1 if ( lens < next ) then return end if end if ! ! Is the next character a colon? ! if ( s(next:next) /= ':' ) then cycle end if ! ! Increase the pointer past the colon. ! next = next + 1 if ( lens < next ) then return end if ! ! Find the next integer in the string. ! call s_to_i4 ( s(next:), intval, ierror, length ) if ( ierror /= 0 ) then return end if ! ! Move the pointer. ! next = next + length ! ! Generate integers between the two values. ! ilo = ival(nval) if ( ilo <= intval ) then inc = + 1 else inc = -1 end if do i = ilo+inc, intval, inc if ( maxval <= nval ) then return end if nval = nval + 1 ival(nval) = i end do end do return end subroutine rat_to_s_left ( ival, jval, s ) !*****************************************************************************80 ! !! RAT_TO_S_LEFT returns a left-justified representation of IVAL/JVAL. ! ! Discussion: ! ! If the ratio is negative, a minus sign precedes IVAL. ! A slash separates IVAL and JVAL. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 February 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IVAL, JVAL, the integers whose ratio ! IVAL/JVAL is to be represented. ! ! If IVAL is nonzero and JVAL is 0, the string will be returned as "Inf" ! or "-Inf" (Infinity), and if both IVAL and JVAL are zero, the string ! will be returned as "NaN" (Not-a-Number). ! ! Output: ! ! character ( len = * ) S, a left-justified string ! containing the representation of IVAL/JVAL. ! implicit none integer ival integer ival2 integer jval integer jval2 character ( len = * ) s character ( len = 22 ) s2 ! ! Take care of simple cases right away. ! if ( ival == 0 ) then if ( jval /= 0 ) then s2 = '0' else s2 = 'NaN' end if else if ( jval == 0 ) then if ( 0 < ival ) then s2 = 'Inf' else s2 = '-Inf' end if ! ! Make copies of IVAL and JVAL. ! else ival2 = ival jval2 = jval if ( jval2 == 1 ) then write ( s2, '(i11)' ) ival2 else write ( s2, '(i11, ''/'', i10)' ) ival2, jval2 end if call s_blank_delete ( s2 ) end if s = s2 return end subroutine rat_to_s_right ( ival, jval, s ) !*****************************************************************************80 ! !! RAT_TO_S_RIGHT returns a right-justified representation of IVAL/JVAL. ! ! Discussion: ! ! If the ratio is negative, a minus sign precedes IVAL. ! A slash separates IVAL and JVAL. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 February 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer IVAL, JVAL, the two integers whose ! ratio IVAL/JVAL is to be represented. ! ! Note that if IVAL is nonzero and JVAL is 0, the string will ! be returned as "Inf" or "-Inf" (Infinity), and if both ! IVAL and JVAL are zero, the string will be returned as "NaN" ! (Not-a-Number). ! ! Output: ! ! character ( len = * ) S, a right-justified string ! containing the representation of IVAL/JVAL. ! implicit none integer ival integer jval character ( len = * ) s call rat_to_s_left ( ival, jval, s ) call s_adjustr ( s ) return end subroutine s_adjustl ( s ) !*****************************************************************************80 ! !! S_ADJUSTL flushes a string left. ! ! Discussion: ! ! Both blanks and tabs are treated as "white space". ! ! This routine is similar to the FORTRAN90 ADJUSTL routine. ! ! Example: ! ! Input Output ! ! ' Hello' 'Hello ' ! ' Hi there! ' 'Hi there! ' ! 'Fred ' 'Fred ' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 January 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: a string of characters. ! ! Output: ! ! character ( len = * ) S: any initial blanks or tabs have been removed. ! implicit none integer i integer nonb character ( len = * ) s integer s_length character, parameter :: TAB = achar ( 9 ) ! ! Check the length of the string to the last nonblank. ! If nonpositive, return. ! s_length = len_trim ( s ) if ( s_length <= 0 ) then return end if ! ! Find NONB, the location of the first nonblank, nontab. ! nonb = 0 do i = 1, s_length if ( s(i:i) /= ' ' .and. s(i:i) /= TAB ) then nonb = i exit end if end do if ( nonb == 0 ) then s = ' ' return end if ! ! Shift the string left. ! if ( 1 < nonb ) then do i = 1, s_length + 1 - nonb s(i:i) = s(i+nonb-1:i+nonb-1) end do end if ! ! Blank out the end of the string. ! s(s_length+2-nonb:s_length) = ' ' return end subroutine s_adjustr ( s ) !*****************************************************************************80 ! !! S_ADJUSTR flushes a string right. ! ! Example: ! ! Input Output ! 'Hello ' ' Hello' ! ' Hi there! ' ' Hi there!' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: a string. ! ! Output: ! ! character ( len = * ) S: trailing blank ! characters have been cut, and pasted back onto the front. ! implicit none integer i integer nonb character ( len = * ) s integer s_length ! ! Check the full length of the string. ! s_length = len ( s ) ! ! Find the occurrence of the last nonblank. ! nonb = len_trim ( s ) ! ! Shift the string right. ! do i = s_length, s_length + 1 - nonb, -1 s(i:i) = s(i-s_length+nonb:i-s_length+nonb) end do ! ! Blank out the beginning of the string. ! s(1:s_length-nonb) = ' ' return end subroutine s_after_ss_copy ( s1, ss, s2 ) !*****************************************************************************80 ! !! S_AFTER_SS_COPY copies a string after a given substring. ! ! Discussion: ! ! S1 and S2 can be the same object, in which case the string is ! overwritten by a copy of itself after the substring. ! ! Example: ! ! Input: ! ! S1 = 'ABCDEFGH' ! SS = 'EF' ! ! Output: ! ! S2 = 'GH'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be copied. ! ! character ( len = * ) SS, the substring after which the copy begins. ! ! Output: ! ! character ( len = * ) S2, the copied portion of S. ! implicit none integer first integer last integer last_s2 character ( len = * ) s1 integer s1_length character ( len = * ) s2 character ( len = * ) ss ! ! Find the first occurrence of the substring. ! first = index ( s1, ss ) ! ! If the substring doesn't occur at all, then S2 is blank. ! if ( first == 0 ) then s2 = ' ' return end if ! ! Redefine FIRST to point to the first character to copy after ! the substring. ! first = first + len ( ss ) ! ! Measure the two strings. ! s1_length = len ( s1 ) last_s2 = len ( s2 ) ! ! Adjust effective length of S if S2 is short. ! last = min ( s1_length, last_s2 + first - 1 ) ! ! Copy the string. ! s2(1:s1_length+1-first) = s1(first:s1_length) ! ! Clear out the rest of the copy. ! s2(s1_length+2-first:last_s2) = ' ' return end subroutine s_alpha_last ( s, iloc ) !*****************************************************************************80 ! !! S_ALPHA_LAST returns the location of the last alphabetic character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 May 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! Output: ! ! integer ILOC, the location of the last alphabetic ! character in the string. If there are no alphabetic ! characters, ILOC is returned as 0. ! implicit none logical ch_is_alpha integer i integer iloc character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = s_length, 1, -1 if ( ch_is_alpha ( s(i:i) ) ) then iloc = i return end if end do iloc = 0 return end function s_any_alpha ( s ) !*****************************************************************************80 ! !! S_ANY_ALPHA is TRUE if a string contains any alphabetic character. ! ! Example: ! ! Input Output ! ! Riding Hood TRUE ! 123 + 34 FALSE ! Seven Eleven TRUE ! 1.0E+11 TRUE ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string to be checked. ! ! Output: ! ! logical S_ANY_ALPHA is TRUE if any character in string ! is an alphabetic character. ! implicit none logical ch_is_alpha integer i character ( len = * ) s logical s_any_alpha integer s_length s_any_alpha = .true. s_length = len_trim ( s ) do i = 1, s_length if ( ch_is_alpha ( s(i:i) ) ) then return end if end do s_any_alpha = .false. return end function s_any_control ( s ) !*****************************************************************************80 ! !! S_ANY_CONTROL is TRUE if a string contains any control characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, is the string to check. ! ! Output: ! ! logical S_ANY_CONTROL, is TRUE if any character is ! a control character. ! implicit none logical ch_is_control integer i character ( len = * ) s logical s_any_control integer s_length s_length = len_trim ( s ) do i = 1, s_length if ( ch_is_control ( s(i:i) ) ) then s_any_control = .true. return end if end do s_any_control = .false. return end subroutine s_b2u ( s ) !*****************************************************************************80 ! !! S_B2U replaces interword blanks by underscores. ! ! Discussion: ! ! Initial blanks are deleted by shifting the string to be ! flush left. ! ! This routine is useful for making a multiword name look ! like a single blank-delimited string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i character ( len = * ) s integer s_length s = adjustl ( s ) s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == ' ' ) then s(i:i) = '_' end if end do return end subroutine s_before_ss_copy ( s, ss, s2 ) !*****************************************************************************80 ! !! S_BEFORE_SS_COPY copies a string up to a given substring. ! ! Discussion: ! ! S and S2 can be the same object, in which case the string is ! overwritten by a copy of itself up to the substring, followed ! by blanks. ! ! Example: ! ! Input: ! ! S = 'ABCDEFGH' ! SS = 'EF' ! ! Output: ! ! S2 = 'ABCD'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be copied. ! ! character ( len = * ) SS, the substring before which the copy stops. ! ! Output: ! ! character ( len = * ) S2, the copied portion of S. ! implicit none integer last integer last_s2 character ( len = * ) s character ( len = * ) s2 character ( len = * ) ss ! ! Find the first occurrence of the substring. ! last = index ( s, ss ) ! ! If the substring doesn't occur at all, behave as though it begins ! just after the string terminates. ! ! Now redefine LAST to point to the last character to copy before ! the substring begins. ! if ( last == 0 ) then last = len ( s ) else last = last - 1 end if ! ! Now adjust again in case the copy holder is "short". ! last_s2 = len ( s2 ) last = min ( last, last_s2 ) ! ! Copy the beginning of the string. ! Presumably, compilers now understand that if LAST is 0, we don't ! copy anything. ! Clear out the rest of the copy. ! s2(1:last) = s(1:last) s2(last+1:last_s2) = ' ' return end function s_begin ( s1, s2 ) !*****************************************************************************80 ! !! S_BEGIN is TRUE if one string matches the beginning of the other. ! ! Discussion: ! ! The strings are compared, ignoring blanks, spaces and capitalization. ! ! Example: ! ! S1 S2 S_BEGIN ! ! 'Bob' 'BOB' TRUE ! ' B o b ' ' bo b' TRUE ! 'Bob' 'Bobby' TRUE ! 'Bobo' 'Bobb' FALSE ! ' ' 'Bob' FALSE (Do not allow a blank to match ! anything but another blank string.) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 January 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to be compared. ! ! Output: ! ! logical S_BEGIN, is TRUE if the strings match up to ! the end of the shorter string, ignoring case. ! implicit none logical ch_eqi integer i1 integer i2 logical s_begin character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len_trim ( s1 ) s2_length = len_trim ( s2 ) ! ! If either string is blank, then both must be blank to match. ! Otherwise, a blank string matches anything, which is not ! what most people want. ! if ( s1_length == 0 .or. s2_length == 0 ) then if ( s1_length == 0 .and. s2_length == 0 ) then s_begin = .true. else s_begin = .false. end if return end if i1 = 0 i2 = 0 ! ! Find the next nonblank in S1. ! do do i1 = i1 + 1 if ( s1_length < i1 ) then s_begin = .true. return end if if ( s1(i1:i1) /= ' ' ) then exit end if end do ! ! Find the next nonblank in S2. ! do i2 = i2 + 1 if ( s2_length < i2 ) then s_begin = .true. return end if if ( s2(i2:i2) /= ' ' ) then exit end if end do ! ! If the characters match, get the next pair. ! if ( .not. ch_eqi ( s1(i1:i1), s2(i2:i2) ) ) then exit end if end do s_begin = .false. return end subroutine s_behead_substring ( s, sub ) !*****************************************************************************80 ! !! S_BEHEAD_SUBSTRING "beheads" a string, removing a given substring. ! ! Discussion: ! ! Initial blanks in the string are removed first. ! ! Then, if the initial part of the string matches the substring, ! that part is removed and the remainder shifted left. ! ! Initial blanks in the substring are NOT ignored. ! ! Capitalization is ignored. ! ! If the substring is equal to the string, then the resultant ! string is returned as a single blank. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 January 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! character ( len = * ) SUB, the substring to be removed from ! the beginning of the string. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ( len = * ) s logical s_eqi integer s_length character ( len = * ) sub integer sub_length ! ! Remove leading blanks from the string. ! s = adjustl ( s ) ! ! Get lengths. ! s_length = len_trim ( s ) sub_length = len_trim ( sub ) if ( s_length < sub_length ) then return end if ! ! If the string begins with the substring, chop it off. ! if ( s_eqi ( s(1:sub_length), sub(1:sub_length) ) ) then if ( sub_length < s_length ) then s = s(sub_length+1:s_length) s = adjustl ( s ) else s = ' ' end if end if return end subroutine s_blank_delete ( s ) !*****************************************************************************80 ! !! S_BLANK_DELETE removes blanks from a string, left justifying the remainder. ! ! Discussion: ! ! All TAB characters are also removed. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 26 July 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer get integer put character ( len = * ) s integer s_length character, parameter :: tab = achar ( 9 ) put = 0 s_length = len_trim ( s ) do get = 1, s_length ch = s(get:get) if ( ch /= ' ' .and. ch /= tab ) then put = put + 1 s(put:put) = ch end if end do s(put+1:s_length) = ' ' return end subroutine s_blanks_delete ( s ) !*****************************************************************************80 ! !! S_BLANKS_DELETE replaces consecutive blanks by one blank. ! ! Discussion: ! ! Thanks to Bill Richmond for pointing out a programming flaw which ! meant that, as characters were slid to the left through multiple ! blanks, their original images were not blanked out. This problem ! is easiest resolved by using a copy of the string. ! ! The remaining characters are left justified and right padded with blanks. ! TAB characters are converted to spaces. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 September 2004 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i integer j character newchr character oldchr character ( len = * ) s character ( len = len ( s ) ) s_copy integer s_length character, parameter :: TAB = achar ( 9 ) s_length = len ( s ) j = 0 s_copy(1:s_length) = s(1:s_length) s(1:s_length) = ' ' newchr = ' ' do i = 1, s_length oldchr = newchr newchr = s_copy(i:i) if ( newchr == TAB ) then newchr = ' ' end if if ( oldchr /= ' ' .or. newchr /= ' ' ) then j = j + 1 s(j:j) = newchr end if end do return end subroutine s_blanks_insert ( s, ilo, ihi ) !*****************************************************************************80 ! !! S_BLANKS_INSERT inserts blanks into a string, sliding old characters over. ! ! Discussion: ! ! Characters at the end of the string "drop off" and are lost. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! integer ILO, the location where the first blank ! is to be inserted. ! ! integer IHI, the location where the last blank ! is to be inserted. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer i integer get integer ihi integer ilo integer imax integer imin integer put integer nmove character ( len = * ) s integer s_length s_length = len ( s ) if ( ihi < ilo .or. s_length < ilo ) then return end if if ( ihi <= s_length ) then imax = ihi else imax = s_length end if if ( 1 <= ilo ) then imin = ilo else imin = 1 end if nmove = s_length - imax do i = 1, nmove put = s_length + 1 - i get = s_length - imax + imin - i ch = s(get:get) s(put:put) = ch end do do i = imin, imax s(i:i) = ' ' end do return end subroutine s_cap ( s ) !*****************************************************************************80 ! !! S_CAP replaces any lowercase letters by uppercase ones in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length ch = s(i:i) call ch_cap ( ch ) s(i:i) = ch end do return end subroutine s_cat ( s1, s2, s3 ) !*****************************************************************************80 ! !! S_CAT concatenates two strings to make a third string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 September 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the "prefix" string. ! ! character ( len = * ) S2, the "postfix" string. ! ! Output: ! ! character ( len = * ) S3, the string made by ! concatenating S1 and S2, ignoring any trailing blanks. ! implicit none character ( len = * ) s1 character ( len = * ) s2 character ( len = * ) s3 if ( s1 == ' ' .and. s2 == ' ' ) then s3 = ' ' else if ( s1 == ' ' ) then s3 = s2 else if ( s2 == ' ' ) then s3 = s1 else s3 = trim ( s1 ) // trim ( s2 ) end if return end subroutine s_cat1 ( s1, s2, s3 ) !*****************************************************************************80 ! !! S_CAT1 concatenates two strings, with a single blank separator. ! ! Example: ! ! S1 S2 S ! ! 'cat' 'dog' 'cat dog' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 September 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the "prefix" string. ! ! character ( len = * ) S2, the "postfix" string. ! ! Output: ! ! character ( len = * ) S3, the string made by concatenating ! S1, a blank, and S2, ignoring any trailing blanks. ! implicit none character ( len = * ) s1 character ( len = * ) s2 character ( len = * ) s3 if ( s1 == ' ' .and. s2 == ' ' ) then s3 = ' ' else if ( s1 == ' ' ) then s3 = s2 else if ( s2 == ' ' ) then s3 = s1 else s3 = trim ( s1 ) // ' ' // trim ( s2 ) end if return end subroutine s_center ( s ) !*****************************************************************************80 ! !! S_CENTER centers the non-blank portion of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 October 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: a string to be centered. ! ! Output: ! ! character ( len = * ) S: the centered string. ! implicit none integer l1 integer l2 integer n1 integer n2 integer n3 character ( len = * ) s ! ! How much space is in the string? ! n1 = len ( s ) ! ! Shift the string flush left and find the last nonblank. ! s = adjustl ( s ) n2 = len_trim ( s ) if ( n2 <= 0 ) then return end if if ( n2 == n1 .or. n2 == n1 - 1 ) then return end if n3 = n1 - n2 l1 = n3 / 2 l2 = l1 + n2 + 1 s(l1+1:l2-1) = s(1:n2) s(1:l1) = ' ' s(l2:n1) = ' ' return end subroutine s_center_insert ( s1, s2 ) !*****************************************************************************80 ! !! S_CENTER_INSERT inserts one string into the center of another. ! ! Discussion: ! ! The receiving string is not blanked out first. Therefore, if there is ! already information in it, some of it may still be around ! after the insertion. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string to be inserted into S2. ! ! Output: ! ! character ( len = * ) S2, the string to receive S1. ! implicit none integer ihi integer ilo integer jhi integer jlo integer m character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len_trim ( s1 ) s2_length = len ( s2 ) if ( s1_length < s2_length ) then m = s2_length - s1_length ilo = 1 ihi = s1_length jlo = ( m / 2 ) + 1 jhi = jlo + s1_length - 1 else if ( s2_length < s1_length ) then m = s1_length - s2_length ilo = ( m / 2 ) + 1 ihi = ilo + s2_length - 1 jlo = 1 jhi = s2_length else ilo = 1 ihi = s1_length jlo = 1 jhi = s2_length end if s2(jlo:jhi) = s1(ilo:ihi) return end subroutine s_ch_blank ( s, ch ) !*****************************************************************************80 ! !! S_CH_BLANK replaces each occurrence of a particular character by a blank. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! character CH, the character to be removed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == ch ) then s(i:i) = ' ' end if end do return end subroutine s_ch_count ( s, ch, ch_count ) !*****************************************************************************80 ! !! S_CH_COUNT counts occurrences of a particular character in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 13 January 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! character CH, the character to be counted. ! ! Output: ! ! integer CH_COUNT, the number of occurrences. ! implicit none character ch integer ch_count integer i character ( len = * ) s integer s_length ch_count = 0 s_length = len ( s ) do i = 1, s_length if ( s(i:i) == ch ) then ch_count = ch_count + 1 end if end do return end subroutine s_ch_delete ( s, ch ) !*****************************************************************************80 ! !! S_CH_DELETE removes all occurrences of a character from a string. ! ! Discussion: ! ! Each time the given character is found in the string, the characters ! to the right of the string are shifted over one position. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! character CH, the character to be removed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer get integer put character ( len = * ) s integer s_length s_length = len_trim ( s ) put = 1 do get = 1, s_length if ( s(get:get) == ch ) then else if ( put == get ) then put = put + 1 else s(put:put) = s(get:get) put = put + 1 end if end do s(put:s_length) = ' ' return end function s_ch_last ( s ) !*****************************************************************************80 ! !! S_CH_LAST returns the last nonblank character in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! character S_CH_LAST, the last nonblank character in S, ! or ' ' if S is all blank. ! implicit none character ( len = * ) s character s_ch_last integer s_length s_length = len_trim ( s ) if ( 0 < s_length ) then s_ch_last = s(s_length:s_length) else s_ch_last = ' ' end if return end subroutine s_chop ( s, ilo, ihi ) !*****************************************************************************80 ! !! S_CHOP "chops out" a portion of a string, and closes up the hole. ! ! Example: ! ! S = 'Fred is not a jerk!' ! ! call s_chop ( S, 9, 12 ) ! ! S = 'Fred is a jerk! ' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 July 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! integer ILO, IHI, the locations of the first and last ! characters to be removed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer ihi integer ihi2 integer ilo integer ilo2 character ( len = * ) s integer s_length s_length = len ( s ) ilo2 = max ( ilo, 1 ) ihi2 = min ( ihi, s_length ) if ( ihi2 < ilo2 ) then return end if s(ilo2:s_length+ilo2-ihi2-1) = s(ihi2+1:s_length) s(s_length+ilo2-ihi2:s_length) = ' ' return end subroutine s_compare ( s1, s2, order ) !*****************************************************************************80 ! !! S_COMPARE compares two strings. ! ! Discussion: ! ! The FORTRAN function LLT ( S1, S2 ) returns TRUE if S1 is lexically ! strictly less than S2, and FALSE otherwise. ! ! There are related functions LLE, LGT, LGE. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 July 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! integer ORDER: ! -1, S1 < S2. ! 0, S1 = S2 ! +1, S1 > S2 ! implicit none integer i integer order character ( len = * ) s1 integer s1_len character ( len = * ) s2 integer s2_len s1_len = len_trim ( s1 ) s2_len = len_trim ( s2 ) order = 0 do i = 1, min ( s1_len, s2_len ) if ( s1(i:i) < s2(i:i) ) then order = -1 return else if ( s2(i:i) < s1(i:i) ) then order = +1 return end if end do ! ! If one string is actually longer than the other, and nonblank, ! it must come after the other. ! if ( s1_len < s2_len ) then order = -1 return else if ( s2_len < s1_len ) then order = +1 return end if return end subroutine s_control_blank ( s ) !*****************************************************************************80 ! !! S_CONTROL_BLANK replaces control characters with blanks. ! ! Discussion: ! ! A "control character" has ASCII code <= 31 or 127 <= ASCII code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none logical ch_is_control integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length if ( ch_is_control ( s(i:i) ) ) then s(i:i) = ' ' end if end do return end subroutine s_control_count ( s, ifound ) !*****************************************************************************80 ! !! S_CONTROL_COUNT returns the number of control characters in a string. ! ! Discussion: ! ! A "control character" has ASCII code <= 31 or 127 <= ASCII code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! Output: ! ! integer IFOUND, the number of control characters. ! implicit none logical ch_is_control integer ifound integer i character ( len = * ) s integer s_length ifound = 0 s_length = len_trim ( s ) do i = 1, s_length if ( ch_is_control ( s(i:i) ) ) then ifound = ifound + 1 end if end do return end subroutine s_control_delete ( s ) !*****************************************************************************80 ! !! S_CONTROL_DELETE removes all control characters from a string. ! ! Discussion: ! ! The string is collapsed to the left, and padded on the right with ! blanks to replace the removed characters. ! ! A "control character" has ASCII code <= 31 or 127 <= ASCII code. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, is the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none logical ch_is_control integer get integer put character ( len = * ) s integer s_length put = 0 s_length = len_trim ( s ) do get = 1, s_length if ( .not. ch_is_control ( s(get:get) ) ) then put = put + 1 s(put:put) = s(get:get) end if end do ! ! Pad the end of the string with blanks ! s(put+1:) = ' ' return end subroutine s_copy ( s1, s2 ) !*****************************************************************************80 ! !! S_COPY copies one string into another. ! ! Discussion: ! ! If S1 is shorter than S2, the rest of S2 is blank. ! If S1 is longer than S2, then the excess information is lost. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 January 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be copied. ! ! Output: ! ! character ( len = * ) S2, the copy. ! implicit none character ( len = * ) s1 character ( len = * ) s2 s2(1:min(len(s1),len(s2))) = s1(1:min(len(s1),len(s2))) s2(len(s1)+1:len(s2)) = ' ' return end subroutine s_detag ( s ) !*****************************************************************************80 ! !! S_DETAG removes from a string all substrings marked by angle brackets. ! ! Example: ! ! Input: ! ! S = 'This is Italic whereas this is boldly not!' ! ! Output: ! ! S = ' whereas this is not!' ! ! Discussion: ! ! This routine was written to help extract some data that was hidden ! inside an elaborate HTML table. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 September 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i1 integer i2 character ( len = * ) s integer s_length do s_length = len_trim ( s ) if ( len_trim ( s ) == 0 ) then exit end if i1 = index ( s, '<' ) if ( i1 <= 0 .or. s_length <= i1 ) then exit end if i2 = index ( s(i1+1:), '>' ) if ( i2 == 0 ) then exit end if i2 = i2 + i1 ! ! Shift. ! s(i1:s_length+i1-i2-1) = s(i2+1:s_length) ! ! Pad. ! s(s_length+i1-i2:) = ' ' end do return end subroutine s_detroff ( s ) !*****************************************************************************80 ! !! S_DETROFF removes obnoxious "character" + backspace pairs from a string. ! ! Discussion: ! ! Given the string of characters: ! 'AB#C#D#E' ! where we are using "#" to represent a backspace, the returned string ! will be ! 'AE'. ! ! This function was written for use in "cleaning up" UNICOS MAN pages. ! These MAN pages were formatted in the Byzantine TROFF printing format. ! Although the files were text, and would seem to "print" correctly to ! the screen, an unholy mess would emerge if the same file was sent ! to the printer. This is because the screen handled the backspaces ! by backspacing, but most printers don't know anymore how to handle ! TROFF's backspaces, and so they just print them as blobs, instead of, ! say, spacing back. ! ! In particular: ! ! Passages which are to be underlined are written so: ! "_#T_#e_#x_#t" when what is meant is that "Text" is to be ! underlined if possible. Note that the seemingly equivalent ! "T#_e#_x#_t#_" is NOT used. This is because, in the olden ! days, certain screen terminals could backspace, but would only ! display the new character, obliterating rather than ! overwriting the old one. This convention allows us to know ! that we want to delete "character" + Backspace, rather than ! Backspace + "character". ! ! Passages which are meant to be in BOLDFACE are written so: ! "U#U#U#Ug#g#g#gl#l#l#ly#y#y#y", when what is meant is that ! "Ugly" is to be printed as boldly as possible. These boldface ! passages may also be cleaned up using the same rule of ! removing all occurrences of "character" + Backspace. ! ! It is truly a fright to look at the text of one of these MAN ! pages with all the ugly Backspace's, which display on VMS as ^H. ! These files print or type properly, but look awful in an editor. ! Moreoever, the lavish use of boldface means that text that is ! meant to fit in 80 columns can sometimes require 7 times as much ! space to describe. This can cause a VMS editor to abort, or to ! skip the line, since 255 characters is the maximum for EDT. ! ! A FORTRAN program that tries to read a long line like that will ! also fail if not careful, since a formatted sequential file ! on VMS has a default maximum record length of something like ! 133 characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 January 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the line of text to be de-TROFF'ed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character, parameter :: BS = achar ( 8 ) integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) i = 1 do while ( i <= s_length ) if ( s(i:i) == BS ) then if ( i == 1 ) then s(1:s_length-1) = s(2:s_length) s(s_length:s_length) = ' ' s_length = s_length - 1 i = i - 1 else s(i-1:s_length-2) = s(i+1:s_length) s(s_length-1:s_length) = ' ' s_length = s_length - 2 i = i - 2 end if end if i = i + 1 end do return end function s_digits_count ( s ) !*****************************************************************************80 ! !! S_DIGITS_COUNT counts the digits in a string. ! ! Discussion: ! ! The string may include spaces, letters, and dashes, but only the ! digits 0 through 9 will be counted. ! ! Example: ! ! S => 34E94-70.6 ! N <= 7 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 08 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! Output: ! ! integer S_DIGITS_COUNT, the number of digits. ! implicit none character c logical ch_is_digit integer n character ( len = * ) s integer s_digits_count integer s_len integer s_pos s_len = len_trim ( s ) s_pos = 0 n = 0 do while ( s_pos < s_len ) s_pos = s_pos + 1 c = s(s_pos:s_pos) if ( ch_is_digit ( c ) ) then n = n + 1 end if end do s_digits_count = n return end function s_eqi ( s1, s2 ) !*****************************************************************************80 ! !! s_eqi() is a case insensitive comparison of two strings for equality. ! ! Discussion: ! ! S_EQI ( 'Anjana', 'ANJANA' ) is TRUE. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_EQI, the result of the comparison. ! implicit none character c1 character c2 integer i integer lenc logical s_eqi character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len ( s1 ) s2_length = len ( s2 ) lenc = min ( s1_length, s2_length ) s_eqi = .false. do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( c1 /= c2 ) then return end if end do do i = lenc + 1, s1_length if ( s1(i:i) /= ' ' ) then return end if end do do i = lenc + 1, s2_length if ( s2(i:i) /= ' ' ) then return end if end do s_eqi = .true. return end function s_eqidb ( s1, s2 ) !*****************************************************************************80 ! !! S_EQIDB compares two strings, ignoring case and blanks. ! ! Example: ! ! S_EQIDB ( 'Nor Way', 'NORway' ) is TRUE. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Modified: ! ! 19 July 1998 ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_EQIDB, the result of the comparison. ! implicit none character c1 character c2 integer i1 integer i2 integer len2 logical s_eqidb character ( len = * ) s1 integer s1_length character ( len = * ) s2 ! ! Get the length of each string to the last nonblank. ! s1_length = len_trim ( s1 ) len2 = len_trim ( s2 ) ! ! Assume we're going to fail. ! s_eqidb = .false. ! ! Initialize the pointers to characters in each string. ! i1 = 0 i2 = 0 do ! ! If we've matched all the nonblank characters in both strings, ! then return with S_EQIDB = TRUE. ! if ( i1 == s1_length .and. i2 == len2 ) then s_eqidb = .true. return end if ! ! Get the next nonblank character in the first string. ! do i1 = i1 + 1 if ( s1_length < i1 ) then return end if if ( s1(i1:i1) /= ' ' ) then exit end if end do c1 = s1(i1:i1) call ch_cap ( c1 ) ! ! Get the next nonblank character in the second string. ! do i2 = i2 + 1 if ( len2 < i2 ) then return end if c2 = s2(i2:i2) if ( c2 /= ' ' ) then exit end if end do call ch_cap ( c2 ) if ( c1 /= c2 ) then exit end if end do return end subroutine s_escape_tex ( s1, s2 ) !*****************************************************************************80 ! !! S_ESCAPE_TEX de-escapes TeX escape sequences. ! ! Discussion: ! ! In particular, every occurrence of the characters '\', '_', ! '^', '{' and '}' will be replaced by '\\', '\_', '\^', ! '\{' and '\}'. A TeX interpreter, on seeing these character ! strings, is then likely to return the original characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 19 January 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be de-escaped. ! ! Output: ! ! character ( len = * ) S2, a copy of the string, ! modified to avoid TeX escapes. ! implicit none character ch character ( len = * ) s1 integer s1_length integer s1_pos character ( len = * ) s2 integer s2_pos s1_length = len_trim ( s1 ) s1_pos = 0 s2_pos = 0 s2 = ' ' do while ( s1_pos < s1_length ) s1_pos = s1_pos + 1 ch = s1(s1_pos:s1_pos) if ( ch == '\' .or. & ch == '_' .or. & ch == '^' .or. & ch == '{' .or. & ch == '}' ) then s2_pos = s2_pos + 1 s2(s2_pos:s2_pos) = '\' end if s2_pos = s2_pos + 1 s2(s2_pos:s2_pos) = ch end do return end subroutine s_escape_tex2 ( s1, s2 ) !*****************************************************************************80 ! !! S_ESCAPE_TEX2 de-escapes TeX escape sequences. ! ! Discussion: ! ! In particular, every occurrence of the characters '\', '_', ! '^', '{' and '}' will be replaced by '\\', '\_', '\^', ! '\{' and '\}'. A TeX interpreter, on seeing these character ! strings, is then likely to return the original characters. ! ! In some cases, it seems like TWO backslashes are needed. ! This version of the function provides them. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 August 2019 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be de-escaped. ! ! Output: ! ! character ( len = * ) S2, a copy of the string, ! modified to avoid TeX escapes. ! implicit none character ch character ( len = * ) s1 integer s1_length integer s1_pos character ( len = * ) s2 integer s2_pos s1_length = len_trim ( s1 ) s1_pos = 0 s2_pos = 0 s2 = ' ' do while ( s1_pos < s1_length ) s1_pos = s1_pos + 1 ch = s1(s1_pos:s1_pos) if ( ch == '\' .or. & ch == '_' .or. & ch == '^' .or. & ch == '{' .or. & ch == '}' ) then s2_pos = s2_pos + 1 s2(s2_pos:s2_pos) = '\' s2_pos = s2_pos + 1 s2(s2_pos:s2_pos) = '\' end if s2_pos = s2_pos + 1 s2(s2_pos:s2_pos) = ch end do return end subroutine s_fill ( s, ch ) !*****************************************************************************80 ! !! S_FILL overwrites every character of a string by a given character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be overwritten. ! ! Output: ! ! character CH, the overwriting character. ! implicit none character ch integer i character ( len = * ) s integer s_length s_length = len ( s ) do i = 1, s_length s(i:i) = ch end do return end function s_first_nonblank ( s ) !*****************************************************************************80 ! !! S_FIRST_NONBLANK returns the location of the first nonblank. ! ! Discussion: ! ! If all characters are blanks, a 0 is returned. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! integer S_FIRST_NONBLANK, the location of the first ! nonblank character in the string, or 0 if all are blank. ! implicit none integer i character ( len = * ) s integer s_first_nonblank integer s_length s_length = len ( s ) do i = 1, s_length if ( s(i:i) /= ' ' ) then s_first_nonblank = i return end if end do s_first_nonblank = 0 return end function s_gei ( s1, s2 ) !*****************************************************************************80 ! !! S_GEI = ( S1 is lexically greater than or equal to S2 ). ! ! Discussion: ! ! The comparison is done in a case-insensitive way. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_GEI, the result of the comparison. ! implicit none character c1 character c2 integer i integer lenc logical s_gei character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len_trim ( s1 ) s2_length = len_trim ( s2 ) lenc = min ( s1_length, s2_length ) do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( lgt ( c1, c2 ) ) then s_gei = .true. return else if ( llt ( c1, c2 ) ) then s_gei = .false. return end if end do if ( s1_length < s2_length ) then s_gei = .false. else s_gei = .true. end if return end function s_gti ( s1, s2 ) !*****************************************************************************80 ! !! S_GTI = S1 is lexically greater than S2. ! ! Discussion: ! ! The comparison is done in a case-insensitive way. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_GTI, the result of the comparison. ! implicit none character c1 character c2 integer i integer lenc logical s_gti character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len ( s1 ) s2_length = len ( s2 ) lenc = min ( s1_length, s2_length ) do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( lgt ( c1, c2 ) ) then s_gti = .true. return else if ( llt ( s1, s2 ) ) then s_gti = .false. return end if end do if ( s1_length <= s2_length ) then s_gti = .false. else s_gti = .true. end if return end function s_index ( s, sub ) !*****************************************************************************80 ! !! S_INDEX seeks the first occurrence of a substring. ! ! Discussion: ! ! The function returns the location in the string at which the ! substring SUB is first found, or 0 if the substring does not ! occur at all. ! ! The routine is trailing blank insensitive. This is very ! important for those cases where you have stored information in ! larger variables. If S is of length 80, and SUB is of ! length 80, then if S = 'FRED' and SUB = 'RED', a match would ! not be reported by the standard FORTRAN INDEX, because it treats ! both variables as being 80 characters long! This routine assumes that ! trailing blanks represent garbage! ! ! Because of the suppression of trailing blanks, this routine cannot be ! used to find, say, the first occurrence of the two-character ! string 'A '. However, this routine treats as a special case the ! occurrence where S or SUB is entirely blank. Thus you can ! use this routine to search for occurrences of double or triple blanks ! in a string, for example. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 February 2005 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character ( len = * ) SUB, the substring to search for. ! ! Output: ! ! integer S_INDEX. 0 if SUB does not occur in ! the string. Otherwise S(S_INDEX:S_INDEX+LENS-1) = SUB, ! where LENS is the length of SUB, and is the first place ! this happens. ! implicit none integer i character ( len = * ) s integer s_index integer s_length character ( len = * ) sub integer sub_length s_index = 0 s_length = len_trim ( s ) sub_length = len_trim ( sub ) ! ! In case S or SUB is blanks, use LEN. ! if ( s_length == 0 ) then s_length = len ( s ) end if if ( sub_length == 0 ) then sub_length = len ( sub ) end if if ( s_length < sub_length ) then return end if do i = 1, s_length + 1 - sub_length if ( s(i:i+sub_length-1) == sub(1:sub_length) ) then s_index = i return end if end do return end function s_index_set ( s1, s2 ) !*****************************************************************************80 ! !! S_INDEX_SET searches a string for any of a set of characters. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be examined. ! ! character ( len = * ) S2, the characters to search for. ! ! Output: ! ! integer S_INDEX_SET, the first location of a ! character from S2 in S1, or 0 if no character from S2 occurs in S1. ! implicit none integer i integer j integer k character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s_index_set s1_length = len ( s1 ) j = s1_length + 1 do i = 1, len ( s2 ) k = index ( s1, s2(i:i) ) if ( k /= 0 ) then j = min ( j, k ) end if end do if ( j == s1_length + 1 ) then j = 0 end if s_index_set = j return end function s_indexi ( s, sub ) !*****************************************************************************80 ! !! S_INDEXI is a case-insensitive INDEX function. ! ! Discussion: ! ! The function returns the location in the string at which the ! substring SUB is first found, or 0 if the substring does not ! occur at all. ! ! The routine is also trailing blank insensitive. This is very ! important for those cases where you have stored information in ! larger variables. If S is of length 80, and SUB is of ! length 80, then if S = 'FRED' and SUB = 'RED', a match would ! not be reported by the standard FORTRAN INDEX, because it treats ! both variables as being 80 characters long! This routine assumes that ! trailing blanks represent garbage! ! ! Because of the suppression of trailing blanks, this routine cannot be ! used to find, say, the first occurrence of the two-character ! string 'A '. However, this routine treats as a special case the ! occurrence where S or SUB is entirely blank. Thus you can ! use this routine to search for occurrences of double or triple blanks ! in a string, for example, although INDEX itself would be just as ! suitable for that problem. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character ( len = * ) SUB, the substring to search for. ! ! Output: ! ! integer S_INDEXI. 0 if SUB does not occur in ! the string. Otherwise S(S_INDEXI:S_INDEXI+LENS-1) = SUB, ! where LENS is the length of SUB, and is the first place ! this happens. However, note that this routine ignores case, ! unlike the standard FORTRAN INDEX function. ! implicit none integer i integer llen2 character ( len = * ) s logical s_eqi integer s_indexi integer s_length character ( len = * ) sub s_indexi = 0 s_length = len_trim ( s ) llen2 = len_trim ( sub ) ! ! In case S or SUB is blanks, use LEN. ! if ( s_length == 0 ) then s_length = len ( s ) end if if ( llen2 == 0 ) then llen2 = len ( sub ) end if if ( s_length < llen2 ) then return end if do i = 1, s_length + 1 - llen2 if ( s_eqi ( s(i:i+llen2-1), sub ) ) then s_indexi = i return end if end do return end function s_index_last ( s, sub ) !*****************************************************************************80 ! !! S_INDEX_LAST finds the LAST occurrence of a given substring. ! ! Discussion: ! ! It returns the location in the string at which the substring SUB is ! first found, or 0 if the substring does not occur at all. ! ! The routine is also trailing blank insensitive. This is very ! important for those cases where you have stored information in ! larger variables. If S is of length 80, and SUB is of ! length 80, then if S = 'FRED' and SUB = 'RED', a match would ! not be reported by the standard FORTRAN INDEX, because it treats ! both variables as being 80 characters long! This routine assumes that ! trailing blanks represent garbage! ! ! This means that this routine cannot be used to find, say, the last ! occurrence of a substring 'A ', since it assumes the blank space ! was not specified by the user, but is, rather, padding by the ! system. However, as a special case, this routine can properly handle ! the case where either S or SUB is all blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character ( len = * ) SUB, the substring to search for. ! ! Output: ! ! integer S_INDEX_LAST. 0 if SUB does not occur in ! the string. Otherwise S_INDEX_LAST = I, where S(I:I+LENS-1) = SUB, ! where LENS is the length of SUB, and is the last place ! this happens. ! implicit none integer i integer j integer llen2 character ( len = * ) s integer s_index_last integer s_length character ( len = * ) sub s_index_last = 0 s_length = len_trim ( s ) llen2 = len_trim ( sub ) ! ! In case S or SUB is blanks, use LEN. ! if ( s_length == 0 ) then s_length = len ( s ) end if if ( llen2 == 0 ) then llen2 = len ( sub ) end if if ( s_length < llen2 ) then return end if do j = 1, s_length + 1 - llen2 i = s_length + 2 - llen2 - j if ( s(i:i+llen2-1) == sub ) then s_index_last = i return end if end do return end function s_index_last_c ( s, c ) !*****************************************************************************80 ! !! S_INDEX_LAST_C finds the LAST occurrence of a given character. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 December 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! character C, the character to search for. ! ! Output: ! ! integer S_INDEX_LAST_C, the index in S where C occurs ! last, or -1 if it does not occur. ! implicit none character c integer i character ( len = * ) s integer s_length integer s_index_last_c if ( c == ' ' ) then s_length = len ( s ) else s_length = len_trim ( s ) end if do i = s_length, 1, -1 if ( s(i:i) == c ) then s_index_last_c = i return end if end do s_index_last_c = -1 return end subroutine s_i_append ( s, i, done ) !*****************************************************************************80 ! !! S_I_APPEND appends an integer to a string. ! ! Discussion: ! ! A blank space will separate the integer from the text already ! in the line. ! ! The routine warns the user if the integer will not fit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: the current string. ! ! integer I, an integer to be appended to the line. ! ! Output: ! ! character ( len = * ) S: the current string with the value ! appended. ! ! logical DONE, is FALSE if there was not enough room ! to append the integer. ! implicit none logical done integer i integer lents integer lenw integer next character ( len = * ) s integer s_length character ( len = 13 ) w done = .false. s_length = len ( s ) lents = len_trim ( s ) call i4_to_s_left ( i, w ) lenw = len_trim ( w ) if ( lents == 0 ) then if ( s_length < lenw ) then done = .true. return end if else if ( s_length < lents + 1 + lenw ) then done = .true. return end if end if if ( lents == 0 ) then next = 1 else next = lents + 1 s(next:next) = ' ' next = next + 1 end if s(next:next+lenw-1) = w(1:lenw) return end subroutine s_inc_c ( s ) !*****************************************************************************80 ! !! S_INC_C "increments" the characters in a string. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! The routine tries to produce the next string, in dictionary order, ! following the input value of a string. Digits, spaces, and other ! nonalphabetic characters are ignored. Case is respected; in other ! words, the case of every alphabetic character on input will be the ! same on output. ! ! The following error conditions can occur: ! ! There are no alphabetic characters in the string. No ! incrementing is possible. ! ! All alphabetic characters are equal to 'Z' or 'z'. In this ! the string is also "wrapped around" so that all alphabetic ! characters are "A" or "a". ! ! If the word "Tax" were the successive outputs would be ! "Tay", "Taz", "Tba", "Tbb", ... If the input word "January 4, 1989" ! were the output would be "Januarz 4, 1989". ! ! This routine could be useful when trying to create a unique file ! name or variable name at run time. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 April 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string whose ! alphabetic successor is desired. ! ! Output: ! ! character ( len = * ) S: the successor string. ! implicit none integer ihi integer ilo integer iloc character ( len = * ) s ilo = 1 ihi = len ( s ) ! ! Find the last alphabetic character in the string. ! do call s_alpha_last ( s(ilo:ihi), iloc ) ! ! If there is no alphabetic character, we can't help. ! if ( iloc == 0 ) then return end if if ( s(iloc:iloc) == achar ( 122 ) ) then s(iloc:iloc) = achar ( 97 ) ihi = iloc - 1 if ( ihi <= 0 ) then exit end if else if ( s(iloc:iloc) == achar ( 90 ) ) then s(iloc:iloc) = achar ( 65 ) ihi = iloc - 1 if ( ihi <= 0 ) then return end if else s(iloc:iloc) = achar ( iachar ( s(iloc:iloc) ) + 1 ) exit end if end do return end subroutine s_inc_n ( s ) !*****************************************************************************80 ! !! S_INC_N increments the digits in a string. ! ! Discussion: ! ! Instead of CHAR and ICHAR, we now use the ACHAR and IACHAR functions, which ! guarantees the ASCII collating sequence. ! ! It is assumed that the digits in the name, whether scattered or ! connected, represent a number that is to be increased by 1 on ! each call. If this number is all 9's on the output number ! is all 0's. Non-numeric letters of the name are unaffected. ! ! If the name is empty, then the routine stops. ! ! If the name contains no digits, the empty string is returned. ! ! Example: ! ! Input Output ! ----- ------ ! 'a7to11.txt' 'a7to12.txt' ! 'a7to99.txt' 'a8to00.txt' ! 'a9to99.txt' 'a0to00.txt' ! 'cat.txt' ' ' ! ' ' STOP! ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 September 2005 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: a character string to be incremented. ! ! Output: ! ! character ( len = * ) S: the incremented string. ! implicit none character c integer change integer digit integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) if ( s_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_INC_N - Fatal error!' write ( *, '(a)' ) ' The input string is empty.' stop 1 end if change = 0 do i = s_length, 1, -1 c = s(i:i) if ( lge ( c, '0' ) .and. lle ( c, '9' ) ) then change = change + 1 digit = iachar ( c ) - 48 digit = digit + 1 if ( digit == 10 ) then digit = 0 end if c = achar ( digit + 48 ) s(i:i) = c if ( c /= '0' ) then return end if end if end do if ( change == 0 ) then s = ' ' return end if return end subroutine s_input ( string, value, ierror ) !*****************************************************************************80 ! !! s_input() prints a prompt string and reads a string from the user. ! ! Discussion: ! ! If the input line starts with a comment character ('#'), or is blank, ! the routine ignores that line, and tries to read the next one. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) STRING, the prompt string. ! ! Output: ! ! character ( len = * ) VALUE, the value input by the user. ! ! integer IERROR, an error flag, which is 0 ! if no error occurred. ! implicit none integer ierror character ( len = * ) string character ( len = * ) value ierror = 0 value = ' ' ! ! Write the prompt. ! write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( string ) do read ( *, '(a)', iostat = ierror ) value if ( ierror /= 0 ) then value = 'S_INPUT: Input error!' return end if ! ! If the line begins with a comment character, go back and read the next line. ! if ( value(1:1) == '#' ) then cycle end if if ( len_trim ( value ) == 0 ) then cycle end if exit end do return end function s_is_alpha ( s ) !*****************************************************************************80 ! !! S_IS_ALPHA returns TRUE if the string contains only alphabetic characters. ! ! Discussion: ! ! Here, alphabetic characters are 'A' through 'Z' and 'a' through 'z'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical S_IS_ALPHA, is TRUE if the string contains ! only alphabetic characters. ! implicit none logical ch_is_alpha integer i character ( len = * ) s logical s_is_alpha integer s_length s_is_alpha = .false. s_length = len_trim ( s ) do i = 1, s_length if ( .not. ch_is_alpha ( s(i:i) ) ) then return end if end do s_is_alpha = .true. return end function s_is_alphanumeric ( s ) !*****************************************************************************80 ! !! S_IS_ALPHANUMERIC = string contains only alphanumeric characters. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Alphanumeric characters are 'A' through 'Z', 'a' through 'z' and ! '0' through '9'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical S_IS_ALPHANUMERIC, is TRUE if the string ! contains only alphabetic characters and numerals. ! implicit none integer i integer itemp character ( len = * ) s logical s_is_alphanumeric integer s_length s_is_alphanumeric = .false. s_length = len_trim ( s ) do i = 1, s_length itemp = iachar ( s(i:i) ) if ( .not. ( 65 <= itemp .and. itemp <= 90 ) ) then if ( .not. ( 97 <= itemp .and. itemp <= 122 ) ) then if ( .not. ( 48 <= itemp .and. itemp <= 57 ) ) then return end if end if end if end do s_is_alphanumeric = .true. return end function s_is_digit ( s ) !*****************************************************************************80 ! !! S_IS_DIGIT returns TRUE if a string contains only decimal digits. ! ! Discussion: ! ! This is a strict comparison. ! The check is made from the first character to the last nonblank. ! Each character in between must be one of '0', '1', ..., '9'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical S_IS_DIGIT, is TRUE if S contains only digits. ! implicit none character c integer i character ( len = * ) s logical s_is_digit integer s_length s_length = len_trim ( s ) s_is_digit = .false. do i = 1, s_length c = s(i:i) if ( llt ( c, '0' ) .or. lgt ( c, '9' ) ) then return end if end do s_is_digit = .true. return end function s_is_f77_name ( s ) !*****************************************************************************80 ! !! S_IS_F77_NAME = input string represent a legal FORTRAN77 identifier. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! logical S_IS_F77_NAME, is TRUE if the string ! is a legal FORTRAN77 identifier. That is, the string must begin with ! an alphabetic character, and all subsequent characters must be ! alphanumeric. The string may terminate with blanks. No underscores ! are allowed. ! implicit none logical ch_is_alpha character ( len = * ) s logical s_is_alphanumeric logical s_is_f77_name integer s_length s_is_f77_name = .false. s_length = len_trim ( s ) if ( s_length <= 0 ) then return end if if ( .not. ch_is_alpha ( s(1:1) ) ) then return end if if ( .not. s_is_alphanumeric ( s(2:s_length) ) ) then return end if s_is_f77_name = .true. return end function s_is_f90_name ( s ) !*****************************************************************************80 ! !! S_IS_F90_NAME = input string represent a legal FORTRAN90 identifier. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! logical S_IS_F90_NAME, is TRUE if the string is a ! legal FORTRAN90 identifier. That is, the string must begin with an ! alphabetic character, and all subsequent characters must be alphanumeric ! or underscores. The string may terminate with blanks. ! implicit none logical ch_is_alpha integer i logical malphnum2 character ( len = * ) s logical s_is_f90_name integer s_length s_is_f90_name = .false. s_length = len_trim ( s ) if ( s_length <= 0 ) then return end if if ( .not. ch_is_alpha ( s(1:1) ) ) then return end if do i = 2, s_length if ( .not. malphnum2 ( s(i:i) ) ) then return end if end do s_is_f90_name = .true. return end function s_is_i ( s, i ) !*****************************************************************************80 ! !! S_IS_I is TRUE if a string represents an integer. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! integer I. If the string represents an integer, ! I is the integer represented. Otherwise I is 0. ! ! logical S_IS_I, is TRUE if the string represents an ! integer. ! implicit none integer i integer ierror integer length character ( len = * ) s logical s_is_i integer s_length s_length = len_trim ( s ) call s_to_i4 ( s, i, ierror, length ) if ( ierror == 0 .and. s_length <= length ) then s_is_i = .true. else s_is_i = .false. i = 0 end if return end subroutine s_is_r ( s, r, lval ) !*****************************************************************************80 ! !! S_IS_R is TRUE if a string represents a real number. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! real ( kind = rk ) R. If the string represents a real number, ! then R is the real number represented. Otherwise R is 0. ! ! logical LVAL, is TRUE if the string represents ! a real number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer ierror integer length logical lval real ( kind = rk ) r character ( len = * ) s integer s_length s_length = len_trim ( s ) call s_to_r4 ( s, r, ierror, length ) if ( ierror == 0 .and. s_length <= length ) then lval = .true. else lval = .false. r = 0.0E+00 end if return end subroutine s_left_insert ( s1, s2 ) !*****************************************************************************80 ! !! S_LEFT_INSERT inserts one string flush left into another. ! ! Discussion: ! ! S2 is not blanked out first. Therefore, if there is ! already information in S2, some of it may still be around ! after S1 is written into S2. Users may want to first ! assign S2 = ' ' if this is not the effect desired. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string to be inserted into S2. Only ! the portion of S1 up to the last nonblank will be used. ! ! Output: ! ! character ( len = * ) S2, a string which will contain, ! a left flush copy of S1. ! implicit none integer ihi integer ilo integer jhi integer jlo character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len_trim ( s1 ) s2_length = len ( s2 ) if ( s1_length < s2_length ) then ilo = 1 ihi = s1_length jlo = 1 jhi = s1_length else if ( s2_length < s1_length ) then ilo = 1 ihi = s2_length jlo = 1 jhi = s2_length else ilo = 1 ihi = s1_length jlo = 1 jhi = s2_length end if s2(jlo:jhi) = s1(ilo:ihi) return end function s_lei ( s1, s2 ) !*****************************************************************************80 ! !! S_LEI = ( S1 is lexically less than or equal to S2 ). ! ! Discussion: ! ! The comparison is done in a case-insensitive way. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_LEI, the result of the comparison. ! implicit none character c1 character c2 integer i integer len2 integer lenc logical s_lei character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len ( s1 ) len2 = len ( s2 ) lenc = min ( s1_length, len2 ) do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( llt ( c1, c2 ) ) then s_lei = .true. return else if ( lgt ( c1, c2 ) ) then s_lei = .false. return end if end do if ( s1_length <= len2 ) then s_lei = .true. else s_lei = .false. end if return end function s_len_trim ( s ) !*********************************************************************72 ! !! S_LEN_TRIM returns the length of a string to the last nonblank. ! ! Discussion: ! ! The FORTRAN90 function "len_trim()" should be used insted of ! this emulation. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 July 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string. ! ! Output: ! ! integer S_LEN_TRIM, the length of the string to the last nonblank. ! implicit none integer i character ( len = * ) s integer s_len integer s_len_trim s_len = len ( s ) do i = s_len, 1, -1 if ( s(i:i) .ne. ' ' ) then s_len_trim = i return end if end do s_len_trim = 0 return end subroutine s_low ( s ) !*****************************************************************************80 ! !! S_LOW replaces all uppercase letters by lowercase ones. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 19 July 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the string is all lowercase. ! implicit none integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length call ch_low ( s(i:i) ) end do return end function s_lti ( s1, s2 ) !*****************************************************************************80 ! !! S_LTI = ( S1 is lexically less than S2 ). ! ! Discussion: ! ! The comparison is done in a case-insensitive way. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_LTI, the result of the comparison. ! implicit none character c1 character c2 integer i integer len2 integer lenc logical s_lti character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len ( s1 ) len2 = len ( s2 ) lenc = min ( s1_length, len2 ) do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( llt ( c1, c2 ) ) then s_lti = .true. return else if ( lgt ( c1, c2 ) ) then s_lti = .false. return end if end do if ( s1_length < len2 ) then s_lti = .true. else s_lti = .false. end if return end function s_neqi ( s1, s2 ) !*****************************************************************************80 ! !! S_NEQI compares two strings for non-equality, ignoring case. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 November 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to compare. ! ! Output: ! ! logical S_NEQI, the result of the comparison. ! implicit none character c1 character c2 integer i integer len2 integer lenc logical s_neqi character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len ( s1 ) len2 = len ( s2 ) lenc = min ( s1_length, len2 ) s_neqi = .true. do i = 1, lenc c1 = s1(i:i) c2 = s2(i:i) call ch_cap ( c1 ) call ch_cap ( c2 ) if ( c1 /= c2 ) then return end if end do do i = lenc + 1, s1_length if ( s1(i:i) /= ' ' ) then return end if end do do i = lenc + 1, len2 if ( s2(i:i) /= ' ' ) then return end if end do s_neqi = .false. return end function s_no_control ( s ) !*****************************************************************************80 ! !! S_NO_CONTROL = string contains no control characters. ! ! Discussion: ! ! Non-control characters are ASCII codes 32 through 127 inclusive. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 January 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, is the string to be checked. ! ! Output: ! ! logical S_NO_CONTROL, is TRUE if S contains only ! printable characters, FALSE otherwise. ! implicit none logical ch_is_control integer i logical s_no_control character ( len = * ) s integer s_length s_no_control = .false. s_length = len_trim ( s ) do i = 1, s_length if ( ch_is_control ( s(i:i) ) ) then return end if end do s_no_control = .true. return end subroutine s_nonalpha_delete ( s ) !*****************************************************************************80 ! !! S_NONALPHA_DELETE removes nonalphabetic characters from a string. ! ! Discussion: ! ! The remaining characters are left justified and blank padded. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 August 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer get integer put character ( len = * ) s integer s_length put = 0 s_length = len_trim ( s ) do get = 1, s_length ch = s(get:get) if ( ( lle ( 'A', ch ) .and. lle ( ch, 'Z' ) ) .or. & ( lle ( 'a', ch ) .and. lle ( ch, 'z' ) ) ) then put = put + 1 s(put:put) = ch end if end do s(put+1:s_length) = ' ' return end function s_of_i4 ( i ) !*****************************************************************************80 ! !! s_of_i4() converts an integer to a left-justified string. ! ! Example: ! ! I S ! ! 1 1 ! -1 -1 ! 0 0 ! 1952 1952 ! 123456 123456 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer I, an integer to be converted. ! ! Output: ! ! character ( len = 11 ) S_OF_I4, the representation of the ! integer. The integer will be left-justified. ! implicit none character c integer i integer idig integer ihi integer ilo integer ipos integer ival integer j character ( len = 11 ) s character ( len = 11 ) s_of_i4 s = ' ' ilo = 1 ihi = 11 ! ! Make a copy of the integer. ! ival = i ! ! Handle the negative sign. ! if ( ival < 0 ) then if ( ihi <= 1 ) then s(1:1) = '*' return end if ival = -ival s(1:1) = '-' ilo = 2 end if ! ! The absolute value of the integer goes into S(ILO:IHI). ! ipos = ihi ! ! Find the last digit, strip it off, and stick it into the string. ! do idig = mod ( ival, 10 ) ival = ival / 10 if ( ipos < ilo ) then do j = 1, ihi s(j:j) = '*' end do return end if call digit_to_ch ( idig, c ) s(ipos:ipos) = c ipos = ipos - 1 if ( ival == 0 ) then exit end if end do ! ! Shift the string to the left. ! s(ilo:ilo+ihi-ipos-1) = s(ipos+1:ihi) s(ilo+ihi-ipos:ihi) = ' ' s_of_i4 = s return end function s_only_alphab ( s ) !*****************************************************************************80 ! !! S_ONLY_ALPHAB checks if a string is only alphabetic and blanks. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Acceptable characters are 'A' through 'Z' and 'a' through 'z' and blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical S_ONLY_ALPHAB, is TRUE if the string contains ! only alphabetic characters and blanks. ! implicit none character c integer i integer itemp character ( len = * ) s integer s_length logical s_only_alphab s_only_alphab = .false. s_length = len_trim ( s ) do i = 1, s_length c = s(i:i) if ( c /= ' ' ) then itemp = iachar ( c ) if ( .not. ( 65 <= itemp .and. itemp <= 90 ) ) then if ( .not. ( 97 <= itemp .and. itemp <= 122 ) ) then return end if end if end if end do s_only_alphab = .true. return end function s_only_digitb ( s ) !*****************************************************************************80 ! !! S_ONLY_DIGITB returns TRUE if the string contains only digits or blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be checked. ! ! Output: ! ! logical S_ONLY_DIGITB, is TRUE if the string ! contains only digits and blanks. ! implicit none character c integer i character ( len = * ) s integer s_length logical s_only_digitb s_only_digitb = .false. s_length = len_trim ( s ) do i = 1, s_length c = s(i:i) if ( c /= ' ' ) then if ( llt ( c, '0' ) .or. lgt ( c, '9' ) ) then return end if end if end do s_only_digitb = .true. return end subroutine s_overlap ( s1, s2, overlap ) !*****************************************************************************80 ! !! S_OVERLAP determines the overlap between two strings. ! ! Discussion: ! ! To determine the overlap, write the first word followed immediately ! by the second word. Find the longest substring S which is both ! a suffix of S1 and a prefix of S2. The length of this substring ! is the overlap. ! ! Example: ! ! S1 S2 OVERLAP ! ! 'timber' 'beret' 3 ! 'timber' 'timber' 6 ! 'beret' 'timber' 1 ! 'beret' 'berets' 5 ! 'beret' 'berth' 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2, the strings to be checked. ! ! Output: ! ! integer OVERLAP, the length of the overlap. ! implicit none integer i integer len2 integer len3 integer overlap character ( len = * ) s1 integer s1_length character ( len = * ) s2 overlap = 0 s1_length = len_trim ( s1 ) len2 = len_trim ( s2 ) len3 = min ( s1_length, len2 ) do i = 1, len3 if ( s1(s1_length+1-i:s1_length) == s2(1:i) ) then overlap = i end if end do return end function s_paren_check ( s ) !*****************************************************************************80 ! !! S_PAREN_CHECK checks the parentheses in a string. ! ! Discussion: ! ! Blanks are removed from the string, and then the following checks ! are made: ! ! 1) as we read the string left to right, there must never be more ! right parentheses than left ones; ! 2) there must be an equal number of left and right parentheses; ! 3) there must be no occurrences of the abutting packages '...)(...'. ! 4) there must be no occurrences of the empty package '()'. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 November 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to check. ! ! Output: ! ! logical S_PAREN_CHECK is TRUE if the string passed ! the checks. ! implicit none integer i integer isum character ( len = * ) s character ( len = 255 ) s_copy integer s_length logical s_paren_check s_copy = s call s_blank_delete ( s_copy) s_length = len_trim ( s_copy ) ! ! 1) Letting '(' = +1 and ')' = -1, check that the running parentheses sum ! is always nonnegative. ! isum = 0 do i = 1, s_length if ( s_copy(i:i) == '(' ) then isum = isum + 1 end if if ( s_copy(i:i) == ')' ) then isum = isum - 1 if ( isum < 0 ) then s_paren_check = .false. return end if end if end do ! ! 2) Check that the final parentheses sum is zero. ! if ( isum /= 0 ) then s_paren_check = .false. return end if ! ! 3) Check that there are no ")(" pairs. ! do i = 2, s_length if ( s_copy(i-1:i) == ')(' ) then s_paren_check = .false. return end if end do ! ! 4) Check that there are no "()" pairs. ! do i = 2, s_length if ( s_copy(i-1:i) == '()' ) then s_paren_check = .false. return end if end do ! ! The checks were passed. ! s_paren_check = .true. return end subroutine s_quote ( s1, mark, s2 ) !*****************************************************************************80 ! !! S_QUOTE "quotes" a string. ! ! Discussion: ! ! Actually, it simply puts the string MARK before and after the string S1. ! ! Sometimes, when you print a string, you want to put quote marks around it. ! This is one way to do that. ! ! Examples: ! ! S1 MARK S2 ! -------- ---- ---------- ! Hi, Bob! " "Hi, Bob!" ! De Loop LoopDeLoop ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 January 2016 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string to be "quoted". ! ! character ( len = * ) MARK, the "quote mark". ! ! Output: ! ! character ( len = * ) S2, the "quoted" string. ! implicit none character ( len = * ) mark character ( len = * ) s1 character ( len = * ) s2 s2 = trim ( mark ) // trim ( s1 ) // trim ( mark ) return end subroutine s_r_append ( s, r, done ) !*****************************************************************************80 ! !! S_R_APPEND appends a real number to a string. ! ! Discussion: ! ! A blank space will separate the value from the text already ! in the line. ! ! The routine warns the user if the value will not fit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a line of text. ! ! real ( kind = rk ) R, the real number to be appended to the line. ! ! Output: ! ! character ( len = * ) S: the current string with appended value. ! ! logical DONE, is FALSE if there was not enough room ! to append the data. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) logical done integer lens integer lents integer lenw integer next real ( kind = rk ) r character ( len = * ) s character ( len = 14 ) w done = .false. lens = len ( s ) lents = len_trim ( s ) call r4_to_s_left ( r, w ) lenw = len_trim ( w ) if ( lents == 0 ) then if ( lens < lenw ) then done = .true. return end if else if ( lens < lents + 1 + lenw ) then done = .true. return end if end if if ( lents == 0 ) then next = 1 else next = lents + 1 s(next:next) = ' ' next = next + 1 end if s(next:next+lenw-1) = w(1:lenw) return end subroutine s_replace_ch ( s, c1, c2 ) !*****************************************************************************80 ! !! s_replace_ch() replaces all occurrences of one character by another. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! character C1, C2, the character to be replaced, and the ! replacement character. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character c1 character c2 integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == c1 ) then s(i:i) = c2 end if end do return end subroutine s_replace_one ( s1, sub1, sub2, s2 ) !*****************************************************************************80 ! !! S_REPLACE_ONE replaces the first occurrence of SUB1 with SUB2. ! ! Discussion: ! ! The input and output strings may coincide. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 07 November 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the initial string. ! ! character ( len = * ) SUB1, the string to be replaced. ! ! character ( len = * ) SUB2, the replacement string. ! ! Output: ! ! character ( len = * ) S2, the final string. ! implicit none integer i1 integer i2 integer i3 integer i4 character ( len = * ) s1 character ( len = * ) s2 character ( len = 255 ) s3 character ( len = * ) sub1 character ( len = * ) sub2 s3 = ' ' i1 = index ( s1, sub1 ) if ( i1 == 0 ) then s3 = s1 else s3(1:i1-1) = s1(1:i1-1) i2 = len_trim ( sub2 ) s3(i1:i1+i2-1) = sub2(1:i2) i3 = i1 + len_trim ( sub1 ) i4 = len_trim ( s1 ) s3(i1+i2:i1+i2+1+i4-i3) = s1(i3:i4) end if s2 = s3 return end subroutine s_replace_rec ( s, sub1, sub2, irep ) !*****************************************************************************80 ! !! S_REPLACE_REC is a recursive replacement of one string by another. ! ! Discussion: ! ! All occurrences of SUB1 should be replaced by SUB2. ! This is not always true if SUB2 is longer than SUB1. ! The replacement is recursive. In other words, replacing all ! occurrences of "ab" by "a" in "abbbbb" will return "a" rather ! than "abbbb". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: the string in which occurrences are to be replaced. ! ! character ( len = * ) SUB1, the string which is to be replaced. ! ! character ( len = * ) SUB2, the replacement string. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! ! integer IREP, the number of replacements made. ! If IREP is negative, then its absolute value is the ! number of replacements made, and SUB2 is longer than ! SUB1, and at least one substring SUB1 could not be ! replaced by SUB2 because there was no more space in ! S. (If S = 'aab' and SUB1 = 'a' and SUB2 = 'cc' ! then the result would be S = 'cca'. The first 'a' ! was replaced, the 'b' fell off the end, the second 'a' ! was not replaced because the replacement 'cc' would ! have fallen off the end) ! implicit none integer irep integer len1 integer len2 integer loc character ( len = * ) s integer s_length character ( len = * ) sub1 character ( len = * ) sub2 irep = 0 s_length = len ( s ) if ( s_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_REC - Serious error!' write ( *, '(a)' ) ' Null string not allowed!' return end if len1 = len ( sub1 ) if ( len1 <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_REC - Serious error!' write ( *, '(a)' ) ' Null SUB1 not allowed!' return end if len2 = len ( sub2 ) if ( len2 == len1 ) then if ( sub1 == sub2 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_REC - Warning!' write ( *, '(a)' ) ' Replacement = original!' return end if do loc = index ( s, sub1 ) if ( loc == 0 ) then exit end if irep = irep + 1 s(loc:loc+len1-1) = sub2 end do else if ( len2 < len1 ) then do loc = index ( s, sub1 ) if ( loc == 0 ) then exit end if irep = irep + 1 s(loc:loc+len2-1) = sub2 call s_chop ( s, loc+len2, loc+len1-1 ) end do else do loc = index ( s, sub1 ) if ( loc == 0 ) then exit end if irep = irep + 1 if ( s_length < loc + len2 - 1 ) then irep = -irep write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_REC - Warning!' write ( *, '(a)' ) ' Some replaceable elements remain!' return end if call s_blanks_insert ( s, loc, loc+len2-1-len1 ) s(loc:loc+len2-1) = sub2 end do end if return end subroutine s_replace ( s, sub1, sub2, irep ) !*****************************************************************************80 ! !! S_REPLACE replaces all occurrences of SUB1 by SUB2 in a string. ! ! Discussion: ! ! This is not always true if SUB2 is longer than SUB1. The ! replacement is NOT recursive. In other words, replacing all ! occurrences of "ab" by "a" in "abbbbb" will return "abbbb" ! rather than "a". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: the string in which occurrences are to be replaced. ! ! character ( len = * ) SUB1, the string which is to be replaced. ! Trailing blank characters are ignored. The routine is case sensitive. ! ! character ( len = * ) SUB2, the replacement string. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! ! integer IREP, the number of replacements made. ! If IREP is negative, then its absolute value is the ! number of replacements made, and SUB2 is longer than ! SUB1, and at least one substring SUB1 could not be ! replaced by SUB2 because there was no more space. ! (If S = 'aab' and SUB1 = 'a' and SUB2 = 'cc' ! then the result would be S = 'cca'. The first 'a' ! was replaced, the 'b' fell off the end, the second 'a' ! was not replaced because the replacement 'cc' would have ! fallen off the end) ! implicit none integer ilo integer irep integer len1 integer len2 integer lens integer loc character ( len = * ) s character ( len = * ) sub1 character ( len = * ) sub2 irep = 0 lens = len ( s ) if ( lens <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE - Serious error!' write ( *, '(a)' ) ' Null string not allowed!' return end if len1 = len_trim ( sub1 ) if ( len1 <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE - Serious error!' write ( *, '(a)' ) ' Null SUB1 not allowed!' return end if len2 = len_trim ( sub2 ) if ( len2 == len1 ) then if ( sub1(1:len1) == sub2(1:len2) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE - Warning!' write ( *, '(a)' ) ' Replacement = original!' return end if ilo = 1 do loc = index ( s(ilo:lens), sub1(1:len1) ) if ( loc == 0 ) then exit end if loc = loc + ilo - 1 irep = irep + 1 s(loc:loc+len1-1) = sub2(1:len2) ilo = loc + len1 if ( lens < ilo ) then exit end if end do else if ( len2 < len1 ) then ilo = 1 do loc = index ( s(ilo:lens), sub1(1:len1) ) if ( loc == 0 ) then exit end if irep = irep + 1 loc = loc + ilo - 1 s(loc:loc+len2-1) = sub2(1:len2) call s_chop ( s, loc+len2, loc+len1-1 ) ilo = loc + len2 if ( lens < ilo ) then exit end if end do else ilo = 1 do loc = index ( s(ilo:lens), sub1(1:len1) ) if ( loc == 0 ) then exit end if loc = loc + ilo - 1 irep = irep + 1 if ( lens < loc + len2 - 1 ) then irep = -irep write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE - Warning!' write ( *, '(a)' ) ' Some replaceable elements remain!' exit end if call s_blanks_insert ( s, loc, loc+len2-1-len1 ) s(loc:loc+len2-1) = sub2(1:len2) ilo = loc + len2 end do end if return end subroutine s_replace_i ( s, sub1, sub2 ) !*****************************************************************************80 ! !! S_REPLACE_I replaces all occurrences of SUB1 by SUB2 in a string. ! ! Discussion: ! ! Matches are made without regard to case. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: the string in which occurrences are to be replaced. ! ! character ( len = * ) SUB1, the string which is to be replaced. ! ! character ( len = * ) SUB2, the replacement string. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! ! integer IREP, the number of replacements made. ! If IREP is negative, then its absolute value is the ! number of replacements made, and SUB2 is longer than ! SUB1, and at least one substring SUB1 could not be ! replaced by SUB2 because there was no more space. ! (If S = 'aab' and SUB1 = 'a' and SUB2 = 'cc' ! then the result would be S = 'cca'. The first 'a' ! was replaced, the 'b' fell off the end, the second 'a' ! was not replaced because the replacement 'cc' would have ! fallen off the end) ! implicit none integer ilo integer len1 integer len2 integer lens integer s_indexi character ( len = * ) s character ( len = * ) sub1 character ( len = * ) sub2 lens = len ( s ) if ( lens <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_I - Serious error!' write ( *, '(a)' ) ' Null string not allowed!' return end if len1 = len ( sub1 ) if ( len1 <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_REPLACE_I - Serious error!' write ( *, '(a)' ) ' Null SUB1 not allowed!' return end if len2 = len ( sub2 ) ilo = s_indexi ( s, sub1 ) ! ! If the match string has been found, then insert the replacement. ! if ( ilo /= 0 ) then s(ilo+len2:lens+len2-len1) = s(ilo+len1:lens) s(ilo:ilo+len2-1) = sub2(1:len2) end if return end subroutine s_reverse ( s ) !*****************************************************************************80 ! !! S_REVERSE reverses the characters in a string. ! ! Example: ! ! Input Output ! ! ' Cat' 'taC ' ! 'Goo gol ' 'log ooG ' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 November 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to reverse. ! Trailing blanks are ignored. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch integer i integer j character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length / 2 j = s_length + 1 - i ch = s(i:i) s(i:i) = s(j:j) s(j:j) = ch end do return end subroutine s_right_insert ( s1, s2 ) !*****************************************************************************80 ! !! S_RIGHT_INSERT inserts a string flush right into another. ! ! Discussion: ! ! S2 is not blanked out first. If there is already information in S2, ! some of it may still be around after S1 is written into S2. Users may ! want to first assign S2 = ' ' if this is not the effect desired. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string which is to be ! inserted into S2. Only the portion of S1 up to the last ! nonblank will be used. ! ! Output: ! ! character ( len = * ) S2, a string whose length ! will be determined by a call to LEN, and which will ! contain a right flush copy of S1. ! implicit none integer ihi integer ilo integer jhi integer jlo integer len1 integer len2 character ( len = * ) s1 character ( len = * ) s2 len1 = len_trim ( s1 ) len2 = len ( s2 ) if ( len1 < len2 ) then ilo = 1 ihi = len1 jlo = len2 + 1 - len1 jhi = len2 else if ( len2 < len1 ) then ilo = len1 + 1 - len2 ihi = len1 jlo = 1 jhi = len2 else ilo = 1 ihi = len1 jlo = 1 jhi = len2 end if s2(jlo:jhi) = s1(ilo:ihi) return end subroutine s_roman_to_i4 ( s, i ) !*****************************************************************************80 ! !! S_ROMAN_TO_I4 converts a Roman numeral to an integer. ! ! Example: ! ! S I ! ! X 10 ! XIX 19 ! MI 1001 ! CXC 190 ! ! Discussion: ! ! The subroutine does not check carefully as to whether the Roman numeral ! is properly formed. In particular, it will accept a string like 'IM' ! and return 999, even though this is not a well formed Roman numeral. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string containing a Roman numeral. ! ! Output: ! ! integer I, the corresponding value. ! implicit none integer ch_roman_to_i4 character c1 character c2 logical done integer i integer i1 integer i2 character ( len = * ) s i = 0 done = .true. do call ch_next ( s, c2, done ) if ( done ) then return end if i2 = ch_roman_to_i4 ( c2 ) if ( i2 == 0 .and. c2 /= ' ' ) then return end if do c1 = c2 i1 = i2 call ch_next ( s, c2, done ) if ( done ) then i = i + i1 return end if i2 = ch_roman_to_i4 ( c2 ) if ( i2 == 0 .and. c2 /= ' ' ) then i = i + i1 return end if if ( i1 < i2 ) then i = i + i2 - i1 c1 = ' ' c2 = ' ' exit end if i = i + i1 end do end do return end subroutine s_s_delete ( s, sub, irep ) !*****************************************************************************80 ! !! S_S_DELETE removes all occurrences of a substring from a string. ! ! Discussion: ! ! The remainder is left justified and padded with blanks. ! ! The deletion is not recursive. Removing all occurrences of "ab" from ! "aaaaabbbbbQ" results in "aaaabbbbQ" rather than "Q". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! character ( len = * ) SUB1, the substring to be removed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! ! integer IREP, the number of occurrences of SUB1 ! which were found. ! implicit none integer ihi integer ilo integer irep integer loc integer nsub character ( len = * ) s character ( len = * ) sub nsub = len_trim ( sub ) irep = 0 ilo = 1 ihi = len_trim ( s ) do while ( ilo <= ihi ) loc = index ( s(ilo:ihi), sub ) if ( loc == 0 ) then return end if irep = irep + 1 loc = loc + ilo - 1 call s_chop ( s, loc, loc+nsub-1 ) ilo = loc ihi = ihi - nsub end do return end subroutine s_s_delete2 ( s, sub, irep ) !*****************************************************************************80 ! !! S_S_DELETE2 recursively removes a substring from a string. ! ! Discussion: ! ! The remainder is left justified and padded with blanks. ! ! The substitution is recursive, so ! that, for example, removing all occurrences of "ab" from ! "aaaaabbbbbQ" results in "Q". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! character ( len = * ) SUB, the substring to be removed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! ! integer IREP, the number of occurrences of ! the substring. ! implicit none integer ihi integer irep integer loc integer nsub character ( len = * ) s integer s_length character ( len = * ) sub s_length = len ( s ) nsub = len ( sub ) irep = 0 ihi = s_length do while ( 0 < ihi ) loc = index ( s(1:ihi), sub ) if ( loc == 0 ) then return end if irep = irep + 1 call s_chop ( s, loc, loc+nsub-1 ) ihi = ihi - nsub end do return end subroutine s_s_insert ( s1, ipos, s2 ) !*****************************************************************************80 ! !! S_S_INSERT inserts a substring into a string. ! ! Discussion: ! ! Characters in the string are moved to the right to make room, and ! hence the trailing characters, if any, are lost. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string into which ! the second string is to be inserted. ! ! integer IPOS, the position in S at which S2 is ! to be inserted. ! ! character ( len = * ) S2, the string to be inserted. ! ! Output: ! ! character ( len = * ) S1: the transformed string. ! implicit none integer ihi integer ipos character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s1_length = len ( s1 ) s2_length = len_trim ( s2 ) ihi = min ( s1_length, ipos+s2_length-1 ) call s_blanks_insert ( s1, ipos, ihi ) s1(ipos:ihi) = s2 return end function s_s_subanagram ( s1, s2 ) !*****************************************************************************80 ! !! S_S_SUBANAGRAM determines if S2 is a "subanagram" of S1. ! ! Discussion: ! ! S2 is an anagram of S1 if S2 can be formed by permuting the letters ! of S1 ! ! S2 is an subanagram of S1 if S2 can be formed by selecting SOME of ! the letters of S1 and permuting them. ! ! Blanks (trailing or otherwise), punctuation, and capitalization ! are all significant, so be sure to input exactly the information ! you want to check. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the master string. ! ! character ( len = * ) S2, the second string. ! ! Output: ! ! logical S_S_SUBANAGRAM is TRUE if S2 is a subanagram ! of S1. ! implicit none integer i1 integer i2 logical s_s_subanagram character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s_s_subanagram = .false. ! ! Sort both. ! call s_sort_a ( s1 ) call s_sort_a ( s2 ) s1_length = len ( s1 ) s2_length = len ( s2 ) i1 = 0 do i2 = 1, s2_length do i1 = i1 + 1 ! ! Ran out of S1 before finishing. No match is possible. ! if ( s1_length < i1 ) then return end if ! ! The current character in S1 is already greater than the character in S2. ! No match is possible. ! if ( llt ( s2(i2:i2), s1(i1:i1) ) ) then return end if ! ! Found an exact match for current character. Keep going. ! if ( s1(i1:i1) == s2(i2:i2) ) then exit end if ! ! Didn't find a match, but one might be possible if we increase I1. ! end do end do ! ! We matched every character of S2 with something in S1. ! s_s_subanagram = .true. return end function s_s_subanagram_sorted ( s1, s2 ) !*****************************************************************************80 ! !! S_S_SUBANAGRAM_SORTED determines if S2 is a "subanagram" of S1. ! ! Discussion: ! ! This routine assumes that S1 and S2 have already been sorted. ! ! S2 is an anagram of S1 if S2 can be formed by permuting the letters ! of S1 ! ! S2 is an subanagram of S1 if S2 can be formed by selecting SOME of ! the letters of S1 and permuting them. ! ! Blanks (trailing or otherwise), punctuation, and capitalization ! are all significant, so be sure to input exactly the information ! you want to check. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the master string. ! ! character ( len = * ) S2, the second string. ! ! Output: ! ! logical S_S_SUBANAGRAM_SORTED is TRUE if S2 ! is a subanagram of S1. ! implicit none integer i1 integer i2 logical s_s_subanagram_sorted character ( len = * ) s1 integer s1_length character ( len = * ) s2 integer s2_length s_s_subanagram_sorted = .false. s1_length = len ( s1 ) s2_length = len ( s2 ) i1 = 0 do i2 = 1, s2_length do i1 = i1 + 1 ! ! Ran out of S1 before finishing. No match is possible. ! if ( s1_length < i1 ) then return end if ! ! The current character in S1 is already greater than the character in S2. ! No match is possible. ! if ( llt ( s2(i2:i2), s1(i1:i1) ) ) then return end if ! ! Found an exact match for current character. Keep going. ! if ( s1(i1:i1) == s2(i2:i2) ) then exit end if ! ! Didn't find a match, but one might be possible if we increase I1. ! end do end do ! ! We matched every character of S2 with something in S1. ! s_s_subanagram_sorted = .true. return end function s_scrabble_points ( s ) !*****************************************************************************80 ! !! S_SCRABBLE_POINTS returns the Scrabble point value of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 January 2013 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! Output: ! ! integer S_SCRABBLE_POINTS, the point value of ! the string. ! implicit none integer ch_scrabble_points integer i character ( len = * ) s integer s_length integer s_scrabble_points integer value s_length = len ( s ) value = 0 do i = 1, s_length value = value + ch_scrabble_points ( s(i:i) ) end do s_scrabble_points = value return end subroutine s_set_delete ( s1, s2 ) !*****************************************************************************80 ! !! s_set_delete() removes any characters in one string from another string. ! ! Discussion: ! ! When an element is removed, the rest of the string is shifted to the ! left, and padded with blanks on the right. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be examined. ! ! character ( len = * ) S2, the characters to be removed. ! implicit none integer i integer j integer nset character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len ( s1 ) nset = len ( s2 ) i = 0 do while ( i < s1_length ) i = i + 1 do j = 1, nset if ( s1(i:i) == s2(j:j) ) then call s_chop ( s1, i, i ) s1_length = s1_length - 1 i = i - 1 exit end if end do end do return end subroutine s_shift_circular ( s, ishft ) !*****************************************************************************80 ! !! S_SHIFT_CIRCULAR circular shifts the characters in a string to the right. ! ! Discussion: ! ! Thus, a shift of -1 would change "Violin" to "iolinV", and a shift ! of 1 would change it to "nVioli". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be shifted. ! ! integer ISHFT, the number of positions to the ! right to shift the characters. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character chrin character chrout integer icycle integer idid integer igoto integer imove integer ishft integer jshft character ( len = * ) s integer s_length s_length = len ( s ) if ( s_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_SHIFT_CIRCULAR - Serious error!' write ( *, '(a)' ) ' String has nonpositive length!' return end if ! ! Force the shift to be positive and between 0 and S_LENGTH. ! jshft = ishft do while ( jshft < 0 ) jshft = jshft + s_length end do do while ( s_length < jshft ) jshft = jshft - s_length end do if ( jshft == 0 ) then return end if ! ! Shift the first character. Shift the character that got ! displaced by the first character...Repeat until you've shifted ! all, or have "cycled" back to the first character early. ! ! If you've cycled, start again at the second character, and ! so on. ! icycle = 0 idid = 0 imove = 0 do while ( idid < s_length ) if ( imove == icycle ) then imove = imove + 1 icycle = icycle + 1 chrin = s(imove:imove) end if idid = idid + 1 igoto = imove + jshft if ( s_length < igoto ) then igoto = igoto - s_length end if chrout = s(igoto:igoto) s(igoto:igoto) = chrin chrin = chrout imove = igoto end do return end subroutine s_shift_left ( s, ishft ) !*****************************************************************************80 ! !! S_SHIFT_LEFT shifts the characters in a string to the left and blank pads. ! ! Discussion: ! ! A shift of 2 would change "Violin" to "olin ". ! A shift of -2 would change "Violin" to " Violin". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be shifted. ! ! integer ISHFT, the number of positions to the ! left to shift the characters. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i integer ishft character ( len = * ) s integer s_length s_length = len ( s ) if ( 0 < ishft ) then do i = 1, s_length - ishft s(i:i) = s(i+ishft:i+ishft) end do do i = s_length - ishft + 1, s_length s(i:i) = ' ' end do else if ( ishft < 0 ) then do i = s_length, - ishft + 1, - 1 s(i:i) = s(i+ishft:i+ishft) end do do i = -ishft, 1, -1 s(i:i) = ' ' end do end if return end subroutine s_shift_right ( s, ishft ) !*****************************************************************************80 ! !! S_SHIFT_RIGHT shifts the characters in a string to the right and blank pads. ! ! Discussion: ! ! A shift of 2 would change "Violin" to " Viol". ! A shift of -2 would change "Violin" to "olin ". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 August 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be shifted. ! ! integer ISHFT, the number of positions to the ! right to shift the characters. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i integer ishft character ( len = * ) s integer s_length s_length = len ( s ) if ( s_length <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_SHIFT_RIGHT - Serious error!' write ( *, '(a)' ) ' String has nonpositive length!' return end if if ( 0 < ishft ) then do i = s_length, ishft + 1, - 1 s(i:i) = s(i-ishft:i-ishft) end do do i = ishft, 1, -1 s(i:i) = ' ' end do else if ( ishft < 0 ) then do i = 1, s_length + ishft s(i:i) = s(i-ishft:i-ishft) end do do i = s_length + ishft + 1, s_length s(i:i) = ' ' end do end if end function s_skip_set ( s1, s2 ) !*****************************************************************************80 ! !! S_SKIP_SET finds the first entry of a string that is NOT in a set. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 May 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, the string to be examined. ! ! character ( len = * ) S2, the characters to skip. ! ! Output: ! ! integer S_SKIP_SET, the location of the first ! character in S1 that is not in S2, or 0 if no such index was found. ! implicit none integer i integer s_skip_set character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len_trim ( s1 ) do i = 1, s1_length if ( index ( s2, s1(i:i) ) == 0 ) then s_skip_set = i return end if end do s_skip_set = 0 return end subroutine s_sort_a ( s ) !*****************************************************************************80 ! !! S_SORT_A sorts a string into ascending order. ! ! Discussion: ! ! The string is assumed to be short, and so a simple bubble sort is used. ! ! ALL the characters are sorted, including blanks and punctuation. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 June 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be sorted. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character c integer i integer j integer k character ( len = * ) s integer s_length s_length = len ( s ) do i = 1, s_length - 1 c = s(i:i) j = i do k = i + 1, s_length if ( iachar ( s(k:k) ) < iachar ( s(j:j) ) ) then j = k end if end do if ( i /= j ) then s(i:i) = s(j:j) s(j:j) = c end if end do return end subroutine s_split ( s, sub, s1, s2, s3 ) !*****************************************************************************80 ! !! S_SPLIT divides a string into three parts, given the middle. ! ! Discussion: ! ! This version of the routine is case-insensitive. ! ! Example: ! ! Input: ! ! S = 'aBCdEfgh' ! S2 = 'eF' ! ! Output: ! ! S1 = 'aBCd' ! S2 = 'gh' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 March 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be analyzed. ! ! character ( len = * ) SUB, the substring used to "split" S. ! Trailing blanks in SUB are ignored. ! ! Output: ! ! character ( len = * ) S1, the entries in the string, up ! to, but not including, the first occurrence, if any, ! of SUB. If SUB occurs immediately, then S1 = ' '. ! If SUB is not long enough, trailing entries will be lost. ! ! character ( len = * ) S2, the part of the string that matched SUB. ! If S2 is ' ', then there wasn't a match. ! ! character ( len = * ) S3, the part of the string after the match. ! If there was no match, then S3 is blank. ! implicit none integer i integer lenm character ( len = * ) s integer s_indexi integer s_length character ( len = * ) s1 character ( len = * ) s2 character ( len = * ) s3 character ( len = * ) sub s_length = len_trim ( s ) lenm = len_trim ( sub ) if ( lenm == 0 ) then lenm = 1 end if i = s_indexi ( s, sub ) ! ! The substring did not occur. ! if ( i == 0 ) then s1 = s s2 = ' ' s3 = ' ' ! ! The substring begins immediately. ! else if ( i == 1 ) then s1 = ' ' s2 = s(1:lenm) s3 = s(lenm+1:) ! ! What am I checking here? ! else if ( s_length < i + lenm ) then s1 = s s2 = ' ' s3 = ' ' ! ! The substring occurs in the middle. ! else s1 = s(1:i-1) s2 = s(i:i+lenm-1) s3 = s(i+lenm: ) end if ! ! Drop leading blanks. ! s1 = adjustl ( s1 ) s2 = adjustl ( s2 ) s3 = adjustl ( s3 ) return end subroutine s_swap ( s1, s2 ) !*****************************************************************************80 ! !! S_SWAP swaps two strings. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 July 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, S2: two strings. ! ! Output: ! ! character ( len = * ) S1, S2: the values of S1 ! and S2 have been interchanged. ! implicit none character ( len = * ) s1 character ( len = * ) s2 character ( len = 255 ) s3 s3 = s1 s1 = s2 s2 = s3 return end subroutine s_tab_blank ( s ) !*****************************************************************************80 ! !! S_TAB_BLANK replaces each TAB character by one space. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i character ( len = * ) s integer s_length character, parameter :: tab = achar ( 9 ) s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == tab ) then s(i:i) = ' ' end if end do return end subroutine s_tab_blanks ( s ) !*****************************************************************************80 ! !! S_TAB_BLANKS replaces TAB characters by 6 spaces. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be modified. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i integer get integer put integer lenc integer lens integer ntab character ( len = * ) s character, parameter :: tab = achar ( 9 ) ! ! If no TAB's occur in the line, there is nothing to do. ! if ( index ( s, tab ) == 0 ) then return end if ! ! Otherwise, find out how long the string is. ! lenc = len_trim ( s ) lens = len ( s ) ! ! Count the TAB's. ! ntab = 0 do i = 1, lenc if ( s(i:i) == tab ) then ntab = ntab + 1 end if end do ! ! Now copy the string onto itself, going backwards. ! As soon as we've processed the first TAB, we're done. ! put = lenc + 5 * ntab do get = lenc, 1, - 1 if ( s(get:get) /= tab ) then if ( put <= lens ) then s(put:put) = s(get:get) end if put = put - 1 else do i = put, put - 5, -1 if ( i <= lens ) then s(i:i) = ' ' end if end do put = put - 6 ntab = ntab - 1 if ( ntab == 0 ) then return end if end if end do return end subroutine s_to_c4 ( s, cval, ierror, length ) !*****************************************************************************80 ! !! S_TO_C4 reads a complex number from a string. ! ! Discussion: ! ! A C4 is simply a complex number to be stored as a ! "complex ( kind = rk )" value. ! ! This routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the number. ! ! Legal input is: ! ! 1 blanks, ! 2 '+' or '-' sign, ! 3 integer part, ! 4 decimal point, ! 5 fraction part, ! 6 'E' or 'e' or 'D' or 'd', exponent marker, ! 7 exponent sign, ! 8 exponent integer part, ! 9 exponent decimal point, ! 10 exponent fraction part, ! 11 blanks, ! 12 '+' or '-' sign, ! 13 integer part, ! 14 decimal point, ! 15 fraction part, ! 16 'E' or 'e' or 'D' or 'd', exponent marker, ! 17 exponent sign, ! 18 exponent integer part, ! 19 exponent decimal point, ! 20 exponent fraction part, ! 21 blanks, ! 22 "*" ! 23 spaces ! 24 I ! 25 comma or semicolon ! ! with most quantities optional. ! ! Example: ! ! S CVAL IERROR LENGTH ! ! '1' 1 0 1 ! '1+I' 1 + 1 i 0 3 ! '1+1 i' 1 + 1 i 0 5 ! '1+1*i' 1 + 1 i 0 5 ! 'i' 1 i 0 1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read to form a legal real. Blanks, ! commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! complex ( kind = rk ) CVAL, the value that was read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! 1, the string was empty. ! 2, could not read A correctly. ! 3, could not read B correctly. ! 4, could not read I correctly. ! ! integer LENGTH, the number of characters read from ! the string to form the number, including any terminating ! characters such as a trailing comma or blanks. ! implicit none integer, parameter :: ck = kind ( ( 1.0E+00, 1.0E+00 ) ) integer, parameter :: rk = kind ( 1.0E+00 ) real ( kind = rk ) aval real ( kind = rk ) bval character c character c2 logical ch_eqi complex ( kind = ck ) cval integer ichr integer ichr2 integer ierror integer length logical s_neqi character ( len = * ) s ! ! Initialize the return arguments. ! ierror = 0 aval = 0.0E+00 bval = 0.0E+00 cval = cmplx ( aval, bval, kind = ck ) length = 0 ! ! Get the length of the line, and if it's zero, return. ! if ( len_trim ( s ) <= 0 ) then ierror = 1 return end if call nexchr ( s, ichr, c ) ! ! If the next character is "I", then this number is 0+I. ! if ( ch_eqi ( c, 'I' ) ) then aval = 0.0E+00 bval = 1.0E+00 length = length + ichr cval = cmplx ( aval, bval, kind = ck ) return end if ! ! OK, the next string has to be a number! ! call s_to_r4 ( s, aval, ierror, ichr ) if ( ierror /= 0 ) then ierror = 2 length = 0 return end if length = length + ichr ! ! See if this is a pure real number, because: ! ! 1) There's no more input left. ! if ( len_trim ( s(length+1:) ) == 0 ) then cval = cmplx ( aval, bval, kind = ck ) return end if ! ! 2) The last character read was a comma. ! if ( s(length:length) == ',' .or. s(length:length) == ';' ) then cval = cmplx ( aval, bval, kind = ck ) return end if ! ! If the very next character is "I", then this is a pure ! imaginary number! ! call nexchr ( s(length+1:), ichr, c ) if ( ch_eqi ( c, 'I' ) ) then bval = aval aval = 0.0E+00 length = length + ichr cval = cmplx ( aval, bval, kind = ck ) return end if ! ! If the very next character is "*" and the one after that is ! "I", then this is a pure imaginary number! ! if ( c == '*' ) then call nexchr ( s(length+ichr+1:), ichr2, c2 ) if ( ch_eqi ( c2, 'I' ) ) then bval = aval aval = 0.0E+00 length = length + ichr + ichr2 end if cval = cmplx ( aval, bval, kind = ck ) return end if ! ! OK, now we've got A. We have to be careful because the next ! thing we see MIGHT be "+ I" or "- I" which we can't let CHRCTR ! see, because it will have fits. So let's check these two ! possibilities. ! call nexchr ( s(length+1:), ichr, c ) call nexchr ( s(length+1+ichr:), ichr2, c2 ) if ( ch_eqi ( c2, 'I' ) ) then if ( c == '+' ) then bval = 1 length = length + ichr + ichr2 cval = cmplx ( aval, bval, kind = ck ) return else if ( c == '-' ) then bval = -1 length = length + ichr + ichr2 cval = cmplx ( aval, bval, kind = ck ) return end if end if ! ! Read the next real number. ! call s_to_r4 ( s(length+1:), bval, ierror, ichr ) if ( ierror /= 0 ) then ierror = 3 length = 0 return end if length = length + ichr ! ! If the next character is a "*", that's OK, advance past it. ! call nexchr ( s(length+1:), ichr, c ) if ( c == '*' ) then length = length + ichr end if ! ! Now we really do want the next character to be "I". ! call nexchr ( s(length+1:), ichr, c ) if ( s_neqi ( c, 'I' ) ) then ierror = 4 length = 0 return end if ! ! Form the complex number. ! cval = cmplx ( aval, bval, kind = ck ) return end subroutine s_to_caesar ( s1, k, s2 ) !*****************************************************************************80 ! !! S_TO_CAESAR applies a Caesar shift cipher to a string. ! ! Discussion: ! ! The Caesar shift cipher incremented each letter by 1, with Z going to A. ! ! This function can apply a Caesar shift cipher to a string of characters, ! using an arbitrary shift K, which can be positive, negative or zero. ! ! Letters A through Z will be shifted by K, mod 26. ! Letters a through z will be shifted by K, mod 26. ! ! call s_to_caesar ( s1, 1, s2 ) will apply the traditional Caesar cipher. ! call s_to_caesar ( s2, -1, s3 ) will decipher the result. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 January 2016 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string of characters. ! ! integer K, the increment. ! ! Output: ! ! character ( len = * ) S2, the string of enciphered characters. ! implicit none integer i integer i1 integer i2 integer i4_modp integer iacap integer ialow integer k character ( len = * ) s1 integer s1_len character ( len = * ) s2 iacap = iachar ( 'A' ); ialow = iachar ( 'a' ); s1_len = len_trim ( s1 ) s2 = '' do i = 1, s1_len i1 = iachar ( s1(i:i) ) if ( iacap <= i1 .and. i1 <= iacap + 25 ) then i2 = i4_modp ( i1 + k - iacap, 26 ) + iacap s2(i:i) = achar ( i2 ) else if ( ialow <= i1 .and. i1 <= ialow + 25 ) then i2 = i4_modp ( i1 + k - ialow, 26 ) + ialow s2(i:i) = achar ( i2 ) else s2(i:i) = s1(i:i) end if end do return end subroutine s_to_chvec ( s, n, chvec ) !*****************************************************************************80 ! !! S_TO_CHVEC converts a string to a character vector. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 March 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string of characters. ! ! integer N. ! if N is -1, extract characters from 1 to len(S); ! if N is 0, extract characters up to the last nonblank; ! if N is positive, extract characters from 1 to N. ! ! Output: ! ! integer N: the number of characters successfully extracted. ! ! character CHVEC(N), the characters extracted from S. ! implicit none character chvec(*) integer i integer n character ( len = * ) s if ( n <= - 1 ) then n = len ( s ) else if ( n == 0 ) then n = len_trim ( s ) else n = min ( n, len ( s ) ) end if do i = 1, n chvec(i) = s(i:i) end do return end subroutine s_to_date ( s1, s2 ) !*****************************************************************************80 ! !! S_TO_DATE converts the F90 date string to a more usual format. ! ! Example: ! ! S1 S2 ! -------- ---------------- ! 20010204 4 February 2001 ! 17760704 4 July 1776 ! 19520310 10 March 1952 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 February 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 8 ) S1, the F90 date string returned by ! the routine DATE_AND_TIME. ! ! Output: ! ! character ( len = * ) S2, a more usual format for the date. ! Allowing 16 characters for S2 should be sufficient for the ! forseeable future. ! implicit none integer i integer m character ( len = 8 ) month character ( len = * ) s1 character ( len = * ) s2 if ( s1(7:7) == '0' ) then s2(1:1) = s1(8:8) i = 1 else s2(1:2) = s1(7:8) i = 2 end if i = i + 1 s2(i:i) = ' ' read ( s1(5:6), '(i2)' ) m call i4_to_month_name ( m, month ) s2(i+1:) = month i = i + len_trim ( month ) i = i + 1 s2(i:i) = ' ' s2(i+1:i+4) = s1(1:4) i = i + 4 return end subroutine s_to_dec ( s, itop, ibot, length ) !*****************************************************************************80 ! !! S_TO_DEC reads a number from a string, returning a decimal result. ! ! Discussion: ! ! The integer may be in real format, for example '2.25'. It ! returns ITOP and IBOT. If the input number is an integer, ITOP ! equals that integer, and IBOT is 1. But in the case of 2.25, ! the program would return ITOP = 225, IBOT = 100. ! ! Legal input is ! ! blanks, ! 2 initial sign, ! blanks, ! 3 whole number, ! 4 decimal point, ! 5 fraction, ! 6 'E' or 'e' or 'D' or 'd', exponent marker, ! 7 exponent sign, ! 8 exponent, ! blanks ! 9 comma or semicolon ! 10 end of information ! ! Example: ! ! S ITOP IBOT Length Meaning ! ! '1' 1 0 1 1 ! ' 1 ' 1 0 6 1 ! '1A' 1 0 1 1 ! '12,34,56' 12 0 3 12 ! ' 34 7' 34 0 4 34 ! '-1E2ABCD' -1 2 4 -100 ! '-1X2ABCD' -1 0 2 -1 ! ' 2E-1' 2 -1 5 0.2 ! '23.45' 2345 -2 5 23.45 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 February 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading begins at position 1 and ! terminate when no more characters ! can be read to form a legal integer. Blanks, commas, ! or other nonnumeric data will, in particular, cause ! the conversion to halt. ! ! Output: ! ! integer ITOP, the integer read from the string, ! assuming that no negative exponents or fractional parts ! were used. Otherwise, the 'integer' is ITOP/IBOT. ! ! integer IBOT, the integer divisor required to ! represent numbers which are in real format or have a ! negative exponent. ! ! integer LENGTH, the number of characters used. ! implicit none character c logical ch_is_digit integer digit integer exponent integer exponent_sign integer ibot integer ihave integer iterm integer itop integer length integer mantissa_sign character ( len = * ) s logical s_eqi itop = 0 ibot = 0 if ( len ( s ) <= 0 ) then length = 0 return end if length = -1 exponent_sign = 0 mantissa_sign = 1 exponent = 0 ihave = 1 iterm = 0 ! ! Consider the next character in the string. ! do length = length + 1 c = s(length+1:length+1) ! ! Blank. ! if ( c == ' ' ) then if ( ihave == 1 ) then else if ( ihave == 2 ) then else iterm = 1 end if ! ! Comma or semicolon. ! else if ( c == ',' .or. c == ';' ) then if ( ihave /= 1 ) then iterm = 1 ihave = 9 length = length + 1 end if ! ! Minus sign. ! else if ( c == '-' ) then if ( ihave == 1 ) then ihave = 2 mantissa_sign = -1 else if ( ihave == 6 ) then ihave = 7 exponent_sign = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 1 ) then ihave = 2 mantissa_sign = +1 else if ( ihave == 6 ) then ihave = 7 exponent_sign = +1 else iterm = 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( ihave < 4 ) then ihave = 4 else iterm = 1 end if ! ! Exponent marker. ! else if ( s_eqi ( c, 'E' ) .or. s_eqi ( c, 'D' ) ) then if ( ihave < 6 ) then ihave = 6 else iterm = 1 end if ! ! Digit. ! else if ( ch_is_digit ( c ) ) then if ( ihave <= 3 ) then ihave = 3 call ch_to_digit ( c, digit ) itop = 10 * itop + digit else if ( ihave <= 5 ) then ihave = 5 call ch_to_digit ( c, digit ) itop = 10 * itop + digit ibot = ibot - 1 else if ( ihave <= 8 ) then ihave = 8 call ch_to_digit ( c, digit ) exponent = 10 * exponent + digit else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_DEC: Fatal error!' write ( *, '(a,i8)' ) ' IHAVE = ', ihave stop 1 end if ! ! Anything else is regarded as a terminator. ! else iterm = 1 end if if ( iterm == 1 ) then exit end if if ( len ( s ) <= length + 1 ) then length = len ( s ) exit end if end do ! ! Number seems to have terminated. ! Have we got a legal number? ! if ( ihave == 1 ) then return else if ( ihave == 2 .or. ihave == 6 .or. ihave == 7 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_DEC - Serious error!' write ( *, '(a)' ) ' Illegal or nonnumeric input:' write ( *, '(a)' ) ' "' // trim ( s ) // '"' return end if ! ! Normalize. ! if ( 0 < itop ) then do while ( mod ( itop, 10 ) == 0 ) itop = itop / 10 ibot = ibot + 1 end do end if ! ! Consolidate the number in the form ITOP * 10**IBOT. ! ibot = ibot + exponent_sign * exponent itop = mantissa_sign * itop if ( itop == 0 ) then ibot = 0 end if return end subroutine s_to_digits ( s, n, dvec ) !*****************************************************************************80 ! !! S_TO_DIGITS extracts N digits from a string. ! ! Discussion: ! ! The string may include spaces, letters, and dashes, but only the ! digits 0 through 9 will be extracted. ! ! Example: ! ! S => 34E94-70.6 ! N => 5 ! D <= (/ 3, 4, 9, 4, 7 /) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 08 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! integer N, the number of digits to extract. ! ! Output: ! ! integer DVEC(N), the extracted digits. ! implicit none integer n character c logical ch_is_digit integer d integer d_pos integer dvec(n) integer lenc character ( len = * ) s integer s_pos lenc = len_trim ( s ) s_pos = 0 d_pos = 0 do while ( d_pos < n ) s_pos = s_pos + 1 if ( lenc < s_pos ) then write ( *, '(a)' ) '' write ( *, '(a)' ) 'S_TO_DIGITS - Fatal error!' write ( *, '(a)' ) ' Could not read enough data from string.' stop 1 end if c = s(s_pos:s_pos) if ( ch_is_digit ( c ) ) then d_pos = d_pos + 1 call ch_to_digit ( c, d ) dvec(d_pos) = d end if end do return end subroutine s_to_ebcdic ( s ) !*****************************************************************************80 ! !! S_TO_EBCDIC converts a character string from ASCII to EBCDIC. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S: the ASCII string. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ch_to_ebcdic integer i character ( len = * ) s integer s_length s_length = len ( s ) do i = 1, s_length s(i:i) = ch_to_ebcdic ( s(i:i) ) end do return end subroutine s_to_format ( s, r, code, w, m ) !*****************************************************************************80 ! !! S_TO_FORMAT reads a FORTRAN format from a string. ! ! Discussion: ! ! This routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the format. This routine is limited in its ability to ! recognize FORTRAN formats. In particular, we are only expecting ! a single format specification, and cannot handle extra features ! such as 'ES' and 'EN' codes, '5X' spacing, and so on. ! ! Legal input is: ! ! 0 nothing ! 1 blanks ! 2 optional '(' ! 3 blanks ! 4 optional repeat factor R ! 5 blanks ! 6 CODE ( 'A', 'B', 'E', 'F', 'G', 'I', 'L', 'O', 'Z', '*' ) ! 7 blanks ! 8 width W ! 9 optional decimal point ! 10 optional mantissa M ! 11 blanks ! 12 optional ')' ! 13 blanks ! ! Example: ! ! S R CODE W M ! ! 'I12 1 I 12 0 ! 'E8.0' 1 E 8 0 ! 'F10.5' 1 F 10 5 ! '2G14.6' 2 G 14 6 ! '*' 1 * -1 -1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read. ! ! Output: ! ! integer R, the repetition factor, which defaults to 1. ! ! character CODE, the format code. ! ! integer W, the field width. ! ! integer M, the mantissa width. ! implicit none character c logical ch_is_digit logical ch_is_format_code character code integer d logical, parameter :: debug = .true. integer, parameter :: LEFT = 1 integer m integer paren_sum integer pos integer r integer, parameter :: RIGHT = -1 character ( len = * ) s integer s_length integer state integer w state = 0 paren_sum = 0 pos = 0 s_length = len_trim ( s ) r = 0 w = 0 code = '?' m = 0 do while ( pos < s_length ) pos = pos + 1 c = s(pos:pos) ! ! BLANK character: ! if ( c == ' ' ) then if ( state == 4 ) then state = 5 else if ( state == 6 ) then state = 7 else if ( state == 10 ) then state = 11 else if ( state == 12 ) then state = 13 end if ! ! LEFT PAREN ! else if ( c == '(' ) then if ( state < 2 ) then paren_sum = paren_sum + LEFT else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if ! ! DIGIT (R, F, or W) ! else if ( ch_is_digit ( c ) ) then if ( state <= 3 ) then state = 4 call ch_to_digit ( c, r ) else if ( state == 4 ) then call ch_to_digit ( c, d ) r = 10 * r + d else if ( state == 6 .or. state == 7 ) then if ( code == '*' ) then if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a,i8)' ) ' Current code = "' // code // '".' write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if state = 8 call ch_to_digit ( c, w ) else if ( state == 8 ) then call ch_to_digit ( c, d ) w = 10 * w + d else if ( state == 9 ) then state = 10 call ch_to_digit ( c, m ) else if ( state == 10 ) then call ch_to_digit ( c, d ) m = 10 * m + d else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if ! ! DECIMAL POINT ! else if ( c == '.' ) then if ( state == 8 ) then state = 9 else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if ! ! RIGHT PAREN ! else if ( c == ')' ) then paren_sum = paren_sum + RIGHT if ( paren_sum /= 0 ) then if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current paren sum = ', paren_sum write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if if ( state == 6 .and. code == '*' ) then state = 12 else if ( 6 <= state ) then state = 12 else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if ! ! Code ! else if ( ch_is_format_code ( c ) ) then if ( state < 6 ) then state = 6 code = c else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if ! ! Unexpected character ! else if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a,i8)' ) ' Current state = ', state write ( *, '(a)' ) ' Input character = "' // c // '".' end if state = -1 exit end if end do if ( paren_sum /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a)' ) ' Parentheses mismatch.' stop 1 end if if ( state < 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_FORMAT - Fatal error!' write ( *, '(a)' ) ' Parsing error.' stop 1 end if if ( r == 0 ) then r = 1 end if return end subroutine s_to_hex ( s, hex ) !*****************************************************************************80 ! !! S_TO_HEX replaces a character string by a hexadecimal representation. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! The string 'ABC' causes the hexadecimal string '414243' to be returned. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string of characters. ! ! Output: ! ! character ( len = * ) HEX, the string of hex values. ! implicit none character ( len = * ) hex integer i integer intval integer j integer ndo integer nhex character ( len = * ) s integer s_length s_length = len_trim ( s ) nhex = len ( hex ) ndo = min ( nhex / 2, s_length ) hex = ' ' do i = 1, ndo j = 2 * i - 1 intval = iachar ( s(i:i) ) call i4_to_hex ( intval, hex(j:j+1) ) end do return end subroutine s_to_i4 ( s, value, ierror, length ) !*****************************************************************************80 ! !! s_to_i4() reads an I4 from a string. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string to be examined. ! ! Output: ! ! integer VALUE, the value read from the string. ! If the string is blank, then VALUE will be returned 0. ! ! integer IERROR, an error flag. ! 0, no error. ! 1, an error occurred. ! ! integer LENGTH, the number of characters ! of S used to make the integer. ! implicit none character c integer i integer ierror integer isgn integer length character ( len = * ) s integer state character :: TAB = achar ( 9 ) integer value value = 0 ierror = 0 length = 0 state = 0 isgn = 1 do i = 1, len_trim ( s ) c = s(i:i) ! ! STATE = 0, haven't read anything. ! if ( state == 0 ) then if ( c == ' ' .or. c == TAB ) then else if ( c == '-' ) then state = 1 isgn = -1 else if ( c == '+' ) then state = 1 isgn = +1 else if ( lle ( '0', c ) .and. lle ( c, '9' ) ) then state = 2 value = iachar ( c ) - iachar ( '0' ) else ierror = 1 return end if ! ! STATE = 1, have read the sign, expecting digits or spaces. ! else if ( state == 1 ) then if ( c == ' ' .or. c == TAB ) then else if ( lle ( '0', c ) .and. lle ( c, '9' ) ) then state = 2 value = iachar ( c ) - iachar ( '0' ) else ierror = 1 return end if ! ! STATE = 2, have read at least one digit, expecting more. ! else if ( state == 2 ) then if ( lle ( '0', c ) .and. lle ( c, '9' ) ) then value = 10 * value + iachar ( c ) - iachar ( '0' ) else value = isgn * value ierror = 0 length = i - 1 return end if end if end do ! ! If we read all the characters in the string, see if we're OK. ! if ( state == 2 ) then value = isgn * value ierror = 0 length = len_trim ( s ) else value = 0 ierror = 1 length = 0 end if return end subroutine s_to_i4vec ( s, n, i4vec, ierror ) !*****************************************************************************80 ! !! S_TO_I4VEC reads an integer vector from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 08 October 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be read. ! ! integer N, the number of values expected. ! ! Output: ! ! integer I4VEC(N), the values read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! -K, could not read data for entries -K through N. ! implicit none integer n integer i integer ierror integer ilo integer i4vec(n) integer length character ( len = * ) s i = 0 ierror = 0 ilo = 1 do while ( i < n ) i = i + 1 call s_to_i4 ( s(ilo:), i4vec(i), ierror, length ) if ( ierror /= 0 ) then ierror = -i exit end if ilo = ilo + length end do return end subroutine s_to_isbn_digits ( s, n, dvec ) !*****************************************************************************80 ! !! S_TO_ISBN_DIGITS extracts N ISBN digits from a string. ! ! Discussion: ! ! The string may include spaces, letters, and dashes, but only the ! digits '0' through '9' and 'X' will be extracted. ! ! Example: ! ! S => 34E9X-70.6 ! N => 5 ! D <= (/ 3, 4, 9, 10, 7 /) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 September 2015 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! integer N, the number of digits to extract. ! ! Output: ! ! integer DVEC(N), the extracted digits. ! implicit none integer n character c logical ch_is_isbn_digit integer d_pos integer dvec(n) integer isbn_digit_to_i4 integer lenc character ( len = * ) s integer s_pos lenc = len_trim ( s ) s_pos = 0 d_pos = 0 do while ( d_pos < n ) s_pos = s_pos + 1 if ( lenc < s_pos ) then write ( *, '(a)' ) '' write ( *, '(a)' ) 'S_TO_ISBN_DIGITS - Fatal error!' write ( *, '(a)' ) ' Could not read enough data from string.' stop 1 end if c = s(s_pos:s_pos) if ( ch_is_isbn_digit ( c ) ) then d_pos = d_pos + 1 dvec(d_pos) = isbn_digit_to_i4 ( c ) end if end do return end function s_to_l4 ( s ) !*****************************************************************************80 ! !! S_TO_L4 reads a logical value from a string. ! ! Discussion: ! ! There are several ways of representing logical data that this routine ! recognizes: ! ! False True ! ----- ---- ! ! 0 1 ! F T ! f t ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 03 December 2010 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be read. ! ! Output: ! ! logical S_TO_L4, the logical value read from the string. ! implicit none integer i character ( len = * ) s integer s_length logical s_to_l4 s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == '0' .or. s(i:i) == 'F' .or. s(i:i) == 'f' ) then s_to_l4 = .false. return else if ( s(i:i) == '1' .or. s(i:i) == 'T' .or. s(i:i) == 't' ) then s_to_l4 = .true. return end if end do write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_L4 - Fatal error!' write ( *, '(a)' ) ' Input text did not contain logical data.' stop 1 end subroutine s_to_r4 ( s, r, ierror, length ) !*****************************************************************************80 ! !! S_TO_R4 reads an R4 value from a string. ! ! Discussion: ! ! An "R4" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! This routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the real number. ! ! Legal input is: ! ! 1 blanks, ! 2 '+' or '-' sign, ! 2.5 spaces ! 3 integer part, ! 4 decimal point, ! 5 fraction part, ! 6 'E' or 'e' or 'D' or 'd', exponent marker, ! 7 exponent sign, ! 8 exponent integer part, ! 9 exponent decimal point, ! 10 exponent fraction part, ! 11 blanks, ! 12 final comma or semicolon. ! ! with most quantities optional. ! ! Example: ! ! S R ! ! '1' 1.0 ! ' 1 ' 1.0 ! '1A' 1.0 ! '12,34,56' 12.0 ! ' 34 7' 34.0 ! '-1E2ABCD' -100.0 ! '-1X2ABCD' -1.0 ! ' 2E-1' 0.2 ! '23.45' 23.45 ! '-4.2E+2' -420.0 ! '17d2' 1700.0 ! '-14e-2' -0.14 ! 'e2' 100.0 ! '-12.73e-9.23' -12.73 * 10.0^(-9.23) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 February 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read to form a legal real. Blanks, ! commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! real ( kind = rk ) R, the real value that was read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! 1, 2, 6 or 7, the input number was garbled. The ! value of IERROR is the last type of input successfully ! read. For instance, 1 means initial blanks, 2 means ! a plus or minus sign, and so on. ! ! integer LENGTH, the number of characters read from ! the string to form the number, including any terminating ! characters such as a trailing comma or blanks. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) character c logical ch_eqi integer ierror integer ihave integer isgn integer iterm integer jbot integer jsgn integer jtop integer length integer ndig real ( kind = rk ) r real ( kind = rk ) rbot real ( kind = rk ) rexp real ( kind = rk ) rtop character ( len = * ) s integer s_length character, parameter :: TAB = achar ( 9 ) s_length = len_trim ( s ) ierror = 0 r = 0.0E+00 length = -1 isgn = 1 rtop = 0.0E+00 rbot = 1.0E+00 jsgn = 1 jtop = 0 jbot = 1 ihave = 1 iterm = 0 do length = length + 1 c = s(length+1:length+1) ! ! Blank or TAB character. ! if ( c == ' ' .or. c == TAB ) then if ( ihave == 2 ) then else if ( ihave == 6 .or. ihave == 7 ) then iterm = 1 else if ( 1 < ihave ) then ihave = 11 end if ! ! Comma. ! else if ( c == ',' .or. c == ';' ) then if ( ihave /= 1 ) then iterm = 1 ihave = 12 length = length + 1 end if ! ! Minus sign. ! else if ( c == '-' ) then if ( ihave == 1 ) then ihave = 2 isgn = -1 else if ( ihave == 6 ) then ihave = 7 jsgn = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 1 ) then ihave = 2 else if ( ihave == 6 ) then ihave = 7 else iterm = 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( ihave < 4 ) then ihave = 4 else if ( 6 <= ihave .and. ihave <= 8 ) then ihave = 9 else iterm = 1 end if ! ! Exponent marker. ! else if ( ch_eqi ( c, 'E' ) .or. ch_eqi ( c, 'D' ) ) then if ( ihave < 6 ) then ihave = 6 else iterm = 1 end if ! ! Digit. ! else if ( ihave < 11 .and. lle ( '0', c ) .and. lle ( c, '9' ) ) then if ( ihave <= 2 ) then ihave = 3 else if ( ihave == 4 ) then ihave = 5 else if ( ihave == 6 .or. ihave == 7 ) then ihave = 8 else if ( ihave == 9 ) then ihave = 10 end if call ch_to_digit ( c, ndig ) if ( ihave == 3 ) then rtop = 10.0E+00 * rtop + real ( ndig, kind = rk ) else if ( ihave == 5 ) then rtop = 10.0E+00 * rtop + real ( ndig, kind = rk ) rbot = 10.0E+00 * rbot else if ( ihave == 8 ) then jtop = 10 * jtop + ndig else if ( ihave == 10 ) then jtop = 10 * jtop + ndig jbot = 10 * jbot end if ! ! Anything else is regarded as a terminator. ! else iterm = 1 end if ! ! If we haven't seen a terminator, and we haven't examined the ! entire string, go get the next character. ! if ( iterm == 1 .or. s_length <= length + 1 ) then exit end if end do ! ! If we haven't seen a terminator, and we have examined the ! entire string, then we're done, and LENGTH is equal to S_LENGTH. ! if ( iterm /= 1 .and. length + 1 == s_length ) then length = s_length end if ! ! Number seems to have terminated. Have we got a legal number? ! Not if we terminated in states 1, 2, 6 or 7! ! if ( ihave == 1 .or. ihave == 2 .or. ihave == 6 .or. ihave == 7 ) then ierror = ihave return end if ! ! Number seems OK. Form it. ! if ( jtop == 0 ) then rexp = 1.0E+00 else if ( jbot == 1 ) then rexp = 10.0E+00**( jsgn * jtop ) else rexp = jsgn * jtop rexp = rexp / jbot rexp = 10.0E+00**rexp end if end if r = isgn * rexp * rtop / rbot return end subroutine s_to_r4vec ( s, n, r4vec, ierror ) !*****************************************************************************80 ! !! S_TO_R4VEC reads an R4VEC from a string. ! ! Discussion: ! ! An R4VEC is a vector of real values, of type "real ( kind = rk )". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 19 February 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be read. ! ! integer N, the number of values expected. ! ! Output: ! ! real ( kind = rk ) R4VEC(N), the values read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! -K, could not read data for entries -K through N. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer n integer i integer ierror integer ilo integer length real ( kind = rk ) r4vec(n) character ( len = * ) s i = 0 ierror = 0 ilo = 1 do while ( i < n ) i = i + 1 call s_to_r4 ( s(ilo:), r4vec(i), ierror, length ) if ( ierror /= 0 ) then ierror = -i exit end if ilo = ilo + length end do return end subroutine s_to_r8 ( s, r8 ) !*****************************************************************************80 ! !! S_TO_R8 reads an R8 value from a string. ! ! Discussion: ! ! An "R8" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! The routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the number. ! ! Legal input is: ! ! 1 blanks, ! 2 '+' or '-' sign, ! 2.5 blanks ! 3 integer part, ! 4 decimal point, ! 5 fraction part, ! 6 'E' or 'e' or 'D' or 'd', exponent marker, ! 7 exponent sign, ! 8 exponent integer part, ! 9 exponent decimal point, ! 10 exponent fraction part, ! 11 blanks, ! 12 final comma or semicolon, ! ! with most quantities optional. ! ! Example: ! ! S R8 ! ! '1' 1.0 ! ' 1 ' 1.0 ! '1A' 1.0 ! '12,34,56' 12.0 ! ' 34 7' 34.0 ! '-1E2ABCD' -100.0 ! '-1X2ABCD' -1.0 ! ' 2E-1' 0.2 ! '23.45' 23.45 ! '-4.2E+2' -420.0 ! '17d2' 1700.0 ! '-14e-2' -0.14 ! 'e2' 100.0 ! '-12.73e-9.23' -12.73 * 10.0^(-9.23) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 06 January 2013 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read to form a legal real. Blanks, ! commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! real ( kind = rk ) R8, the value read from the string. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) character c integer ierror integer ihave integer isgn integer iterm integer jbot integer jsgn integer jtop integer length integer ndig real ( kind = rk ) r8 real ( kind = rk ) rbot real ( kind = rk ) rexp real ( kind = rk ) rtop character ( len = * ) s integer s_length character :: TAB = achar ( 9 ) s_length = len_trim ( s ) ierror = 0 r8 = 0.0D+00 length = -1 isgn = 1 rtop = 0 rbot = 1 jsgn = 1 jtop = 0 jbot = 1 ihave = 1 iterm = 0 do length = length + 1 if ( s_length < length + 1 ) then exit end if c = s(length+1:length+1) ! ! Blank character. ! if ( c == ' ' .or. c == TAB ) then if ( ihave == 2 ) then else if ( ihave == 6 .or. ihave == 7 ) then iterm = 1 else if ( 1 < ihave ) then ihave = 11 end if ! ! Comma. ! else if ( c == ',' .or. c == ';' ) then if ( ihave /= 1 ) then iterm = 1 ihave = 12 length = length + 1 end if ! ! Minus sign. ! else if ( c == '-' ) then if ( ihave == 1 ) then ihave = 2 isgn = -1 else if ( ihave == 6 ) then ihave = 7 jsgn = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 1 ) then ihave = 2 else if ( ihave == 6 ) then ihave = 7 else iterm = 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( ihave < 4 ) then ihave = 4 else if ( 6 <= ihave .and. ihave <= 8 ) then ihave = 9 else iterm = 1 end if ! ! Scientific notation exponent marker. ! else if ( c == 'E' .or. c == 'e' .or. c == 'D' .or. c == 'd' ) then if ( ihave < 6 ) then ihave = 6 else iterm = 1 end if ! ! Digit. ! else if ( ihave < 11 .and. lle ( '0', c ) .and. lle ( c, '9' ) ) then if ( ihave <= 2 ) then ihave = 3 else if ( ihave == 4 ) then ihave = 5 else if ( ihave == 6 .or. ihave == 7 ) then ihave = 8 else if ( ihave == 9 ) then ihave = 10 end if ndig = iachar ( c ) - 48 if ( ihave == 3 ) then rtop = 10.0D+00 * rtop + real ( ndig, kind = rk ) else if ( ihave == 5 ) then rtop = 10.0D+00 * rtop + real ( ndig, kind = rk ) rbot = 10.0D+00 * rbot else if ( ihave == 8 ) then jtop = 10 * jtop + ndig else if ( ihave == 10 ) then jtop = 10 * jtop + ndig jbot = 10 * jbot end if ! ! Anything else is regarded as a terminator. ! else iterm = 1 end if ! ! If we haven't seen a terminator, and we haven't examined the ! entire string, go get the next character. ! if ( iterm == 1 ) then exit end if end do ! ! If we haven't seen a terminator, and we have examined the ! entire string, then we're done, and LENGTH is equal to S_LENGTH. ! if ( iterm /= 1 .and. length + 1 == s_length ) then length = s_length end if ! ! Number seems to have terminated. Have we got a legal number? ! Not if we terminated in states 1, 2, 6 or 7! ! if ( ihave == 1 .or. ihave == 2 .or. ihave == 6 .or. ihave == 7 ) then ierror = ihave write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_R8 - Serious error!' write ( *, '(a)' ) ' Illegal or nonnumeric input:' write ( *, '(a)' ) ' "' // trim ( s ) // '"' stop 1 end if ! ! Number seems OK. Form it. ! if ( jtop == 0 ) then rexp = 1.0D+00 else if ( jbot == 1 ) then rexp = 10.0D+00 ** ( jsgn * jtop ) else rexp = 10.0D+00 ** ( real ( jsgn * jtop, kind = rk ) & / real ( jbot, kind = rk ) ) end if end if r8 = real ( isgn, kind = rk ) * rexp * rtop / rbot return end subroutine s_to_r8_old ( s, dval, ierror, length ) !*****************************************************************************80 ! !! S_TO_R8_OLD reads an R8 value from a string. ! ! Discussion: ! ! An "R8" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! The routine will read as many characters as possible until it reaches ! the end of the string, or encounters a character which cannot be ! part of the number. ! ! Legal input is: ! ! 1 blanks, ! 2 '+' or '-' sign, ! 2.5 blanks ! 3 integer part, ! 4 decimal point, ! 5 fraction part, ! 6 'E' or 'e' or 'D' or 'd', exponent marker, ! 7 exponent sign, ! 8 exponent integer part, ! 9 exponent decimal point, ! 10 exponent fraction part, ! 11 blanks, ! 12 final comma or semicolon, ! ! with most quantities optional. ! ! Example: ! ! S DVAL ! ! '1' 1.0 ! ' 1 ' 1.0 ! '1A' 1.0 ! '12,34,56' 12.0 ! ' 34 7' 34.0 ! '-1E2ABCD' -100.0 ! '-1X2ABCD' -1.0 ! ' 2E-1' 0.2 ! '23.45' 23.45 ! '-4.2E+2' -420.0 ! '17d2' 1700.0 ! '-14e-2' -0.14 ! 'e2' 100.0 ! '-12.73e-9.23' -12.73 * 10.0**(-9.23) ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 January 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string containing the ! data to be read. Reading will begin at position 1 and ! terminate at the end of the string, or when no more ! characters can be read to form a legal real. Blanks, ! commas, or other nonnumeric data will, in particular, ! cause the conversion to halt. ! ! Output: ! ! real ( kind = rk ) DVAL, the value read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! 1, 2, 6 or 7, the input number was garbled. The ! value of IERROR is the last type of input successfully ! read. For instance, 1 means initial blanks, 2 means ! a plus or minus sign, and so on. ! ! integer LENGTH, the number of characters read ! to form the number, including any terminating ! characters such as a trailing comma or blanks. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) character c logical ch_eqi real ( kind = rk ) dval integer ierror integer ihave integer isgn integer iterm integer jbot integer jsgn integer jtop integer length integer ndig real ( kind = rk ) rbot real ( kind = rk ) rexp real ( kind = rk ) rtop character ( len = * ) s integer s_length character :: TAB = achar ( 9 ) s_length = len_trim ( s ) ierror = 0 dval = 0.0D+00 length = -1 isgn = 1 rtop = 0 rbot = 1 jsgn = 1 jtop = 0 jbot = 1 ihave = 1 iterm = 0 do length = length + 1 if ( s_length < length + 1 ) then exit end if c = s(length+1:length+1) ! ! Blank character. ! if ( c == ' ' .or. c == TAB ) then if ( ihave == 2 ) then else if ( ihave == 6 .or. ihave == 7 ) then iterm = 1 else if ( 1 < ihave ) then ihave = 11 end if ! ! Comma. ! else if ( c == ',' .or. c == ';' ) then if ( ihave /= 1 ) then iterm = 1 ihave = 12 length = length + 1 end if ! ! Minus sign. ! else if ( c == '-' ) then if ( ihave == 1 ) then ihave = 2 isgn = -1 else if ( ihave == 6 ) then ihave = 7 jsgn = -1 else iterm = 1 end if ! ! Plus sign. ! else if ( c == '+' ) then if ( ihave == 1 ) then ihave = 2 else if ( ihave == 6 ) then ihave = 7 else iterm = 1 end if ! ! Decimal point. ! else if ( c == '.' ) then if ( ihave < 4 ) then ihave = 4 else if ( 6 <= ihave .and. ihave <= 8 ) then ihave = 9 else iterm = 1 end if ! ! Scientific notation exponent marker. ! else if ( ch_eqi ( c, 'E' ) .or. ch_eqi ( c, 'D' ) ) then if ( ihave < 6 ) then ihave = 6 else iterm = 1 end if ! ! Digit. ! else if ( ihave < 11 .and. lle ( '0', c ) .and. lle ( c, '9' ) ) then if ( ihave <= 2 ) then ihave = 3 else if ( ihave == 4 ) then ihave = 5 else if ( ihave == 6 .or. ihave == 7 ) then ihave = 8 else if ( ihave == 9 ) then ihave = 10 end if call ch_to_digit ( c, ndig ) if ( ihave == 3 ) then rtop = 10.0D+00 * rtop + real ( ndig, kind = rk ) else if ( ihave == 5 ) then rtop = 10.0D+00 * rtop + real ( ndig, kind = rk ) rbot = 10.0D+00 * rbot else if ( ihave == 8 ) then jtop = 10 * jtop + ndig else if ( ihave == 10 ) then jtop = 10 * jtop + ndig jbot = 10 * jbot end if ! ! Anything else is regarded as a terminator. ! else iterm = 1 end if ! ! If we haven't seen a terminator, and we haven't examined the ! entire string, go get the next character. ! if ( iterm == 1 ) then exit end if end do ! ! If we haven't seen a terminator, and we have examined the ! entire string, then we're done, and LENGTH is equal to S_LENGTH. ! if ( iterm /= 1 .and. length + 1 == s_length ) then length = s_length end if ! ! Number seems to have terminated. Have we got a legal number? ! Not if we terminated in states 1, 2, 6 or 7! ! if ( ihave == 1 .or. ihave == 2 .or. ihave == 6 .or. ihave == 7 ) then ierror = ihave write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'S_TO_R8_OLD - Serious error!' write ( *, '(a)' ) ' Illegal or nonnumeric input:' write ( *, '(a)' ) ' "' // trim ( s ) // '"' return end if ! ! Number seems OK. Form it. ! if ( jtop == 0 ) then rexp = 1.0D+00 else if ( jbot == 1 ) then rexp = 10.0D+00 ** ( jsgn * jtop ) else rexp = 10.0D+00 ** ( real ( jsgn * jtop, kind = rk ) & / real ( jbot, kind = rk ) ) end if end if dval = real ( isgn, kind = rk ) * rexp * rtop / rbot return end subroutine s_to_r8vec ( s, n, r8vec, ierror ) !*****************************************************************************80 ! !! S_TO_R8VEC reads an R8VEC from a string. ! ! Discussion: ! ! An R8VEC is a vector of real values, of type "real ( kind = rk )". ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 25 January 2005 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be read. ! ! integer N, the number of values expected. ! ! Output: ! ! real ( kind = rk ) R8VEC(N), the values read from the string. ! ! integer IERROR, error flag. ! 0, no errors occurred. ! -K, could not read data for entries -K through N. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer i integer ierror integer ilo integer lchar real ( kind = rk ) r8vec(n) character ( len = * ) s i = 0 ierror = 0 ilo = 1 do while ( i < n ) i = i + 1 call s_to_r8_old ( s(ilo:), r8vec(i), ierror, lchar ) if ( ierror /= 0 ) then ierror = -i exit end if ilo = ilo + lchar end do return end subroutine s_to_rot13 ( s1, s2 ) !*****************************************************************************80 ! !! S_TO_ROT13 "rotates" the alphabetical characters in a string by 13 positions. ! ! Discussion: ! ! Two applications of the routine will return the original string. ! ! Example: ! ! Input: Output: ! ! abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm ! Cher Pure ! James Thurston Howell Wnzrf Guhefgba Ubjryy ! 0123456789 5678901234 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 January 2016 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a string to be "rotated". ! ! Output: ! ! character ( len = * ) S2, the rotated string. ! implicit none character ch_to_rot13 integer i character ( len = * ) s1 integer s1_length character ( len = * ) s2 s1_length = len_trim ( s1 ) s2 = '' do i = 1, s1_length s2(i:i) = ch_to_rot13 ( s1(i:i) ) end do return end subroutine s_to_soundex ( s, code ) !*****************************************************************************80 ! !! S_TO_SOUNDEX computes the Soundex code of a string. ! ! Example: ! ! Input: Output: ! ! Ellery E460 ! Euler E460 ! Gauss G200 ! Ghosh G200 ! Heilbronn H416 ! Hilbert H416 ! Kant K530 ! Knuth K530 ! Ladd L300 ! Lloyd L300 ! Lissajous L222 ! Lukasiewicz L222 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 May 2003 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Donald Knuth, ! The Art of Computer Programming, ! Volume 3, Sorting and Searching, ! Second Edition, ! Addison Wesley, 1998, ! ISBN: 0201896850, ! LC: QA76.6.K64. ! ! Input: ! ! character ( len = * ) S, a string to be converted. ! ! Output: ! ! character ( len = 4 ) CODE, the Soundex code for the string. ! implicit none character c character c_put logical ch_is_alpha character ch_s character ch_s_old character ( len = 4 ) code integer get integer nget integer put character ( len = * ) s ch_s = '0' code = ' ' nget = len_trim ( s ) get = 0 ! ! Try to fill position PUT of the code. ! do put = 1, 4 do if ( nget <= get ) then c_put = '0' exit end if get = get + 1 c = s(get:get) call ch_cap ( c ) if ( .not. ch_is_alpha ( c ) ) then cycle end if ch_s_old = ch_s call ch_to_soundex ( c, ch_s ) if ( put == 1 ) then c_put = c exit else if ( ch_s /= ch_s_old .and. ch_s /= '0' ) then c_put = ch_s exit end if end do code(put:put) = c_put end do return end subroutine s_to_w ( s, w, ierror, last ) !*****************************************************************************80 ! !! S_TO_W reads the next blank-delimited word from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 15 November 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string to be examined. ! ! Output: ! ! character ( len = * ) W, the word that was read. ! ! integer IERROR, an error flag. ! 0, no error. ! 1, an error occurred. ! ! integer LAST, the last character of S used to make W. ! implicit none character c integer first integer i integer ierror integer last character ( len = * ) s integer state character ( len = * ) w w = ' ' ierror = 0 state = 0 first = 0 last = 0 i = 0 do i = i + 1 if ( len_trim ( s ) < i ) then if ( state == 0 ) then ierror = 1 last = 0 else last = i-1 w = s(first:last) end if exit end if c = s(i:i) if ( state == 0 ) then if ( c /= ' ' ) then first = i state = 1 end if else if ( state == 1 ) then if ( c == ' ' ) then last = i - 1 w = s(first:last) exit end if end if end do return end subroutine s_token_equal ( s, set, nset, iset ) !*****************************************************************************80 ! !! S_TOKEN_EQUAL checks whether a string is equal to any of a set of strings. ! ! Discussion: ! ! The comparison is case-insensitive. ! ! Trailing blanks in S and the elements of SET are ignored. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to check. ! ! character ( len = * ) SET(NSET), the set of strings. ! ! integer NSET, the number of elements of SET. ! ! Output: ! ! integer ISET, equals 0 if no element of SET ! equals S. If ISET is nonzero, then SET(ISET) equals ! S, disregarding case. ! implicit none integer i integer iset integer nset character ( len = * ) s logical s_eqi character ( len = * ) set(*) iset = 0 do i = 1, nset if ( s_eqi ( s, set(i) ) ) then iset = i return end if end do return end subroutine s_token_match ( s, token_num, token, match ) !*****************************************************************************80 ! !! S_TOKEN_MATCH matches the beginning of a string and a set of tokens. ! ! Example: ! ! Input: ! ! S = 'TOMMYGUN' ! TOKEN = 'TOM', 'ZEBRA', 'TOMMY', 'TOMMYKNOCKER' ! ! Output: ! ! MATCH = 3 ! ! Discussion: ! ! The longest possible match is taken. ! Matching is done without regard to case or trailing blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! integer TOKEN_NUM, the number of tokens to be compared. ! ! character ( len = * ) TOKEN(TOKEN_NUM), the tokens. ! ! Output: ! ! integer MATCH, the index of the (longest) ! token that matched the string, or 0 if no match was found. ! implicit none integer token_num integer match integer match_length character ( len = * ) s logical s_eqi integer s_length integer token_i integer token_length character ( len = * ) token(token_num) match = 0 match_length = 0 s_length = len_trim ( s ) do token_i = 1, token_num token_length = len_trim ( token ( token_i ) ) if ( match_length < token_length ) then if ( token_length <= s_length ) then if ( s_eqi ( s(1:token_length), token(token_i)(1:token_length) ) ) then match_length = token_length match = token_i end if end if end if end do return end subroutine s_trim_zeros ( s ) !*****************************************************************************80 ! !! S_TRIM_ZEROS removes trailing zeros from a string. ! ! Example: ! ! Input: ! ! S = '1401.072500' ! ! Output: ! ! S = '1401.0725' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be operated on. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character ( len = * ) s integer s_length s_length = len_trim ( s ) do while ( 0 < s_length .and. s(s_length:s_length) == '0' ) s(s_length:s_length) = ' ' s_length = s_length - 1 end do return end subroutine s_u2b ( s ) !*****************************************************************************80 ! !! S_U2B replaces underscores by blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) do i = 1, s_length if ( s(i:i) == '_' ) then s(i:i) = ' ' end if end do return end subroutine s_word_append ( s, w, done ) !*****************************************************************************80 ! !! S_WORD_APPEND appends a word to a string. ! ! Discussion: ! ! A blank space will separate the word from the text already ! in the line. ! ! The routine warns the user if the word will not fit. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 December 2002 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a line of text. ! ! character ( len = * ) W, a word to be appended. ! Trailing blanks in the word are ignored. ! ! Output: ! ! character ( len = * ) S: the string with the word appended. ! ! logical DONE, is FALSE if there was not enough room ! to append the word. ! implicit none logical done integer lens integer lents integer lenw integer next character ( len = * ) s character ( len = * ) w done = .false. lens = len ( s ) lents = len_trim ( s ) lenw = len_trim ( w ) if ( lents == 0 ) then if ( lens < lenw ) then done = .true. return end if else if ( lens < lents + 1 + lenw ) then done = .true. return end if end if if ( lents == 0 ) then next = 1 else next = lents + 1 s(next:next) = ' ' next = next + 1 end if s(next:next+lenw-1) = w(1:lenw) return end subroutine s_word_cap ( s ) !*****************************************************************************80 ! !! S_WORD_CAP capitalizes the first character of each word in a string. ! ! Example: ! ! Input: ! ! S = 'it is time to turn the page.' ! ! Output: ! ! S = 'It Is Time To Turn The Page.' ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 August 2009 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be transformed. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none logical blank integer i character ( len = * ) s integer s_length s_length = len_trim ( s ) blank = .true. do i = 1, s_length if ( blank ) then call ch_cap ( s(i:i) ) else call ch_low ( s(i:i) ) end if blank = ( s(i:i) == ' ' ) end do return end subroutine s_word_count ( s, word_num ) !*****************************************************************************80 ! !! s_word_count() counts the number of "words" in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 September 2021 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! Output: ! ! integer WORD_NUM, the number of "words" in the ! string. Words are presumed to be separated by one or more blanks. ! implicit none logical blank integer i character ( len = * ) s integer s_length character, parameter :: TAB = achar ( 9 ) integer word_num word_num = 0 s_length = len ( s ) if ( s_length <= 0 ) then return end if blank = .true. do i = 1, s_length if ( s(i:i) == ' ' .or. s(i:i) == TAB ) then blank = .true. else if ( blank ) then word_num = word_num + 1 blank = .false. end if end do return end subroutine s_word_extract_first ( s, w ) !*****************************************************************************80 ! !! s_word_extract_first() extracts the first word from a string. ! ! Discussion: ! ! A "word" is a string of characters terminated by a blank or ! the end of the string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 31 January 2006 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string. ! ! Output: ! ! character ( len = * ) S: the transformed string. The first word ! has been removed, and the remaining string shifted left. ! ! character ( len = * ) W, the leading word of the string. ! implicit none integer get1 integer get2 character ( len = * ) s integer s_length character ( len = * ) w w = ' ' s_length = len_trim ( s ) if ( s_length < 1 ) then return end if ! ! Find the first nonblank. ! get1 = 0 do get1 = get1 + 1 if ( s_length < get1 ) then return end if if ( s(get1:get1) /= ' ' ) then exit end if end do ! ! Look for the last contiguous nonblank. ! get2 = get1 do if ( s_length <= get2 ) then exit end if if ( s(get2+1:get2+1) == ' ' ) then exit end if get2 = get2 + 1 end do ! ! Copy the word. ! w = s(get1:get2) ! ! Shift the string. ! s(1:get2) = ' ' s = adjustl ( s ) return end subroutine s_word_find ( s, iword, word, nchar ) !*****************************************************************************80 ! !! s_word_find() finds the word of a given index in a string. ! ! Discussion: ! ! A "word" is any string of nonblank characters, separated from other ! words by one or more blanks or TABS. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 January 2012 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be searched. ! ! integer IWORD, the index of the word to be ! searched for. If IWORD is positive, then the IWORD-th ! word is sought. If IWORD is zero or negative, then ! assuming that the string has N words in it, the ! N+IWORD-th word will be sought. ! ! Output: ! ! character ( len = * ) WORD, the IWORD-th word of the ! string, or ' ' if the WORD could not be found. ! ! integer NCHAR, the number of characters in WORD, ! or 0 if the word could not be found. ! implicit none integer i integer iblank integer ihi integer ilo integer iword integer jhi integer jlo integer jword integer kword integer nchar character ( len = * ) s integer s_len character, parameter :: TAB = achar ( 9 ) character ( len = * ) word ilo = 0 ihi = 0 s_len = len_trim ( s ) nchar = 0 word = '' if ( s_len <= 0 ) then return end if if ( 0 < iword ) then if ( s(1:1) == ' ' .or. s(1:1) == TAB ) then iblank = 1 jword = 0 jlo = 0 jhi = 0 else iblank = 0 jword = 1 jlo = 1 jhi = 1 end if i = 1 do i = i + 1 if ( s_len < i ) then if ( jword == iword ) then ilo = jlo ihi = s_len nchar = s_len + 1 - jlo word = s(ilo:ihi) else ilo = 0 ihi = 0 nchar = 0 word = ' ' end if return end if if ( ( s(i:i) == ' ' .or. s(i:i) == TAB ) .and. iblank == 0 ) then jhi = i - 1 iblank = 1 if ( jword == iword ) then ilo = jlo ihi = jhi nchar = jhi + 1 - jlo word = s(ilo:ihi) return end if else if ( s(i:i) /= ' ' .and. s(i:i) /= TAB .and. iblank == 1 ) then jlo = i jword = jword + 1 iblank = 0 end if end do else iblank = 0 kword = 1 - iword jword = 1 jlo = s_len jhi = s_len i = s_len do i = i - 1 if ( i <= 0 ) then if ( jword == kword ) then ilo = 1 ihi = jhi nchar = jhi word = s(ilo:ihi) else ilo = 0 ihi = 0 nchar = 0 word = ' ' end if return end if if ( ( s(i:i) == ' ' .or. s == TAB ) .and. iblank == 0 ) then jlo = i + 1 iblank = 1 if ( jword == kword ) then ilo = jlo ihi = jhi nchar = jhi + 1 - jlo word = s(ilo:ihi) return end if else if ( s(i:i) /= ' ' .and. s(i:i) /= TAB .and. iblank == 1 ) then jhi = i jword = jword + 1 iblank = 0 end if end do end if return end subroutine s_word_index ( s, indx, ilo, ihi ) !*****************************************************************************80 ! !! s_word_index() finds the word of a given index in a string. ! ! Discussion: ! ! The routine returns in ILO and IHI the beginning and end of the INDX-th ! word, or 0 and 0 if there is no INDX-th word. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S is the string of words to be analyzed. ! ! integer INDX is the index of the desired token. ! ! Output: ! ! integer ILO is the index of the first character ! of the INDX-th word, or 0 if there was no INDX-th word. ! ! integer IHI is the index of the last character ! of the INDX-th word, or 0 if there was no INDX-th word. ! implicit none integer i integer ihi integer ilo integer indx character ( len = * ) s ihi = 0 ilo = 0 do i = 1, indx call word_next ( s, ilo, ihi ) if ( ilo == 0 ) then return end if end do return end subroutine s_word_next ( s, word, done ) !*****************************************************************************80 ! !! s_word_next() "reads" words from a string, one at a time. ! ! Special cases: ! ! The following characters are considered to be a single word, ! whether surrounded by spaces or not: ! ! " ( ) { } [ ] ! ! Also, if there is a trailing comma on the word, it is stripped off. ! This is to facilitate the reading of lists. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 May 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string, presumably containing words ! separated by spaces. ! ! logical DONE: On input with a fresh string, set DONE to TRUE. ! ! Output: ! ! character ( len = * ) WORD. ! If DONE is FALSE, then WORD contains the "next" word read. ! If DONE is TRUE, then WORD is blank, because there was no more to read. ! ! logical DONE: output signal. ! FALSE if another word was read, ! TRUE if no more words could be read. ! implicit none logical done integer ilo integer, save :: next = 1 character ( len = * ) s integer, save :: s_length = 0 character, parameter :: TAB = achar ( 9 ) character ( len = * ) word ! ! We "remember" S_LENGTH and NEXT from the previous call. ! ! An input value of DONE = TRUE signals a new line of text to examine. ! if ( done ) then next = 1 done = .false. s_length = len_trim ( s ) if ( s_length <= 0 ) then done = .true. word = ' ' return end if end if ! ! Beginning at index NEXT, search the string for the next nonblank, ! which signals the beginning of a word. ! ilo = next ! ! ...S(NEXT:) is blank. Return with WORD = ' ' and DONE = TRUE. ! do if ( s_length < ilo ) then word = ' ' done = .true. next = s_length + 1 return end if ! ! If the current character is blank, skip to the next one. ! if ( s(ilo:ilo) /= ' ' .and. s(ilo:ilo) /= TAB ) then exit end if ilo = ilo + 1 end do ! ! ILO is the index of the next nonblank character in the string. ! ! If this initial nonblank is a special character, ! then that's the whole word as far as we're concerned, ! so return immediately. ! if ( s(ilo:ilo) == '"' .or. & s(ilo:ilo) == '(' .or. & s(ilo:ilo) == ')' .or. & s(ilo:ilo) == '{' .or. & s(ilo:ilo) == '}' .or. & s(ilo:ilo) == '[' .or. & s(ilo:ilo) == ']' ) then word = s(ilo:ilo) next = ilo + 1 return end if ! ! Now search for the last contiguous character that is not a ! blank, TAB, or special character. ! next = ilo + 1 do while ( next <= s_length ) if ( s(next:next) == ' ' ) then exit else if ( s(next:next) == TAB ) then exit else if ( s(next:next) == '"' ) then exit else if ( s(next:next) == '(' ) then exit else if ( s(next:next) == ')' ) then exit else if ( s(next:next) == '{' ) then exit else if ( s(next:next) == '}' ) then exit else if ( s(next:next) == '[' ) then exit else if ( s(next:next) == ']' ) then exit end if next = next + 1 end do ! ! Ignore a trailing comma. ! if ( s(next-1:next-1) == ',' ) then word = s(ilo:next-2) else word = s(ilo:next-1) end if return end subroutine s_word_permute ( s1, n, perm, s2 ) !*****************************************************************************80 ! !! s_word_permute() permutes the words in a string. ! ! Discussion: ! ! A word is a blank-delimited sequence of characters. ! ! The string is assumed to contain N "words". If more words are ! in the string, their position is not affected. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 January 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S1, a line of text. ! ! integer N, the number of words to permute. ! ! integer PERM(N), the permutation. PERM(1) is the new ! location of the item whose original location was 1. ! ! Output: ! ! character ( len = * ) S2, a copy of S1 with the ! first N words permuted. ! implicit none integer n character c1 character c2 integer index1 integer index2 integer perm(n) integer perm_inv(n) character ( len = * ) s1 integer s1_length integer s1_pos integer s1_word_index(n) integer s1_word_length(n) character ( len = * ) s2 integer s2_pos integer word_length ! ! Set up word position and length vectors. ! s1_length = len ( s1 ) s1_word_length(1:n) = 0 s1_word_index(1:n) = 0 index1 = 0 c2 = ' ' do s1_pos = 1, s1_length c1 = c2 c2 = s1(s1_pos:s1_pos) if ( s1_pos == 1 .or. ( c1 /= ' ' .and. c2 == ' ' ) ) then if ( n <= index1 ) then exit end if index1 = index1 + 1 s1_word_index(index1) = s1_pos end if s1_word_length(index1) = s1_word_length(index1) + 1 end do ! ! Invert the permutation. ! call perm_inverse3 ( n, perm, perm_inv ) ! ! Copy S1 into S2, so we get any trailing information. ! call s_copy ( s1, s2 ) ! ! Copy the first N words of S1 into S2 in permuted order. ! s2_pos = 1 do index2 = 1, n index1 = perm_inv(index2) s1_pos = s1_word_index(index1) word_length = s1_word_length(index1) s2(s2_pos:s2_pos+word_length-1) = s1(s1_pos:s1_pos+word_length-1) s2_pos = s2_pos + word_length end do return end function s32_to_i4 ( s32 ) !*****************************************************************************80 ! !! s32_to_i4() returns an I4 equivalent to a 32 character string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 32 ) S32, the character value. ! ! Output: ! ! integer S32_TO_I4, a corresponding I4. ! implicit none integer i integer intval character ( len = 32 ) s32 integer s32_to_i4 character ( len = 32 ) scopy scopy = s32 if ( scopy(1:1) == '1' ) then do i = 2, 32 if ( scopy(i:i) == '0' ) then scopy(i:i) = '1' else scopy(i:i) = '0' end if end do end if intval = 0 do i = 2, 32 intval = 2 * intval if ( scopy(i:i) == '1' ) then intval = intval + 1 end if end do if ( scopy(1:1) == '1' ) then intval = - intval end if s32_to_i4 = intval return end function s32_to_r4 ( s32 ) !*****************************************************************************80 ! !! s32_to_r4() converts a 32-character variable into an R4. ! ! Discussion: ! ! An "R4" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! The first bit is 1 for a negative real, or 0 for a ! positive real. Bits 2 through 9 are the exponent. Bits 10 ! through 32 are used for a normalized representation of the ! mantissa. Since it is assumed that normalization means the first ! digit of the mantissa is 1, this 1 is in fact not stored. ! ! The special case of 0 is represented by all 0 bits. ! ! It is believed that this method corresponds to the format used ! in VMS FORTRAN for reals. ! ! Because of the limits on the mantissa, many Cray numbers are not ! representable at all by this method. These numbers are very big ! or very small in magnitude. Other numbers will simply be ! represented with less accuracy. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = 32 ) S32, the character variable to be decoded. ! ! Output: ! ! real ( kind = rk ) RCHAR32, the corresponding real value. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer i integer iexp integer j integer mant character ( len = 32 ) s32 real ( kind = rk ) s32_to_r4 real ( kind = rk ) sgn ! ! Read sign bit. ! if ( s32(1:1) == '1' ) then sgn = -1.0E+00 else sgn = 1.0E+00 end if ! ! Construct exponent from bits 2 through 9, subtract 128. ! iexp = 0 do i = 2, 9 if ( s32(i:i) == '0' ) then j = 0 else j = 1 end if iexp = 2 * iexp + j end do if ( iexp == 0 ) then s32_to_r4 = 0.0E+00 return end if iexp = iexp - 128 ! ! Read mantissa from positions 10 through 32. ! Note that, unless exponent equals 0, the most significant bit is ! assumed to be 1 and hence is not stored. ! mant = 1 do i = 10, 32 mant = 2 * mant if ( s32(i:i) == '1' ) then mant = mant + 1 end if end do s32_to_r4 = sgn * mant * ( 2.0E+00 ** ( iexp - 23 ) ) return end subroutine sef_to_b4_ieee ( s, e, f, word ) !*****************************************************************************80 ! !! sef_to_b4_ieee() converts SEF information to a 4 byte IEEE real word. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer S, the sign bit: ! 0, if R is nonnegative; ! 1, if R is negative. ! ! integer E, the exponent, base 2. ! Normally, -127 < E <= 127. ! If E = 128, then the data is interpreted as NaN, Inf, or -Inf. ! If -127 < E <= 127, the data is a normalized value. ! If E < -127, then the data is a denormalized value. ! ! integer F, the mantissa. ! ! Output: ! ! integer WORD, the real number stored in IEEE format. ! implicit none integer e integer e2 integer f integer, parameter :: f_max = 2**24 integer, parameter :: f_min = 2**23 integer f2 integer s integer s2 integer word s2 = s e2 = e f2 = f ! ! Handle +Inf and -Inf. ! if ( f /= 0 .and. e == 128 ) then e2 = e2 + 127 f2 = 2**23 - 1 call mvbits ( s2, 0, 1, word, 31 ) call mvbits ( e2, 0, 8, word, 23 ) call mvbits ( f2, 0, 23, word, 0 ) return end if ! ! Handle NaN. ! if ( f == 0 .and. e == 128 ) then e2 = e2 + 127 f2 = 0 call mvbits ( s2, 0, 1, word, 31 ) call mvbits ( e2, 0, 8, word, 23 ) call mvbits ( f2, 0, 23, word, 0 ) return end if ! ! Handle +0 and -0. ! if ( f == 0 ) then e2 = 0 call mvbits ( s2, 0, 1, word, 31 ) call mvbits ( e2, 0, 8, word, 23 ) call mvbits ( f2, 0, 23, word, 0 ) return end if ! ! Normalize. ! if ( f < 0 ) then s2 = 1 - s2 f2 = -f2 end if e2 = e2 + 127 + 23 do while ( f_max <= f2 ) f2 = f2 / 2 e2 = e2 + 1 end do do while ( f2 < f_min ) f2 = f2 * 2 e2 = e2 - 1 end do ! ! The biased exponent cannot be negative. ! Shift it up to zero, and reduce F2. ! do while ( e2 < 0 .and. f2 /= 0 ) e2 = e2 + 1 f2 = f2 / 2 end do ! ! Normalized values drop the leading 1. ! if ( 0 < e2 ) then call mvbits ( s2, 0, 1, word, 31 ) call mvbits ( e2, 0, 8, word, 23 ) f2 = f2 - f_min call mvbits ( f2, 0, 23, word, 0 ) ! ! Denormalized values have a biased exponent of 0. ! else call mvbits ( s2, 0, 1, word, 31 ) call mvbits ( e2, 0, 8, word, 23 ) call mvbits ( f2, 0, 23, word, 0 ) end if return end subroutine sef_to_r4 ( s, e, f, r ) !*****************************************************************************80 ! !! sef_to_r4() converts SEF information to an R4 = S * 2.0**E * F. ! ! Discussion: ! ! An "R4" value is simply a real number to be stored as a ! variable of type "real ( kind = rk )". ! ! Assuming no arithmetic problems, in fact, this equality should be ! exact, that is, S, E and F should exactly express the value ! as stored on the computer. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 11 November 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer S, the sign bit: ! 0, if R is nonnegative; ! 1, if R is negative. ! ! integer E, the exponent, base 2. ! ! integer F, the mantissa. ! ! Output: ! ! real ( kind = rk ) R, the real number. ! implicit none integer, parameter :: rk = kind ( 1.0E+00 ) integer e integer f integer i real ( kind = rk ) r integer s if ( f == 0 ) then r = 0.0E+00 return end if if ( s == 0 ) then r = 1.0E+00 else if ( s == 1 ) then r = -1.0E+00 else write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'SEF_TO_R4 - Fatal error!' write ( *, '(a,i8)' ) ' Illegal input value of S = ', s stop 1 end if r = r * real ( f, kind = rk ) if ( 0 < e ) then do i = 1, e r = r * 2.0E+00 end do else if ( e < 0 ) then do i = 1, -e r = r / 2.0E+00 end do end if return end subroutine sort_heap_external ( n, indx, i, j, isgn ) !*****************************************************************************80 ! !! sort_heap_external() externally sorts a list of items into ascending order. ! ! Discussion: ! ! The actual list of data is not passed to the routine. Hence this ! routine may be used to sort integers, reals, numbers, names, ! dates, shoe sizes, and so on. After each call, the routine asks ! the user to compare or interchange two items, until a special ! return value signals that the sorting is completed. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 February 2004 ! ! Author: ! ! Original version by Albert Nijenhuis, Herbert Wilf. ! FORTRAN90 version by John Burkardt. ! ! Reference: ! ! Albert Nijenhuis, Herbert Wilf, ! Combinatorial Algorithms for Computers and Calculators, ! Academic Press, 1978, second edition, ! ISBN 0-12-519260-6, ! LC: QA164.N54. ! ! Input: ! ! integer N, the number of items to be sorted. ! ! integer INDX, the main communication signal. ! ! The user must set INDX to 0 before the first call. ! Thereafter, the user should not change the value of INDX until ! the sorting is done. ! ! integer ISGN, results of comparison of elements ! I and J. (Used only when the previous call returned INDX less than 0). ! ISGN <= 0 means I is less than or equal to J; ! 0 <= ISGN means I is greater than or equal to J. ! ! Output: ! ! integer INDX, the main communication signal. ! ! On return, if INDX is ! ! greater than 0, ! * interchange items I and J; ! * call again. ! ! less than 0, ! * compare items I and J; ! * set ISGN = -1 if I < J, ISGN = +1 if J < I; ! * call again. ! ! equal to 0, the sorting is done. ! ! integer I, J, the indices of two items. ! On return with INDX positive, elements I and J should be interchanged. ! On return with INDX negative, elements I and J should be compared, and ! the result reported in ISGN on the next call. ! implicit none integer i integer, save :: i_save = 0 integer indx integer isgn integer j integer, save :: j_save = 0 integer, save :: k = 0 integer, save :: k1 = 0 integer n integer, save :: n1 = 0 ! ! INDX = 0: This is the first call. ! if ( indx == 0 ) then i_save = 0 j_save = 0 k = n / 2 k1 = k n1 = n ! ! INDX < 0: The user is returning the results of a comparison. ! else if ( indx < 0 ) then if ( indx == -2 ) then if ( isgn < 0 ) then i_save = i_save + 1 end if j_save = k1 k1 = i_save indx = -1 i = i_save j = j_save return end if if ( 0 < isgn ) then indx = 2 i = i_save j = j_save return end if if ( k <= 1 ) then if ( n1 == 1 ) then i_save = 0 j_save = 0 indx = 0 else i_save = n1 n1 = n1 - 1 j_save = 1 indx = 1 end if i = i_save j = j_save return end if k = k - 1 k1 = k ! ! 0 < INDX, the user was asked to make an interchange. ! else if ( indx == 1 ) then k1 = k end if do i_save = 2 * k1 if ( i_save == n1 ) then j_save = k1 k1 = i_save indx = -1 i = i_save j = j_save return else if ( i_save <= n1 ) then j_save = i_save + 1 indx = -2 i = i_save j = j_save return end if if ( k <= 1 ) then exit end if k = k - 1 k1 = k end do if ( n1 == 1 ) then i_save = 0 j_save = 0 indx = 0 i = i_save j = j_save else i_save = n1 n1 = n1 - 1 j_save = 1 indx = 1 i = i_save j = j_save end if return end function state_id ( state ) !*****************************************************************************80 ! !! STATE_ID returns the 2 letter Postal Code for one of the 50 states. ! ! Discussion: ! ! The states are listed in order of their admission to the union. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 April 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer STATE, the index of a state. ! ! Output: ! ! character ( len = 2 ) STATE_ID, the 2 letter code. ! implicit none character ( len = 2 ), parameter, dimension ( 50 ) :: id = (/ & 'DE', 'PA', 'NJ', 'GA', 'CT', & 'MA', 'MD', 'SC', 'NH', 'VA', & 'NY', 'NC', 'RI', 'VT', 'KY', & 'TN', 'OH', 'LA', 'IN', 'MS', & 'IL', 'AL', 'ME', 'MO', 'AR', & 'MI', 'FL', 'TX', 'IA', 'WI', & 'CA', 'MN', 'OR', 'KS', 'WV', & 'NV', 'NE', 'CO', 'ND', 'SD', & 'MT', 'WA', 'ID', 'WY', 'UT', & 'OK', 'NM', 'AZ', 'AL', 'HI' /) integer state character ( len = 2 ) state_id if ( state < 1 ) then state_id = '??' else if ( state <= 50 ) then state_id = id(state) else state_id = '??' end if return end function state_name ( state ) !*****************************************************************************80 ! !! STATE_NAME returns the name of one of the 50 states. ! ! Discussion: ! ! The states are listed in order of their admission to the union. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 April 2007 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer STATE, the index of a state. ! ! Output: ! ! character ( len = 14 ) STATE_NAME, the name of the state. ! implicit none character ( len = 14 ), parameter, dimension ( 50 ) :: name = (/ & 'Delaware ', & 'Pennsylvania ', & 'New Jersey ', & 'Georgia ', & 'Connecticut ', & 'Massachusetts ', & 'Maryland ', & 'South Carolina', & 'New Hampshire ', & 'Virginia ', & 'New York ', & 'North Carolina', & 'Rhode Island ', & 'Vermont ', & 'Kentucky ', & 'Tennessee ', & 'Ohio ', & 'Louisiana ', & 'Indiana ', & 'Missippi ', & 'Illinois ', & 'Alabama ', & 'Maine ', & 'Missouri ', & 'Arkansas ', & 'Michigan ', & 'Florida ', & 'Texas ', & 'Iowa ', & 'Wisconsin ', & 'California ', & 'Minnesota ', & 'Oregon ', & 'Kansas ', & 'West Virginia ', & 'Nevada ', & 'Nebraska ', & 'Colorado ', & 'North Dakota ', & 'South Dakota ', & 'Montana ', & 'Washington ', & 'Idaho ', & 'Wyoming ', & 'Utah ', & 'Oklahoma ', & 'New Mexico ', & 'Arizona ', & 'Alaska ', & 'Hawaii ' /) integer state character ( len = 14 ) state_name if ( state < 1 ) then state_name = '??????????????' else if ( state <= 50 ) then state_name = name(state) else state_name = '??????????????' end if return end subroutine svec_lab ( n, nuniq, svec, ident ) !*****************************************************************************80 ! !! SVEC_LAB makes an index array for an array of (repeated) strings. ! ! Discussion: ! ! The routine is given an array of strings. It assigns an integer ! to each unique string, and returns an equivalent array of ! these values. ! ! Note that blank strings are treated specially. Any blank ! string gets an identifier of 0. Blank strings are not ! counted in the value of NUNIQ. ! ! Example: ! ! SVEC IDENT ! ! ALPHA 1 ! ALPHA -1 ! BETA 2 ! ALPHA -1 ! BETA -2 ! GAMMA 3 ! ALPHA -1 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 19 February 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries. ! ! character ( len = * ) SVEC(N), the list of strings. ! ! Output: ! ! integer NUNIQ, the number of unique nonblank entries. ! ! integer IDENT(N), the identifiers assigned to the ! strings. If SVEC(I) is blank, then IDENT(I) is 0. ! Otherwise, if SVEC(I) is the first occurrence of a ! given string, then it is assigned a positive identifier. ! If SVEC(I) is a later occurrence of a string, then ! it is assigned a negative identifier, whose absolute ! value is the identifier of the first occurrence. ! implicit none integer n integer i integer ident(n) integer j integer match integer nuniq character ( len = * ) svec(n) nuniq = 0 do i = 1, n if ( svec(i) == ' ' ) then ident(i) = 0 else match = 0 do j = 1, i-1 if ( 0 < ident(j) ) then if ( svec(j) == svec(i) ) then ident(i) = -ident(j) match = j exit end if end if end do if ( match == 0 ) then nuniq = nuniq + 1 ident(i) = nuniq end if end if end do return end subroutine svec_merge_a ( na, a, nb, b, nc, c ) !*****************************************************************************80 ! !! SVEC_MERGE_A merges two ascending sorted string arrays. ! ! Discussion: ! ! The elements of A and B should be sorted in ascending order. ! ! The elements in the array C will be in ascending order, and unique. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 17 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer NA, the dimension of A. ! ! character ( len = * ) A(NA), the first sorted array. ! ! integer NB, the dimension of B. ! ! character ( len = * ) B(NB), the second sorted array. ! ! Output: ! ! integer NC, the number of elements in the array C ! array. Note that C should usually be dimensioned at least NA+NB in the ! calling routine. ! ! character ( len = * ) C(NC), the merged unique sorted array. ! implicit none integer na integer nb character ( len = * ) a(na) character ( len = * ) b(nb) character ( len = * ) c(na+nb) integer j integer ja integer jb integer na2 integer nb2 integer nc na2 = na nb2 = nb ja = 0 jb = 0 nc = 0 do ! ! If we've used up all the entries of A, stick the rest of B on the end. ! if ( na2 <= ja ) then do j = 1, nb2 - jb jb = jb + 1 if ( nc == 0 ) then nc = nc + 1 c(nc) = b(jb) else if ( llt ( c(nc), b(jb) ) ) then nc = nc + 1 c(nc) = b(jb) end if end do exit ! ! If we've used up all the entries of B, stick the rest of A on the end. ! else if ( nb2 <= jb ) then do j = 1, na2 - ja ja = ja + 1 if ( nc == 0 ) then nc = nc + 1 c(nc) = a(ja) else if ( llt ( c(nc), a(ja) ) ) then nc = nc + 1 c(nc) = a(ja) end if end do exit ! ! Otherwise, if the next entry of A is smaller, that's our candidate. ! else if ( lle ( a(ja+1), b(jb+1) ) ) then ja = ja + 1 if ( nc == 0 ) then nc = nc + 1 c(nc) = a(ja) else if ( llt ( c(nc), a(ja) ) ) then nc = nc + 1 c(nc) = a(ja) end if ! ! ...or if the next entry of B is the smaller, consider that. ! else jb = jb + 1 if ( nc == 0 ) then nc = nc + 1 c(nc) = b(jb) else if ( llt ( c(nc), b(jb) ) ) then nc = nc + 1 c(nc) = b(jb) end if end if end do return end subroutine svec_permute ( n, a, p ) !*****************************************************************************80 ! !! SVEC_PERMUTE permutes a string vector in place. ! ! Example: ! ! Input: ! ! N = 5 ! P = ( 3, 2, 4, 2, 1 ) ! A = ( 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE' ) ! ! Results: ! ! A = ( 'FIVE', 'FOUR', 'ONE', 'THREE', 'TWO' ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 20 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of objects. ! ! character ( len = * ) A(N), the array to be permuted. ! ! integer P(N), the permutation. P(I) = J means ! that the I-th element of the array should be the J-th ! element of the input array. P must be a legal permutation ! of the integers from 1 to N, otherwise the algorithm will ! fail catastrophically. ! ! Output: ! ! character ( len = * ) A(N), the permuted array. ! implicit none integer n character ( len = * ) a(n) character ( len = 255 ) a_temp integer ierror integer iget integer iput integer istart integer p(n) call perm_check ( n, p, ierror ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'SVEC_PERMUTE - Fatal error!' write ( *, '(a)' ) ' The input array does not represent' write ( *, '(a)' ) ' a proper permutation. In particular, the' write ( *, '(a,i8)' ) ' array is missing the value ', ierror stop 1 end if ! ! Search for the next element of the permutation that has not been used. ! do istart = 1, n if ( p(istart) < 0 ) then cycle else if ( p(istart) == istart ) then p(istart) = -p(istart) cycle else a_temp = a(istart) iget = istart ! ! Copy the new value into the vacated entry. ! do iput = iget iget = p(iget) p(iput) = -p(iput) if ( iget < 1 .or. n < iget ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'SVEC_PERMUTE - Fatal error!' write ( *, '(a)' ) ' A permutation index is out of range.' write ( *, '(a,i8,a,i8)' ) ' P(', iput, ') = ', iget stop 1 end if if ( iget == istart ) then a(iput) = a_temp exit end if a(iput) = a(iget) end do end if end do ! ! Restore the signs of the entries. ! p(1:n) = -p(1:n) return end subroutine svec_reverse ( n, a ) !*****************************************************************************80 ! !! SVEC_REVERSE reverses the elements of a string vector. ! ! Example: ! ! Input: ! ! N = 4, ! A = ( 'Bob', 'Carol', 'Ted', 'Alice' ). ! ! Results: ! ! A = ( 'Alice', 'Ted', 'Carol', 'Bob' ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in the array. ! ! character ( len = * ) A(N), the array to be reversed. ! ! Output: ! ! character ( len = * ) A(N): the transformed array. ! implicit none integer n character ( len = * ) a(n) character ( len = 255 ) a_temp integer i do i = 1, n / 2 a_temp = a(i) a(i) = a(n+1-i) a(n+1-i) = a_temp end do return end subroutine svec_search_binary_a ( n, a, b, indx ) !*****************************************************************************80 ! !! SVEC_SEARCH_BINARY_A searches an ascending sorted string vector. ! ! Discussion: ! ! Binary search is used. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 July 2000 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Donald Kreher, Douglas Simpson, ! Algorithm 1.9, ! Combinatorial Algorithms, ! CRC Press, 1998, page 26. ! ! Input: ! ! integer N, the number of elements in the vector. ! ! character ( len = * ) A(N), the array to be searched. A must ! be sorted in increasing order. ! ! character ( len = * ) B, the value to be searched for. ! ! Output: ! ! integer INDX, the result of the search. ! 0, B does not occur in A. ! I, A(I) = B. ! implicit none integer n character ( len = * ) a(n) character ( len = * ) b integer high integer indx integer low integer mid indx = 0 low = 1 high = n do while ( low <= high ) mid = ( low + high ) / 2 if ( a(mid) == b ) then indx = mid exit else if ( llt ( a(mid), b ) ) then low = mid + 1 else if ( lgt ( a(mid), b ) ) then high = mid - 1 end if end do return end subroutine svec_sort_heap_a ( n, a ) !*****************************************************************************80 ! !! SVEC_SORT_HEAP_A ascending sorts an SVEC using heap sort. ! ! Discussion: ! ! The ASCII collating sequence is used. This means ! A < B < C < .... < Y < Z < a < b < .... < z. ! Numbers and other symbols may also occur, and will be sorted according to ! the ASCII ordering. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of strings ! ! character ( len = * ) A(N): an array of strings to be sorted. ! ! Output: ! ! character ( len = * ) A(N): the transformed array. ! implicit none integer n character ( len = * ) a(n) integer i integer indx integer isgn integer j ! ! Do the sorting using the external heap sort routine. ! i = 0 indx = 0 isgn = 0 j = 0 do call sort_heap_external ( n, indx, i, j, isgn ) if ( 0 < indx ) then call s_swap ( a(i), a(j) ) else if ( indx < 0 ) then if ( lle ( a(i), a(j) ) ) then isgn = -1 else isgn = +1 end if else if ( indx == 0 ) then exit end if end do return end subroutine svec_sort_heap_a_index ( n, sarray, indx ) !*****************************************************************************80 ! !! SVEC_SORT_HEAP_A_INDEX: case-sensitive indexed heap sort of an SVEC. ! ! Discussion: ! ! The sorting is not actually carried out. ! Rather an index array is created which defines the sorting. ! This array may be used to sort or index the array, or to sort or ! index related arrays keyed on the original array. ! ! The ASCII collating sequence is used, and case is significant. ! This means ! ! A < B < C < .... < Y < Z < a < b < .... < z. ! ! Numbers and other symbols may also occur, and will be sorted according to ! the ASCII ordering. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 27 July 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in SARRAY. ! ! character ( len = * ) SARRAY(N), an array to be sorted. ! ! Output: ! ! integer INDX(N), contains the sort index. The ! I-th element of the sorted array is SARRAY ( INDX(I) ). ! implicit none integer n integer i integer indx(n) integer indxt integer ir integer j integer l character ( len = * ) sarray(n) character ( len = 255 ) string do i = 1, n indx(i) = i end do l = n / 2 + 1 ir = n do if ( 1 < l ) then l = l - 1 indxt = indx(l) string = sarray(indxt) else indxt = indx(ir) string = sarray(indxt) indx(ir) = indx(1) ir = ir - 1 if ( ir == 1 ) then indx(1) = indxt return end if end if i = l j = l + l do while ( j <= ir ) if ( j < ir ) then if ( llt ( sarray ( indx(j) ), sarray ( indx(j+1) ) ) ) then j = j + 1 end if end if if ( llt ( string, sarray ( indx(j) ) ) ) then indx(i) = indx(j) i = j j = j + j else j = ir + 1 end if end do indx(i) = indxt end do return end subroutine svec_sorted_unique ( n, a, unique_num ) !*****************************************************************************80 ! !! SVEC_SORTED_UNIQUE: number of unique entries in a sorted SVEC. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 09 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of elements in the array. ! ! character ( len = * ) A(N): the sorted list of strings. ! ! Output: ! ! character ( len = * ) A(N): the unique elements, in sorted order. ! ! integer UNIQUE_NUM, the number of unique elements ! in the array. ! implicit none integer n character ( len = * ) a(n) integer itest integer unique_num if ( n <= 0 ) then unique_num = 0 return end if unique_num = 1 do itest = 2, n if ( a(itest) /= a(unique_num) ) then unique_num = unique_num + 1 a(unique_num) = a(itest) end if end do return end subroutine sveci_search_binary_a ( n, a, b, indx ) !*****************************************************************************80 ! !! SVECI_SEARCH_BINARY_A: search ascending sorted implicitly capitalized SVEC ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 July 2000 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Donald Kreher, Douglas Simpson, ! Algorithm 1.9, ! Combinatorial Algorithms, ! CRC Press, 1998, page 26. ! ! Input: ! ! integer N, the number of elements in the vector. ! ! character ( len = * ) A(N), the array to be searched. A must ! be sorted in increasing order. ! ! character ( len = * ) B, the value to be searched for. ! ! Output: ! ! integer INDX, the result of the search. ! 0, B does not occur in A. ! I, A(I) = B, ignoring capitalization. ! implicit none integer n character ( len = * ) a(n) character ( len = * ) b integer high integer indx integer low integer mid logical s_eqi logical s_gti logical s_lti indx = 0 low = 1 high = n do while ( low <= high ) mid = ( low + high ) / 2 if ( s_eqi ( a(mid), b ) ) then indx = mid exit else if ( s_lti ( a(mid), b ) ) then low = mid + 1 else if ( s_gti ( a(mid), b ) ) then high = mid - 1 end if end do return end subroutine sveci_sort_heap_a ( n, sarray ) !*****************************************************************************80 ! !! SVECI_SORT_HEAP_A heap sorts an SVEC of implicitly capitalized strings. ! ! Discussion: ! ! The characters in an implicitly capitalized string are treated as ! though they had been capitalized. Thus, the letters 'a' and 'A' ! are considered equal, both 'a' and 'A' precede 'B', and ! 'Fox' and 'fOx' are considered equal. ! ! The ASCII collating sequence is used, except that all ! alphabetic characters are treated as though they were uppercase. ! ! This means ! ! A = a < B = b < C = c < .... < Y = y < Z = z. ! ! Numbers and other symbols may also occur, and will be sorted ! according to the ASCII ordering. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 28 July 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in SARRAY. ! ! character ( len = * ) SARRAY(N), the array to be sorted. ! ! Output: ! ! character ( len = * ) SARRAY(N): the sorted array. ! implicit none integer n integer l integer l1 integer m integer n1 logical s_gei logical s_lti character ( len = * ) sarray(n) character ( len = 255 ) s n1 = n l = n / 2 s = sarray(l) l1 = l do m = 2 * l1 if ( m <= n1 ) then if ( m < n1 ) then if ( s_gei ( sarray(m+1), sarray(m) ) ) then m = m + 1 end if end if if ( s_lti ( s, sarray(m) ) ) then sarray(l1) = sarray(m) l1 = m cycle end if end if sarray(l1) = s if ( 1 < l ) then l = l - 1 s = sarray(l) l1 = l cycle end if if ( n1 < 2 ) then exit end if s = sarray(n1) sarray(n1) = sarray(1) n1 = n1 - 1 l1 = l end do return end subroutine sveci_sort_heap_a_index ( n, sarray, indx ) !*****************************************************************************80 ! !! SVECI_SORT_HEAP_A_INDEX index heap sorts an SVECI. ! ! Discussion: ! ! The sorting is not actually carried out, ! but rather an index vector is returned, which defines the ! sorting. This index vector may be used to sort the array, or ! to sort related arrays keyed on the first one. ! ! The ASCII collating sequence is used, except that all ! alphabetic characters are treated as though they were uppercase. ! ! This means ! ! A = a < B = b < C = c < .... < Y = y < Z = z. ! ! Numbers and other symbols may also occur, and will be sorted according to ! the ASCII ordering. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 16 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the number of entries in SARRAY. ! ! character ( len = * ) SARRAY(N), an array to be sorted. ! ! Output: ! ! integer INDX(N), contains the sort index. The ! I-th element of the sorted array is SARRAY ( INDX(I) ). ! implicit none integer n integer i integer indx(n) integer indxt integer ir integer j integer l logical s_lti character ( len = * ) sarray(n) character ( len = 255 ) s do i = 1, n indx(i) = i end do l = n / 2 + 1 ir = n do if ( 1 < l ) then l = l - 1 indxt = indx(l) s = sarray(indxt) else indxt = indx(ir) s = sarray(indxt) indx(ir) = indx(1) ir = ir - 1 if ( ir == 1 ) then indx(1) = indxt return end if end if i = l j = l + l do while ( j <= ir ) if ( j < ir ) then if ( s_lti ( sarray ( indx(j) ), sarray ( indx(j+1) ) ) ) then j = j + 1 end if end if if ( s_lti ( s, sarray ( indx(j) ) ) ) then indx(i) = indx(j) i = j j = j + j else j = ir + 1 end if end do indx(i) = indxt end do return end subroutine sym_to_ch ( sym, c, ihi ) !*****************************************************************************80 ! !! SYM_TO_CH returns the character represented by a symbol. ! ! Discussion: ! ! Instead of ICHAR, we now use the IACHAR function, which ! guarantees the ASCII collating sequence. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) SYM is a string containing printable symbols. ! ! Output: ! ! character C, is the ASCII character represented by the ! first symbol in SYM. ! ! integer IHI, C is represented by SYM(1:IHI). ! IHI = 0 if there was a problem. ! implicit none character c integer ialt integer ichr integer ictl integer ihi logical s_eqi character ( len = * ) sym integer sym_length c = ' ' sym_length = len_trim ( sym ) if ( sym_length <= 0 ) then c = ' ' ihi = 0 return end if ialt = 0 ictl = 0 ihi = 1 ! ! Could it be an ALT character? ! if ( sym(ihi:ihi) == '!' .and. ihi < sym_length ) then ialt = 1 ihi = ihi + 1 end if ! ! Could it be a control character? ! if ( sym(ihi:ihi) == '^' .and. ihi < sym_length ) then ictl = 1 ihi = ihi + 1 end if ! ! Could it be a DEL character? ! ichr = iachar ( sym(ihi:ihi) ) if ( ihi+2 <= sym_length ) then if ( s_eqi ( sym(ihi:ihi+2), 'DEL' ) ) then ichr = 127 ihi = ihi + 2 end if end if ! ! Could it be an SP character? ! if ( ihi + 1 <= sym_length ) then if ( s_eqi ( sym(ihi:ihi+1), 'SP' ) ) then ichr = 32 ihi = ihi + 1 end if end if ! ! Interpret the character. ! if ( ialt == 1 ) then ichr = ichr + 128 end if if ( ictl == 1 ) then ichr = ichr - 64 end if c = achar ( ichr ) return end subroutine timestamp ( ) !*****************************************************************************80 ! !! TIMESTAMP prints the current YMDHMS date as a time stamp. ! ! Example: ! ! 31 May 2001 9:45:54.872 AM ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 May 2013 ! ! Author: ! ! John Burkardt ! ! Input: ! ! None ! implicit none character ( len = 8 ) ampm integer d integer h integer m integer mm character ( len = 9 ), parameter, dimension(12) :: month = (/ & 'January ', 'February ', 'March ', 'April ', & 'May ', 'June ', 'July ', 'August ', & 'September', 'October ', 'November ', 'December ' /) integer n integer s integer values(8) integer y call date_and_time ( values = values ) y = values(1) m = values(2) d = values(3) h = values(5) n = values(6) s = values(7) mm = values(8) if ( h < 12 ) then ampm = 'AM' else if ( h == 12 ) then if ( n == 0 .and. s == 0 ) then ampm = 'Noon' else ampm = 'PM' end if else h = h - 12 if ( h < 12 ) then ampm = 'PM' else if ( h == 12 ) then if ( n == 0 .and. s == 0 ) then ampm = 'Midnight' else ampm = 'AM' end if end if end if write ( *, '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' ) & d, trim ( month(m) ), y, h, ':', n, ':', s, '.', mm, trim ( ampm ) return end subroutine token_expand ( s, tokens ) !*****************************************************************************80 ! !! TOKEN_EXPAND makes sure certain tokens have spaces surrounding them. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 July 1998 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string to be examined. ! ! character ( len = * ) TOKENS, a string of characters. Every ! occurrence of a character from TOKENS in S must be ! preceded and followed by a blank space, except if the occurrence ! is in the first or last positions of S, in which a ! preceding or trailing blank space is implicit. ! ! Output: ! ! character ( len = * ) S: the transformed string. ! implicit none character c1 character c2 character c3 integer i integer put integer j integer lenc integer lent character ( len = * ) s character ( len = 255 ) s2 character ( len = * ) tokens lenc = len_trim ( s ) lent = len_trim ( tokens ) s2 = ' ' put = 0 c2 = ' ' c3 = s(1:1) do i = 1, lenc c1 = c2 c2 = c3 if ( i < lenc ) then c3 = s(i+1:i+1) else c3 = ' ' end if do j = 1, lent if ( c2 == tokens(j:j) ) then if ( c1 /= ' ' ) then put = put + 1 if ( put <= 255 ) then s2(put:put) = ' ' end if end if end if end do put = put + 1 if ( put <= 255 ) then s2(put:put) = c2 end if do j = 1, lent if ( c2 == tokens(j:j) ) then if ( c3 /= ' ' ) then put = put + 1 if ( put <= 255 ) then s2(put:put) = ' ' end if end if end if end do end do s = s2 return end subroutine token_extract ( s, token_num, token, match ) !*****************************************************************************80 ! !! TOKEN_EXTRACT "extracts" a token from the beginning of a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 November 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S; a string from ! whose beginning a token is to be extracted. ! ! integer TOKEN_NUM, the number of tokens to be ! compared. ! ! character ( len = * ) TOKEN(TOKEN_NUM), the tokens. ! ! Output: ! ! character ( len = * ) S: the string after token removal. ! ! integer MATCH, the index of the (longest) token ! that matched the string, or 0 if no match was found. ! implicit none integer token_num integer left integer match character ( len = * ) s character ( len = * ) token(token_num) call s_token_match ( s, token_num, token, match ) if ( match /= 0 ) then left = len_trim ( token(match) ) call s_shift_left ( s, left ) end if return end subroutine token_index ( s, indx, ilo, ihi ) !*****************************************************************************80 ! !! TOKEN_INDEX finds the N-th FORTRAN variable name in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S is the string of words to be analyzed. ! ! integer INDX is the index of the desired token. ! ! Output: ! ! integer ILO is the index of the first character ! of the INDX-th token, or 0 if there was no INDX-th token. ! ! integer IHI is the index of the last character ! of the INDX-th token, or 0 if there was no INDX-th token. ! implicit none integer i integer ihi integer ilo integer indx character ( len = * ) s ihi = 0 ilo = 0 do i = 1, indx call token_next ( s, ilo, ihi) if ( ilo == 0 ) then return end if end do return end subroutine token_next ( s, ilo, ihi ) !*****************************************************************************80 ! !! TOKEN_NEXT finds the next FORTRAN variable name in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 June 2000 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S is the string of words to be analyzed. ! ! integer IHI: be the LAST character of the ! PREVIOUS word, or 0 if the first word is sought. ! ! Output: ! ! integer ILO is the location of the first character ! of the next word, or 0 if there was no next word. ! ! integer IHI: the index of the last character of ! the next word, or 0 if there was no next word. ! implicit none integer ihi integer ilo character ( len = * ) s integer s_len logical s_only_alphab logical s_only_digitb s_len = len_trim ( s ) ilo = ihi if ( ilo < 0 ) then ilo = 0 end if ! ! Find ILO, the index of the next alphabetic character. ! do ilo = ilo + 1 if ( s_len < ilo ) then ilo = 0 ihi = 0 return end if if ( s_only_alphab ( s(ilo:ilo) ) ) then exit end if end do ! ! Find the index of the next character which is neither ! alphabetic nor numeric. ! ihi = ilo do ihi = ihi + 1 if ( s_len < ihi ) then ihi = s_len return end if if ( .not. ( s_only_alphab ( s(ihi:ihi) ) ) .and. & .not. ( s_only_digitb ( s(ihi:ihi) ) ) ) then exit end if end do ihi = ihi - 1 return end subroutine word_bounds ( line, word_num, word_start, word_end ) !*****************************************************************************80 ! !! WORD_BOUNDS returns the start and end of each word in a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 October 2003 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) LINE, a string containing words ! separated by spaces. ! ! integer WORD_NUM, the number of words in the line. ! ! Output: ! ! integer WORD_START(WORD_NUM), WORD_END(WORD_NUM), ! the locations in LINE of the beginning and end of each word. ! implicit none integer word_num logical blank character c logical, parameter :: debug = .true. integer i character ( len = * ) line integer line_len integer w integer word_end(word_num) integer word_start(word_num) i = 0 w = 0 blank = .true. line_len = len_trim ( line ) do i = 1, line_len + 1 if ( i <= line_len ) then c = line(i:i) else c = ' ' end if if ( c == ' ' ) then if ( .not. blank ) then word_end(w) = i-1 if ( w == word_num ) then exit end if end if blank = .true. else if ( blank ) then w = w + 1 word_start(w) = i end if blank = .false. end if end do if ( w /= word_num ) then if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'WORD_BOUNDS - Warning:' write ( *, '(a)' ) ' Found fewer words than requested.' end if end if return end subroutine word_last_read ( s, word ) !*****************************************************************************80 ! !! WORD_LAST_READ returns the last word from a string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 April 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string containing words separated ! by spaces. ! ! Output: ! ! character ( len = * ) WORD, the last word. ! implicit none integer first integer last character ( len = * ) s character ( len = * ) word last = len_trim ( s ) if ( last <= 0 ) then word = ' ' return end if first = last do if ( first <= 1 ) then exit end if if ( s(first-1:first-1) == ' ' ) then exit end if first = first - 1 end do word = s(first:last) return end subroutine word_next ( s, ilo, ihi ) !*****************************************************************************80 ! !! WORD_NEXT finds the next (blank separated) word in a string. ! ! Discussion: ! ! This routine is usually used repetitively on a fixed string. On each ! call, it accepts IHI, the index of the last character of the ! previous word extracted from the string. ! ! It then computes ILO and IHI, the first and last characters of ! the next word in the string. ! ! It is assumed that words are separated by one or more spaces. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 April 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string of words to be analyzed. ! ! integer IHI: the LAST character of the ! PREVIOUS word, or 0 if the first word is sought. ! ! Output: ! ! character ( len = * ) S, the transformed string. ! ! integer ILO is the location of the first character ! of the next word, or 0 if there was no next word. ! ! integer IHI: the index of the last character of ! the next word, or 0 if there was no next word. ! implicit none integer ihi integer ilo character ( len = * ) s integer s_len s_len = len_trim ( s ) ! ! Find ILO, the index of the first nonblank character after ! (the old value of) IHI. ! if ( ihi < 0 ) then ilo = 0 else ilo = ihi end if do ilo = ilo + 1 if ( s_len < ilo ) then ilo = 0 ihi = 0 return end if if ( s(ilo:ilo) /= ' ') then exit end if end do ! ! Find IHI, the index of the next blank character, or end of line. ! ihi = ilo do ihi = ihi + 1 if ( s_len <= ihi ) then ihi = s_len return end if if ( s(ihi:ihi) == ' ' ) then exit end if end do ! ! Decrement IHI to point to the previous, nonblank, character. ! ihi = ihi - 1 return end subroutine word_next_read ( s, word, done ) !*****************************************************************************80 ! !! WORD_NEXT_READ "reads" words from a string, one at a time. ! ! Discussion: ! ! This routine was written to process tokens in a file. ! A token is considered to be an alphanumeric string delimited ! by whitespace, or any of various "brackets". ! ! The following characters are considered to be a single word, ! whether surrounded by spaces or not: ! ! " ( ) { } [ ] ! ! Also, if there is a trailing comma on the word, it is stripped off. ! This is to facilitate the reading of lists. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 May 2001 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string, presumably containing words ! separated by spaces. ! ! logical DONE: On input with a fresh string, set DONE to TRUE. ! ! Output: ! ! character ( len = * ) WORD. ! If DONE is FALSE, then WORD contains the "next" word read. ! If DONE is TRUE, then WORD is blank, because there was no more to read. ! ! logical DONE: ! FALSE if another word was read, ! TRUE if no more words could be read. ! implicit none logical done integer ilo integer, save :: lenc = 0 integer, save :: next = 1 character ( len = * ) s character, parameter :: TAB = achar ( 9 ) character ( len = * ) word ! ! We "remember" LENC and NEXT from the previous call. ! ! An input value of DONE = TRUE signals a new line of text to examine. ! if ( done ) then next = 1 done = .false. lenc = len_trim ( s ) if ( lenc <= 0 ) then done = .true. word = ' ' return end if end if ! ! Beginning at index NEXT, search the string for the next nonblank, ! which signals the beginning of a word. ! ilo = next ! ! ...S(NEXT:) is blank. Return with WORD = ' ' and DONE = TRUE. ! do if ( lenc < ilo ) then word = ' ' done = .true. next = lenc + 1 return end if ! ! If the current character is blank, skip to the next one. ! if ( s(ilo:ilo) /= ' ' .and. s(ilo:ilo) /= TAB ) then exit end if ilo = ilo + 1 end do ! ! ILO is the index of the next nonblank character in the string. ! ! If this initial nonblank is a special character, ! then that's the whole word as far as we're concerned, ! so return immediately. ! if ( s(ilo:ilo) == '"' .or. & s(ilo:ilo) == '(' .or. & s(ilo:ilo) == ')' .or. & s(ilo:ilo) == '{' .or. & s(ilo:ilo) == '}' .or. & s(ilo:ilo) == '[' .or. & s(ilo:ilo) == ']' ) then word = s(ilo:ilo) next = ilo + 1 return end if ! ! Now search for the last contiguous character that is not a ! blank, TAB, or special character. ! next = ilo + 1 do while ( next <= lenc ) if ( s(next:next) == ' ' ) then exit else if ( s(next:next) == TAB ) then exit else if ( s(next:next) == '"' ) then exit else if ( s(next:next) == '(' ) then exit else if ( s(next:next) == ')' ) then exit else if ( s(next:next) == '{' ) then exit else if ( s(next:next) == '}' ) then exit else if ( s(next:next) == '[' ) then exit else if ( s(next:next) == ']' ) then exit end if next = next + 1 end do if ( s(next-1:next-1) == ',' ) then word = s(ilo:next-2) else word = s(ilo:next-1) end if return end subroutine word_next2 ( s, first, last ) !*****************************************************************************80 ! !! WORD_NEXT2 returns the first word in a string. ! ! Discussion: ! ! "Words" are any string of characters, separated by commas or blanks. ! ! The routine returns: ! * FIRST, the first string of nonblank, noncomma characters; ! * LAST, the characters of the string that occur after FIRST and ! the commas and blanks. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, the string of words to be analyzed. ! ! Output: ! ! character ( len = * ) FIRST, the next word in the string. ! ! character ( len = * ) LAST, the remaining string. ! implicit none character c character ( len = * ) first integer i integer ido integer ifirst integer ilast character ( len = * ) last integer lenf integer lenl integer lens character ( len = * ) s first = ' ' last = ' ' ifirst = 0 ilast = 0 lens = len_trim ( s ) lenf = len ( first ) lenl = len ( last ) ido = 0 do i = 1, lens c = s(i:i) if ( ido == 0 ) then if ( c /= ' ' .and. c /= ',' ) then ido = 1 end if end if if ( ido == 1 ) then if ( c /= ' ' .and. c /= ',' ) then ifirst = ifirst + 1 if ( ifirst <= lenf ) then first(ifirst:ifirst) = c end if else ido = 2 end if end if if ( ido == 2 ) then if ( c /= ' ' .and. c /= ',' ) then ido = 3 end if end if if ( ido == 3 ) then ilast = ilast + 1 if ( ilast <= lenl ) then last(ilast:ilast) = c end if end if end do return end subroutine word_swap ( s, i1, i2 ) !*****************************************************************************80 ! !! WORD_SWAP swaps two words in a given string. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) S, a string, in which some words are to be swapped. ! "Words" in the string are presumed to be separated by blanks. ! ! integer I1, I2, the indices of the words to be swapped. ! If either I1 or I2 is nonpositive, or greater than the number of ! words in the string, then nothing is done to the string. Otherwise, ! words I1 and I2 are swapped. ! ! Output: ! ! character ( len = * ) S, the string after swapping. ! implicit none logical blank integer i integer i1 integer i2 integer j1 integer j1beg integer j1end integer j2 integer j2beg integer j2end integer lens character ( len = * ) s character ( len = 255 ) s2 integer word_num lens = len_trim ( s ) if ( lens <= 0 ) then return end if if ( 80 < lens ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'WORD_SWAP - Warning!' write ( *, '(a)' ) ' The internal temporary string is too short' write ( *, '(a)' ) ' to copy your string. Errors may result!' stop 1 end if ! ! We need to make a copy of the input arguments, because we ! might alter them. We want to ensure that J1 <= J2. ! j1 = min ( i1, i2) j2 = max ( i1, i2) if ( j1 <= 0 ) then return else if ( j2 <= 0 ) then return else if ( j1 == j2 ) then return end if j1beg = 0 j1end = 0 j2beg = 0 j2end = 0 word_num = 0 blank = .true. do i = 1, lens if ( s(i:i) == ' ' ) then if ( j1beg /= 0 .and. j1end == 0 ) then j1end = i - 1 else if ( j2beg /= 0 .and. j2end == 0 ) then j2end = i - 1 end if blank = .true. else if ( blank ) then word_num = word_num + 1 if ( word_num == j1 ) then j1beg = i else if ( word_num == j2 ) then j2beg = i end if blank = .false. end if end do if ( j1beg /= 0 .and. j1end == 0 ) then j1end = lens else if ( j2beg /= 0 .and. j2end == 0 ) then j2end = lens end if if ( word_num < j1 .or. word_num < j2 ) then return end if ! ! OK, we can swap words J1 and J2. ! s2 = s ! ! Copy word 2. ! s( j1beg : j1beg + j2end - j2beg ) = s2 ( j2beg : j2end ) ! ! Copy (possibly null) string between word 1 and word 2. ! s ( j1beg + j2end - j2beg + 1 : j1beg + j2end - j1end - 1 ) & = s2 ( j1end + 1 : j2beg - 1 ) ! ! Copy word 1. ! s ( j1beg + j2end - j1end : j2end ) = s2 ( j1beg : j1end ) return end