gtool5 Fortran 90/95 ライブラリ 1.0.0-rc5
English
Loading...
Searching...
No Matches
dcstringsprintf.f90
Go to the documentation of this file.
1! -*- mode: f90; coding: utf-8 -*-
2!-----------------------------------------------------------------------
3! Copyright (c) 2000-2026 Gtool Development Group. All rights reserved.
4!-----------------------------------------------------------------------
5!>
6!> @author Yasuhiro MORIKAWA, Eizi TOYODA
7!> @copyright Copyright (C) GFD Dennou Club, 2000-2026. All rights reserved. <br/>
8!> License is BSD-2-Clause. see [COPYRIGHT](@ref COPYRIGHT) in detail
9!> @en
10!> @brief Formatted output conversion (similar to C sprintf)
11!> @details
12!> Format a string like C sprintf(3).
13!> Note that the implementation is quite different from C sprintf(3).
14!>
15!> ### Format specifiers
16!>
17!> Format specifiers used in dc_string#CPrintf and dc_string#Printf
18!> start with **%**. Available specifiers are:
19!>
20!> | Specifier | Argument | Description |
21!> |---------------|---------------|------------------------------------------|
22!> | `%d`, `%D` | `i(:)` | Display integer (decimal). Use %2d or %04d for digit control |
23!> | `%o`, `%O` | `i(:)` | Display integer (octal) |
24!> | `%x`, `%X` | `i(:)` | Display integer (hexadecimal) |
25!> | `%f`, `%F` | `d(:)` | Display double precision real |
26!> | `%r`, `%R` | `r(:)` | Display single precision real |
27!> | `%b`, `%B` | `L(:)` | Display logical (T/F) |
28!> | `%y`, `%Y` | `L(:)` | Display logical (yes/no) |
29!> | `%c`, `%C` | `c1,c2,c3` | Display character (variable) |
30!> | `%a`, `%A` | `ca` | Display character (array) |
31!> | `%*` | `n(:)` | Repeat count for multiple data output |
32!>
33!> @enden
34!>
35!> @ja
36!> @brief 書式変換出力 (C の sprintf 風)
37!> @details
38!> C の sprintf(3) のように文字列をフォーマットして返します。
39!> ただし、実装は C の sprintf(3) とは大分違うのでご注意ください。
40!>
41!> ### フォーマット指示子
42!>
43!> dc_string#CPrintf, dc_string#Printf のフォーマット引数に
44!> 用いられる指示子は **%** で始まります。種類は以下の通りです:
45!>
46!> | 指示子 | 引数 | 説明 |
47!> |---------------|---------------|-------------------------------------------|
48!> | `%d`, `%D` | `i(:)` | 整数データ (10進数)。%2d や %04d で桁数指定可 |
49!> | `%o`, `%O` | `i(:)` | 整数データ (8進数) |
50!> | `%x`, `%X` | `i(:)` | 整数データ (16進数) |
51!> | `%f`, `%F` | `d(:)` | 倍精度実数データ |
52!> | `%r`, `%R` | `r(:)` | 単精度実数データ |
53!> | `%b`, `%B` | `L(:)` | 論理データ (T/F) |
54!> | `%y`, `%Y` | `L(:)` | 論理データ (yes/no) |
55!> | `%c`, `%C` | `c1,c2,c3` | 文字データ (変数) |
56!> | `%a`, `%A` | `ca` | 文字データ (配列) |
57!> | `%*` | `n(:)` | 複数データ出力の繰り返し回数 |
58!>
59!> @endja
60!>
61
62!> @en
63!> @brief Format and output string to character variable
64!> @details
65!> Return a formatted string according to format string `fmt`.
66!> Use specifiers starting with '%' in `fmt`.
67!> Use '%%' to output a literal '%'.
68!> See dcstringsprintf.f90 for specifier details and examples.
69!>
70!> @param[out] unit Output character variable
71!> @param[in] fmt Format string with specifiers
72!> @param[in] i Integer array data for %d, %o, %x
73!> @param[in] r Single precision real array data for %r
74!> @param[in] d Double precision real array data for %f
75!> @param[in] L Logical array data for %b, %y
76!> @param[in] n Repeat counts for %* specifier
77!> @param[in] c1 First character string for %c
78!> @param[in] c2 Second character string for %c
79!> @param[in] c3 Third character string for %c
80!> @param[in] ca Character array for %a
81!> @enden
82!>
83!> @ja
84!> @brief 書式変換して文字変数に出力
85!> @details
86!> フォーマット文字列 `fmt` に従って変換された文字列を `unit` に返します。
87!> `fmt` には '%' で始まる指示子を含む文字列を与えます。
88!> '%' を出力したい場合は '%%' と記述します。
89!> 指示子および用例に関しての詳細は dcstringsprintf.f90 を参照ください。
90!>
91!> @param[out] unit 出力先の文字変数
92!> @param[in] fmt 指示子を含むフォーマット文字列
93!> @param[in] i %d, %o, %x 用の整数配列データ
94!> @param[in] r %r 用の単精度実数配列データ
95!> @param[in] d %f 用の倍精度実数配列データ
96!> @param[in] L %b, %y 用の論理配列データ
97!> @param[in] n %* 用の繰り返し回数
98!> @param[in] c1 %c 用の1番目の文字列
99!> @param[in] c2 %c 用の2番目の文字列
100!> @param[in] c3 %c 用の3番目の文字列
101!> @param[in] ca %a 用の文字配列
102!> @endja
103subroutine dcstringsprintf(unit, fmt, i, r, d, L, n, c1, c2, c3, ca)
104
105 use dc_types, only: sp, dp
106 implicit none
107 character(*), intent(out) :: unit
108 character(*), intent(in) :: fmt
109 integer, intent(in), optional :: i(:), n(:)
110 real(SP), intent(in), optional :: r(:)
111 real(DP), intent(in), optional :: d(:)
112 logical, intent(in), optional :: L(:)
113 character(*), intent(in), optional :: c1, c2, c3
114 character(*), intent(in), optional :: ca(:)
115
116 ! 上記配列引数のカウンタ
117 integer :: ni, nr, nd, nl, nc, na, nn
118 integer :: ucur ! unit に書かれた文字数
119 integer :: endp ! 既に処理された fmt の文字数
120 integer :: cur ! 現在着目中の文字は fmt(cur:cur) である
121 integer :: ptr ! fmt から検索をするときに使用
122 integer :: exp_ptr ! fmt から数値の指数部を検索をするときに使用
123 integer :: minus_ptr ! '-' を検索する時に使用
124 integer :: repeat ! %数字 または %* から決定された繰返し数
125 integer :: m ! 1:repeat の範囲で動くループ変数
126 integer :: stat ! エラー処理
127 character(80) :: cbuf ! read/write 文のバッファ
128 character(80) :: exp_buf ! real/write 文の指数部のバッファ (実数型用)
129 character(80) :: ibuf ! real/write 文のバッファ (整数型用)
130 integer :: len_ibuf ! ibuf の長さ
131 integer :: figs_ibuf ! ibuf の有効な桁数
132 logical :: int_zero_fill ! 先頭を 0 で埋めるかどうかを判定するフラグ (整数型用)
133 integer :: int_figs ! 整数型を出力する際の桁数 (整数型用)
134 continue
135 ni = 0; nr = 0; nd = 0; nl = 0; nc = 0; na = 0; nn = 0
136 unit = ""
137 ucur = 0
138 endp = 0
139 int_figs = 0
140 int_zero_fill = .false.
141 mainloop: do
142 cur = endp + 1
143 if (cur > len(fmt)) exit mainloop
144 !
145 ! リテラルに転写できる文字列 fmt(cur:endp-1) を発見処理
146 !
147 endp = cur - 1 + scan(fmt(cur: ), '%')
148 if (endp > cur) then
149 call append(unit, ucur, fmt(cur:endp-1), stat)
150 if (stat /= 0) exit mainloop
151 else if (endp == cur - 1) then
152 call append(unit, ucur, fmt(cur: ), stat)
153 exit mainloop
154 endif
155 !
156 ! % から書式指定文字までを fmt(cur:endp) とする
157 !
158 cur = endp + 1
159 endp = cur - 1 + scan(fmt(cur: ), 'DdOoXxFfRrBbYySsCcAa%')
160 if (endp < cur) then
161 call append(unit, ucur, fmt(cur-1: ), stat)
162 exit mainloop
163 endif
164 cbuf = fmt(cur:endp-1)
165 !
166 ! %* がある場合、n(:) に渡された数から繰り返し回数を取得
167 !
168 if (cbuf(1:1) == '*') then
169 nn = nn + 1
170 if (nn > size(n)) then
171 repeat = 1
172 else
173 repeat = n(nn)
174 endif
175 ibuf = cbuf(2:)
176 else
177 repeat = 1
178 ibuf = cbuf
179! else if (cbuf == '') then
180! repeat = 1
181! else
182! ptr = verify(cbuf, " 0123456789")
183! if (ptr > 0) cbuf(ptr: ) = " "
184! read(cbuf, "(I80)", iostat=ptr) repeat
185 endif
186 !
187 ! %2d や %04d のように '%' の後ろに数字が指定され、
188 ! かつ d (整数型変数の表示) の場合には先頭に空白
189 ! または 0 を埋める.
190 !
191 if (scan(ibuf(1:1),'1234567890') > 0) then
192 if (ibuf(1:1) == '0') then
193 int_zero_fill = .true.
194 else
195 int_zero_fill = .false.
196 end if
197 read(unit=ibuf, fmt="(i80)") int_figs
198 else
199 int_figs = 0
200 int_zero_fill = .false.
201 endif
202 percentrepeat: do m = 1, repeat
203 if (m > 1) then
204 call append(unit, ucur, ", ", stat)
205 if (stat /= 0) exit mainloop
206 endif
207 select case(fmt(endp:endp))
208 case('d', 'D')
209 if (.not. present(i)) cycle mainloop
210 ni = ni + 1; if (ni > size(i)) cycle mainloop
211 write(ibuf, "(i20)") i(ni)
212 len_ibuf = len(trim(adjustl(ibuf)))
213 figs_ibuf = verify(ibuf, ' ')
214 cbuf = ' '
215 if (int_figs > len_ibuf) then
216 minus_ptr = scan(ibuf, '-')
217 if (int_zero_fill) then
218 if (minus_ptr /= 0) then
219 len_ibuf = len_ibuf - 1
220 figs_ibuf = figs_ibuf + 1
221 cbuf(1:int_figs-len_ibuf) = '-0000000000000000000'
222 else
223 cbuf(1:int_figs-len_ibuf) = '00000000000000000000'
224 end if
225 end if
226 cbuf(int_figs-len_ibuf+1:) = ibuf(figs_ibuf:20)
227 else
228 cbuf = ibuf(figs_ibuf:20)
229 end if
230 call append(unit, ucur, trim(cbuf), stat)
231 if (stat /= 0) exit mainloop
232 case('o', 'O')
233 if (.not. present(i)) cycle mainloop
234 ni = ni + 1; if (ni > size(i)) cycle mainloop
235 write(cbuf, "(o20)") i(ni)
236 call append(unit, ucur, trim(adjustl(cbuf)), stat)
237 if (stat /= 0) exit mainloop
238 case('x', 'X')
239 if (.not. present(i)) cycle mainloop
240 ni = ni + 1; if (ni > size(i)) cycle mainloop
241 write(cbuf, "(z20)") i(ni)
242 call append(unit, ucur, trim(adjustl(cbuf)), stat)
243 if (stat /= 0) exit mainloop
244 case('f', 'F')
245 if (.not. present(d)) cycle mainloop
246 nd = nd + 1; if (nd > size(d)) cycle mainloop
247 write(cbuf, "(f80.40)") d(nd)
248 cbuf = adjustl(cbuf)
249 exp_ptr = verify(cbuf, ' 1234567890-+.', back=.true.)
250 exp_buf = ' '
251 if (exp_ptr > 0) then
252 exp_buf = cbuf(exp_ptr: )
253 cbuf(exp_ptr: ) = " "
254 end if
255 ptr = verify(cbuf, " 0", back=.true.)
256 if (ptr > 0) cbuf(ptr+1: ) = " "
257 cbuf = trim(cbuf) // trim(exp_buf)
258 call append(unit, ucur, trim(adjustl(cbuf)), stat)
259 if (stat /= 0) exit mainloop
260 case('r', 'R')
261 if (.not. present(r)) cycle mainloop
262 nr = nr + 1 ; if (nr > size(r)) cycle mainloop
263 write(cbuf, "(f80.40)") r(nr)
264 cbuf = adjustl(cbuf)
265 exp_ptr = verify(cbuf, ' 1234567890-+.', back=.true.)
266 exp_buf = ' '
267 if (exp_ptr > 0) then
268 exp_buf = cbuf(exp_ptr: )
269 cbuf(exp_ptr: ) = " "
270 end if
271 ptr = verify(cbuf, " 0", back=.true.)
272 if (ptr > 0) cbuf(ptr+1: ) = " "
273 cbuf = trim(cbuf) // trim(exp_buf)
274 call append(unit, ucur, trim(adjustl(cbuf)), stat)
275 if (stat /= 0) exit mainloop
276 case('b', 'B')
277 if (.not. present(l)) cycle mainloop
278 nl = nl + 1; if (nl > size(l)) cycle mainloop
279 write(cbuf, "(L1)") l(nl)
280 call append(unit, ucur, trim(adjustl(cbuf)), stat)
281 if (stat /= 0) exit mainloop
282 case('y', 'Y')
283 if (.not. present(l)) cycle mainloop
284 nl = nl + 1; if (nl > size(l)) cycle mainloop
285 if (l(nl)) then
286 call append(unit, ucur, "yes", stat)
287 if (stat /= 0) exit mainloop
288 else
289 call append(unit, ucur, "no", stat)
290 if (stat /= 0) exit mainloop
291 endif
292 case('c', 'C')
293 nc = nc + 1
294 if (nc == 1) then
295 if (.not. present(c1)) cycle percentrepeat
296 call append(unit, ucur, c1, stat)
297 if (stat /= 0) exit mainloop
298 else if (nc == 2) then
299 if (.not. present(c2)) cycle percentrepeat
300 call append(unit, ucur, c2, stat)
301 if (stat /= 0) exit mainloop
302 else if (nc == 3) then
303 if (.not. present(c3)) cycle percentrepeat
304 call append(unit, ucur, c3, stat)
305 if (stat /= 0) exit mainloop
306 endif
307 case('a', 'A')
308 if (.not. present(ca)) cycle mainloop
309 na = na + 1; if (na > size(ca)) cycle mainloop
310 call append(unit, ucur, trim(adjustl(ca(na))), stat)
311 if (stat /= 0) exit mainloop
312 case('%')
313 call append(unit, ucur, '%', stat)
314 if (stat /= 0) exit mainloop
315 end select
316 enddo percentrepeat
317 enddo mainloop
318 return
319contains
320
321 !> @en
322 !> @brief Append string to output buffer
323 !> @param[inout] unitx Output buffer string
324 !> @param[inout] ucur Current position in unitx
325 !> @param[in] val String to append
326 !> @param[out] stat Status (0=success, 1=truncated, 2=overflow)
327 !> @enden
328 !> @ja
329 !> @brief 出力バッファに文字列を追加
330 !> @param[inout] unitx 出力バッファ文字列
331 !> @param[inout] ucur unitx の現在位置
332 !> @param[in] val 追加する文字列
333 !> @param[out] stat ステータス (0=成功, 1=切り詰め, 2=オーバーフロー)
334 !> @endja
335 subroutine append(unitx, ucur, val, stat)
336 character(*), intent(inout):: unitx ! 最終的に返される文字列
337 integer, intent(inout):: ucur ! unitx の文字数
338 character(*), intent(in) :: val ! unitx に付加される文字列
339 integer, intent(out) :: stat ! ステータス
340 integer :: wrsz ! val の文字列
341 continue
342 ! unitx の最大長を越えた場合には stat = 2 を返す。
343 if (ucur >= len(unitx)) then
344 stat = 2
345 ! 正常時の処理
346 else
347 ! unitx の長さを越えた場合も考慮して unitx に val を付加する。
348 wrsz = min(len(val), len(unitx) - ucur)
349 unitx(1+ucur: wrsz+ucur) = val(1: wrsz)
350 ucur = ucur + wrsz
351 stat = 0
352 if (wrsz < len(val)) stat = 1
353 endif
354 end subroutine append
355
356end subroutine dcstringsprintf
subroutine append(unitx, ucur, val, stat)
subroutine dcstringsprintf(unit, fmt, i, r, d, l, n, c1, c2, c3, ca)
書式変換出力 (C の sprintf 風)
種別型パラメタを提供します。
Definition dc_types.f90:55
integer, parameter, public dp
倍精度実数型変数
Definition dc_types.f90:92
integer, parameter, public sp
単精度実数型変数
Definition dc_types.f90:82