Get the next character from the file (or string).
This routine ignores non-printing ASCII characters
(iachar<=31
) that are in strings.
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) – only used if |
||
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 |
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. c == json%comment_char) ) 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