-
Notifications
You must be signed in to change notification settings - Fork 221
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 29 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
aacc748
8b9189b
ecacf54
8d02086
15c1196
53535fb
a6f7556
57f6f19
e1b63b1
50eb65f
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
jvdp1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| `fmt`: (optional): Fortran format specifier for the text save. Defaults to the write format for the data type. | ||||||
jvdp1 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| `fmt`: (optional): Fortran format specifier for the text save. Defaults to the write format for the data type. | |
| `fmt` (optional): Fortran format specifier for the text save. Defaults to the write format for the data type. |
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
Copilot
AI
Jan 29, 2026
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.
There is an extra colon after footer in the parameter description. It should be footer (optional): not footer: (optional) for consistency with other parameter descriptions in the documentation.
| `footer`: (optional) Shall be a character expression that will be written at the end of the file. | |
| `footer` (optional): Shall be a character expression that will be written at the end of the file. |
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| 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 | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -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'] | ||||||||
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| #:for k1, t1 in KINDS_TYPES | ||||||||
| module procedure savetxt_${t1[0]}$${k1}$ | ||||||||
| module procedure savetxt_${t1[0]}$${k1}$${a1}$ | ||||||||
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| #: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=1), intent(in), optional :: delimiter ! Column delimiter. Default is a space ' '. | ||||||||
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| 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 | ||||||||
| !! ------- | ||||||||
|
|
@@ -255,40 +267,101 @@ contains | |||||||
| integer :: s, i, ios | ||||||||
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| character(len=1) :: delimiter_ | ||||||||
| character(len=3) :: delim_str | ||||||||
| character(len=:), allocatable :: default_fmt | ||||||||
| character(len=:), allocatable :: fmt_ | ||||||||
| character(len=:), allocatable :: comments_ | ||||||||
| character(len=:), allocatable :: header_ | ||||||||
| character(len=:), allocatable :: footer_ | ||||||||
| character(len=1024) :: iomsg, msgout | ||||||||
| #: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 '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) | ||||||||
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| #: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") | ||||||||
| #:else | ||||||||
| inquire (unit=unit, opened=opened) | ||||||||
| 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.
@fiolj Is this a valid suggestion?
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
jvdp1 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
fiolj marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Copilot
AI
Jan 29, 2026
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 prepend function does not handle empty strings correctly. When Sin is an empty string, it still initializes Sout to com_ (comment plus space), which would return a non-empty string for empty input. While the current callers guard against this by checking if (header_ /= '') before calling prepend, the function itself should be more robust. Consider adding an early return: if (len(Sin) == 0) then; Sout = ''; return; end if at the beginning of the function.
Copilot
AI
Jan 29, 2026
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 prepend function has a logical issue. When there is no newline in the input string (eol == bol - 1 on the first iteration), the function exits the loop without appending the actual input string content to Sout. The condition if (eol < len(Sin)) on line 362 should handle this, but when eol is bol - 1 (which equals 0), and len(Sin) > 0, the content would still be added. However, for a string with newlines, the last line without a trailing newline is handled correctly. The logic appears correct but is difficult to follow. Consider adding comments to clarify the intended behavior for each case.
Uh oh!
There was an error while loading. Please reload this page.