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.
Complete rewrite of the original FSON routine, which had some problems.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(json_core), | intent(inout) | :: | json | |||
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), | pointer | :: | value |
subroutine parse_number(json, unit, str, value)
implicit none
class(json_core),intent(inout) :: json
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 !! temp string
character(kind=CK,len=1) :: c !! character returned by [[pop_char]]
logical(LK) :: eof !! end of file flag
real(RK) :: rval !! real value
integer(IK) :: ival !! integer value
logical(LK) :: first !! first character
logical(LK) :: is_integer !! it is an integer
integer(IK) :: ip !! index to put next character
!! [to speed up by reducing the number
!! of character string reallocations]
if (.not. json%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:
call json%pop_char(unit, str=str, eof=eof, skip_ws=.true., popped=c)
if (eof) then
call json%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 json%push_char(c)
!string to value:
if (is_integer) then
ival = json%string_to_int(tmp)
call json%to_integer(value,ival)
else
rval = json%string_to_dble(tmp)
call json%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