program quote ! !******************************************************************************* ! !! QUOTE extracts a random quote from a file. ! ! ! Usage: ! ! quote ! ! extracts a quote from the default quote file. ! ! quote FILE ! ! extracts a quote from the file FILE. ! ! Discussion: ! ! This version of QUOTE is descended from a program written ! by David Moses. ! ! The quote file contains a series of quotes, separated by a blank line. ! When printing out a quote from the file, any line that ends with a ! quotation mark is followed by an extra blank line. ! ! Modified: ! ! 01 December 2000 ! ! Author: ! ! John Burkardt ! implicit none ! logical, parameter :: DEBUG = .false. integer i integer iarg integer iargc integer ierror integer ilen integer iline integer ipxfargc integer iquote character ( len = 80 ) line character ( len = 80 ) list_file_name integer nline integer nquote integer numarg character ( len = 80 ) quote_file_name character ( len = 80 ) quote_file_title integer seed ! write ( *, '(a)' ) ' ' call timestamp ( ) ! ! Initialize the random number generator, which is too ! lazy to properly scramble itself. ! seed = 0 call random_initialize ( seed ) ! ! Count the command line arguments. ! ! Old style: ! numarg = iargc ( ) ! ! New style: ! ! numarg = ipxfargc ( ) ! ! If a quote file was not specified, open QUOTE_FILES.TXT and ! pick a file at random. ! if ( numarg == 0 ) then list_file_name = '/math/WWW/f_src/quote/quote_files.txt' call file_line_count ( list_file_name, nline ) if ( nline < 1 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'QUOTE - Fatal error.' write ( *, '(a)' ) ' The list of quote files is missing.' stop end if if ( DEBUG ) then write ( *, '(a)' ) 'Number of quote file listing entries is ', nline end if call i_random ( 1, nline, iline ) if ( DEBUG ) then write ( *, '(a)' ) 'Choosing file number ', iline end if call file_line_get ( list_file_name, iline, line ) call word_next2 ( line, quote_file_name, quote_file_title ) if ( DEBUG ) then write ( *, '(a)' ) trim ( quote_file_title ) end if else iarg = 1 ! ! Old style: ! call getarg ( iarg, quote_file_name ) ! ! New style: ! ! call pxfgetarg ( iarg, quote_file_name, ilen, ierror ) ! ! if ( ierror /= 0 ) then ! write ( *, '(a)' ) ' ' ! write ( *, '(a)' ) 'QUOTE - Fatal error.' ! write ( *, '(a)' ) ' Could not read the command line argument.' ! stop ! end if quote_file_title = 'One of my favorite quotations.' end if ! ! Compute NQUOTE, the number of quotes in the file. ! call file_para_count ( quote_file_name, nquote ) if ( nquote <= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'QUOTE - Fatal error trying to count the quotes.' stop end if ! ! Set IQUOTE, the number of the quote to be displayed. ! call i_random ( 1, nquote, iquote ) if ( iquote <= 0 ) then iquote = 1 end if if ( iquote > nquote ) then iquote = nquote end if if ( DEBUG ) then write ( *, '(a,i6)' ) 'Extract quote number ', iquote end if ! ! Read from the quote file until you reach the desired quote. ! JQUOTE tells us which quote we are currently reading. ! Quotes are presumed to be separated by a single blank line. ! call quote_file_print ( quote_file_name, quote_file_title, iquote, ierror ) stop end subroutine file_line_count ( file_name, nline ) ! !******************************************************************************* ! !! FILE_LINE_COUNT counts the number of lines in a file. ! ! ! Discussion: ! ! The file is assumed to be a simple text file. ! ! Modified: ! ! 21 August 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) FILE_NAME, the name of the file. ! ! Output, integer NLINE, the number of lines found in the file. ! implicit none ! character ( len = * ) file_name integer ios integer iunit integer nline ! nline = 0 ! ! Open the file. ! call get_unit ( iunit ) if ( iunit == 0 ) then nline = -1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_LINE_COUNT - Fatal error!' write ( *, '(a)' ) ' Could not find a free FORTRAN unit.' return end if open ( unit = iunit, file = file_name, status = 'old', form = 'formatted', & access = 'sequential', iostat = ios ) if ( ios /= 0 ) then nline = - 1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_LINE_COUNT - Fatal error!' write ( *, '(a)' ) ' Could not open the file:' write ( *, '(a)' ) trim ( file_name ) return end if ! ! Count the lines. ! do read ( iunit, '(a)', iostat = ios ) if ( ios /= 0 ) then exit end if nline = nline + 1 end do close ( unit = iunit ) return end subroutine file_line_get ( file_name, nline, line ) ! !******************************************************************************* ! !! FILE_LINE_GET gets a particular line of a file. ! ! ! Discussion: ! ! The file is assumed to be a simple text file. ! ! Modified: ! ! 21 August 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) FILE_NAME, the name of the file. ! ! Input, integer NLINE, the line number to be read. ! ! Output, character ( len = * ) LINE, the text of the line. ! implicit none ! character ( len = * ) file_name integer i integer ios integer iunit character ( len = * ) line integer nline ! ! Open the file. ! call get_unit ( iunit ) if ( iunit == 0 ) then line = ' ' write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_LINE_GET - Fatal error!' write ( *, '(a)' ) ' Could not find a free FORTRAN unit.' return end if open ( unit = iunit, file = file_name, status = 'old', form = 'formatted', & access = 'sequential', iostat = ios ) if ( ios /= 0 ) then line = ' ' write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_LINE_GET - Fatal error!' write ( *, '(a)' ) ' Could not open the file:' write ( *, '(a)' ) trim ( file_name ) return end if ! ! Count the lines. ! do i = 1, nline read ( iunit, '(a)', iostat = ios ) line if ( ios /= 0 ) then line = ' ' write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_LINE_GET - Fatal error!' write ( *, '(a)' ) ' Unexpected end of file.' return end if end do close ( unit = iunit ) return end subroutine file_para_count ( file_name, npara ) ! !******************************************************************************* ! !! FILE_PARA_COUNT counts the number of paragraphs in a file. ! ! ! Discussion: ! ! The file is assumed to be a simple text file. A paragraph is ! a sequence of nonblank lines. ! ! Modified: ! ! 13 August 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) FILE_NAME, the name of the file. ! ! Output, integer NPARA, the number of paragraphs found in the file. ! implicit none ! character ( len = * ) file_name integer ios integer iunit integer lenc integer lenc_old character ( len = 256 ) line integer npara ! npara = 0 ! ! Open the file. ! call get_unit ( iunit ) if ( iunit == 0 ) then npara = -1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_PARA_COUNT - Fatal error!' write ( *, '(a)' ) ' Could not find a free FORTRAN unit.' return end if open ( unit = iunit, file = file_name, status = 'old', form = 'formatted', & access = 'sequential', iostat = ios ) if ( ios /= 0 ) then npara = - 1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'FILE_PARA_COUNT - Fatal error!' write ( *, '(a)') ' Could not open the file:' write ( *, '(a)' ) trim ( file_name ) return end if ! ! Count the paragraphs. ! lenc = 0 do read ( iunit, '(a)', iostat = ios ) line if ( ios /= 0 ) then exit end if lenc_old = lenc lenc = len_trim ( line ) if ( lenc > 0 .and. lenc_old <= 0 ) then npara = npara + 1 end if end do close ( unit = iunit ) return end subroutine get_unit ( iunit ) ! !******************************************************************************* ! !! 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. ! ! Modified: ! ! 02 March 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Output, integer IUNIT. ! ! 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. ! 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 i_random ( ilo, ihi, i ) ! !******************************************************************************* ! !! I_RANDOM returns a random integer in a given range. ! ! ! Modified: ! ! 01 December 2000 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer ILO, IHI, the minimum and maximum acceptable values. ! ! Output, integer I, the randomly chosen integer. ! implicit none ! integer i integer ihi integer ilo real r real rhi real rlo ! ! Pick a random number in (0,1). ! call random_seed call random_number ( harvest = r ) ! ! Set a real interval [RLO,RHI] which contains the integers [ILO,IHI], ! each with a "neighborhood" of width 1. ! rlo = real ( ilo ) - 0.5E+00 rhi = real ( ihi ) + 0.5E+00 ! ! Set I to the integer that is nearest the scaled value of R. ! i = nint ( ( 1.0E+00 - r ) * rlo + r * rhi ) ! ! In case of oddball events at the boundary, enforce the limits. ! i = max ( i, ilo ) i = min ( i, ihi ) return end subroutine quote_file_print ( quote_file_name, quote_file_title, iquote, & ierror ) ! !******************************************************************************* ! !! QUOTE_FILE_PRINT prints a given quote from a quote file. ! ! ! Discussion: ! ! The index of the desired quote is specified. ! ! Modified: ! ! 09 September 2000 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) QUOTE_FILE_NAME, the name of the quote file. ! ! Input, character ( len = * ) QUOTE_FILE_TITLE, the title of the quote file. ! ! Input, integer IQUOTE, the index of the quote to be printed. ! The first quote has IQUOTE = 1, and so on. If there are fewer ! that IQUOTE quotes in the file, then nothing will be printed. ! ! Output, integer IERROR, error flag. ! 0, no error was encountered. ! nonzero, an error occurred. ! implicit none ! integer ierror integer ios integer iquote integer jquote integer lenc integer lencold character ( len = 100 ) line character ( len = * ) quote_file_name character ( len = * ) quote_file_title integer quote_file_unit ! ! Open the quote file. ! call get_unit ( quote_file_unit ) if ( quote_file_unit == 0 ) then ierror = 1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'QUOTE_FILE_PRINT - Fatal error!' write ( *, '(a)' ) ' Could not find a free FORTRAN unit.' return end if open ( unit = quote_file_unit, file = quote_file_name, status = 'old', & form = 'formatted', access = 'sequential', iostat = ios ) if ( ios /= 0 ) then ierror = 1 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'QUOTE_FILE_PRINT - Fatal error!' write ( *, '(a)' ) ' Could not open the quote file:' write ( *, '(a)' ) trim ( quote_file_name ) return end if jquote = 1 lenc = 0 write ( *, * ) ' ' do read ( quote_file_unit, '(a)', iostat = ios ) line if ( ios /= 0 ) then if ( iquote /= jquote ) then ierror = 2 write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'QUOTE_FILE_PRINT - Fatal error!' write ( *, '(a)' ) ' Could not find the desired quote.' end if close ( unit = quote_file_unit ) return end if lencold = lenc lenc = len_trim ( line ) if ( lenc > 0 .and. lencold <= 0 ) then jquote = jquote + 1 end if if ( jquote < iquote ) then else if ( jquote == iquote ) then write ( *, '(5x,a)' ) trim ( line ) if ( lenc > 0 ) then if ( line(lenc:lenc) == '"' ) then write ( *, '(a)' ) ' ' end if end if else if ( jquote > iquote ) then exit end if end do write ( *, '(5x,a)' ) trim ( quote_file_title ) write ( *, '(a)' ) ' ' close ( unit = quote_file_unit ) return end subroutine random_initialize ( seed ) ! !******************************************************************************* ! !! RANDOM_INITIALIZE initializes the FORTRAN 90 random number seed. ! ! ! Discussion: ! ! If you don't initialize the random number generator, its behavior ! is not specified. If you initialize it simply by: ! ! call random_seed ! ! its behavior is not specified. On the DEC ALPHA, if that's all you ! do, the same random number sequence is returned. In order to actually ! try to scramble up the random number generator a bit, this routine ! goes through the tedious process of getting the size of the random ! number seed, making up values based on the current time, and setting ! the random number seed. ! ! Modified: ! ! 19 December 2001 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input/output, integer SEED. ! If SEED is zero on input, then you're asking this routine to come up ! with a seed value, which is returned as output. ! If SEED is nonzero on input, then you're asking this routine to ! use the input value of SEED to initialize the random number generator, ! and SEED is not changed on output. ! implicit none ! integer count integer count_max integer count_rate logical, parameter :: debug = .false. integer i integer seed integer, allocatable :: seed_vector(:) integer seed_size real t ! ! Initialize the random number seed. ! call random_seed ! ! Determine the size of the random number seed. ! call random_seed ( size = seed_size ) ! ! Allocate a seed of the right size. ! allocate ( seed_vector(seed_size) ) if ( seed /= 0 ) then if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'RANDOM_INITIALIZE' write ( *, '(a,i20)' ) ' Initialize RANDOM_NUMBER, user SEED = ', seed end if else call system_clock ( count, count_rate, count_max ) seed = count if ( debug ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'RANDOM_INITIALIZE' write ( *, '(a,i20)' ) ' Initialize RANDOM_NUMBER, arbitrary SEED = ', & seed end if end if ! ! Now set the seed. ! seed_vector(1:seed_size) = seed call random_seed ( put = seed_vector(1:seed_size) ) ! ! Free up the seed space. ! deallocate ( seed_vector ) ! ! Call the random number routine a bunch of times. ! do i = 1, 100 call random_number ( harvest = t ) end do return end subroutine timestamp ( ) ! !******************************************************************************* ! !! TIMESTAMP prints the current YMDHMS date as a time stamp. ! ! ! Example: ! ! May 31 2001 9:45:54.872 AM ! ! Modified: ! ! 31 May 2001 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! None ! implicit none ! character ( len = 8 ) ampm integer d character ( len = 8 ) date 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 character ( len = 10 ) time integer values(8) integer y character ( len = 5 ) zone ! call date_and_time ( date, time, zone, 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 ( *, '(5x,a,1x,i2,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' ) & trim ( month(m) ), d, y, h, ':', n, ':', s, '.', mm, trim ( ampm ) return end subroutine word_next2 ( s, first, last ) ! !******************************************************************************* ! !! 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. ! ! Modified: ! ! 14 April 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input/output, character ( len = * ) S, the string of words to be analyzed. ! ! Output, character ( len = * ) FIRST, the next word in the string. ! ! Output, 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