-
Notifications
You must be signed in to change notification settings - Fork 216
Savetxt unit #1085
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Savetxt unit #1085
Changes from all commits
d6cc685
e2d1c09
94c36cc
af2137b
4db2dd0
5c8397c
eb4acc6
dc2c9f8
e6a02f7
d390d79
9cd8e51
b75e631
036ce25
ab357fa
e6af81a
04061b8
fbe6d0a
3f6aff3
d491c8f
390857d
4e574eb
d470409
6c43047
a01ffe7
e3c13f3
86fa060
8403d30
241e146
45ee7c2
672ad8a
2b16ff3
5ecd021
20c1a3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -106,15 +106,25 @@ Saves a rank-2 `array` into a text file. | |||||
|
|
||||||
| ### Syntax | ||||||
|
|
||||||
| `call ` [[stdlib_io(module):savetxt(interface)]] `(filename, array [, delimiter])` | ||||||
| `call ` [[stdlib_io(module):savetxt(interface)]] `(filename, array [, delimiter] [, fmt] [, header] [, footer] [, comments])` | ||||||
|
|
||||||
| `call ` [[stdlib_io(module):savetxt(interface)]] `(unit, array[, delimiter] [, fmt] [, header] [, footer] [, comments])` | ||||||
|
|
||||||
| ### Arguments | ||||||
|
|
||||||
| `filename`: Shall be a character expression containing the name of the file that will contain the 2D `array`. | ||||||
| `filename or unit`: Shall be either a character expression containing the name of the file or an integer containing the unit of an already open file, that will contain the 2D `array`. Setting the two of them shall give an error. | ||||||
|
|
||||||
| `array`: Shall be a rank-2 array of type `real`, `complex` or `integer`. | ||||||
|
|
||||||
| `delimiter` (optional): Shall be a character expression of length 1 that contains the delimiter used to separate the columns. The default is `' '`. | ||||||
| `delimiter` (optional): Shall be a character expression of any length that contains the delimiter used to separate the columns. The default is a single space `' '`. | ||||||
jvdp1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| `delimiter` (optional): Shall be a character expression of any length that contains the delimiter used to separate the columns. The default is a single space `' '`. | |
| `delimiter` (optional): Shall be a character expression of length 1 (a single character) that contains the delimiter used to separate the columns. The default is a single space `' '`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,12 @@ | ||
| program example_savetxt | ||
| use stdlib_io, only: savetxt | ||
| use, intrinsic :: iso_fortran_env, only: output_unit | ||
| implicit none | ||
| real :: x(3, 2) = 1 | ||
| call savetxt('example.dat', x) | ||
| call savetxt('example.csv', x, delimiter=',') | ||
| call savetxt('example1.dat', x, header='x (x-units) y (y-units)') | ||
| call savetxt('example2.dat', x, header='x (x-units) y (y-units)', comments='!#', footer='This is all data') | ||
| call savetxt('example3.dat', x, fmt='g0.7') | ||
| call savetxt(output_unit, x, header='x (x-units) y (y-units)') | ||
| end program example_savetxt |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,7 @@ module stdlib_io | |||||||
| FMT_COMPLEX_SP, FMT_COMPLEX_DP, FMT_COMPLEX_XDP, FMT_COMPLEX_QP | ||||||||
| use stdlib_error, only: error_stop, state_type, STDLIB_IO_ERROR | ||||||||
| use stdlib_optval, only: optval | ||||||||
| use stdlib_ascii, only: is_blank | ||||||||
| use stdlib_ascii, only: is_blank, whitespace, CR,LF,VT,FF | ||||||||
| use stdlib_string_type, only : string_type, assignment(=), move | ||||||||
| implicit none | ||||||||
| private | ||||||||
|
|
@@ -47,6 +47,8 @@ module stdlib_io | |||||||
|
|
||||||||
| !> Default delimiter for loadtxt, savetxt and number_of_columns | ||||||||
| character(len=1), parameter :: delimiter_default = " " | ||||||||
| character(len=1), parameter :: comment_default = "#" | ||||||||
| character(len=1), parameter :: nl = new_line('a') | ||||||||
|
|
||||||||
| public :: FMT_INT, FMT_REAL_SP, FMT_REAL_DP, FMT_REAL_XDP, FMT_REAL_QP | ||||||||
| public :: FMT_COMPLEX_SP, FMT_COMPLEX_DP, FMT_COMPLEX_XDP, FMT_COMPLEX_QP | ||||||||
|
|
@@ -76,8 +78,10 @@ module stdlib_io | |||||||
| !! | ||||||||
| !! Saves a 2D array into a text file | ||||||||
| !! ([Specification](../page/specs/stdlib_io.html#description_2)) | ||||||||
| #:for a1 in ['f', 'u'] | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| #:for k1, t1 in KINDS_TYPES | ||||||||
| module procedure savetxt_${t1[0]}$${k1}$ | ||||||||
| module procedure savetxt_${t1[0]}$${k1}$${a1}$ | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can use arg1 but I was thinking on only using the first letter to identify the name of the routine, as in the definition (
|
||||||||
| #:endfor | ||||||||
| #:endfor | ||||||||
| end interface | ||||||||
|
|
||||||||
|
|
@@ -230,19 +234,27 @@ contains | |||||||
| end subroutine loadtxt_${t1[0]}$${k1}$ | ||||||||
| #:endfor | ||||||||
|
|
||||||||
|
|
||||||||
| #:for arg1 in ['filename', 'unit'] | ||||||||
| #:for k1, t1 in KINDS_TYPES | ||||||||
| subroutine savetxt_${t1[0]}$${k1}$(filename, d, delimiter) | ||||||||
| subroutine savetxt_${t1[0]}$${k1}$${arg1[0]}$ (${arg1}$, d, delimiter, fmt, header, footer, comments) | ||||||||
| !! version: experimental | ||||||||
| !! | ||||||||
| !! Saves a 2D array into a text file. | ||||||||
| !! | ||||||||
| !! Arguments | ||||||||
| !! --------- | ||||||||
| !! | ||||||||
| #:if 'filename' in arg1 | ||||||||
| character(len=*), intent(in) :: filename ! File to save the array to | ||||||||
| #:elif 'unit' in arg1 | ||||||||
| integer, intent(in) :: unit | ||||||||
jvdp1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| #:endif | ||||||||
| ${t1}$, intent(in) :: d(:,:) ! The 2D array to save | ||||||||
| character(len=1), intent(in), optional :: delimiter ! Column delimiter. Default is a space. | ||||||||
| character(len=*), intent(in), optional :: delimiter ! Column delimiter. Default is a space ' '. | ||||||||
| character(len=*), intent(in), optional :: fmt !< Fortran format specifier. Defaults to the write format for the data type. | ||||||||
| character(len=*), intent(in), optional :: header !< If present, text to write before data. | ||||||||
| character(len=*), intent(in), optional :: footer !< If present, text to write after data. | ||||||||
| character(len=*), intent(in), optional :: comments !< Comment character. Default "#". | ||||||||
| !! | ||||||||
| !! Example | ||||||||
| !! ------- | ||||||||
|
|
@@ -253,42 +265,131 @@ contains | |||||||
| !!``` | ||||||||
| !! | ||||||||
| integer :: s, i, ios | ||||||||
|
||||||||
| character(len=1) :: delimiter_ | ||||||||
| character(len=3) :: delim_str | ||||||||
| character(len=:), allocatable :: delimiter_ | ||||||||
| character(len=:), allocatable :: delim_str | ||||||||
| character(len=:), allocatable :: default_fmt | ||||||||
| character(len=:), allocatable :: fmt_ | ||||||||
| character(len=1024) :: iomsg, msgout | ||||||||
| character(len=:), allocatable :: comments_ | ||||||||
| character(len=:), allocatable :: header_ | ||||||||
| character(len=:), allocatable :: footer_ | ||||||||
| character(len=1024) :: iomsg, msgout, fout | ||||||||
|
|
||||||||
| #:if 'filename' in arg1 | ||||||||
| integer :: unit | ||||||||
| #:else | ||||||||
| logical :: opened | ||||||||
| #:endif | ||||||||
|
|
||||||||
| delimiter_ = optval(delimiter, delimiter_default) | ||||||||
| delim_str = "'"//delimiter_//"'" | ||||||||
| comments_ = optval(comments, comment_default) | ||||||||
| header_ = optval(header, '') | ||||||||
| footer_ = optval(footer, '') | ||||||||
|
|
||||||||
| if(index(delimiter_, comments_) /= 0) then | ||||||||
| write (msgout,'(a)') 'savetxt error: delimiter string cannot include the comments string' | ||||||||
| call error_stop(msg=trim(msgout)) | ||||||||
| end if | ||||||||
|
|
||||||||
| if(scan(whitespace, comments_) /= 0) then | ||||||||
| write (msgout,'(a)') 'savetxt error: comments string cannot include whitespaces' | ||||||||
| call error_stop(msg=trim(msgout)) | ||||||||
| end if | ||||||||
|
|
||||||||
| if(scan(LF//CR//VT//FF, delimiter_ ) /= 0) then | ||||||||
| write (msgout,'(a)') 'savetxt error: delimiter cannot include newline' | ||||||||
| call error_stop(msg=trim(msgout)) | ||||||||
| end if | ||||||||
|
|
||||||||
|
|
||||||||
| #:if 'real' in t1 | ||||||||
| fmt_ = "(*"//FMT_REAL_${k1}$(1:len(FMT_REAL_${k1}$)-1)//",:,"//delim_str//"))" | ||||||||
| default_fmt = FMT_REAL_${k1}$(2:len(FMT_REAL_${k1}$)-1) | ||||||||
| #:elif 'complex' in t1 | ||||||||
| fmt_ = "(*"//FMT_COMPLEX_${k1}$(1:11)//delim_str//FMT_COMPLEX_${k1}$(14:23)//",:,"//delim_str//"))" | ||||||||
| default_fmt = FMT_COMPLEX_${k1}$(2:11)//delim_str//FMT_COMPLEX_${k1}$(14:23) | ||||||||
| #:elif 'integer' in t1 | ||||||||
| fmt_ = "(*"//FMT_INT(1:len(FMT_INT)-1)//",:,"//delim_str//"))" | ||||||||
| default_fmt = FMT_INT(2:len(FMT_INT)-1) | ||||||||
| #:endif | ||||||||
| fmt_ = "(*("//optval(fmt, default_fmt)//",:,"//delim_str//"))" | ||||||||
|
|
||||||||
| #:if 'filename' in arg1 | ||||||||
| unit = open (filename, "w") | ||||||||
| fout = filename | ||||||||
| #:else | ||||||||
| inquire (unit=unit, opened=opened) | ||||||||
| write(fout,'(i0)') unit | ||||||||
| fout = adjustl(fout) | ||||||||
| if(.not. opened) then | ||||||||
| write (msgout,'(a,i0,a)') 'savetxt error: unit ',unit,' not open' | ||||||||
|
||||||||
| write (msgout,'(a,i0,a)') 'savetxt error: unit ',unit,' not open' | |
| write (msgout,'(a,i0,a)') 'savetxt error: unit ',unit,' not open' | |
| call error_stop(msg=trim(msgout)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation states "Setting the two of them shall give an error," but there is no validation in the implementation to prevent both
filenameandunitfrom being specified simultaneously. Since these are generated as separate procedures (one with filename, one with unit parameter), they cannot both be provided at the same time through the interface - this is enforced by the procedure signature itself. The documentation should clarify that these are two different procedure variants, or remove the misleading statement about setting both parameters.