Skip to content

Commit

Permalink
New utility function "isnum()"
Browse files Browse the repository at this point in the history
  • Loading branch information
haniibrahim committed Apr 10, 2022
1 parent a88cb9d commit ac83acc
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 4 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Parsing features:
* Parse short options without argumentss and they can be embraced (e.g.: -xv)
* Parse long option without argument (e.g: --longarg)
* Parse long option with argument (e.g.: --arg 5.0 or --arg=5.0)
* ***NEW*** Utility function checking numbers in option's arguments

## Requirements

Expand Down Expand Up @@ -104,9 +105,7 @@ Put `f90getopt.f90` and your sample program from above (let's say `f90getopt_sam
gfortran f90getopt.F90 f90getopt_sample.f90 -o f90getopt_sample
```

(you can omit `.exe` in `-o f90getopt_sample` on Windows)

to compile it.
(you can omit `.exe` in `-o f90getopt_sample` on Windows) to compile it. Be advised that the capital F90 in the file extention of f90getopt is mandatory.

### Run the sample program

Expand All @@ -131,6 +130,8 @@ Output is:
option beta/b=23.2
```

A complete sample program with all features is provided in the [Wiki](https://github.com/haniibrahim/f90getopt/wiki/Full-working-example)

## Changelog

| Version | Description |
Expand All @@ -141,6 +142,7 @@ Output is:
| 1.0.2 | Bug in README.md fixed |
| 1.0.3 | Bug in README.md (sample code section) fixed |
| 1.0.4 | Portable declaration of stdin/out/err fixed, minor refactoring and documentation, => GPL 3.0, Wiki page |
| 1.1.0 | New utility function "isnum()" checks for numbers in option's arguments, More sophisticated sample program in the Wiki |

## License

Expand Down
99 changes: 98 additions & 1 deletion f90getopt.F90
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ module f90getopt
! ------------------ Implicit -----------------------------------------------------------------------------------------------------
IMPLICIT NONE
! ------------------ Local declarations -------------------------------------------------------------------------------------------
PUBLIC :: getopt, option_s, optarg
PUBLIC :: getopt, option_s, optarg, isnum
PRIVATE ! all other are private (hidden)
! ------------------ Constant declarations ----------------------------------------------------------------------------------------

Expand Down Expand Up @@ -247,4 +247,101 @@ character function process_short( optstring, arg )
endif
end function process_short

! ----------------------------------------
! Utility function(s)
! ----------------------------------------

integer function isnum (txtval)
! Verify whether a character string represents a numerical value
!
! Can be used to check "optarg" for numbers. Can distinguish
! integer, real/double and character strings:
!
! isnum = 0 => txtval is a string
! isnum = 1 => txtval is a integer
! isnum > 1 => txtval is a real/double

character(len=*), intent(in) :: txtval

! Declaration local constants
integer, parameter :: CINT = 1 ! when txtval contains integer
integer, parameter :: CREAL = 2 ! when txtval contains real
integer, parameter :: CREXP = 3 ! when txtval contains real (exponential)

! Declaration local variables
integer :: num ! numerical indicator variable, if > 0 (0 >= num >= CREXP)
logical :: isint ! integer indicator, if .true.
logical :: isexp ! real with exponent indicator, if .true.
logical :: issign ! sign (+/-) indicator, if .true.
logical :: issignexp ! sign (+/-) indicator for exponents, if .true.
logical :: isblank ! indicator for blanks between characters
integer :: i ! control variable (index), max. len(txtvar)

! Initialize local variables
num = 0
isint = .false.
isexp = .false.
issign = .false.
issignexp = .false.
isblank = .false.
i = 0

! loop over characters
do
if (i >= len(txtval)) then
! last check
if (isint .eqv. .false.) exit
if (num >= CREXP .AND. (isexp .eqv. .false.)) exit
isnum = num
return
end if

i = i + 1

select case (txtval(i:i))
! process blanks
case (' ')
if (num == 0 .and. (isblank .eqv. .false.)) then ! preceding or trailing blanks
continue
else if (num /= 0) then ! blank after sign or number
isblank = .true.
end if
! process digits
case ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
if (num == 0) num = CINT ! first number
if (num < CREXP) then ! no exponent number
isint = .true.
else ! exponent number
isexp = .true.
end if
if (isblank .eqv. .true.) exit ! if blanks are in the middle => string
! process signs
case ('+', '-')
if (num == 0) then ! sign of number
if (issign .eqv. .true.) exit ! second sign without number => string
issign = .true.
num = CINT
else ! sign of exponent
if (num < CREXP) exit
if (issignexp .eqv. .true.) exit
issignexp = .true.
end if
! process decimal point
case ('.')
if (num /= CINT .AND. i /= 1) exit
num = CREAL
! process exponent
case ('e', 'E', 'd', 'D')
if (num >= CREXP) exit
if (isint .eqv. .false.) exit
num = CREXP
case DEFAULT ! any other character means the string is non-numeric
exit
end SELECT
end DO

isnum = 0 ! if this point is reached, the string is non-numeric
RETURN
end function isnum

end module f90getopt

0 comments on commit ac83acc

Please sign in to comment.