From ac61bf40224516a1d7ca846a7b9aa227d6c5093d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Thu, 2 Jan 2020 20:33:45 -0700 Subject: [PATCH 01/14] Implement open(filename, mode) and use it --- src/stdlib_experimental_io.f90 | 43 ++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index ed93c63e1..3623b8c01 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -1,8 +1,9 @@ module stdlib_experimental_io use iso_fortran_env, only: sp=>real32, dp=>real64, qp=>real128 +use stdlib_experimental_error, only: error_stop implicit none private -public :: loadtxt, savetxt +public :: loadtxt, savetxt, open interface loadtxt module procedure sloadtxt @@ -46,7 +47,7 @@ subroutine sloadtxt(filename, d) integer :: s integer :: nrow,ncol,i -open(newunit=s, file=filename, status="old", action="read") +s = open(filename) ! determine number of columns ncol = number_of_columns(s) @@ -89,7 +90,7 @@ subroutine dloadtxt(filename, d) integer :: s integer :: nrow,ncol,i -open(newunit=s, file=filename, status="old", action="read") +s = open(filename) ! determine number of columns ncol = number_of_columns(s) @@ -132,7 +133,7 @@ subroutine qloadtxt(filename, d) integer :: s integer :: nrow,ncol,i -open(newunit=s, file=filename, status="old", action="read") +s = open(filename) ! determine number of columns ncol = number_of_columns(s) @@ -164,7 +165,7 @@ subroutine ssavetxt(filename, d) ! call savetxt("log.txt", data) integer :: s, i -open(newunit=s, file=filename, status="replace", action="write") +s = open(filename, "w") do i = 1, size(d, 1) write(s, *) d(i, :) end do @@ -187,7 +188,7 @@ subroutine dsavetxt(filename, d) ! call savetxt("log.txt", data) integer :: s, i -open(newunit=s, file=filename, status="replace", action="write") +s = open(filename, "w") do i = 1, size(d, 1) write(s, *) d(i, :) end do @@ -210,7 +211,7 @@ subroutine qsavetxt(filename, d) ! call savetxt("log.txt", data) integer :: s, i -open(newunit=s, file=filename, status="replace", action="write") +s = open(filename, "w") do i = 1, size(d, 1) write(s, *) d(i, :) end do @@ -268,4 +269,32 @@ logical function whitechar(char) ! white character end if end function +integer function open(filename, mode) result(u) +! Open a file +! +! To open a file to read: +! +! u = open("somefile.txt") # The default `mode` is "r" +! u = open("somefile.txt", "r") +! +! To open a file to write: +! +! u = open("somefile.txt", "w") + +character(*), intent(in) :: filename +character(*), intent(in), optional :: mode +character(:), allocatable :: mode_ +mode_ = "r" +if (present(mode)) mode_ = mode +! Note: the Fortran standard says that the default values for `status` and +! `action` are processor dependent, so we have to explicitly set them below +if (mode_ == "r") then + open(newunit=u, file=filename, status="old", action="read") +else if (mode_ == "w") then + open(newunit=u, file=filename, status="replace", action="write") +else + call error_stop("Unsupported mode") +end if +end function + end module From c8a3fcaa7d78e7e3cfefa5c2a024246d1a824875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Thu, 2 Jan 2020 21:26:37 -0700 Subject: [PATCH 02/14] Implement mode="a" --- src/stdlib_experimental_io.f90 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index 3623b8c01..778dc5d67 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -281,6 +281,10 @@ integer function open(filename, mode) result(u) ! ! u = open("somefile.txt", "w") +! To append to the end of the file if it exists: +! +! u = open("somefile.txt", "a") + character(*), intent(in) :: filename character(*), intent(in), optional :: mode character(:), allocatable :: mode_ @@ -292,6 +296,9 @@ integer function open(filename, mode) result(u) open(newunit=u, file=filename, status="old", action="read") else if (mode_ == "w") then open(newunit=u, file=filename, status="replace", action="write") +else if (mode_ == "a") then + open(newunit=u, file=filename, position="append", status="old", & + action="write") else call error_stop("Unsupported mode") end if From d2d3bfa9cb81018a32e1205e7f1bcc7bef83e095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Fri, 3 Jan 2020 09:04:39 -0700 Subject: [PATCH 03/14] Rename loadtxt test directory to io --- src/tests/CMakeLists.txt | 2 +- src/tests/Makefile.manual | 8 ++++---- src/tests/{loadtxt => io}/CMakeLists.txt | 0 src/tests/{loadtxt => io}/Makefile.manual | 0 src/tests/{loadtxt => io}/array1.dat | 0 src/tests/{loadtxt => io}/array2.dat | 0 src/tests/{loadtxt => io}/array3.dat | 0 src/tests/{loadtxt => io}/array4.dat | 0 src/tests/{loadtxt => io}/test_loadtxt.f90 | 0 src/tests/{loadtxt => io}/test_loadtxt_qp.f90 | 0 src/tests/{loadtxt => io}/test_savetxt.f90 | 0 src/tests/{loadtxt => io}/test_savetxt_qp.f90 | 0 12 files changed, 5 insertions(+), 5 deletions(-) rename src/tests/{loadtxt => io}/CMakeLists.txt (100%) rename src/tests/{loadtxt => io}/Makefile.manual (100%) rename src/tests/{loadtxt => io}/array1.dat (100%) rename src/tests/{loadtxt => io}/array2.dat (100%) rename src/tests/{loadtxt => io}/array3.dat (100%) rename src/tests/{loadtxt => io}/array4.dat (100%) rename src/tests/{loadtxt => io}/test_loadtxt.f90 (100%) rename src/tests/{loadtxt => io}/test_loadtxt_qp.f90 (100%) rename src/tests/{loadtxt => io}/test_savetxt.f90 (100%) rename src/tests/{loadtxt => io}/test_savetxt_qp.f90 (100%) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 7ba8c4a4f..a8ac32b8e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(ascii) -add_subdirectory(loadtxt) +add_subdirectory(io) diff --git a/src/tests/Makefile.manual b/src/tests/Makefile.manual index 2669a98f8..73d0db113 100644 --- a/src/tests/Makefile.manual +++ b/src/tests/Makefile.manual @@ -1,13 +1,13 @@ .PHONY: all clean -all: ascii/test_ascii loadtxt/test_loadtxt +all: ascii/test_ascii io/test_loadtxt ascii/test_ascii: $(MAKE) -f Makefile.manual --directory=ascii -loadtxt/test_loadtxt: - $(MAKE) -f Makefile.manual --directory=loadtxt +io/test_loadtxt: + $(MAKE) -f Makefile.manual --directory=io clean: $(MAKE) -f Makefile.manual --directory=ascii clean - $(MAKE) -f Makefile.manual --directory=loadtxt clean + $(MAKE) -f Makefile.manual --directory=io clean diff --git a/src/tests/loadtxt/CMakeLists.txt b/src/tests/io/CMakeLists.txt similarity index 100% rename from src/tests/loadtxt/CMakeLists.txt rename to src/tests/io/CMakeLists.txt diff --git a/src/tests/loadtxt/Makefile.manual b/src/tests/io/Makefile.manual similarity index 100% rename from src/tests/loadtxt/Makefile.manual rename to src/tests/io/Makefile.manual diff --git a/src/tests/loadtxt/array1.dat b/src/tests/io/array1.dat similarity index 100% rename from src/tests/loadtxt/array1.dat rename to src/tests/io/array1.dat diff --git a/src/tests/loadtxt/array2.dat b/src/tests/io/array2.dat similarity index 100% rename from src/tests/loadtxt/array2.dat rename to src/tests/io/array2.dat diff --git a/src/tests/loadtxt/array3.dat b/src/tests/io/array3.dat similarity index 100% rename from src/tests/loadtxt/array3.dat rename to src/tests/io/array3.dat diff --git a/src/tests/loadtxt/array4.dat b/src/tests/io/array4.dat similarity index 100% rename from src/tests/loadtxt/array4.dat rename to src/tests/io/array4.dat diff --git a/src/tests/loadtxt/test_loadtxt.f90 b/src/tests/io/test_loadtxt.f90 similarity index 100% rename from src/tests/loadtxt/test_loadtxt.f90 rename to src/tests/io/test_loadtxt.f90 diff --git a/src/tests/loadtxt/test_loadtxt_qp.f90 b/src/tests/io/test_loadtxt_qp.f90 similarity index 100% rename from src/tests/loadtxt/test_loadtxt_qp.f90 rename to src/tests/io/test_loadtxt_qp.f90 diff --git a/src/tests/loadtxt/test_savetxt.f90 b/src/tests/io/test_savetxt.f90 similarity index 100% rename from src/tests/loadtxt/test_savetxt.f90 rename to src/tests/io/test_savetxt.f90 diff --git a/src/tests/loadtxt/test_savetxt_qp.f90 b/src/tests/io/test_savetxt_qp.f90 similarity index 100% rename from src/tests/loadtxt/test_savetxt_qp.f90 rename to src/tests/io/test_savetxt_qp.f90 From 6a263ffa40ae122c9e074de170eecbf47775d74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Fri, 3 Jan 2020 09:05:02 -0700 Subject: [PATCH 04/14] Add a test for "open" --- src/tests/io/CMakeLists.txt | 5 ++++ src/tests/io/test_open.f90 | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/tests/io/test_open.f90 diff --git a/src/tests/io/CMakeLists.txt b/src/tests/io/CMakeLists.txt index 5cef2a4f8..fb3d7179e 100644 --- a/src/tests/io/CMakeLists.txt +++ b/src/tests/io/CMakeLists.txt @@ -10,6 +10,9 @@ target_link_libraries(test_loadtxt_qp fortran_stdlib) add_executable(test_savetxt_qp test_savetxt_qp.f90) target_link_libraries(test_savetxt_qp fortran_stdlib) +add_executable(test_open test_open.f90) +target_link_libraries(test_open fortran_stdlib) + add_test(NAME loadtxt COMMAND $ ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME savetxt COMMAND $ ${CMAKE_CURRENT_BINARY_DIR} @@ -18,6 +21,8 @@ add_test(NAME loadtxt_qp COMMAND $ ${CMAKE_CURRENT_ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME savetxt_qp COMMAND $ ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME open COMMAND $ ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set_tests_properties(loadtxt_qp PROPERTIES LABELS quadruple_precision) set_tests_properties(savetxt_qp PROPERTIES LABELS quadruple_precision) diff --git a/src/tests/io/test_open.f90 b/src/tests/io/test_open.f90 new file mode 100644 index 000000000..eb66af519 --- /dev/null +++ b/src/tests/io/test_open.f90 @@ -0,0 +1,49 @@ +program test_open +use stdlib_experimental_io, only: open +use stdlib_experimental_error, only: assert +implicit none + +character(:), allocatable :: filename +integer :: u, a(3) + +filename = get_outpath() // "/io_open.dat" + +! Test mode "w" +u = open(filename, "w") +write(u, *) 1, 2, 3 +close(u) + +! Test mode "r" +u = open(filename, "r") +read(u, *) a +call assert(all(a == [1, 2, 3])) +close(u) + +! Test mode "a" +u = open(filename, "a") +write(u, *) 4, 5, 6 +close(u) +u = open(filename, "r") +read(u, *) a +call assert(all(a == [1, 2, 3])) +read(u, *) a +call assert(all(a == [4, 5, 6])) +close(u) + + +contains + + function get_outpath() result(outpath) + integer :: ierr + character(256) :: argv + character(:), allocatable :: outpath + + call get_command_argument(1, argv, status=ierr) + if (ierr==0) then + outpath = trim(argv) + else + outpath = '.' + endif + end function get_outpath + +end program From ab5c469d7c253e494e40818a3dd8afd9319b1905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Fri, 3 Jan 2020 09:11:35 -0700 Subject: [PATCH 05/14] Apply suggestions from code review Co-Authored-By: Jeremie Vandenplas --- src/stdlib_experimental_io.f90 | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index 778dc5d67..b3fa9c3a4 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -274,7 +274,7 @@ integer function open(filename, mode) result(u) ! ! To open a file to read: ! -! u = open("somefile.txt") # The default `mode` is "r" +! u = open("somefile.txt") # The default `mode` is "rt" ! u = open("somefile.txt", "r") ! ! To open a file to write: @@ -288,17 +288,22 @@ integer function open(filename, mode) result(u) character(*), intent(in) :: filename character(*), intent(in), optional :: mode character(:), allocatable :: mode_ -mode_ = "r" +mode_ = "rt" if (present(mode)) mode_ = mode ! Note: the Fortran standard says that the default values for `status` and ! `action` are processor dependent, so we have to explicitly set them below -if (mode_ == "r") then - open(newunit=u, file=filename, status="old", action="read") -else if (mode_ == "w") then - open(newunit=u, file=filename, status="replace", action="write") -else if (mode_ == "a") then +if (mode_ == "r" .or. mode_ == 'rt') then + open(newunit=u, file=filename, status="old", action="read", & + access='sequential', form='formatted') +else if (mode_ == "w" .or. mode_ == "wt") then + open(newunit=u, file=filename, status="replace", action="write", & + access='sequential', form='formatted') +else if (mode_ == "a" .or. mode_ == "at") then open(newunit=u, file=filename, position="append", status="old", & - action="write") + action="write", access='sequential', form='formatted') +else if (mode_ == "x" .or. mode_ == "xt") then + open(newunit=u, file=filename, status="new", & + action="write", access='sequential', form='formatted') else call error_stop("Unsupported mode") end if From 13a668ead5e9d0a1b22da9659b8b6d1a6f04a15c Mon Sep 17 00:00:00 2001 From: "Vandenplas, Jeremie" Date: Sat, 4 Jan 2020 11:14:12 +0100 Subject: [PATCH 06/14] stdlib_experimental_io: addition of a parser and characters "+" and "s"/"b" for stream access --- src/stdlib_experimental_io.f90 | 95 +++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index b3fa9c3a4..79188d65c 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -287,26 +287,85 @@ integer function open(filename, mode) result(u) character(*), intent(in) :: filename character(*), intent(in), optional :: mode -character(:), allocatable :: mode_ -mode_ = "rt" -if (present(mode)) mode_ = mode -! Note: the Fortran standard says that the default values for `status` and -! `action` are processor dependent, so we have to explicitly set them below -if (mode_ == "r" .or. mode_ == 'rt') then - open(newunit=u, file=filename, status="old", action="read", & - access='sequential', form='formatted') -else if (mode_ == "w" .or. mode_ == "wt") then - open(newunit=u, file=filename, status="replace", action="write", & - access='sequential', form='formatted') -else if (mode_ == "a" .or. mode_ == "at") then - open(newunit=u, file=filename, position="append", status="old", & - action="write", access='sequential', form='formatted') -else if (mode_ == "x" .or. mode_ == "xt") then - open(newunit=u, file=filename, status="new", & - action="write", access='sequential', form='formatted') +integer :: io +character(3):: mode_ +character(:),allocatable :: action_, position_, status_, access_, form_ + + +mode_ = "r t" +if (present(mode)) mode_ = parse_mode(mode) + +if (mode_(1:2) == 'r ') then + action_='read' + position_='asis' + status_='old' +else if (mode_(1:2) == 'w ') then + action_='write' + position_='asis' + status_='replace' +else if (mode_(1:2) == 'a ') then + action_='write' + position_='append' + status_='old' +else if (mode_(1:2) == 'x ') then + action_='write' + position_='asis' + status_='new' +else if (mode_(1:2) == 'r+') then + action_='readwrite' + position_='asis' + status_='old' +else if (mode_(1:2) == 'w+') then + action_='readwrite' + position_='asis' + status_='replace' +else if (mode_(1:2) == 'a+') then + action_='readwrite' + position_='append' + status_='old' +else if (mode_(1:2) == 'x+') then + action_='readwrite' + position_='asis' + status_='new' else - call error_stop("Unsupported mode") + call error_stop("Unsupported mode: "//mode_(1:2)) end if + +if (mode_(3:3) == 't') then + access_='sequential' + form_='formatted' +else if (mode_(3:3) == 'b' .or. mode_(3:3) == 's') then + access_='stream' + form_='unformatted' +else + call error_stop("Unsupported mode: "//mode_(3:3)) +endif + +open(newunit=u, file=filename, & + action = action_, position = position_, status = status_, & + access = access_, form = form_, & + iostat = io) + +end function + +character(3) function parse_mode(mode) result(mode_) +character(*), intent(in) :: mode + +mode_ = 'r t' +mode_(1:1) = mode(1:1) + +if (len_trim(adjustl(mode)) > 1) then + if (mode(2:2) == '+' )then + mode_(2:2) = '+' + else + mode_(3:3) = mode(2:2) + endif +end if + +if (len_trim(adjustl(mode)) > 2) then + mode_(3:3) = mode(3:3) +end if + end function end module From 2f1a0e813dcdaec0e881663d5ce9942b61a260a3 Mon Sep 17 00:00:00 2001 From: "Vandenplas, Jeremie" Date: Sat, 4 Jan 2020 15:01:40 +0100 Subject: [PATCH 07/14] test_open: addition of a test for stream files --- src/tests/io/Makefile.manual | 7 +++++-- src/tests/io/test_open.f90 | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/tests/io/Makefile.manual b/src/tests/io/Makefile.manual index 716f41678..b3df0f5d8 100644 --- a/src/tests/io/Makefile.manual +++ b/src/tests/io/Makefile.manual @@ -5,7 +5,7 @@ OBJS = ../../stdlib_experimental_error.o \ .PHONY: all clean .SUFFIXES: .f90 .o -all: test_loadtxt test_savetxt +all: test_loadtxt test_savetxt test_open test_loadtxt: test_loadtxt.f90 $(OBJS) $(FC) $(FCFLAGS) $(CPPFLAGS) $< -o $@ $(OBJS) @@ -13,8 +13,11 @@ test_loadtxt: test_loadtxt.f90 $(OBJS) test_savetxt: test_savetxt.f90 $(OBJS) $(FC) $(FCFLAGS) $(CPPFLAGS) $< -o $@ $(OBJS) +test_open: test_open.f90 $(OBJS) + $(FC) $(FCFLAGS) $(CPPFLAGS) $< -o $@ $(OBJS) + %.o: %.mod clean: - $(RM) test_loadtxt test_savetxt + $(RM) test_loadtxt test_savetxt test_open $(RM) *.o *.mod diff --git a/src/tests/io/test_open.f90 b/src/tests/io/test_open.f90 index eb66af519..2169d0861 100644 --- a/src/tests/io/test_open.f90 +++ b/src/tests/io/test_open.f90 @@ -6,6 +6,7 @@ program test_open character(:), allocatable :: filename integer :: u, a(3) +! Text file filename = get_outpath() // "/io_open.dat" ! Test mode "w" @@ -31,6 +32,32 @@ program test_open close(u) + +! Stream file +filename = get_outpath() // "/io_open.stream" + +! Test mode "w" +u = open(filename, "wb") +write(u) 1, 2, 3 +close(u) + +! Test mode "r" +u = open(filename, "rb") +read(u) a +call assert(all(a == [1, 2, 3])) +close(u) + +! Test mode "a" +u = open(filename, "ab") +write(u) 4, 5, 6 +close(u) +u = open(filename, "rb") +read(u) a +call assert(all(a == [1, 2, 3])) +read(u) a +call assert(all(a == [4, 5, 6])) +close(u) + contains function get_outpath() result(outpath) From 041a4e13607972fd720fc3d3e7d944f09856c8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 13:37:03 -0700 Subject: [PATCH 08/14] Clean test files --- src/tests/io/Makefile.manual | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/io/Makefile.manual b/src/tests/io/Makefile.manual index d83b5c91a..0e18c6aca 100644 --- a/src/tests/io/Makefile.manual +++ b/src/tests/io/Makefile.manual @@ -4,7 +4,7 @@ PROGS_SRC = test_loadtxt.f90 \ test_savetxt_qp.f90 \ test_open.f90 -CLEAN_FILES = tmp.dat tmp_qp.dat +CLEAN_FILES = tmp.dat tmp_qp.dat io_open.dat io_open.stream include ../Makefile.manual.test.mk From b0b3dbfe6d62b8888e9afa214c8ea6a2db030a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 13:55:52 -0700 Subject: [PATCH 09/14] Add tests for parse_mode() --- src/stdlib_experimental_io.f90 | 5 ++++ src/tests/io/test_open.f90 | 45 +++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index 79188d65c..d034d6fbc 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -3,8 +3,13 @@ module stdlib_experimental_io use stdlib_experimental_error, only: error_stop implicit none private +! Public API public :: loadtxt, savetxt, open +! Private API that is exposed so that we can test it in tests +public :: parse_mode + + interface loadtxt module procedure sloadtxt module procedure dloadtxt diff --git a/src/tests/io/test_open.f90 b/src/tests/io/test_open.f90 index 2169d0861..c85192c14 100644 --- a/src/tests/io/test_open.f90 +++ b/src/tests/io/test_open.f90 @@ -1,11 +1,13 @@ program test_open -use stdlib_experimental_io, only: open +use stdlib_experimental_io, only: open, parse_mode use stdlib_experimental_error, only: assert implicit none character(:), allocatable :: filename integer :: u, a(3) +call test_parse_mode() + ! Text file filename = get_outpath() // "/io_open.dat" @@ -73,4 +75,45 @@ function get_outpath() result(outpath) endif end function get_outpath + subroutine test_parse_mode() + character(3) :: m + m = parse_mode("") + call assert(m == "r t") + + m = parse_mode("r") + call assert(m == "r t") + m = parse_mode("w") + call assert(m == "w t") + m = parse_mode("a") + call assert(m == "a t") + + m = parse_mode("rb") + call assert(m == "r b") + m = parse_mode("wb") + call assert(m == "w b") + m = parse_mode("ab") + call assert(m == "a b") + + m = parse_mode("br") + !call assert(m == "r b") + m = parse_mode("bw") + !call assert(m == "w b") + m = parse_mode("ba") + !call assert(m == "a b") + + m = parse_mode("r+") + call assert(m == "r+t") + m = parse_mode("w+") + call assert(m == "w+t") + m = parse_mode("a+") + call assert(m == "a+t") + + m = parse_mode("r+b") + call assert(m == "r+b") + m = parse_mode("w+b") + call assert(m == "w+b") + m = parse_mode("a+b") + call assert(m == "a+b") + end subroutine + end program From 08dc86b8c514276ca4564d7359df5e69329c580e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 14:00:07 -0700 Subject: [PATCH 10/14] Allow any order of characters in the mode --- src/stdlib_experimental_io.f90 | 5 +++++ src/tests/io/test_open.f90 | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index d034d6fbc..c03b31e39 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -371,6 +371,11 @@ integer function open(filename, mode) result(u) mode_(3:3) = mode(3:3) end if +if (mode_(1:1) == 'b') then + mode_(1:1) = mode_(3:3) + mode_(3:3) = 'b' +end if + end function end module diff --git a/src/tests/io/test_open.f90 b/src/tests/io/test_open.f90 index c85192c14..471c43952 100644 --- a/src/tests/io/test_open.f90 +++ b/src/tests/io/test_open.f90 @@ -95,11 +95,11 @@ subroutine test_parse_mode() call assert(m == "a b") m = parse_mode("br") - !call assert(m == "r b") + call assert(m == "r b") m = parse_mode("bw") - !call assert(m == "w b") + call assert(m == "w b") m = parse_mode("ba") - !call assert(m == "a b") + call assert(m == "a b") m = parse_mode("r+") call assert(m == "r+t") From 5128458615fa8e5dca2156da657c28fa5909a538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 14:04:24 -0700 Subject: [PATCH 11/14] Fix an out of bounds error --- src/stdlib_experimental_io.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index c03b31e39..4e34fbc83 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -357,6 +357,7 @@ integer function open(filename, mode) result(u) character(*), intent(in) :: mode mode_ = 'r t' +if (len_trim(mode) == 0) return mode_(1:1) = mode(1:1) if (len_trim(adjustl(mode)) > 1) then From 48cbf24fff34577cd465332d91dcc006fbab0053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 14:07:51 -0700 Subject: [PATCH 12/14] Let parse_mode() set the default value --- src/stdlib_experimental_io.f90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index 4e34fbc83..07c060300 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -297,8 +297,11 @@ integer function open(filename, mode) result(u) character(:),allocatable :: action_, position_, status_, access_, form_ -mode_ = "r t" -if (present(mode)) mode_ = parse_mode(mode) +! Note: with `optval` this could be written as: +! mode_ = parse_mode(optval(mode, "")) +mode_ = "" +if (present(mode)) mode_ = mode +mode_ = parse_mode(mode_) if (mode_(1:2) == 'r ') then action_='read' From a98832cc23542e8714015a5e87262671c9a69f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 14:11:20 -0700 Subject: [PATCH 13/14] Manual Makefiles: add a new dependency --- src/Makefile.manual | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.manual b/src/Makefile.manual index 71b6a8a31..a58dfb852 100644 --- a/src/Makefile.manual +++ b/src/Makefile.manual @@ -27,3 +27,4 @@ clean: # Fortran module dependencies f18estop.o: stdlib_experimental_error.o +stdlib_experimental_io.o: stdlib_experimental_error.o From a8416a10a1b2db974dfa6192fe486c8d16b24e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Sat, 4 Jan 2020 14:23:37 -0700 Subject: [PATCH 14/14] Use optval --- src/Makefile.manual | 2 +- src/stdlib_experimental_io.f90 | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Makefile.manual b/src/Makefile.manual index c2af5de63..31ca7cad7 100644 --- a/src/Makefile.manual +++ b/src/Makefile.manual @@ -28,4 +28,4 @@ clean: # Fortran module dependencies f18estop.o: stdlib_experimental_error.o -stdlib_experimental_io.o: stdlib_experimental_error.o +stdlib_experimental_io.o: stdlib_experimental_error.o stdlib_experimental_optval.o diff --git a/src/stdlib_experimental_io.f90 b/src/stdlib_experimental_io.f90 index 07c060300..91757f2a2 100644 --- a/src/stdlib_experimental_io.f90 +++ b/src/stdlib_experimental_io.f90 @@ -1,6 +1,7 @@ module stdlib_experimental_io use iso_fortran_env, only: sp=>real32, dp=>real64, qp=>real128 use stdlib_experimental_error, only: error_stop +use stdlib_experimental_optval, only: optval implicit none private ! Public API @@ -297,11 +298,7 @@ integer function open(filename, mode) result(u) character(:),allocatable :: action_, position_, status_, access_, form_ -! Note: with `optval` this could be written as: -! mode_ = parse_mode(optval(mode, "")) -mode_ = "" -if (present(mode)) mode_ = mode -mode_ = parse_mode(mode_) +mode_ = parse_mode(optval(mode, "")) if (mode_(1:2) == 'r ') then action_='read'