Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer(kind=IK), | intent(in) | :: | unit | file unit number (if parsing from a file) |
||
character(kind=CK,len=*), | intent(in) | :: | str | JSON string (if parsing from a string) |
||
type(json_value), | intent(inout), | pointer | :: | value |
Read a numerical value from the file (or string). The routine will determine if it is an integer or a double, and allocate the type accordingly.
subroutine parse_number(unit, str, value)
implicit none
integer(IK),intent(in) :: unit !! file unit number (if parsing from a file)
character(kind=CK,len=*),intent(in) :: str !! JSON string (if parsing from a string)
type(json_value),pointer :: value
character(kind=CK,len=:),allocatable :: tmp
character(kind=CK,len=1) :: c
logical(LK) :: eof
real(RK) :: rval
integer(IK) :: ival
logical(LK) :: first
logical(LK) :: is_integer
!to speed up by reducing the number of character string reallocations:
integer(IK) :: ip !index to put next character
if (.not. exception_thrown) then
tmp = repeat(space, chunk_size)
ip = 1
first = .true.
is_integer = .true. !assume it may be an integer, unless otherwise determined
!read one character at a time and accumulate the string:
do
!get the next character:
c = pop_char(unit, str=str, eof = eof, skip_ws = .true.)
if (eof) then
call throw_exception('Error in parse_number:'//&
' Unexpected end of file while parsing number.')
return
else
select case (c)
case(CK_'-',CK_'+') !note: allowing a '+' as the first character here.
if (is_integer .and. (.not. first)) is_integer = .false.
!add it to the string:
!tmp = tmp // c !...original
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
tmp(ip:ip) = c
ip = ip + 1
case(CK_'.',CK_'E',CK_'e') !can be present in real numbers
if (is_integer) is_integer = .false.
!add it to the string:
!tmp = tmp // c !...original
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
tmp(ip:ip) = c
ip = ip + 1
case(CK_'0':CK_'9') !valid characters for numbers
!add it to the string:
!tmp = tmp // c !...original
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
tmp(ip:ip) = c
ip = ip + 1
case default
!push back the last character read:
call push_char(c)
!string to value:
if (is_integer) then
ival = string_to_integer(tmp)
call to_integer(value,ival)
else
rval = string_to_double(tmp)
call to_double(value,rval)
end if
exit !finished
end select
end if
if (first) first = .false.
end do
!cleanup:
if (allocated(tmp)) deallocate(tmp)
end if
end subroutine parse_number