Skip to content

Commit c3e4816

Browse files
authored
Addition of checks and use of stdlib_experimental_ascii (#82)
* parse_mode: addition of conditionals for checking wrong modes * stblib_experimental_io: addition of an io variable in the open function * stdlib_experimental_io: changed whitechar for is_blank provided by stdlib_experimental_ascii * correction of a typo * changed lastwhite to lastblank (proposed by @ivan-pi) * changes suggested by @certik * added 1 io in test_open
1 parent a6af72c commit c3e4816

File tree

3 files changed

+81
-36
lines changed

3 files changed

+81
-36
lines changed

src/stdlib_experimental_io.f90

+38-31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module stdlib_experimental_io
22
use stdlib_experimental_kinds, only: sp, dp, qp
33
use stdlib_experimental_error, only: error_stop
44
use stdlib_experimental_optval, only: optval
5+
use stdlib_experimental_ascii, only: is_blank
56
implicit none
67
private
78
! Public API
@@ -231,16 +232,16 @@ integer function number_of_columns(s)
231232

232233
integer :: ios
233234
character :: c
234-
logical :: lastwhite
235+
logical :: lastblank
235236

236237
rewind(s)
237238
number_of_columns = 0
238-
lastwhite = .true.
239+
lastblank = .true.
239240
do
240241
read(s, '(a)', advance='no', iostat=ios) c
241242
if (ios /= 0) exit
242-
if (lastwhite .and. .not. whitechar(c)) number_of_columns = number_of_columns + 1
243-
lastwhite = whitechar(c)
243+
if (lastblank .and. .not. is_blank(c)) number_of_columns = number_of_columns + 1
244+
lastblank = is_blank(c)
244245
end do
245246
rewind(s)
246247

@@ -265,17 +266,7 @@ integer function number_of_rows_numeric(s)
265266

266267
end function
267268

268-
pure logical function whitechar(char) ! white character
269-
! returns .true. if char is space (32) or tab (9), .false. otherwise
270-
character, intent(in) :: char
271-
if (iachar(char) == 32 .or. iachar(char) == 9) then
272-
whitechar = .true.
273-
else
274-
whitechar = .false.
275-
end if
276-
end function
277-
278-
integer function open(filename, mode) result(u)
269+
integer function open(filename, mode, iostat) result(u)
279270
! Open a file
280271
!
281272
! To open a file to read:
@@ -293,8 +284,10 @@ integer function open(filename, mode) result(u)
293284

294285
character(*), intent(in) :: filename
295286
character(*), intent(in), optional :: mode
296-
integer :: io
297-
character(3):: mode_
287+
integer, intent(out), optional :: iostat
288+
289+
integer :: io_
290+
character(3) :: mode_
298291
character(:),allocatable :: action_, position_, status_, access_, form_
299292

300293

@@ -348,37 +341,51 @@ integer function open(filename, mode) result(u)
348341
call error_stop("Unsupported mode: "//mode_(3:3))
349342
end select
350343

351-
open(newunit=u, file=filename, &
352-
action = action_, position = position_, status = status_, &
353-
access = access_, form = form_, &
354-
iostat = io)
344+
if (present(iostat)) then
345+
open(newunit=u, file=filename, &
346+
action = action_, position = position_, status = status_, &
347+
access = access_, form = form_, &
348+
iostat = iostat)
349+
else
350+
open(newunit=u, file=filename, &
351+
action = action_, position = position_, status = status_, &
352+
access = access_, form = form_)
353+
end if
355354

356355
end function
357356

358357
character(3) function parse_mode(mode) result(mode_)
359358
character(*), intent(in) :: mode
360359

361-
integer::i
362-
character(:),allocatable::a
360+
integer :: i
361+
character(:),allocatable :: a
362+
logical :: lfirst(3)
363363

364364
mode_ = 'r t'
365365

366366
if (len_trim(mode) == 0) return
367367
a=trim(adjustl(mode))
368368

369+
lfirst = .true.
369370
do i=1,len(a)
370-
select case (a(i:i))
371-
case('r', 'w', 'a', 'x')
371+
if (lfirst(1) &
372+
.and. (a(i:i) == 'r' .or. a(i:i) == 'w' .or. a(i:i) == 'a' .or. a(i:i) == 'x') &
373+
) then
372374
mode_(1:1) = a(i:i)
373-
case('+')
375+
lfirst(1)=.false.
376+
else if (lfirst(2) .and. a(i:i) == '+') then
374377
mode_(2:2) = a(i:i)
375-
case('t', 'b')
378+
lfirst(2)=.false.
379+
else if (lfirst(3) .and. (a(i:i) == 't' .or. a(i:i) == 'b')) then
376380
mode_(3:3) = a(i:i)
377-
case(' ')
378-
cycle
379-
case default
381+
lfirst(3)=.false.
382+
else if (a(i:i) == ' ') then
383+
cycle
384+
else if(any(.not.lfirst)) then
385+
call error_stop("Wrong mode: "//trim(a))
386+
else
380387
call error_stop("Wrong character: "//a(i:i))
381-
end select
388+
endif
382389
end do
383390

384391
end function

src/tests/io/test_open.f90

+24-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ program test_open
44
implicit none
55

66
character(:), allocatable :: filename
7-
integer :: u, a(3)
8-
7+
integer :: io, u, a(3)
98

109
! Text file
1110
filename = get_outpath() // "/io_open.dat"
@@ -59,6 +58,29 @@ program test_open
5958
call assert(all(a == [4, 5, 6]))
6059
close(u)
6160

61+
62+
63+
!0 and non-0 open
64+
filename = get_outpath() // "/io_open.stream"
65+
66+
u = open(filename, "rb", io)
67+
call assert(io == 0)
68+
if (io == 0) close(u)
69+
70+
u = open(filename, "ab", io)
71+
call assert(io == 0)
72+
if (io == 0) close(u)
73+
74+
75+
filename = get_outpath() // "/does_not_exist.error"
76+
77+
u = open(filename, "a", io)
78+
call assert(io /= 0)
79+
80+
u = open(filename, "r", io)
81+
call assert(io /= 0)
82+
83+
6284
contains
6385

6486
function get_outpath() result(outpath)

src/tests/io/test_parse_mode.f90

+19-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ program test_parse_mode
99

1010
call test_parse_mode_random_order()
1111

12+
!call test_parse_mode_always_fail()
13+
1214
contains
1315

1416
subroutine test_parse_mode_expected_order()
@@ -149,16 +151,16 @@ subroutine test_parse_mode_random_order()
149151

150152
m = parse_mode("tr+ ")
151153
call assert(m == "r+t")
152-
m = parse_mode("wtt + ")
154+
m = parse_mode("wt + ")
153155
call assert(m == "w+t")
154156
m = parse_mode("a + t")
155157
call assert(m == "a+t")
156158
m = parse_mode(" xt + ")
157159
call assert(m == "x+t")
158160

159-
m = parse_mode("t + t")
161+
m = parse_mode(" + t")
160162
call assert(m == "r+t")
161-
m = parse_mode(" ww + b")
163+
m = parse_mode(" +w b")
162164
call assert(m == "w+b")
163165
m = parse_mode("a + b")
164166
call assert(m == "a+b")
@@ -167,5 +169,19 @@ subroutine test_parse_mode_random_order()
167169

168170
end subroutine
169171

172+
subroutine test_parse_mode_always_fail()
173+
character(3) :: m
174+
175+
m = parse_mode("r+w")
176+
call assert(m /= "r t")
177+
178+
m = parse_mode("tt")
179+
call assert(m /= "r t")
180+
181+
m = parse_mode("bt")
182+
call assert(m /= "r t")
183+
184+
end subroutine
185+
170186

171187
end program

0 commit comments

Comments
 (0)