MODULE XRD_GETOPTIONS

!**** *XRD_GETOPTIONS*  - Parse command lines options in long form

!     Author. 
!     ------- 
!      Philippe Marguinaud *METEO FRANCE*
!      Original : 11-09-2012

USE EC_PARKIND, ONLY: JPIM, JPRD, JPRM

USE XRD_UNIX_ENV, ONLY: XRD_IARGC, XRD_GETARG, &
  XRD_BASENAME, XRD_COUNTWORDS, XRD_GETENV,    &
  XRD_ISALPHA, XRD_ISDIGIT, XRD_EXIT

IMPLICIT NONE

INTERFACE GETOPTION
  MODULE PROCEDURE GETOPTIONS, GETOPTIONSL, &
                   GETOPTIONI, GETOPTIONIL, &
                   GETOPTIONR4, GETOPTIONR4L, &
                   GETOPTIONR8, GETOPTIONR8L, &
                   GETOPTIONB
                   
END INTERFACE

!! @TODO : LIST WITH FIXED SIZE

PUBLIC :: GETOPTION, INITOPTIONS, CHECKOPTIONS, ADDGROUP

INTEGER, PARAMETER :: ARGSIZEMAX = 256

CHARACTER(LEN=ARGSIZEMAX), POINTER :: MYARGS(:) => NULL()
LOGICAL(KIND=JPIM), POINTER :: CHECK_ARGS(:) => NULL()
LOGICAL(KIND=JPIM) :: LHELP  = .FALSE., LSHELL = .FALSE.

CHARACTER(LEN=1056) :: MESSAGE_OPT = ""


TYPE XRD_OPT
  CHARACTER(LEN=32) :: KEY, TYPE
  CHARACTER(LEN=1024) :: USE
  LOGICAL(KIND=JPIM) :: GROUP = .FALSE.
END TYPE

INTEGER(KIND=JPIM) :: NOPT_SEEN
TYPE(XRD_OPT), POINTER :: OPT_SEEN(:) => NULL()

PRIVATE

CONTAINS

SUBROUTINE ADDGROUP( USE )
CHARACTER(LEN=*), INTENT(IN) :: USE

CALL INIT_OPT_SEEN()
NOPT_SEEN = NOPT_SEEN + 1
CALL GROW_OPT_SEEN()

OPT_SEEN(NOPT_SEEN)%GROUP = .TRUE.
OPT_SEEN(NOPT_SEEN)%USE = USE


END SUBROUTINE ADDGROUP

CHARACTER(LEN=ARGSIZEMAX) FUNCTION GET_ENV_OPT( KEY )
CHARACTER(LEN=*), INTENT(IN) :: KEY
CHARACTER(LEN=ARGSIZEMAX) :: KEY_ENV, VAL_ENV
INTEGER(KIND=JPIM) :: I, N
CHARACTER :: C

KEY_ENV = KEY(3:)

N = LEN(TRIM(KEY_ENV))
DO I = 1, N
  C = KEY_ENV(I:I)
  IF((.NOT.XRD_ISALPHA(C)) .AND. &
     (.NOT.XRD_ISDIGIT(C)) .AND. &
     (C .NE. '_' )) THEN
    KEY_ENV(I:I) = '_'
  ENDIF
ENDDO

VAL_ENV = ""
CALL XRD_GETENV( 'XRD_OPT_'//TRIM(KEY_ENV), VAL_ENV )

!PRINT *, " KEY = ", TRIM(KEY_ENV), " VAL = ", TRIM(VAL_ENV)

GET_ENV_OPT = VAL_ENV

END FUNCTION GET_ENV_OPT

SUBROUTINE MYGETARG( I, S )
  INTEGER(KIND=JPIM), INTENT(IN)  :: I
  CHARACTER(LEN=*),      INTENT(OUT) :: S
!
  IF( I .LE. UBOUND( MYARGS, 1 ) ) THEN
    S = MYARGS(I)
  ELSE
    S = ""
   ENDIF
END SUBROUTINE MYGETARG

INTEGER FUNCTION MYIARGC()
  INTEGER :: N
  N = UBOUND( MYARGS, 1 )
  MYIARGC = N
END FUNCTION MYIARGC

SUBROUTINE ADDOPT_SHELL( KEY, TYPE, MND, USE )
  CHARACTER*(*), INTENT(IN) :: KEY, TYPE, USE
  LOGICAL(KIND=JPIM), INTENT(IN) :: MND
  OPTIONAL :: USE, MND
!
  CHARACTER(LEN=ARGSIZEMAX) :: STR
  INTEGER :: NN, N, N1, I1, I2, K
  CHARACTER(LEN=ARGSIZEMAX), POINTER :: MYARGS1(:)

  MYARGS1 => NULL()

  IF( PRESENT( USE ) ) WRITE( *, '("> ",A)' ) TRIM(USE)
  IF( PRESENT( MND ) ) THEN
    IF( MND ) WRITE( *, * ) "[MANDATORY]"
  ENDIF 
  WRITE( *, * ) "* OPTION: [", TYPE, "]", " ", TRIM(KEY)
  READ( *, '(A)' ) STR

! PRINT *, "STR = ",TRIM(STR)
  IF( TRIM(STR) .NE. "" )  THEN
    IF( TYPE .EQ. 'FLAG' ) THEN
      NN = 0
    ELSE
      NN = XRD_COUNTWORDS( STR )
    ENDIF
    N  = UBOUND( MYARGS, 1 )
    N1 = N + NN + 1

!
! REALLOC MYARGS
!
    ALLOCATE( MYARGS1(0:N1) )
    MYARGS1(0:N) = MYARGS(0:N)
    DEALLOCATE( MYARGS )
    MYARGS => MYARGS1
    MYARGS(N+1) = KEY

!
! PARSE ARGUMENT LIST
!
    IF( TYPE .NE. 'FLAG' ) THEN
      K = 1
      I1 = 1
      LOOP_I1 : DO 
        DO
          IF( I1 .GT. LEN(STR)) EXIT LOOP_I1
          IF( STR(I1:I1) .NE. ' ' ) EXIT
          I1 = I1+1
        ENDDO
        I2 = I1+1
        DO
          IF( I2 .GT. LEN(STR)) EXIT
          IF( STR(I2:I2) .EQ. ' ' ) EXIT
          I2 = I2+1
        ENDDO
!PRINT *, I1, I2
        MYARGS(N+1+K) = STR(I1:I2-1)
!PRINT *, K, TRIM(MYARGS(N+1+K))
        K = K+1
        I1 = I2+1
      ENDDO LOOP_I1
    ENDIF
  ENDIF

END SUBROUTINE ADDOPT_SHELL

SUBROUTINE INIT_OPT_SEEN()

  IF( .NOT. ASSOCIATED( OPT_SEEN ) ) THEN
    NOPT_SEEN = 0
    ALLOCATE( OPT_SEEN( 32 ) )
  ENDIF

END SUBROUTINE INIT_OPT_SEEN

SUBROUTINE GROW_OPT_SEEN()
  INTEGER(KIND=JPIM) :: N
  TYPE(XRD_OPT), POINTER :: OPT_SEEN1(:)

  N = SIZE( OPT_SEEN )
  IF( NOPT_SEEN .GE. N ) THEN ! REALLOC DATA
    OPT_SEEN1 => OPT_SEEN
    ALLOCATE( OPT_SEEN( 2 * N ) )
    OPT_SEEN(1:NOPT_SEEN) = OPT_SEEN1(1:NOPT_SEEN)
    DEALLOCATE( OPT_SEEN1 )
  ENDIF

END SUBROUTINE GROW_OPT_SEEN

SUBROUTINE ADDOPT( KEY, TYPE, USE )
  CHARACTER*(*), INTENT(IN) :: KEY, TYPE, USE
  OPTIONAL :: USE

  CALL INIT_OPT_SEEN()

  NOPT_SEEN = NOPT_SEEN + 1

  CALL GROW_OPT_SEEN()

  OPT_SEEN(NOPT_SEEN)%KEY  = KEY
  OPT_SEEN(NOPT_SEEN)%TYPE = TYPE

  IF( PRESENT( USE ) ) THEN
    OPT_SEEN(NOPT_SEEN)%USE  = USE
  ELSE
    OPT_SEEN(NOPT_SEEN)%USE  = ''
  ENDIF

END SUBROUTINE ADDOPT

SUBROUTINE INITOPTIONS( CDMESSAGE, KOPTMIN, KOPTMAX, CDARGS )
 CHARACTER(LEN=*),    OPTIONAL, INTENT (IN) :: CDMESSAGE
 INTEGER (KIND=JPIM), OPTIONAL, INTENT (IN) :: KOPTMIN, KOPTMAX
 CHARACTER (LEN=*),   OPTIONAL, INTENT (IN) :: CDARGS (0:)
 INTEGER(KIND=JPIM) :: N, I
 INTEGER(KIND=JPIM) :: IOPTMIN, IOPTMAX
 CHARACTER*32 :: STR

 IF (PRESENT (CDARGS)) THEN
   N = UBOUND (CDARGS, 1)
 ELSE
   N = XRD_IARGC()
 ENDIF

 IOPTMIN = 0
 IOPTMAX = N
 IF (PRESENT (KOPTMIN)) IOPTMIN = KOPTMIN
 IF (PRESENT (KOPTMAX)) IOPTMAX = KOPTMAX

 N = IOPTMAX-IOPTMIN

 ALLOCATE( MYARGS(0:N) )
 DO I = 0, N
   IF (PRESENT (CDARGS)) THEN
     MYARGS(I) = CDARGS (IOPTMIN+I)
   ELSE
     CALL XRD_GETARG( IOPTMIN+I, MYARGS(I) )
   ENDIF
 ENDDO

 IF( PRESENT( CDMESSAGE ) ) THEN
  MESSAGE_OPT = CDMESSAGE
 ELSE
  MESSAGE_OPT = ""
 ENDIF

 IF( N .EQ. 1 ) THEN
   CALL MYGETARG( 1_JPIM, STR )
   IF( TRIM( STR ) .EQ. '--help' ) THEN
     LHELP = .TRUE.
     RETURN
   ELSE IF( TRIM( STR ) .EQ. '--shell' ) THEN
     LSHELL = .TRUE.
     RETURN
   ENDIF
 ENDIF

 LHELP = .FALSE.
 ALLOCATE( CHECK_ARGS( N ) )
 CHECK_ARGS = .FALSE.

END SUBROUTINE INITOPTIONS



SUBROUTINE CHECKOPTIONS()
 INTEGER(KIND=JPIM) :: I, N, IS, NS, KS
 CHARACTER(LEN=ARGSIZEMAX) :: OPT, PROG
 LOGICAL(KIND=JPIM) :: PB
 CHARACTER(LEN=10) :: FMT
 CHARACTER(LEN=110) :: BUF

 CALL MYGETARG( 0_JPIM, PROG )

 IF( LHELP ) THEN
   PRINT *, "PROGRAM: ", TRIM(XRD_BASENAME( PROG ))
   IF( TRIM(MESSAGE_OPT) .NE. "" ) THEN
     NS = LEN(MESSAGE_OPT)
     DO IS = 1, NS / 96
       KS = LEN( TRIM(MESSAGE_OPT(1+(IS-1)*96:IS*96)) )
       IF( KS .GT. 0 ) THEN
         IF( IS .EQ. 1 ) THEN
           WRITE( *, '("    ")', ADVANCE = 'NO' )
         ELSE
           WRITE( *, '("  > ")', ADVANCE = 'NO' )
         ENDIF
         WRITE( FMT, '("(A",I2,")")' ) KS
         WRITE( *, FMT ) TRIM(MESSAGE_OPT(1+(IS-1)*96:IS*96))
       ENDIF
     ENDDO
   ENDIF
   DO I = 1, NOPT_SEEN

     IF(OPT_SEEN(I)%GROUP) THEN
       WRITE( *, * ) 
       IF( TRIM(OPT_SEEN(I)%USE) .NE. "" ) &
         WRITE( *, * ) '* '//TRIM(OPT_SEEN(I)%USE)
       CYCLE
     ENDIF

     BUF = ""

     WRITE( BUF, '(A32," = ",A15)' ) &
         TRIM(OPT_SEEN(I)%KEY), &
         TRIM(OPT_SEEN(I)%TYPE)

     IF( TRIM(OPT_SEEN(I)%USE) .NE. '' ) THEN
       NS = LEN( OPT_SEEN(I)%USE) 
       DO IS = 1, NS / 48
         KS = LEN(TRIM(OPT_SEEN(I)%USE(1+(IS-1)*48:IS*48)))
         IF( KS .GT. 0 ) THEN
           IF( IS .EQ. 1 ) THEN
             BUF = TRIM(BUF)//" :   "//TRIM(OPT_SEEN(I)%USE(1+(IS-1)*48:IS*48))
           ELSE
!                   000000000011111111112222222222333333333344444444445555555555
!                   012345678901234567890123456789012345678901234567890123456789
             BUF = "                                                     > "&
                   //TRIM(OPT_SEEN(I)%USE(1+(IS-1)*48:IS*48))
           ENDIF
           WRITE( *, '(A120)' ) BUF
         ENDIF
       ENDDO
     ELSE
       WRITE( *, '(A120)' ) BUF
       WRITE( *, * )
     ENDIF

   ENDDO
   STOP
 ELSE IF( ASSOCIATED( CHECK_ARGS ) ) THEN
   N = SIZE( CHECK_ARGS )
   PB = .FALSE.
   DO I = 1, N
     IF( .NOT. CHECK_ARGS(I) ) THEN
       CALL MYGETARG( I, OPT )
       IF( OPT(1:2) .EQ. '--' ) THEN
         PRINT *, 'INVALID OPTION: ', TRIM(OPT)
         PB = .TRUE.
         CHECK_ARGS(I) = .TRUE.
       ENDIF
     ENDIF
   ENDDO

   DO I = 1, N
     IF( .NOT. CHECK_ARGS(I) ) THEN
       CALL MYGETARG( I, OPT )
       PRINT *, 'GARBAGE IN OPTIONS:`', TRIM(OPT), "'"
       PB = .TRUE.
       EXIT
     ENDIF
   ENDDO

   IF( PB ) CALL XRD_EXIT(1_JPIM)

   DEALLOCATE( CHECK_ARGS )
 ELSE IF( LSHELL ) THEN
   OPEN( 77, FILE = TRIM(PROG)//'.sh', FORM = 'FORMATTED' )
   WRITE( 77, '("#!/bin/sh")' )
   WRITE( 77, * )
   WRITE( 77, '(A)', ADVANCE = 'NO' ) TRIM(PROG)
   N = UBOUND( MYARGS, 1 )
   DO I = 1, N
     IF( MYARGS(I) .EQ. '--shell' ) CYCLE
     IF( MYARGS(I)(1:2) .EQ. '--' ) THEN
       WRITE( 77, '(" \")' )
       WRITE( 77, '("    ")', ADVANCE = 'NO' )
     ENDIF
     WRITE( 77, '(" ",A)', ADVANCE = 'NO' ) TRIM(MYARGS(I))
   ENDDO
   WRITE( 77, * )
   CLOSE(77)
 ENDIF



 IF( ASSOCIATED( OPT_SEEN ) ) DEALLOCATE( OPT_SEEN )
 IF( ASSOCIATED( MYARGS ) ) DEALLOCATE( MYARGS )
END SUBROUTINE CHECKOPTIONS


SUBROUTINE CHECK_MND( KEY, MND, USE )
 CHARACTER(LEN=*),           INTENT(IN) :: KEY
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
!
 CHARACTER(LEN=ARGSIZEMAX) :: PROG

 IF( PRESENT( MND ) ) THEN
   IF( MND ) THEN
     CALL MYGETARG( 0_JPIM, PROG )
     WRITE( *, '("PROGRAM: ",(A))' ) TRIM( PROG )
     WRITE( *, '("ERROR:   OPTION `",(A),"'' IS MANDATORY")' ) TRIM( KEY )
     IF( PRESENT( USE ) ) WRITE( *, '("         ",(A)," : ",(A))' ) TRIM( KEY ), TRIM( USE )
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDIF

END SUBROUTINE CHECK_MND

SUBROUTINE FINDARGINDEX( KEY, I, N )
 CHARACTER(LEN=*),      INTENT(IN)  :: KEY
 INTEGER(KIND=JPIM), INTENT(OUT) :: I, N
 CHARACTER(LEN=ARGSIZEMAX) :: ARG

 N = MYIARGC()
 DO I = 1, N
   CALL MYGETARG( I, ARG )
   IF( TRIM( ARG ) .EQ. TRIM( KEY ) ) RETURN
 ENDDO
 I = -1_JPIM
END SUBROUTINE FINDARGINDEX

SUBROUTINE FINDNEXTARGINDEX( I, J )
 INTEGER(KIND=JPIM), INTENT(IN)  :: I
 INTEGER(KIND=JPIM), INTENT(OUT) :: J
!
 CHARACTER(LEN=ARGSIZEMAX) :: ARG
 INTEGER(KIND=JPIM) :: N

 N = MYIARGC()
 DO J = I+1, N
  CALL MYGETARG( J, ARG )
  IF( ARG(1:2) .EQ. '--' ) EXIT
 ENDDO

END SUBROUTINE FINDNEXTARGINDEX

SUBROUTINE GETOPTIONS( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*), INTENT(IN)  :: KEY
 CHARACTER(LEN=*), INTENT(INOUT) :: VAL
 LOGICAL(KIND=JPIM), INTENT(IN), OPTIONAL :: MND
 CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: USE
!
 INTEGER(KIND=JPIM) :: I, N
 CHARACTER(LEN=ARGSIZEMAX) :: ARG
 LOGICAL(KIND=JPIM) :: LSHELL1
 LOGICAL(KIND=JPIM) :: FOUND

 LSHELL1 = LSHELL

 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'STRING', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'STRING', MND, USE )
 ENDIF

 CALL FINDARGINDEX( KEY, I, N )

 FOUND = ( 0 .LT. I ) .AND. ( I .LT. N )

 IF( FOUND ) THEN
   IF( ASSOCIATED( CHECK_ARGS ) ) THEN
     CHECK_ARGS(I)   = .TRUE.
     CHECK_ARGS(I+1) = .TRUE.
   ENDIF
   CALL MYGETARG( I+1_JPIM, VAL )
 ELSE
   ARG = GET_ENV_OPT( KEY )
   FOUND = ARG .NE. ""
   IF( FOUND ) VAL = ARG
 ENDIF

 IF( .NOT. FOUND ) &
   CALL CHECK_MND( KEY, MND, USE )

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONS

SUBROUTINE GETOPTIONI( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),      INTENT(IN)  :: KEY
 INTEGER(KIND=JPIM), INTENT(INOUT) :: VAL
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX) :: SVAL
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 LSHELL1 = LSHELL
 
 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'INTEGER', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'INTEGER', MND, USE )
 ENDIF
 
 SVAL = ""
 CALL GETOPTIONS( KEY, SVAL, MND, USE )
 IF( TRIM( SVAL ) .NE. "" ) THEN
   READ( SVAL, *, IOSTAT = ERR ) VAL
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDIF

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONI

SUBROUTINE GETOPTIONR4( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),   INTENT(IN)  :: KEY
 REAL(KIND=JPRM), INTENT(INOUT) :: VAL
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX) :: SVAL
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 LSHELL1 = LSHELL
 
 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'REAL', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'REAL', MND, USE )
 ENDIF
 
 SVAL = ""
 CALL GETOPTIONS( KEY, SVAL, MND, USE )
 IF( TRIM( SVAL ) .NE. "" ) THEN
   READ( SVAL, *, IOSTAT = ERR ) VAL
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDIF

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONR4

SUBROUTINE GETOPTIONR8( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),   INTENT(IN)  :: KEY
 REAL(KIND=JPRD), INTENT(INOUT) :: VAL
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX) :: SVAL
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 LSHELL1 = LSHELL
 
 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'REAL', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'REAL', MND, USE )
 ENDIF
 
 SVAL = ""
 CALL GETOPTIONS( KEY, SVAL, MND, USE )
 IF( TRIM( SVAL ) .NE. "" ) THEN
   READ( SVAL, *, IOSTAT = ERR ) VAL
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDIF

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONR8

SUBROUTINE READASLFROMSTRING( VAL, SVAL )
 CHARACTER(LEN=*), INTENT(OUT) :: VAL(:)
 CHARACTER(LEN=*), INTENT(IN) :: SVAL
!
 INTEGER(KIND=JPIM) :: I, J, K, N

 N = LEN( SVAL )

 I = 1
 K = 1
 DO1 : DO 
   DO
     IF( I .GT. N ) EXIT DO1
     IF( SVAL(I:I) .NE. ' ' ) EXIT
     I = I + 1
   ENDDO
   J = I
   DO
     IF( J .GT. N ) EXIT 
     IF( SVAL(J:J) .EQ. ' ' ) EXIT
     J = J + 1
   ENDDO

   VAL(K) = SVAL(I:J-1)
   I = J
   K = K + 1
 ENDDO DO1


END SUBROUTINE READASLFROMSTRING

SUBROUTINE READSLFROMSTRING( VAL, SVAL )
 CHARACTER(LEN=*), POINTER :: VAL(:)
 CHARACTER(LEN=*), INTENT(IN) :: SVAL
!
 INTEGER(KIND=JPIM) :: N

 N = XRD_COUNTWORDS( SVAL )
 ALLOCATE( VAL( N ) )

 CALL READASLFROMSTRING( VAL, SVAL )

END SUBROUTINE READSLFROMSTRING

SUBROUTINE READSLFROMFILE( VAL, SVAL )
 CHARACTER(LEN=*), POINTER :: VAL(:)
 CHARACTER(LEN=*), INTENT(IN) :: SVAL
!
 INTEGER(KIND=JPIM) :: K, N
 INTEGER(KIND=JPIM) :: IOERR
 CHARACTER(LEN=4096) :: BUFFER

 OPEN( 77, FILE = TRIM(SVAL), FORM = 'FORMATTED', STATUS = 'OLD', IOSTAT = IOERR )
 IF( IOERR .NE. 0 ) THEN
   PRINT '( "COULD NOT OPEN ",A, " FOR READING")', TRIM(SVAL)
   CALL XRD_EXIT(1_JPIM)
 ENDIF
 N = 0_JPIM
 DO 
   READ( 77, '(A)', END = 500 ) BUFFER
   N = N + XRD_COUNTWORDS( BUFFER )
 ENDDO

 500 CONTINUE

 REWIND( 77 )

 ALLOCATE( VAL( N ) )
 
 K = 1
 DO 
   READ( 77, '(A)', END = 600 ) BUFFER
   N = XRD_COUNTWORDS( BUFFER )
   CALL READASLFROMSTRING( VAL(K:K+N-1), BUFFER )
   K = K + N
 ENDDO

 600 CONTINUE


 CLOSE( 77 )
 
END SUBROUTINE READSLFROMFILE

SUBROUTINE GETOPTIONSL( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*), INTENT(IN) :: KEY
 CHARACTER(LEN=*), POINTER :: VAL(:)
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 INTEGER(KIND=JPIM) :: I, J, K, N
 CHARACTER(LEN=ARGSIZEMAX) :: ARG
 CHARACTER(LEN=ARGSIZEMAX) :: SVAL
 LOGICAL(KIND=JPIM) :: LSHELL1
 LOGICAL(KIND=JPIM) :: FOUND

 LSHELL1 = LSHELL
 
 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'STRING-LIST', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'STRING-LIST', MND, USE )
 ENDIF
 
 CALL FINDARGINDEX( KEY, I, N )

 FOUND = I >= 0

 IF( FOUND ) THEN

   CALL FINDNEXTARGINDEX( I, J )

   ALLOCATE( VAL( J - I - 1 ) )
   
   IF( ASSOCIATED( CHECK_ARGS ) ) &
     CHECK_ARGS(I) = .TRUE.
   
   DO K = I+1, J-1
     IF( ASSOCIATED( CHECK_ARGS ) ) &
       CHECK_ARGS(K)   = .TRUE.
     CALL MYGETARG( K, ARG )
     IF ((I+1.EQ.J-1) .AND. (ARG(1:7).EQ.'file://')) THEN
       DEALLOCATE (VAL)
       ARG = ARG(8:)
       CALL READSLFROMFILE( VAL, ARG )
     ELSE
       VAL(K-I) = ARG
     ENDIF
   ENDDO

 ENDIF
 
 IF(.NOT. FOUND) THEN
   SVAL = GET_ENV_OPT( KEY )
   FOUND = SVAL .NE. ""
   IF( FOUND ) &
     CALL READSLFROMSTRING( VAL, SVAL )
 ENDIF

 IF( .NOT. FOUND ) &
   CALL CHECK_MND( KEY, MND, USE )

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONSL

SUBROUTINE GETOPTIONIL( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),      INTENT(IN) :: KEY
 INTEGER(KIND=JPIM), POINTER    :: VAL(:)
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX), POINTER :: SVAL(:)
 INTEGER(KIND=JPIM) :: I, N
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 NULLIFY (SVAL)

 LSHELL1 = LSHELL

 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'INTEGER-LIST', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'INTEGER-LIST', MND, USE )
 ENDIF
 
 CALL GETOPTIONSL( KEY, SVAL, MND, USE )

 IF( .NOT. ASSOCIATED( SVAL ) ) GOTO 999

 N = SIZE( SVAL )
 ALLOCATE( VAL( N ) )
 DO I = 1, N
   READ( SVAL( I ), *, IOSTAT = ERR ) VAL( I )
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDDO

 DEALLOCATE( SVAL )

999 CONTINUE
 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONIL

SUBROUTINE GETOPTIONR4L( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),   INTENT(IN) :: KEY
 REAL(KIND=JPRM), POINTER    :: VAL(:)
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX), POINTER :: SVAL(:)
 INTEGER(KIND=JPIM) :: I, N
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 NULLIFY (SVAL)

 LSHELL1 = LSHELL

 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'REAL-LIST', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'REAL-LIST', MND, USE )
 ENDIF
 
 CALL GETOPTIONSL( KEY, SVAL, MND, USE )

 IF( .NOT. ASSOCIATED( SVAL ) ) GOTO 999

 N = SIZE( SVAL )
 ALLOCATE( VAL( N ) )
 DO I = 1, N
   READ( SVAL( I ), *, IOSTAT = ERR ) VAL( I )
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDDO

 DEALLOCATE( SVAL )

999 CONTINUE
 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONR4L

SUBROUTINE GETOPTIONR8L( KEY, VAL, MND, USE )
!
 CHARACTER(LEN=*),   INTENT(IN) :: KEY
 REAL(KIND=JPRD), POINTER    :: VAL(:)
 LOGICAL(KIND=JPIM), OPTIONAL, INTENT(IN) :: MND
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 CHARACTER(LEN=ARGSIZEMAX), POINTER :: SVAL(:)
 INTEGER(KIND=JPIM) :: I, N
 INTEGER :: ERR
 LOGICAL(KIND=JPIM) :: LSHELL1

 NULLIFY (SVAL)

 LSHELL1 = LSHELL

 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'REAL-LIST', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'REAL-LIST', MND, USE )
 ENDIF
 
 CALL GETOPTIONSL( KEY, SVAL, MND, USE )

 IF( .NOT. ASSOCIATED( SVAL ) ) GOTO 999

 N = SIZE( SVAL )
 ALLOCATE( VAL( N ) )
 DO I = 1, N
   READ( SVAL( I ), *, IOSTAT = ERR ) VAL( I )
   IF( ERR .NE. 0 ) THEN
     PRINT *, "ERROR WHILE PARSING OPTION "//TRIM(KEY)
     CALL XRD_EXIT(1_JPIM)
   ENDIF
 ENDDO

 DEALLOCATE( SVAL )

999 CONTINUE
 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONR8L

SUBROUTINE GETOPTIONB( KEY, VAL, USE )
!
 CHARACTER(LEN=*), INTENT(IN)  :: KEY
 LOGICAL(KIND=JPIM), INTENT(INOUT) :: VAL
 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: USE
!
 LOGICAL(KIND=JPIM) :: LSHELL1
 LOGICAL(KIND=JPIM) :: FOUND
 CHARACTER(LEN=ARGSIZEMAX) :: SVAL
 INTEGER(KIND=JPIM) :: I, N
 
 LSHELL1 = LSHELL

 VAL = .FALSE.

 IF( LHELP ) THEN
   CALL ADDOPT( KEY, 'FLAG', USE )
   RETURN
 ELSE IF( LSHELL ) THEN
   LSHELL = .FALSE.
   CALL ADDOPT_SHELL( KEY, 'FLAG', .FALSE._JPIM, USE )
 ENDIF
 
 CALL FINDARGINDEX( KEY, I, N )
 FOUND = I > 0
 IF( FOUND .AND. ASSOCIATED( CHECK_ARGS ) ) THEN
   CHECK_ARGS(I)   = .TRUE.
   VAL = .TRUE.
 ELSE
   SVAL = GET_ENV_OPT( KEY )
   IF( SVAL .NE. "" ) &
     READ( SVAL, * ) VAL
 ENDIF

 LSHELL = LSHELL1

END SUBROUTINE GETOPTIONB

END MODULE XRD_GETOPTIONS
