parse_number Subroutine

private subroutine parse_number(json, unit, str, 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.

Arguments

Type IntentOptional AttributesName
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

Contents

Source Code


Source Code

    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