Question

I am attempting to write a small utility routine that can take a list of menu entries as strings (ideally, defined explicitly in the subroutine call), present these strings as numbered options, and ask the user to choose one. The responsibility for validation is left to the calling routine. My first attempt, using an explicit array of strings defined in the same manner as an array initialization statement, failed, so I tried the approach of sending a single explicit string with 'marker' characters, using continuation lines.

The following seems to work in gfortran 4.7.3 under Cygwin:

PROGRAM menutest
IMPLICIT NONE
INTEGER :: n
CALL menu(n, 'This is option 1$&
              Option Two$&
              Option number three$' )
WRITE(*,*) 'You chose option ' ,n
END PROGRAM menutest

SUBROUTINE menu(n, entrylist)
IMPLICIT NONE
INTEGER :: n, i, nitems,pos1,pos2
CHARACTER (LEN=*) :: entrylist
!
pos1 = 1
pos2 = 1
i=1
! Loop over entries
DO
  entrylist = entrylist(pos1:)
  pos2 = INDEX(entrylist,'$')
  IF (pos2 == 0) THEN
     EXIT
  END IF
  WRITE (*,'(A,I2,A,A)') '(',i,') ',entrylist(:pos2-1)
  i = i+1
  pos1 = pos2+1
END DO
WRITE(*,*) 'Choose an option from the menu'
READ(*,*) n
END SUBROUTINE menu

Unfortunately this fails using Linux gfortran 4.5.x. I need a solution that will work reliably on as many F95 compilers on as many compilers as possible, and on as many platforms as possible. I want to be able to call it many times in my program, with different lengths of lists of different lengths of strings.

Does anyone have a better solution?

Was it helpful?

Solution

You can of course send an array of strings:

CALL menu(n, [character(20) :: 'This is option 1', &
                               'Option Two', &
                               'Option number three'] )
write(*,*) 'You chose option ' ,n

contains
  subroutine menu(n, entrylist)
    CHARACTER(len=*),intent(in) :: entrylist(:)
    integer, intent(out) :: n
    integer i
    do i=1,size(entrylist)
      write(*,*) trim(entrylist(i))
    end do
    read(*,*) n
  end subroutine

end

This form of array constructor is Fortran 2003. If you have to avoid it, then build the array by normal assignments of elements.

strings(1) = 'This is option 1'
strings(2) = 'Option Two'
strings(3) = 'Option number three'
call menu(n, strings)

Note, that the subroutine requires an explicit interface, therefore it is an internal procedure in this short example. You want it typically in a module in full scale programs.

OTHER TIPS

the simple fix, do not modify the string that was passed as literal:

!  entrylist = entrylist(pos1:)  <-- get rid of this offending line
   pos2 = pos1-1+INDEX(entrylist(pos1:),'$')
   IF (pos2 == pos1-1) THEN

      ...

   WRITE (*,'(A,I2,A,A)') '(',i,') ',entrylist(pos1:pos2-1)

tested with gfortran 4.x

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top