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 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 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 subroutine cnf_data_read ( cnf_file_name, v_num, c_num, l_num, l_c_num, l_val ) !*****************************************************************************80 ! !! cnf_data_read() reads the data of a CNF file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 June 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) CNF_FILE_NAME, the name of the CNF file. ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the number of signed literals. ! ! Output: ! ! integer L_C_NUM(C_NUM), the number of signed ! literals occuring in each clause. ! ! integer L_VAL(L_NUM), a list of all the signed ! literals in all the clauses, ordered by clause. ! implicit none integer c_num integer l_num integer v_num integer c_num2 logical ch_eqi logical ch_is_space character ( len = * ) cnf_file_name integer cnf_file_status integer cnf_file_unit integer ierror integer l_c_num(c_num) integer l_c_num2 integer l_num2 integer l_val(l_num) integer l_val2 integer length character ( len = 255 ) line logical s_eqi integer v_num2 character ( len = 20 ) word call i4_fake_use ( v_num ) call get_unit ( cnf_file_unit ) open ( unit = cnf_file_unit, file = cnf_file_name, status = 'old', & iostat = cnf_file_status ) if ( cnf_file_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Could not open file!' stop end if ! ! Read lines until you find one that is not blank and does not begin ! with a "c". This should be the header line. ! line = ' ' do read ( cnf_file_unit, '(a)', iostat = cnf_file_status ) line if ( cnf_file_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Error while reading the file.' stop end if if ( line(1:1) == 'c' .or. line(1:1) == 'C' ) then cycle end if if ( 0 < len_trim ( line ) ) then exit end if end do ! ! We expect to be reading the line "p cnf V_NUM C_NUM" ! if ( .not. ch_eqi ( line(1:1), 'p' ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' First non-comment non-blank line does not start' write ( *, '(a)' ) ' with "p " marker.' stop end if if ( .not. ch_is_space ( line(2:2) ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Character after "p" must be whitespace.' stop end if ! ! Remove the first two characters and shift left to first nonblank. ! line(1:1) = ' ' line(2:2) = ' ' line = adjustl ( line ) ! ! Expect the string 'CNF' ! if ( .not. s_eqi ( line(1:3), 'cnf' ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' First non-comment non-blank line does not start' write ( *, '(a)' ) ' with "p cnf" marker.' stop end if if ( .not. ch_is_space ( line(4:4) ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Character after "p cnf" must be whitespace.' stop end if ! ! Remove the first four characters and shift left. ! line(1:4) = ' ' line = adjustl ( line ) ! ! Extract the next word, which is the number of variables. ! You can compare this to V_NUM for an extra check. ! call s_word_extract_first ( line, word ) if ( len_trim ( word ) <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected end of input.' stop end if call s_to_i4 ( word, v_num2, ierror, length ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected end of input.' stop end if ! ! Extract the next word, which is the number of clauses. ! You can compare this to C_NUM for an extra check. ! call s_word_extract_first ( line, word ) if ( len_trim ( word ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected end of input.' stop end if call s_to_i4 ( word, c_num2, ierror, length ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_data_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected end of input.' stop end if ! ! Read remaining lines, counting the literals, ignoring occurrences of '0'. ! l_num2 = 0 c_num2 = 0 l_c_num2 = 0 line = ' ' do read ( cnf_file_unit, '(a)', iostat = cnf_file_status ) line if ( cnf_file_status /= 0 ) then exit end if if ( line(1:1) == 'c' ) then cycle end if if ( len_trim ( line ) < 0 ) then exit end if do call s_word_extract_first ( line, word ) if ( len_trim ( word ) <= 0 ) then exit end if call s_to_i4 ( word, l_val2, ierror, length ) if ( ierror /= 0 ) then exit end if if ( l_val2 /= 0 ) then l_num2 = l_num2 + 1 l_val(l_num2) = l_val2 l_c_num2 = l_c_num2 + 1 else c_num2 = c_num2 + 1 l_c_num(c_num2) = l_c_num2 l_c_num2 = 0 end if end do end do ! ! At the end: ! ! C_NUM2 should equal C_NUM, ! L_NUM2 should equal L_NUM. ! ! Close file and return. ! close ( unit = cnf_file_unit ) return end subroutine cnf_data_write ( c_num, l_num, l_c_num, l_val, output_unit ) !*****************************************************************************80 ! !! cnf_data_write() writes data to a CNF file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the total number of signed literals. ! ! integer L_C_NUM(C_NUM), the number of signed ! literals occuring in each clause. ! ! integer L_VAL(L_NUM), a list of all the signed ! literals in all the clauses, ordered by clause. ! ! integer OUTPUT_UNIT, the output unit. ! implicit none integer c_num integer l_num integer c integer i1 integer i2 integer l integer l_c integer l_c_num(c_num) integer l_val(l_num) integer output_unit character ( len = 255 ) string l = 0 string = ' ' do c = 1, c_num i1 = 1 i2 = 10 do l_c = 1, l_c_num(c) l = l + 1 write ( string(i1:i2), '(1x,i7)' ) l_val(l) i1 = i1 + 10 i2 = i2 + 10 if ( mod ( l_c, 10 ) == 0 ) then call s_blanks_delete ( string ) write ( output_unit, '(a)' ) string(1:len_trim(string)) string = ' ' end if end do string(i2+1:i2+2) = ' 0' call s_blanks_delete ( string ) write ( output_unit, '(a)' ) string(1:len_trim(string)) string = ' ' end do return end function cnf_evaluate ( v_num, c_num, l_num, l_c_num, l_val, v_val ) !*****************************************************************************80 ! !! cnf_evaluate() evaluates a formula in CNF form. ! ! Discussion: ! ! The formula is in conjunctive normal form. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 29 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the total number of signed literals. ! ! integer L_C_NUM(C_NUM), the number of signed ! literals occuring in each clause. ! ! integer L_VAL(L_NUM), a list of all the signed ! literals in all the clauses, ordered by clause. ! ! logical V_VAL(V_NUM), the values assigned to the variables. ! ! Output: ! ! logical CNF_EVALUATE, the value of the CNF formula for the ! given variable values. ! implicit none integer c_num logical cnf_evaluate integer l_num integer v_num integer c logical c_val logical f_val integer l integer l_c integer l_c_num(c_num) integer l_val(l_num) logical s_val integer v_index logical v_val(v_num) f_val = .true. l = 0 do c = 1, c_num ! ! The clause is false unless some signed literal is true. ! c_val = .false. do l_c = 1, l_c_num(c) l = l + 1 s_val = ( 0 < l_val(l) ) v_index = abs ( l_val(l) ) ! ! The signed literal is true if the sign "equals" the value. ! Note that we CAN'T exit the loop because we need to run out the ! L index! ! if ( v_val(v_index) .eqv. s_val ) then c_val = .true. end if end do ! ! The formula is false if any clause is false. ! if ( .not. c_val ) then f_val = .false. exit end if end do cnf_evaluate = f_val return end subroutine cnf_header_read ( cnf_file_name, v_num, c_num, l_num ) !*****************************************************************************80 ! !! cnf_header_read() reads the header of a CNF file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 01 June 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! character ( len = * ) CNF_FILE_NAME, the name of the CNF file. ! ! Output: ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the number of signed literals. ! implicit none integer c_num logical ch_eqi logical ch_is_space character ( len = * ) cnf_file_name integer cnf_file_status integer cnf_file_unit integer ierror integer l_num integer l_val integer length character ( len = 255 ) line logical s_eqi integer v_num character ( len = 20 ) word call get_unit ( cnf_file_unit ) open ( unit = cnf_file_unit, file = cnf_file_name, status = 'old', & iostat = cnf_file_status ) if ( cnf_file_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Could not open file!' stop end if ! ! Read lines until you find one that is not blank and does not begin ! with a "c". This should be the header line. ! line = ' ' do read ( cnf_file_unit, '(a)', iostat = cnf_file_status ) line if ( cnf_file_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Error while reading the file.' stop end if if ( line(1:1) == 'c' .or. line(1:1) == 'C' ) then cycle end if if ( 0 < len_trim ( line ) ) then exit end if end do ! ! We expect to be reading the line "p cnf V_NUM C_NUM" ! if ( .not. ch_eqi ( line(1:1), 'p' ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' First non-comment non-blank line does not start' write ( *, '(a)' ) ' with "p " marker.' stop end if if ( .not. ch_is_space ( line(2:2) ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Character after "p" must be whitespace.' stop end if ! ! Remove the first two characters and shift left. ! line(1:2) = ' ' line = adjustl ( line ) ! ! Expect the string 'CNF' ! if ( .not. s_eqi ( line(1:3), 'cnf' ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' First non-comment non-blank line does not start' write ( *, '(a)' ) ' with "p cnf" marker.' stop end if if ( .not. ch_is_space ( line(4:4) ) ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Character after "p cnf" must be whitespace.' stop end if ! ! Remove the first four characters and shift left. ! line(1:4) = ' ' line = adjustl ( line ) ! ! Extract the next word, which is the number of variables. ! call s_word_extract_first ( line, word ) if ( len_trim ( word ) <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected End of input.' stop end if call s_to_i4 ( word, v_num, ierror, length ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected End of input.' stop end if ! ! Extract the next word, which is the number of clauses. ! call s_word_extract_first ( line, word ) if ( len_trim ( word ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected End of input.' stop end if call s_to_i4 ( word, c_num, ierror, length ) if ( ierror /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'cnf_header_read(): Fatal error!' write ( *, '(a)' ) ' Unexpected End of input.' stop end if ! ! Read remaining lines, counting the literals, ignoring occurrences of '0'. ! l_num = 0 line = ' ' do read ( cnf_file_unit, '(a)', iostat = cnf_file_status ) line if ( cnf_file_status /= 0 ) then exit end if if ( line(1:1) == 'c' ) then cycle end if if ( len_trim ( line ) < 0 ) then exit end if do call s_word_extract_first ( line, word ) if ( len_trim ( word ) <= 0 ) then exit end if call s_to_i4 ( word, l_val, ierror, length ) if ( ierror /= 0 ) then exit end if if ( l_val /= 0 ) then l_num = l_num + 1 end if end do end do ! ! Close file and return. ! close ( unit = cnf_file_unit ) return end subroutine cnf_header_write ( v_num, c_num, output_name, output_unit ) !*****************************************************************************80 ! !! cnf_header_write() writes the header for a CNF file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 24 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! character ( len = * ) OUTPUT_NAME, the name of the output file. ! ! integer OUTPUT_UNIT, the output unit. ! implicit none integer c_num character ( len = * ) output_name integer output_unit character ( len = 80 ) string integer v_num write ( output_unit, '(a)' ) 'c ' // trim ( output_name ) write ( output_unit, '(a)' ) 'c' write ( string, '(a,1x,i7,1x,i7)' ) 'p cnf', v_num, c_num call s_blanks_delete ( string ) write ( output_unit, '(a)' ) string(1:len_trim(string)) return end subroutine cnf_print ( v_num, c_num, l_num, l_c_num, l_val ) !*****************************************************************************80 ! !! cnf_print() prints CNF information. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the total number of signed literals. ! ! integer L_C_NUM(C_NUM), the number of signed ! literals occuring in each clause. ! ! integer L_VAL(L_NUM), a list of all the signed ! literals in all the clauses, ordered by clause. ! implicit none integer c_num integer l_num integer c integer l integer l_c integer l_c_num(c_num) integer l_val(l_num) integer v_num write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'CNF data printout:' write ( *, '(a)' ) ' ' write ( *, '(a,i8)' ) ' The number of variables V_NUM = ', v_num write ( *, '(a,i8)' ) ' The number of clauses C_NUM = ', c_num write ( *, '(a,i8)' ) ' The number of signed literals L_NUM = ', l_num l = 0 do c = 1, c_num write ( *, '(a)' ) ' ' write ( *, '(a,i8,a,i8,a)' ) & ' Clause ', c, ' includes ', l_c_num(c), ' signed literals' do l_c = 1, l_c_num(c) l = l + 1 write ( *, '(i4)' ) l_val(l) end do end do return end subroutine cnf_write ( v_num, c_num, l_num, l_c_num, l_val, output_name ) !*****************************************************************************80 ! !! cnf_write() writes the header and data of a CNF file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer V_NUM, the number of variables. ! ! integer C_NUM, the number of clauses. ! ! integer L_NUM, the total number of signed literals. ! ! integer L_C_NUM(C_NUM), the number of signed ! literals occuring in each clause. ! ! integer L_VAL(L_NUM), a list of all the signed ! literals in all the clauses, ordered by clause. ! ! character ( len = * ) OUTPUT_NAME, the name of the output file. ! implicit none integer c_num integer l_num integer l_c_num(c_num) integer l_val(l_num) character ( len = * ) output_name integer output_unit integer v_num call get_unit ( output_unit ) open ( unit = output_unit, file = output_name, status = 'replace' ) call cnf_header_write ( v_num, c_num, output_name, output_unit ) call cnf_data_write ( c_num, l_num, l_c_num, l_val, output_unit ) close ( unit = output_unit ) 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 i4_fake_use ( n ) !*****************************************************************************80 ! !! i4_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: ! ! 21 April 2020 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the variable to be "used". ! implicit none integer n if ( n /= n ) then write ( *, '(a)' ) ' i4_fake_use: variable is NAN.' end if return end subroutine lvec_next ( n, lvec ) !*****************************************************************************80 ! !! lvec_next() generates the next logical vector. ! ! Discussion: ! ! Let "0" represent FALSE and "1" represent TRUE. ! Then the vectors have the order ! (0,0,...,0), ! (0,0,...,1), ! ... ! (1,1,...,1) ! ! and the "next" vector after (1,1,...,1) is (0,0,...,0). That is, ! we allow wrap around. ! ! Example: ! ! N = 3 ! ! Input Output ! ----- ------ ! 0 0 0 => 0 0 1 ! 0 0 1 => 0 1 0 ! 0 1 0 => 0 1 1 ! 0 1 1 => 1 0 0 ! 1 0 0 => 1 0 1 ! 1 0 1 => 1 1 0 ! 1 1 0 => 1 1 1 ! 1 1 1 => 0 0 0 ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 30 May 2008 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the dimension of the vectors. ! ! logical LVEC(N), the current value. ! ! Output: ! ! logical LVEC(N), the successor to the input value. ! implicit none integer n integer i logical lvec(n) do i = n, 1, -1 if ( .not. lvec(i) ) then lvec(i) = .true. return end if lvec(i) = .false. end do 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 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 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_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 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 ! 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