Read a numerical value from the file (or string). The routine will determine if it is an integer or a real, and allocate the type accordingly.
Note
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=:),allocatable :: saved_err_message !! temp error message for !! string to int conversion 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 = blank_chunk 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) 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 // blank_chunk tmp(ip:ip) = c ip = ip + 1 case(CK_'.',CK_'E',CK_'e',CK_'D',CK_'d') !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 // blank_chunk 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 // blank_chunk 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 ! it is an integer: ival = json%string_to_int(tmp) if (json%exception_thrown .and. .not. json%strict_integer_type_checking) then ! if it couldn't be converted to an integer, ! then try to convert it to a real value and see if that works saved_err_message = json%err_message ! keep the original error message call json%clear_exceptions() ! clear exceptions rval = json%string_to_dble(tmp) if (json%exception_thrown) then ! restore original error message and continue json%err_message = saved_err_message call json%to_integer(value,ival) ! just so we have something else ! in this case, we return a real call json%to_real(value,rval) end if else call json%to_integer(value,ival) end if else ! it is a real: rval = json%string_to_dble(tmp) call json%to_real(value,rval) end if exit !finished end select if (first) first = .false. end do !cleanup: if (allocated(tmp)) deallocate(tmp) end if end subroutine parse_number