MODULE NFSTR
!
!   NAME:       NFSTR                                      
!   STATUS:     Ver. 1.0                                              
!   PURPOSE:    character utility routines              
!   LIBRARY:    MATH                                                  
!   TYPE:       SINGLE, DOUBLE PRECISION                              
!   AUTHOR:     Shigeru Inagaki                                       
!               National Institute for Fusion Science                 
!               +81-572-58-2143                                       
!               inagaki@LHD.nifs.ac.jp                                
!                                                                     
!   DESCRIPTION:                                                      
!     Character operaters are packaged.  
!                                                                     
!   SEE ALSO:                                           
!   CALLED:                                                            
!   REVISION HISTORY:                                                 
!     01-JUL-2004 (CREATION)                                          
!   COMMENTS:                                                         
!              
  USE NFNUM_KINDS, ONLY : i4b, sp, dp, lgt
!
  IMPLICIT NONE
!
  PRIVATE
!
  INTEGER(i4b), PARAMETER :: strsplit_length = 64
!
  INTERFACE TOSTR
    MODULE PROCEDURE INTTOSTR, FLTTOSTR, DBLTOSTR
  END INTERFACE
!
  PUBLIC :: strsplit_length
  PUBLIC :: ADDNULL
  PUBLIC :: TOINT, TOFLT, TODBL, TOSTR
  PUBLIC :: TOLOWER, TOUPPER, DELCHAR, STRCOUNT, STRSPLIT, STRSPLIT_TO_VEC, STRREPLACE
  PUBLIC :: ISDIGIT, ISREAL
!
CONTAINS
!
!-------------------------------------------------------
!
FUNCTION ADDNULL(fstr) RESULT(cstr)
! 
! Add NULL-character for C-wrapper routines
! 
  CHARACTER(LEN=*), INTENT(IN) :: fstr
  CHARACTER(LEN=LEN_TRIM(fstr)+1) :: cstr
!
  cstr = TRIM(fstr)//CHAR(0)
  RETURN
END FUNCTION ADDNULL 
!
!-------------------------------------------------------
!
FUNCTION TOLOWER(str)
!
! Translate all uppercase characters in STR to their equivalent
! lowercase counterpart. Non-alphabetic characters are not
! altered.
!
  CHARACTER(LEN=*), INTENT(IN) :: str
  CHARACTER(LEN=LEN_TRIM(str)) :: TOLOWER
!
  INTEGER(i4b) :: i, ilen, idx
!
  ilen = LEN_TRIM(str)
  DO i = 1, ilen
    idx = ICHAR(str(i:i))
    IF (65 <= idx .AND. idx <= 90) THEN
      TOLOWER(i:i) = CHAR(idx+32)
    ELSE
      TOLOWER(i:i) = str(i:i)
    ENDIF
  ENDDO
  RETURN
END FUNCTION TOLOWER
!
!-------------------------------------------------------
!
FUNCTION TOUPPER(str)
!
! Translate all lowercase characters in STR to their equivalent
! uppercase counterpart. Non-alphabetic characters are not
! altered.
!
  CHARACTER(LEN=*), INTENT(IN) :: str
  CHARACTER(LEN=LEN_TRIM(str)) :: TOUPPER
!
  INTEGER(i4b) :: i, ilen, idx
!
 ilen = LEN_TRIM(str)
 DO i = 1, ilen
   idx = ICHAR(str(i:i))
   IF (97 <= idx .AND. idx <= 122) THEN
     TOUPPER(i:i) = CHAR(idx-32)
   ELSE
     TOUPPER(i:i) = str(i:i)
   ENDIF
  ENDDO
  RETURN
END FUNCTION TOUPPER
!
!-------------------------------------------------------
!
SUBROUTINE DELCHAR(str, char)
  CHARACTER(LEN=*), INTENT(INOUT) :: str
  CHARACTER(LEN=1), INTENT(IN)    :: char  
!
  CHARACTER(LEN=LEN_TRIM(str)) :: buf
  INTEGER(i4b) :: ilen, i, j
!
  ilen = LEN_TRIM(str)
  j = 0
  DO i = 1, ilen
    IF (str(i:i) /= char) THEN
      j = j + 1
      buf(j:j) = str(i:i)
    ENDIF
  ENDDO
  str = buf(1:j)
  RETURN
END SUBROUTINE DELCHAR  
!
!-------------------------------------------------------
!
SUBROUTINE STRSPLIT_TO_VEC(str, vec, delim)
!
  CHARACTER(LEN=*), INTENT(IN)  :: str
  CHARACTER(LEN=*), INTENT(OUT) :: vec(:)
  CHARACTER(LEN=1), OPTIONAL, INTENT(IN) :: delim
!
  CHARACTER(LEN=1) :: ch
  INTEGER(i4b) :: n, ilen, i, is, ie
!
  IF (PRESENT(delim)) THEN
    ch = delim
  ELSE
    ch = ','
  ENDIF
  n = SIZE(vec)
  IF (n == 0) THEN
    RETURN
  ENDIF
!
  is = 1
  ilen = LEN_TRIM(str)
  IF (n == 1) THEN
    vec(n) = str(is:ilen)
    RETURN
  ENDIF
  DO i = 1, n-1
    ie = INDEX(str(is:ilen), ch) - 1 + is - 1
    IF (ie >= is) THEN
      vec(i) = str(is:ie)
    ELSE
      vec(i) = ''
    ENDIF
    is = ie + 2
  ENDDO
  vec(n) = str(is:ilen)
  RETURN
END SUBROUTINE STRSPLIT_TO_VEC
!
!-------------------------------------------------------
!
FUNCTION STRSPLIT(str, delim) RESULT(vec)
!
  CHARACTER(LEN=*), INTENT(IN) :: str
  CHARACTER(LEN=1), OPTIONAL, INTENT(IN) :: delim
  CHARACTER(LEN=strsplit_length), POINTER :: vec(:)
!
  CHARACTER(LEN=1) :: ch
  INTEGER(i4b) :: istat, n, ilen, i, is, ie
!
  IF (PRESENT(delim)) THEN
    ch = delim
  ELSE
    ch = ','
  ENDIF
  n = STRCOUNT(str, ch) + 1
  ALLOCATE(vec(n), STAT=istat)
  IF (istat /= 0) THEN
    RETURN
  ENDIF
!
  is = 1
  ilen = LEN_TRIM(str)
  IF (n == 1) THEN
    vec(n) = str(is:ilen)
    RETURN
  ENDIF
  DO i = 1, n-1
    ie = INDEX(str(is:ilen), ch) - 1 + is - 1
    IF (ie >= is) THEN
      vec(i) = str(is:ie)
    ELSE
      vec(i) = ''
    ENDIF
    is = ie + 2
  ENDDO
  vec(n) = str(is:ilen)
  RETURN
END FUNCTION STRSPLIT
!
!-------------------------------------------------------
!
FUNCTION STRCOUNT(string, char)
!
! Return numbers of appearance of char in string
!
  CHARACTER(LEN=*), INTENT(IN) :: string
  CHARACTER(LEN=1), INTENT(IN) :: char
  INTEGER(i4b) :: STRCOUNT
!
  INTEGER(i4b) :: i, ilen
!
  STRCOUNT = 0
  ilen = LEN_TRIM(string)
  IF (ilen == 0) THEN
    RETURN
  ENDIF
  DO i = 1, ilen
    IF (string(i:i) == char) THEN
      STRCOUNT = STRCOUNT + 1
    ENDIF
  ENDDO
  RETURN
END FUNCTION STRCOUNT
!
!-------------------------------------------------------
!
FUNCTION STRREPLACE(string, target, change) RESULT(ierr)
!
! Replace target in string to change.
! If target is not changed, 1 is returned. 
!  
  CHARACTER(LEN=*), INTENT(INOUT) :: string
  CHARACTER(LEN=*), INTENT(IN)    :: target
  CHARACTER(LEN=*), INTENT(IN)    :: change
  INTEGER(i4b) :: ierr
!
  INTEGER(i4b) :: ipos
  INTEGER(i4b) :: ilen_string, ilen_target, ilen_change
!
  ilen_string = LEN_TRIM(string)
  ilen_target = LEN_TRIM(target)
  ilen_change = LEN_TRIM(change)
  IF (ilen_string*ilen_target*ilen_change == 0) THEN
    ierr = 1
    RETURN
  ENDIF
  ipos = INDEX(string, TRIM(target))
  IF (ipos == 0) THEN
    ierr = 1
    RETURN
  ENDIF
  string = string(1:ipos-1)//TRIM(change)//TRIM(string(ipos+ilen_target:)) 
  IF (ilen_string + ilen_target + ilen_change > LEN(string)) THEN
    ierr = 2
  ELSE
    ierr = 0
  ENDIF
  RETURN
END FUNCTION STRREPLACE  
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION TOINT(str) RESULT(num)
  CHARACTER(LEN=*), INTENT(IN) :: str
  INTEGER(i4b) :: num
!
  READ(str,*) num
  RETURN
END FUNCTION TOINT
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION TOFLT(str) RESULT(num)
  CHARACTER(LEN=*), INTENT(IN) :: str
  REAL(sp) :: num
!
  READ(str,*) num
  RETURN
END FUNCTION TOFLT
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION TODBL(str) RESULT(num)
  CHARACTER(LEN=*), INTENT(IN) :: str
  REAL(dp) :: num
!
  READ(str,*) num
  RETURN
END FUNCTION TODBL
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION INTTOSTR(num, fmt) RESULT(str)
  INTEGER(i4b),               INTENT(IN) :: num
  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt
  CHARACTER(LEN=11) :: str
!
  IF (PRESENT(fmt)) THEN
    WRITE(str, TRIM(fmt)) num
  ELSE
    WRITE(str,*) num
  ENDIF
  str = ADJUSTL(str)
  RETURN
END FUNCTION INTTOSTR
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION FLTTOSTR(num, fmt) RESULT(str)
  REAL(sp),                   INTENT(IN) :: num
  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt
  CHARACTER(LEN=13) :: str
!
  IF (PRESENT(fmt)) THEN
    WRITE(str, TRIM(fmt)) num
  ELSE
    WRITE(str,*) num
  ENDIF
  str = ADJUSTL(str)
  RETURN
END FUNCTION FLTTOSTR
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION DBLTOSTR(num, fmt) RESULT(str)
  REAL(dp),                   INTENT(IN) :: num
  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt
  CHARACTER(LEN=22) :: str
!
  IF (PRESENT(fmt)) THEN
    WRITE(str, fmt) num
  ELSE
    WRITE(str,*) num
  ENDIF
  str = ADJUSTL(str)
  RETURN
END FUNCTION DBLTOSTR
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION ISDIGIT(str) RESULT(stat)
  CHARACTER(LEN=*), INTENT(IN) :: str
  LOGICAL(lgt) :: stat
!
  IF (LEN_TRIM(str) == 0) THEN
    stat = .FALSE.
    RETURN
  ENDIF
  IF (VERIFY(str, "+-0123456789") /= 0) THEN
   stat = .FALSE.
  ELSE
   stat = .TRUE.
  ENDIF
  RETURN
END FUNCTION ISDIGIT  
!
!-------------------------------------------------------
!
ELEMENTAL FUNCTION ISREAL(str) RESULT(stat)
  CHARACTER(LEN=*), INTENT(IN) :: str
  LOGICAL(lgt) :: stat
!
  IF (LEN_TRIM(str) == 0) THEN
    stat = .FALSE.
    RETURN
  ENDIF
  IF (VERIFY(str, "+-0123456789.EDed") /= 0) THEN
   stat = .FALSE.
  ELSE
   stat = .TRUE.
  ENDIF
  RETURN
END FUNCTION ISREAL
!
END MODULE NFSTR
