pop_char Subroutine

private subroutine pop_char(json, unit, str, skip_ws, skip_comments, eof, popped)

Get the next character from the file (or string).

See also

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) – only used if unit=0

logical(kind=LK), intent(in), optional :: skip_ws

to ignore whitespace [default False]

logical(kind=LK), intent(in), optional :: skip_comments

to ignore comment lines [default False]

logical(kind=LK), intent(out) :: eof

true if the end of the file has been reached.

character(kind=CK,len=1), intent(out) :: popped

the popped character returned


Contents

Source Code


Source Code

    subroutine pop_char(json,unit,str,skip_ws,skip_comments,eof,popped)

    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) -- only used if `unit=0`
    logical(LK),intent(in),optional      :: skip_ws       !! to ignore whitespace [default False]
    logical(LK),intent(in),optional      :: skip_comments !! to ignore comment lines [default False]
    logical(LK),intent(out)              :: eof           !! true if the end of the file has
                                                          !! been reached.
    character(kind=CK,len=1),intent(out) :: popped        !! the popped character returned

    integer(IK)              :: ios             !! `iostat` flag
    integer(IK)              :: str_len         !! length of `str`
    character(kind=CK,len=1) :: c               !! a character read from the file (or string)
    logical(LK)              :: ignore          !! if whitespace is to be ignored
    logical(LK)              :: ignore_comments !! if comment lines are to be ignored
    logical(LK)              :: parsing_comment !! if we are in the process
                                                !! of parsing a comment line

    if (.not. json%exception_thrown) then

        eof = .false.
        if (.not. present(skip_ws)) then
            ignore = .false.
        else
            ignore = skip_ws
        end if
        parsing_comment = .false.
        if (.not. present(skip_comments)) then
            ignore_comments = .false.
        else
            ignore_comments = skip_comments
        end if

        do

            if (json%pushed_index > 0) then

                ! there is a character pushed back on, most likely
                ! from the number parsing. Note: this can only occur if
                ! reading from a file when use_unformatted_stream=.false.
                c = json%pushed_char(json%pushed_index:json%pushed_index)
                json%pushed_index = json%pushed_index - 1

            else

                if (unit/=0) then    !read from the file

                    !read the next character:
                    if (use_unformatted_stream) then

                        ! in this case, we read the file in chunks.
                        ! if we already have the character we need,
                        ! then get it from the chunk. Otherwise,
                        ! read in another chunk.
                        if (json%ichunk<1) then
                            ! read in a chunk:
                            json%ichunk = 0
                            if (json%filesize<json%ipos+len(json%chunk)-1) then
                                ! for the last chunk, we resize
                                ! it to the correct size:
                                json%chunk = repeat(space, json%filesize-json%ipos+1)
                            end if
                            read(unit=unit,pos=json%ipos,iostat=ios) json%chunk
                        else
                            ios = 0
                        end if
                        json%ichunk = json%ichunk + 1
                        if (json%ichunk>len(json%chunk)) then
                            ! check this just in case
                            ios = IOSTAT_END
                        else
                            ! get the next character from the chunk:
                            c = json%chunk(json%ichunk:json%ichunk)
                            if (json%ichunk==len(json%chunk)) then
                                json%ichunk = 0 ! reset for next chunk
                            end if
                        end if

                    else
                        ! a formatted read:
                        read(unit=unit,fmt='(A1)',advance='NO',iostat=ios) c
                    end if
                    json%ipos = json%ipos + 1

                else    !read from the string

                    str_len = len(str)   !length of the string
                    if (json%ipos<=str_len) then
                        c = str(json%ipos:json%ipos)
                        ios = 0
                    else
                        ios = IOSTAT_END  !end of the string
                    end if
                    json%ipos = json%ipos + 1

                end if

                json%char_count = json%char_count + 1    !character count in the current line

                if (IS_IOSTAT_END(ios)) then  !end of file

                    ! no character to return
                    json%char_count = 0
                    eof = .true.
                    popped = space ! just to set a value
                    exit

                else if (IS_IOSTAT_EOR(ios) .or. c==newline) then    !end of record

                    json%char_count = 0
                    json%line_count = json%line_count + 1
                    if (ignore_comments) parsing_comment = .false. ! done parsing this comment line
                    cycle

                end if

            end if

            if (ignore_comments .and. (parsing_comment .or. scan(c,json%comment_char,kind=IK)>0_IK) ) then

                ! skipping the comment
                parsing_comment = .true.
                cycle

            else if (any(c == control_chars)) then

                ! non printing ascii characters
                cycle

            else if (ignore .and. c == space) then

                ! ignoring whitespace
                cycle

            else

                ! return the character
                popped = c
                exit

            end if

        end do

    end if

    end subroutine pop_char