source: trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab@ 468

Last change on this file since 468 was 468, checked in by イグトランス (egtra), 16 years ago

TextWriter, StreamWriterの追加。
SPrintfの浮動小数点数変換で、NaN, Infiniteの出力に対応。
PathとDirectoryInfoのCreateDirectoryで、対象が既に存在するときには例外を投げないように修正。
SimpleTestCase内で使用する一時フォルダの場所にGetTempPathで取得する版を追加(コメントアウト)。

File size: 48.0 KB
RevLine 
[468]1/*!
2@file Include/Classes/ActiveBasic/Strings/SPrintF.ab
3@brief SPrintfとその補助ルーチンが含まれるファイル。
[335]4
[468]5SPrintfで数値変換が行われるとき、呼出の階層は、
6SPrintf→FormatInteger, FormatFloat→FormatIntegerEx, FormatFloatExとなる。
7
8また、次のような変換ルーチンが存在する。
9@li FormatFloatE
10@li FormatFloatF
11@li FormatFloatG
12@li FormatFloatA
13@li FormatIntegerD
14@li FormatIntegerU
15@li FormatIntegerO
16@li FormatIntegerX
17@li FormatCharacter
18@li FormatString
19*/
20
[335]21Namespace ActiveBasic
22Namespace Strings
23
24Namespace Detail
25
26/*!
27@brief 浮動小数点数を文字列化する低水準な関数。符号、指数、仮数に分けて出力。
28@author Egtra
29@date 2007/09/18
30@param[in] x 文字列化する浮動小数点数
31@param[out] e 指数
32@param[out] sign 符号
33@return 仮数
34仮数は1の位から下へ17桁で、小数点を含まない。そのため、誤差を無視すればVal(仮数) * 10 ^ (e - 17) = Abs(x)が成り立つ。
35
[364]36xに無限大、非数を渡した場合の動作は未定義。
[335]37*/
38Function FloatToChars(x As Double, ByRef e As Long, ByRef sign As Boolean) As String
39 Imports System
40
41 '0を弾く
42 If x = 0 Then
43 If GetQWord(VarPtr(x) As *QWord) And &h8000000000000000 Then
44 sign = True
45 Else
46 sign = False
47 End If
48
49 e = 0
50 FloatToChars = "00000000000000000"
51 Exit Function
52 End If
53
54 '符号の判断(同時に符号を取り除く)
55 If x < 0 Then
56 sign = True
57 x = -x
58 Else
59 sign = False
60 End If
61
62 '1e16 <= x < 1e17へ正規化
63 '(元のx) = (正規化後のx) ^ (d - 17)である。
64 Dim d = Math.Floor(Math.Log10(x)) As Long
65 If d < 16 Then
66 x *= ipow(10, +17 - d)
67 ElseIf d > 16 Then
68 x /= ipow(10, -17 + d)
69 End If
70
71 '補正
72 While x < 1e16
73 x *= 10
74 d--
75 Wend
76 While x >= 1e17
77 x /= 10
78 d++
79 Wend
80
81 d--
82 e = d
83
[365]84 FloatToChars = FormatIntegerLU((x As Int64) As QWord, 17, 0, None)
[335]85End Function
86
87/*!
88@brief 書式化関数群で使用するフラグ。
89@author Egtra
90@date 2007/09/18
91*/
92Const Enum FormatFlags
93 '! 何も指定がない。
94 None = &h0
[364]95 /*!
96 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
97 AdjustFieldWidthの仕様から、Format関数郡内からAdjustFieldWidthにかけて、
98 単に数値が符号付である(負の値である)ことを示す意味でも用いられる。
99 */
[335]100 Sign = &h1
101 /*! 空白、空白文字。
102 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。
103 */
104 Blank = &h2
105 /*! ゼロ、0。
106 [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。
107 */
108 Zero = &h4
109 '! 左揃え、-。フィールド内で左揃えにする。
[385]110 LeftSide = &h8
[335]111 /*! 代替表記、#。
[468]112 @li [OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul>
113 @li [AaEeFfGg]では、精度0でも小数点を付ける。</ul>
114 @li [Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul>
[335]115 */
116 Alt = &h10
117 '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。
118 Cap = &h20
[365]119
[383]120 '!BASIC接頭辞。&h, &oなど。
121 BPrefix = &h40
122
[365]123 /*!
124 内部処理用に予約。
125 @note Minusとして使用されている。
126 */
127 Reserved = &h80000000
[335]128End Enum
129
130/*!
[364]131@brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。
[335]132@author Egtra
133@date 2007/09/18
[365]134@param[in] x 文字列化する浮動小数点数値。
[383]135@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
[365]136@param[in] field フィールド幅。
137@param[in] flags 書式フラグ。
138@return xの文字列表現
[468]139*/
140Function FormatFloatE(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
141 FormatFloatE = FormatFloatEx(AddressOf(FormatFloatE_Convert), x, precision, field, flags)
142End Function
[335]143
[468]144/*
145@brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。
146@author Egtra
147@date 2008/03/08
148@param[in,out] sb 書式化した文字列を追加するバッファ。
149@param[in] x 文字列化する浮動小数点数値。
150@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
151@param[in] field フィールド幅。
152@param[in] flags 書式フラグ。
153*/
154Sub FormatFloatE(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
155 FormatFloatEx(sb, AddressOf(FormatFloatE_Convert), x, precision, field, flags)
156End Sub
157
158/*!
159@brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。
160@author Egtra
161@date 2008/03/07
162@param[in,out] sb 書式化した文字列を追加するバッファ。
163@param[in] x 文字列化する浮動小数点数値。
164@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして15となる。
165@param[in] field フィールド幅。
166@param[in,out] flags 書式フラグ。
[365]167@todo 他の実装での末尾桁の扱いを調べる(このコードでは何もしていないので切捨となっている)。
[335]168*/
[468]169Sub FormatFloatE_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
[383]170 If precision = DWORD_MAX Then
[468]171 precision = 15
[364]172 End If
173 Dim e As Long, negative As Boolean
174 Dim s = FloatToChars(x, e, negative)
[468]175 FormatFloatE_Base(sb, s, negative, precision, flags)
[383]176 FormatFloatE_Exponent(sb, e, flags)
[468]177End Sub
[364]178
[383]179/**
180@brief FormatFloatEの符号・基数部の出力用。
181@author Egtra
182@date 2007/10/27
183*/
[468]184Sub FormatFloatE_Base(sb As System.Text.StringBuilder, s As String, negative As Boolean, precision As DWord, ByRef flags As FormatFlags)
185 With sb
186 AppendSign(sb, negative, flags)
[335]187 .Append(s[0])
[383]188 If (flags And Alt) Or precision > 0 Then
[335]189 .Append(".")
190 Dim outputLen = s.Length - 1
[383]191 If outputLen >= precision Then
192 .Append(s, 1, precision)
[335]193 Else 'sで用意された桁が指定された精度より少ないとき
194 .Append(s, 1, outputLen)
[468]195 .Append(&h30 As Char, precision - outputLen) '足りない桁は0埋め
[335]196 End If
197 End If
[383]198 End With
[468]199End Sub
[335]200
[383]201/**
202@brief FormatFloatEの指数部の出力用。
203@author Egtra
204@date 2007/10/27
205*/
[468]206Sub FormatFloatE_Exponent(sb As System.Text.StringBuilder, e As Long, flags As FormatFlags)
207 With sb
[335]208 If flags And Cap Then
209 .Append("E")
210 Else
211 .Append("e")
212 End If
[468]213 FormatIntegerD(sb, e, 2, 0, Sign Or Zero)
[335]214 End With
[383]215End Sub
[335]216
[364]217/*!
[365]218@brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。
[364]219@author Egtra
220@date 2007/10/23
221@param[in] x 文字列化する浮動小数点数値。
[468]222@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値15となる。
[364]223@param[in] field フィールド幅。
224@param[in] flags 書式フラグ。
225@return xの文字列表現
226*/
227Function FormatFloatF(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
[468]228 FormatFloatF = FormatFloatEx(AddressOf(FormatFloatF_Convert), x, precision, field, flags)
229End Function
230
231/*
232@brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。
233@author Egtra
234@date 2008/03/08
235@param[in,out] sb 書式化した文字列を追加するバッファ。
236@param[in] x 文字列化する浮動小数点数値。
237@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
238@param[in] field フィールド幅。
239@param[in] flags 書式フラグ。
240*/
241Sub FormatFloatF(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
242 FormatFloatEx(sb, AddressOf(FormatFloatF_Convert), x, precision, field, flags)
243End Sub
244
245/*!
246@brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。
247@author Egtra
248@date 2008/03/07
249@param[in,out] sb 書式化した文字列を追加するバッファ。
250@param[in] x 文字列化する浮動小数点数値。
251@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値15となる。
252@param[in] field フィールド幅。
253@param[in,out] flags 書式フラグ。
254*/
255Sub FormatFloatF_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
[364]256 If precision = DWORD_MAX Then
[468]257 precision = 15
[364]258 End If
259 Dim e As Long, negative As Boolean
260 Dim s = FloatToChars(x, e, negative)
[468]261 FormatFloatF_Core(sb, s, e, negative, precision, flags)
262End Sub
[364]263
[383]264/**
265@author Egtra
266@date 2007/10/27
267*/
[468]268Sub FormatFloatF_Core(sb As System.Text.StringBuilder, s As String, e As Long, negative As Boolean, precision As DWord, ByRef flags As FormatFlags)
269 With sb
270 AppendSign(sb, negative, flags)
[364]271
272 Dim intPartLen = e + 1
273 Dim outputDigit = 0 As DWord
274 If intPartLen >= 17 Then
275 '有効桁が全て整数部に収まる場合
276 .Append(s)
[468]277 .Append(&h30 As Char, intPartLen - 17)
[364]278 outputDigit = 17
279 ElseIf intPartLen > 0 Then
280 '有効桁の一部が整数部にかかる場合
281 .Append(s, 0, intPartLen)
282 outputDigit = intPartLen
283 Else
284 '有効桁が全く整数部にかからない場合
[468]285 .Append(&h30 As Char)
[364]286 End If
287
288 If precision > 0 Or (flags And Alt) Then
289 .Append(".")
290
291 Dim lastDigit = s.Length - outputDigit
292 If lastDigit >= precision Then '変換して得られた文字列の桁数が精度以上ある場合
293 Dim zeroDigit = 0
294 If intPartLen < 0 Then
295 '1.23e-4 = 0.000123のように指数が負のため小数点以下に0が続く場合
296 zeroDigit = System.Math.Min(-intPartLen As DWord, precision)
[468]297 .Append(&h30 As Char, zeroDigit As Long)
[364]298 End If
299 .Append(s, outputDigit, (precision - zeroDigit) As Long)
300 Else
301 .Append(s, outputDigit, lastDigit)
[468]302 .Append(&h30 As Char, (precision - lastDigit) As Long) '残りの桁は0埋め
[364]303 End If
304 End If
305 End With
[468]306End Sub
[364]307
308/*!
[383]309@brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。
310@author Egtra
311@date 2007/10/23
312@param[in] x 文字列化する浮動小数点数値。
[468]313@param[in] precision 精度。小数点以下の桁数。DWORD_MAXまたは0のとき、指定なしとして既定値15となる。
[383]314@param[in] field フィールド幅。
315@param[in] flags 書式フラグ。
316@return xの文字列表現
317@todo 下位桁の扱いの調査。
318*/
319Function FormatFloatG(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
[468]320 FormatFloatG = FormatFloatEx(AddressOf(FormatFloatG_Convert), x, precision, field, flags)
321End Function
322
323/*
324@brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。
325@author Egtra
326@date 2008/03/08
327@param[in,out] sb 書式化した文字列を追加するバッファ。
328@param[in] x 文字列化する浮動小数点数値。
329@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
330@param[in] field フィールド幅。
331@param[in] flags 書式フラグ。
332*/
333Sub FormatFloatG(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
334 FormatFloatEx(sb, AddressOf(FormatFloatG_Convert), x, precision, field, flags)
335End Sub
336
337/*!
338@brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。
339@author Egtra
340@date 2007/10/23
341@param[in,out] sb 書式化した文字列を追加するバッファ。
342@param[in] x 文字列化する浮動小数点数値。
343@param[in] precision 精度。小数点以下の桁数。DWORD_MAXまたは0のとき、指定なしとして既定値15となる。
344@param[in] field フィールド幅。
345@param[in,out] flags 書式フラグ。
346@todo 下位桁の扱いの調査。
347*/
348Sub FormatFloatG_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
[383]349 'GではE/Fと違い整数部も有効桁数に数えるのでその分を引いておく。
350 If precision = DWORD_MAX Or precision = 0 Then
[468]351 precision = 14
[383]352 Else
353 precision--
354 End If
[468]355 Dim lastLength = sb.Length
[383]356 Dim e As Long, negative As Boolean
357 Dim s = FloatToChars(x, e, negative)
358 If -5 < e And e < precision Then
[468]359 FormatFloatF_Core(sb, s, e, negative, -e + precision, flags)
360 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
[383]361 Else
[468]362 FormatFloatE_Base(sb, s, negative, precision, flags)
363 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
[383]364 FormatFloatE_Exponent(sb, e, flags)
365 End If
[468]366End Sub
[383]367
368/*!
369@brief FormatFloatG/A用の小数点以下末尾の0を削除するルーチン
370@author Egtra
371@date 2007/10/27
372@param[in, out] sb 文字列バッファ
373@param[in] flags フラグ
374flagsでAltが立っているとき、この関数は何もしない。
375*/
[468]376Sub FormatFloatG_RemoveLowDigit(sb As System.Text.StringBuilder, start As Long, flags As FormatFlags)
[383]377 Imports ActiveBasic.Strings
378
379 Dim count = sb.Length
380 If (flags And Alt) = 0 Then
[468]381 Dim p = StrPtr(sb)
382 Dim point = ChrFind(VarPtr(p[start]), (count - start) As SIZE_T, Asc("."))
[383]383 If point = -1 Then
384 Debug
385 End If
386
387 Dim i As Long
388 For i = count - 1 To point + 1 Step -1
389 If sb[i] <> &h30 Then
390 Exit For
391 End If
392 Next
393 If i <> point Then
394 i++
395 End If
396 sb.Length = i
397 End If
398End Sub
399
400/*!
401@brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。
402@author Egtra
403@date 2007/09/18
404@param[in] x 文字列化する浮動小数点数値。
405@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値13となる。
406@param[in] field フィールド幅。
407@param[in] flags 書式フラグ。
408@return xの文字列表現
409
410C99では、末尾の0を取り除いても良いとあるので、
411このルーチンでは取り除くことにしている。
412*/
413Function FormatFloatA(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
[468]414 FormatFloatA = FormatFloatEx(AddressOf(FormatFloatA_Convert), x, precision, field, flags)
415End Function
416
417/*
418@brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。
419@author Egtra
420@date 2008/03/08
421@param[in,out] sb 書式化した文字列を追加するバッファ。
422@param[in] x 文字列化する浮動小数点数値。
423@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
424@param[in] field フィールド幅。
425@param[in] flags 書式フラグ。
426*/
427Sub FormatFloatA(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
428 FormatFloatEx(sb, AddressOf(FormatFloatA_Convert), x, precision, field, flags)
429End Sub
430
431/*!
432@brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。
433@author Egtra
434@date 2008/03/07
435@param[in,out] sb 書式化した文字列を追加するバッファ。
436@param[in] x 文字列化する浮動小数点数値。
437@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値13となる。
438@param[in] field フィールド幅。
439@param[in,out] flags 書式フラグ。
440
441C99では、末尾の0を取り除いても良いとあるので、
442このルーチンでは取り除くことにしている。
443*/
444Sub FormatFloatA_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
[383]445 If precision = DWORD_MAX Then
446 precision = 13
447 End If
[468]448 Dim lastLength = sb.Length
[383]449 Dim pqw = VarPtr(x) As *QWord
450
451 With sb
452 Dim sign = (GetQWord(pqw) And &H8000000000000000) As Boolean
453 pqw[0] And= &h7fffffffffffffff
454
455 AppendSign(sb, sign, flags)
456
457 If flags And BPrefix Then
458 .Append("&H")
459 Else
460 .Append("0X")
461 End If
462
463 Dim biasedExp = (GetQWord(pqw) >> 52) As DWord And &h7FF
464 Dim exp As Long
465 If biasedExp = 0 Then
466 If GetQWord(pqw) <> 0 Then
467 exp = -1022 '非正規化数への対応
468 Else
469 exp = 0
470 End If
471 .Append("0")
472 Else
473 exp = biasedExp - 1023
474 .Append("1")
475 End If
476
477 If precision > 0 Or (flags And Alt) Then
478 .Append(".")
[468]479 Dim fraction = GetQWord(pqw) And &h000fffffffffffff
480 If precision < 13 Then
481 Dim dropped = 13 - precision
482 fraction >>= dropped * 4
483 FormatIntegerLX(sb, fraction, precision, 0, flags And Cap)
[383]484 Else
[468]485 FormatIntegerLX(sb, fraction, 13, 0, flags And Cap)
486 .Append(&h30, precision - 13)
[383]487 End If
488 End If
[468]489 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
[383]490 .Append("P")
[468]491 FormatIntegerD(sb, exp, 1, 0, Sign)
492 AdjustAlphabet(sb, flags, lastLength)
[383]493 End With
[468]494End Sub
[383]495
496/*!
[364]497@brief 先頭に符号もしくはその分の空白を出力する。FormatFloat用。
498@author Egtra
499@date 2007/10/23
500@param[in, out] sb 出力先
501@param[in] negative 符号
502@param[in, out] flags フラグ。negative = Trueなら、Signを立てて返す。
503*/
504Sub AppendSign(sb As System.Text.StringBuilder, negative As Boolean, ByRef flags As FormatFlags)
505 With sb
506 If negative Then
507 .Append("-")
508 flags Or= Sign
509 Else
510 If flags And Sign Then
511 .Append("+")
512 ElseIf flags And Blank Then
513 .Append(" ")
514 End If
515 End If
516 End With
517End Sub
518
[365]519/*!
[364]520@brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。
[335]521@author Egtra
522@date 2007/09/18
523@param[in] x 文字列化する整数値。
524@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
525@param[in] field フィールド幅。
526@param[in] flags 書式フラグ。
527@return xの文字列表現
528*/
529Function FormatIntegerU(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]530 Return FormatIntegerEx(TraitsIntegerU[0], x, d, field, flags And (Not (Sign Or Blank)))
[355]531End Function
[335]532
[358]533/*!
[468]534@brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。
535@author Egtra
536@date 2008/03/07
537@param[in,out] sb 書式化した文字列を追加するバッファ。
538@param[in] x 文字列化する整数値。
539@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
540@param[in] field フィールド幅。
541@param[in] flags 書式フラグ。
542*/
543Sub FormatIntegerU(sb As System.Text.StringBuilder, x As DWord, d As DWord, field As DWord, flags As FormatFlags)
544 FormatIntegerEx(sb, TraitsIntegerU[0], x As QWord, d, field, flags And (Not (Sign Or Blank)))
545End Sub
546
547/*!
[365]548@brief FormatIntegerUのQWord版
549@author Egtra
550@date 2007/10/26
[358]551*/
[365]552Function FormatIntegerLU(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]553 Return FormatIntegerEx(TraitsIntegerU[1], x, d, field, flags And (Not (Sign Or Blank)))
[365]554End Function
[355]555
556/*!
[468]557@brief FormatIntegerUのQWord版
558@author Egtra
559@date 2008/03/07
560@param[in,out] sb 書式化した文字列を追加するバッファ。
561@param[in] x 文字列化する整数値。
562@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
563@param[in] field フィールド幅。
564@param[in] flags 書式フラグ。
565*/
566Sub FormatIntegerLU(sb As System.Text.StringBuilder, x As QWord, d As DWord, field As DWord, flags As FormatFlags)
567 FormatIntegerEx(sb, TraitsIntegerU[0], x, d, field, flags And (Not (Sign Or Blank)))
568End Sub
569
570/*!
[364]571@brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。
[355]572@author Egtra
573@date 2007/10/13
574@param[in] x 文字列化する整数値。
575@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
576@param[in] field フィールド幅。
577@param[in] flags 書式フラグ。
578@return xの文字列表現
579*/
580Function FormatIntegerD(x As Long, d As DWord, field As DWord, flags As FormatFlags) As String
[383]581 Return FormatIntegerEx(TraitsIntegerD[0], (x As Int64) As QWord, d, field, flags)
[365]582End Function
583
584/*!
[468]585@brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。
586@author Egtra
587@date 2008/03/07
588@param[in,out] sb 書式化した文字列を追加するバッファ。
589@param[in] x 文字列化する整数値。
590@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
591@param[in] field フィールド幅。
592@param[in] flags 書式フラグ。
593*/
594Sub FormatIntegerD(sb As System.Text.StringBuilder, x As Long, d As DWord, field As DWord, flags As FormatFlags)
595 FormatIntegerEx(sb, TraitsIntegerD[0], (x As Int64) As QWord, d, field, flags)
596End Sub
597
598/*!
[365]599@brief FormatIntegerDのInt64版
600@author Egtra
601@date 2007/10/26
602*/
603Function FormatIntegerLD(x As Int64, d As DWord, field As DWord, flags As FormatFlags) As String
[383]604 Return FormatIntegerEx(TraitsIntegerD[1], x As QWord, d, field, flags)
[355]605End Function
606
607/*!
[468]608@brief FormatIntegerDのInt64版
[355]609@author Egtra
[365]610@date 2007/10/26
611*/
[468]612Sub FormatIntegerLD(sb As System.Text.StringBuilder, x As Int64, d As DWord, field As DWord, flags As FormatFlags)
613 FormatIntegerEx(sb, TraitsIntegerD[1], x As QWord, d, field, flags)
614End Sub
615
616/*!
617@author Egtra
618@date 2007/10/26
619*/
[383]620Dim TraitsIntegerU[1] As IntegerConvertTraits
621With TraitsIntegerU[0]
622 .Convert = AddressOf(IntegerU_Convert)
623 .Prefix = AddressOf(IntegerU_Prefix)
[365]624End With
[364]625
[383]626With TraitsIntegerU[1]
627 .Convert = AddressOf(IntegerLU_Convert)
628 .Prefix = AddressOf(IntegerU_Prefix)
629End With
630
[365]631/*!
632@author Egtra
[383]633@date 2007/10/28
[355]634*/
[383]635Dim TraitsIntegerD[1] As IntegerConvertTraits
636With TraitsIntegerD[0]
637 .Convert = AddressOf(IntegerD_Convert)
638 .Prefix = AddressOf(IntegerD_Prefix)
639End With
640
641With TraitsIntegerD[1]
642 .Convert = AddressOf(IntegerLD_Convert)
643 .Prefix = AddressOf(IntegerD_Prefix)
[365]644End With
[335]645
[365]646/*!
647@brief 負数を表すフラグ。FormatIntegerD, LDからIntegerDU_Prefixまでの内部処理用。
648@author Egtra
649@date 2007/10/26
650*/
651Const Minus = Reserved
[355]652
[365]653/*!
654@author Egtra
655@date 2007/10/26
656*/
[468]657Function IntegerU_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
[365]658 Dim x = xq As DWord
[468]659 Dim i = MaxSizeLO
[365]660 While x <> 0
[468]661 buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策
[365]662 x \= 10
663 i--
664 Wend
665 Return i
666End Function
[335]667
[365]668/*!
[383]669@brief IntegerU_ConvertのQWord版
[365]670@author Egtra
671@date 2007/10/26
672@bug #117のため、現在Int64の最大値を超える値を正しく処理できない。
673*/
[468]674Function IntegerLU_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
675 Dim i = MaxSizeLO
[365]676 While x <> 0
[468]677 buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策
[365]678 x \= 10
679 i--
680 Wend
681 Return i
682End Function
[335]683
[365]684/*!
685@author Egtra
686@date 2007/10/26
687*/
[383]688Function IntegerU_Prefix(x As QWord, flags As FormatFlags) As String
689End Function
690
691/*!
692@author Egtra
693@date 2007/10/28
694*/
[468]695Function IntegerD_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
[383]696 Return IntegerU_Convert(buf, Abs((xq As DWord) As Long) As DWord, flags)
697End Function
698
699/*!
700@brief IntegerD_ConvertのInt64版
701@author Egtra
702@date 2007/10/28
703*/
[468]704Function IntegerLD_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
[383]705 Return IntegerLU_Convert(buf, Abs(x As Int64) As QWord, flags)
706End Function
707
708/*!
709@author Egtra
710@date 2007/10/28
711*/
712Function IntegerD_Prefix(x As QWord, flags As FormatFlags) As String
713 If (x As Int64) < 0 Then
714 IntegerD_Prefix = "-"
[365]715 ElseIf flags And Sign Then
[383]716 IntegerD_Prefix = "+"
[365]717 ElseIf flags And Blank Then
[383]718 IntegerD_Prefix = " "
[365]719 End If
[355]720End Function
721
[358]722
[468]723
[365]724/*!
725@brief QWordの最大値の八進法表現1777777777777777777777の文字数 - 1 + 1。IntegerO_Convert内で使用。
726@author Egtra
727@date 2007/10/26
728上の式で1を加えているのは、八進接頭辞の分。
729*/
730Const MaxSizeLO = 22
731
732/*!
733@author Egtra
734@date 2007/10/22
735*/
[383]736Dim TraitsIntegerO[1] As IntegerConvertTraits
737With TraitsIntegerO[0]
[364]738 .Convert = AddressOf(IntegerO_Convert)
739 .Prefix = AddressOf(IntegerO_Prefix)
740End With
741
[383]742With TraitsIntegerO[1]
[365]743 .Convert = AddressOf(IntegerLO_Convert)
744 .Prefix = AddressOf(IntegerO_Prefix)
745End With
746
747/*!
[364]748@brief 符号無し整数をprintfの%o(八進法表現)相当の変換で文字列化する関数。
[358]749@author Egtra
750@date 2007/10/19
751@param[in] x 文字列化する整数値。
752@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
753@param[in] field フィールド幅。
754@param[in] flags 書式フラグ。
755@return xの文字列表現
756*/
757Function FormatIntegerO(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]758 Return FormatIntegerEx(TraitsIntegerO[0], x, d, field, flags)
[364]759End Function
[358]760
[365]761/*!
762@brief FormatIntegerOのQWord版。
763@author Egtra
764@date 2007/10/26
765*/
766Function FormatIntegerLO(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]767 Return FormatIntegerEx(TraitsIntegerO[1], x, d, field, flags)
[365]768End Function
769
770/*!
771@author Egtra
772@date 2007/10/22
773*/
[468]774Function IntegerO_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
[364]775 Dim x = xq As DWord
[468]776 Dim i = MaxSizeLO
[364]777 While x <> 0
[468]778 buf[i] = ((x And &o7) + &h30) As Char
[364]779 x >>= 3
780 i--
781 Wend
782 If flags And Alt Then
783 buf[i] = &h30
784 i--
785 End If
[365]786 Return i
[364]787End Function
[358]788
[365]789/*!
790@brief IntegerO_ConvertのQWord版。
791@author Egtra
792@date 2007/10/26
793*/
[468]794Function IntegerLO_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
[365]795 Dim i = MaxSizeLO
796 While x <> 0
[468]797 buf[i] = ((x And &o7) + &h30) As Char
[365]798 x >>= 3
799 i--
800 Wend
801 If flags And Alt Then
802 buf[i] = &h30
803 i--
804 End If
805 Return i
806End Function
807
808/*!
809@author Egtra
810@date 2007/10/22
811@note #フラグ (Alt)の処理は、IntegerO/LO_Convert内で行うので、ここで処理することはない。
812*/
[364]813Function IntegerO_Prefix(x As QWord, flags As FormatFlags) As String
[383]814 If flags And BPrefix Then
815 If x <> 0 Then
816 IntegerO_Prefix = "&O"
817 End If
818 End If
[358]819End Function
820
821/*!
[365]822@author Egtra
823@date 2007/10/24
[358]824*/
[383]825Dim TraitsIntegerX[1] As IntegerConvertTraits
826With TraitsIntegerX[0]
[364]827 .Convert = AddressOf(IntegerX_Convert)
828 .Prefix = AddressOf(IntegerX_Prefix)
829End With
830
[383]831With TraitsIntegerX[1]
[365]832 .Convert = AddressOf(IntegerLX_Convert)
833 .Prefix = AddressOf(IntegerX_Prefix)
834End With
835
836/*!
[364]837@brief 整数をprintfの%x, %X(十六進法)相当の変換で文字列化する関数。
[358]838@author Egtra
839@date 2007/10/19
840@param[in] x 文字列化する整数値。
841@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
842@param[in] field フィールド幅。
843@param[in] flags 書式フラグ。
844@return xの文字列表現
845*/
846Function FormatIntegerX(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]847 Return FormatIntegerEx(TraitsIntegerX[0], x, d, field, flags)
[364]848End Function
849
[365]850/*!
851@brief FormatIntegerXのQWord版。
852@author Egtra
853@date 2007/10/22
854*/
855Function FormatIntegerLX(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
[383]856 Return FormatIntegerEx(TraitsIntegerX[1], x, d, field, flags)
[365]857End Function
858
[468]859/*!
860@brief FormatIntegerXのQWord, StringBuilder版。
861@author Egtra
862@date 2008/03/07
863*/
864Sub FormatIntegerLX(sb As System.Text.StringBuilder, x As QWord, d As DWord, field As DWord, flags As FormatFlags)
865 FormatIntegerEx(sb, TraitsIntegerX[1], x, d, field, flags)
866End Sub
867
[388]868/*
869@brief 0からFまでの文字を収めた表
870@author egtra
871*/
872Dim HexadecimalTable[&h10] = [&h30, &h31, &h32, &h33, &h34, &h35, &h36, &h37, &h38, &h39, &h41, &h42, &h43, &h44, &h45, &h46] As Byte
873
[365]874/*!
875@author Egtra
876@date 2007/10/22
877*/
[468]878Function IntegerX_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
879 Dim i = MaxSizeLO
[364]880 Dim x = xq As DWord
881 While x <> 0
[388]882 buf[i] = HexadecimalTable[x And &h0f]
[364]883 x >>= 4
884 i--
885 Wend
[365]886 Return i
[364]887End Function
888
[365]889/*!
890@brief IntegerX_ConvertのQWord版。
891@author Egtra
892@date 2007/10/22
893*/
[468]894Function IntegerLX_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
895 Dim i = MaxSizeLO
[365]896 While x <> 0
[388]897 buf[i] = HexadecimalTable[x And &h0f]
[365]898 x >>= 4
899 i--
900 Wend
901 Return i
902End Function
903
904/*!
905@author Egtra
906@date 2007/10/24
907*/
[364]908Function IntegerX_Prefix(x As QWord, flags As FormatFlags) As String
[383]909 If x <> 0 Then
910 If flags And Alt Then
[364]911 IntegerX_Prefix = "0X"
[383]912 ElseIf flags And BPrefix Then
913 IntegerX_Prefix = "&H"
[364]914 End If
915 End If
916End Function
917
[365]918/*!
919@brief FormatIntegerExへ渡す変換特性を表す構造体型。
920@author Egtra
921@date 2007/10/22
[383]922
923FormatIntegerの都合上、このファイル内で宣言しているIntegerConvertTraits型の
924変数は全て配列となっている;[0]が32ビット変換、[1]が64ビット変換である。
[365]925*/
[364]926Type IntegerConvertTraits
[365]927 '!変換を行う関数へのポインタ。
[468]928 Convert As *Function(buf As *Char, x As QWord, flags As FormatFlags) As DWord
[365]929 '!接頭辞を取得する関数へのポインタ。
[364]930 Prefix As *Function(x As QWord, flags As FormatFlags) As String
931End Type
932
933/*!
[468]934@brief 整数変換全てを行う関数。
[364]935@author Egtra
936@date 2007/10/22
937@param[in] tr 特性情報。
938@param[in] x 変換元の数値。
939@param[in] d 精度。ここでは最低限出力する桁数。
940@param[in] field フィールド幅。
941@param[in] flags フラグ。
[468]942@return 変換された文字列
[364]943*/
944Function FormatIntegerEx(ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
[468]945 Dim sb = New System.Text.StringBuilder(32)
946 FormatIntegerEx(sb, tr, x, d, field, flags)
947 FormatIntegerEx = sb.ToString
948End Function
949
950/*!
951@brief 整数変換全てを行う関数。これを雛形とし、形式毎の差異はIntegerConvertTraitsで表現する。
952@author Egtra
953@date 2008/03/06
954@param[in,out] sb 書式化した文字列を追加するバッファ。
955@param[in] tr 特性情報。
956@param[in] x 変換元の数値。
957@param[in] d 精度。ここでは最低限出力する桁数。
958@param[in] field フィールド幅。
959@param[in] flags フラグ。
960*/
961Sub FormatIntegerEx(sb As System.Text.StringBuilder, ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags)
[365]962 If d = DWORD_MAX Then
963 d = 1
964 Else
965 '精度が指定されているとき、ゼロフラグは無視される。
966 '仕様上、左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
967 flags And= Not Zero
968 End If
[358]969
[468]970 Dim lastLength = sb.Length
971
[358]972 With sb
[364]973 Dim prefixFunc = tr.Prefix
974 Dim prefix = prefixFunc(x, flags)
975 sb.Append(prefix)
976
[358]977 Dim prefixLen = 0 As DWord
[364]978 If String.IsNullOrEmpty(prefix) = False Then
979 prefixLen = prefix.Length As DWord
[358]980 End If
981
[468]982 'バッファの量は最も必要文字数の多くなるUInt64の8進法変換にあわせている
983 Dim buf[MaxSizeLO] As Char
[364]984 Dim convertFunc = tr.Convert
985 Dim bufStartPos = convertFunc(buf, x, flags)
[358]986
[468]987 Dim len = (MaxSizeLO - bufStartPos) As Long
[365]988 If len < 0 Then
989 Debug
990 End If
[358]991 If len < d Then
[468]992 .Append(&h30 As Char, d - len)
[358]993 End If
[364]994 .Append(buf, bufStartPos + 1, len)
[468]995 AdjustFieldWidth(sb, field, flags And (Not (Sign Or Blank)), prefixLen, lastLength)
996 AdjustAlphabet(sb, flags, lastLength)
[358]997 End With
[468]998End Sub
[358]999
[468]1000/*!
1001@brief 浮動小数点数変換全てを行う関数。これを雛形とし、実際の変換関数は引数converterで与える。
1002@author Egtra
1003@date 2008/03/07
1004@param[in,out] sb 書式化した文字列を追加するバッファ。
1005@param[in] converter 変換関数。
1006@param[in] x 変換元の数値。
1007@param[in] d 精度。ここでは最低限出力する桁数。
1008@param[in] field フィールド幅。
1009@param[in] flags フラグ。
1010*/
1011Sub FormatFloatEx(sb As System.Text.StringBuilder, converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags)
1012 Dim lastLength = sb.Length
1013 If Math.IsNaN(x) Then
1014 sb.Append("NAN")
1015 AdjustAlphabet(sb, flags, lastLength)
1016 ElseIf Math.IsInf(x) Then
1017 AppendSign(sb, (GetQWord(VarPtr(x)) >> 63) As Boolean, flags)
1018 sb.Append("INFINITY")
1019 AdjustAlphabet(sb, flags, lastLength)
[457]1020 Else
[468]1021 converter(sb, x, precision, field, flags)
[457]1022 End If
[468]1023 AdjustFieldWidth(sb, field, flags, 0, lastLength)
1024End Sub
[457]1025
1026
[468]1027/*!
1028@brief 浮動小数点数変換全てを行う関数。
1029@author Egtra
1030@date 2008/03/08
1031@param[in] converter 変換関数。
1032@param[in] x 変換元の数値。
1033@param[in] d 精度。ここでは最低限出力する桁数。
1034@param[in] field フィールド幅。
1035@param[in] flags フラグ。
1036@return 変換された文字列。
1037*/
1038Function FormatFloatEx(converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
1039 Dim sb = New System.Text.StringBuilder
1040 FormatFloatEx(sb, converter, x, precision, field, flags)
1041 FormatFloatEx = sb.ToString
1042End Function
[457]1043
[468]1044/*!
1045@brief 書式化の仕上げとして、Capフラグが指定されていないときに小文字化する作業を行う。
1046@author Egtra
1047@date 2008/03/06
1048@param[in,out] sb 書式化した文字列を格納しているバッファ。
1049@param[in] flags フラグ。
1050@param[in] offset 書式変換した部分の開始位置。
1051*/
1052Sub AdjustAlphabet(sb As System.Text.StringBuilder, flags As FormatFlags, offset As Long)
[457]1053 If (flags And Cap) = 0 Then
1054 Dim len = sb.Length
1055 Dim i As Long
[468]1056 For i = offset To ELM(len)
[457]1057 sb[i] = CType.ToLower(sb[i])
1058 Next
1059 End If
1060End Sub
1061
[355]1062/*!
[457]1063@brief 書式化の仕上げとして、変換部分がフィールド幅まで満たされるように空白などを挿入する。
[365]1064@author Egtra
1065@date 2007/10/13
1066@param[in,out] sb 対象文字列
1067@param[in] field フィールド幅
1068@param[in] hasSign 符号を持っている(負の値か)か否か
1069@param[in] flags フラグ
1070@param[in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
[457]1071@param[in] offset 変換した部分へのオフセット。AppendではなくInsertを行う際に用いられる。
[364]1072sbが"-1"のように負符号を持っている場合は、呼出元でSignフラグ(またはBlank)を立てること。
[355]1073*/
[457]1074Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, flags As FormatFlags, prefixLen = 0 As DWord, offset = 0 As Long)
[355]1075 With sb
[457]1076 Dim len = .Length - offset
1077 If len < field Then
1078 Dim embeddedSize = field - len
[385]1079 If flags And LeftSide Then
[335]1080 .Append(&h20, embeddedSize)
1081 Else
[355]1082 If (flags And Zero) <> 0 Then
[457]1083 offset += prefixLen
[364]1084 If (flags And Blank) Or (flags And Sign) Then
[457]1085 offset++
[355]1086 End If
[457]1087 .Insert(offset, String$(embeddedSize, "0"))
[355]1088 Else
[457]1089 .Insert(offset, String$(embeddedSize, " "))
[355]1090 End If
[335]1091 End If
1092 End If
1093 End With
[355]1094End Sub
[335]1095
[383]1096/*!
1097@brief 文字列をprintfの%s相当の変換で書式化する関数。
1098@author Egtra
1099@date 2007/10/27
1100@param[in] x 文字列。
1101@param[in] d 精度、最大の文字数。
1102@param[in] field フィールド幅。
1103@param[in] flags 書式フラグ。
1104@return 書式化された文字列。
1105*/
1106Function FormatString(x As String, d As DWord, field As DWord, flags As FormatFlags) As String
[468]1107 Imports System
[383]1108 Dim sb = New System.Text.StringBuilder(
[468]1109 Math.Max(Math.Min(x.Length As DWord, d), field) As Long + 1)
1110 FormatString(sb, x, d, field, flags)
[385]1111 AdjustFieldWidth(sb, field, flags And LeftSide)
[383]1112 FormatString = sb.ToString()
1113End Function
1114
1115/*!
[468]1116@brief 文字列をprintfの%s相当の変換で書式化する関数。
1117@author Egtra
1118@date 2008/03/07
1119@param[in,out] sb 書式化した文字列を追加するバッファ。
1120@param[in] x 文字列。
1121@param[in] d 精度、最大の文字数。
1122@param[in] field フィールド幅。
1123@param[in] flags 書式フラグ。
1124@return 書式化された文字列。
1125*/
1126Sub FormatString(sb As System.Text.StringBuilder, x As String, d As DWord, field As DWord, flags As FormatFlags)
1127 Dim len = sb.Length
1128 sb.Append(x, 0, System.Math.Min(x.Length As DWord, d) As Long)
1129 AdjustFieldWidth(sb, field, flags And LeftSide, 0, len)
1130End Sub
1131
1132/*!
[383]1133@brief 文字をprintfの%c相当の変換で書式化する関数。
1134@author Egtra
1135@date 2007/10/27
1136@param[in] x 文字。
1137@param[in] d 精度、最大の文字数。
1138@param[in] field フィールド幅。
1139@param[in] flags 書式フラグ。
1140@return 書式化された文字列。
1141*/
[468]1142Function FormatCharacter(x As Char, d As DWord, field As DWord, flags As FormatFlags) As String
1143 Dim sb = New System.Text.StringBuilder(field + 2)
1144 FormatCharacter(sb, x, d, field, flags)
[383]1145 FormatCharacter = sb.ToString()
1146End Function
1147
1148/*!
[468]1149@brief 文字列をprintfの%s相当の変換で書式化する関数。
[383]1150@author Egtra
[468]1151@date 2008/03/07
1152@param[in,out] sb 書式化した文字列を追加するバッファ。
1153@param[in] x 文字。
1154@param[in] d 精度、最大の文字数。
1155@param[in] field フィールド幅。
1156@param[in] flags 書式フラグ。
1157@return 書式化された文字列。
1158*/
1159Sub FormatCharacter(sb As System.Text.StringBuilder, x As Char, d As DWord, field As DWord, flags As FormatFlags)
1160 Dim len = sb.Length
1161 sb.Append(x)
1162 AdjustFieldWidth(sb, field, flags And LeftSide, 0, len)
1163End Sub
1164
1165/*!
1166@author Egtra
[383]1167@date 2007/10/28
1168*/
[468]1169TypeDef FormatFloatProc = *Sub(sb As System.Text.StringBuilder, x As Double, precision As DWord, fieldWidth As DWord, ByRef flags As FormatFlags)
[383]1170
1171/*!
[384]1172@brief SPrintfから呼ばれる浮動小数点数用書式文字列化関数
[383]1173@author Egtra
1174@date 2007/10/28
1175*/
1176Sub FormatFloat(s As System.Text.StringBuilder, formatProc As FormatFloatProc,
1177 param As Object, precision As DWord, field As DWord, flags As FormatFlags)
1178
1179 Dim x As Double
1180 Dim typeName = param.GetType().FullName
1181 If typeName = "System.Double" Then
1182 x = param As System.Double
1183 ElseIf typeName = "System.Single" Then
1184 x = param As System.Single
1185 End If
[468]1186 FormatFloatEx(s, formatProc, x, precision, field, flags)
[383]1187End Sub
1188
1189/*!
[384]1190@brief SPrintfから呼ばれる整数用書式文字列化関数
[383]1191@author Egtra
1192@date 2007/10/28
1193*/
1194Sub FormatInteger(s As System.Text.StringBuilder, traits As *IntegerConvertTraits,
1195 param As Object, signed As Boolean, typeWidth As Long, precision As DWord, field As DWord, flags As FormatFlags)
1196
1197 Dim x As QWord
1198 Dim typeName = param.GetType().FullName
1199 If typeName = "System.UInt64" Then
1200 x = param As System.UInt64
1201 ElseIf typeName = "System.Int64" Then
1202 x = (param As System.Int64) As QWord
1203 ElseIf typeName = "System.UInt32" Then
1204 x = param As System.UInt32
1205 ElseIf typeName = "System.Int32" Then
1206 x = (param As System.Int32) As QWord
1207 ElseIf typeName = "System.UInt16" Then
1208 x = param As System.UInt16
1209 ElseIf typeName = "System.Int16" Then
1210 x = (param As System.Int16) As QWord
1211 ElseIf typeName = "System.UInt8" Then
1212 x = param As System.Byte
1213 ElseIf typeName = "System.Int8" Then
1214 x = (param As System.SByte) As QWord
1215 End If
1216 '一旦縮めた後、符号・ゼロ拡張させる。
1217 'また、64ビット整数なら64ビット変換Traitsを選択する。
1218 If signed Then
1219 If typeWidth = 1 Then
1220 traits = VarPtr(traits[1])
1221 ElseIf typeWidth = 0 Then
1222 x = (((x As DWord) As Long) As Int64) As QWord
1223 ElseIf typeWidth = -1 Then
1224 x = (((x As Word) As Integer) As Int64) As QWord
1225 ElseIf typeWidth = -2 Then
1226 x = (((x As Byte) As SByte) As Int64) As QWord
1227 End If
1228 Else
1229 If typeWidth = 1 Then
1230 traits = VarPtr(traits[1])
1231 ElseIf typeWidth = 0 Then
1232 x = x As DWord
1233 ElseIf typeWidth = -1 Then
1234 x = x As Word
1235 ElseIf typeWidth = -2 Then
1236 x = x As Byte
1237 End If
1238 End If
[457]1239 FormatIntegerEx(s, ByVal traits, x, precision, field, flags)
[383]1240End Sub
1241
1242'Format関数群ここまで
1243'----
1244
1245/*!
1246@brief 文字列から数値への変換。さらに変換に使われなかった文字列の位置を返す。
1247@author Egtra
1248@date 2007/11/11
1249@param[in] s 変換する文字
1250@param[out] p 変換に使われなかった部分の先頭を指すポインタ
1251@return 変換して得られた数値。変換できなければ0。
1252*/
[468]1253Function StrToLong(s As *Char, ByRef p As *Char) As Long
[383]1254 Dim negative As Boolean
1255 Dim i = 0 As Long
1256 If s[i] = &h2d Then 'Asc("-")
1257 i++
1258 negative = True
1259 End If
1260 Do
1261 Dim c = s[i]
[457]1262 If Not CType.IsDigit(c) Then Exit Do
[383]1263 StrToLong *= 10
1264 StrToLong += ((c As DWord) And &h0f) As Long
1265 i++
1266 Loop
1267 If negative Then
1268 StrToLong = -StrToLong
1269 End If
1270 p = VarPtr(s[i])
1271End Function
1272
1273/*!
1274@brief フィールド幅、精度用の数値読取
1275@author Egtra
1276@date 2007/11/11
1277@param[in, out] fmt 読み途中の書式指定
1278@param[in] params
1279@param[in, out] paramsCount
1280@param[out] ret 読み取った数値。読み取られなかったときの値は不定。
1281@retval True 読取を行った
1282@retval False 行わなかった
1283fmt[0]が*のときにはparamsから1つ読み取る。
1284そうでなく、fmtに数字(先頭に-符号があっても可)が並んでいれば、それを読み取る。
1285*/
[468]1286Function ReadInt(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T, ByRef ret As Long) As Boolean
[383]1287 If fmt[0] = &h2a Then '*
[384]1288 fmt = VarPtr(fmt[1]) 'po
[383]1289 ret = params[paramsCount] As System.Int32
1290 paramsCount++
1291 ReadInt = True
1292 Else
[468]1293 Dim p As *Char
[383]1294 ret = StrToLong(fmt, p)
1295 If fmt <> p Then
1296 fmt = p
1297 ReadInt = True
1298 Else
1299 ReadInt = False
1300 End If
1301 End If
1302End Function
1303
1304/*!
1305@brief フラグ指定の読み込み
1306@author Egtra
1307@date 2007/10/28
1308@param[in, out] fmt
1309@param[out] flags
1310@retval True 読み込みが完了した。
1311@retval False 読み取り中に文字列が終了した(ヌル文字が現れた)。
1312*/
[468]1313Function ReadFlags(ByRef fmt As *Char, ByRef flags As FormatFlags) As Boolean
[383]1314 ReadFlags = False
1315 Do
1316 Select Case fmt[0]
1317 Case &h23 '#
1318 flags Or= Alt
1319 Case &h30 '0
1320 flags Or= Zero
1321 Case &h20 '空白
1322 flags Or= Blank
1323 Case &h2b '+
1324 flags Or= Sign
1325 Case &h2d '-
[385]1326 flags Or = LeftSide
[383]1327 Case &h26 '&
1328 flags Or= BPrefix
1329 Case 0
1330 Exit Function
1331 Case Else
1332 Exit Do
1333 End Select
[384]1334 fmt = VarPtr(fmt[1]) 'po
[383]1335 Loop
1336 ReadFlags = True
1337End Function
1338
1339/*!
1340@brief フィールド幅指定の読み込み
1341@author Egtra
1342@date 2007/10/29
1343@param[in, out] fmt
1344@param[in] params
1345@param[in, out] paramsCount
1346@param[out] fieldWidth
1347@param[in, out] flags
1348*/
[468]1349Sub ReadFieldWidth(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T,
[383]1350 ByRef fieldWidth As DWord, ByRef flags As FormatFlags)
1351 Dim t As Long
1352 If ReadInt(fmt, params, paramsCount, t) Then
1353 If t < 0 Then
[385]1354 flags Or= LeftSide
[383]1355 fieldWidth = -t As DWord
1356 Else
1357 fieldWidth = t As DWord
1358 End If
1359 Else
1360 fieldWidth = 0
1361 End If
1362End Sub
1363
1364/*!
1365@brief 精度の読み込み
1366@author Egtra
1367@date 2007/10/29
1368@param[in, out] fmt
1369@param[in] params
1370@param[in, out] paramsCount
1371@return 読み取った精度。指定がなかったときには、DWORD_MAX。
1372*/
[468]1373Function ReadPrecision(ByRef fmt As *Char,
[383]1374 params As *Object, ByRef paramsCount As SIZE_T) As DWord
1375
1376 If fmt[0] = &h2e Then '.
[384]1377 fmt = VarPtr(fmt[1]) 'po
[383]1378 Dim t As Long
1379 ReadPrecision = 0
1380 If ReadInt(fmt, params, paramsCount, t) Then
1381 If t > 0 Then
1382 ReadPrecision = t As DWord
1383 End If
1384 End If
1385 Else
1386 ReadPrecision = DWORD_MAX
1387 End If
1388End Function
1389
[384]1390#ifdef _WIN64
1391Const PtrLength = 1
1392#else
1393Const PtrLength = 0
1394#endif
1395
[383]1396/*!
1397@biref 長さ指定の読み込み
1398@author Egtra
1399@date 2007/10/29
1400@param[in, out] fmt
1401@param[out] lengthSpec
1402*/
[468]1403Sub ReadLength(ByRef fmt As *Char, ByRef lengthSpec As Long)
[383]1404 Do
1405 Select Case fmt[0]
1406 Case &h6c 'l
1407 lengthSpec++
1408 Case &h68 'h
1409 lengthSpec--
[384]1410 Case &h6a 'j (u)intmax_t = QWord, Int64
[383]1411 lengthSpec = 1
1412 Case &h74 't ptrdiff_t
[384]1413 lengthSpec = PtrLength
1414 Case &h7a 'z (s)size_t
1415 lengthSpec = PtrLength
1416 Case &h70 'p VoidPtr 本来は変換指定子だが、ここで先読み
1417 lengthSpec = PtrLength
1418 Exit Sub 'fmtを進められると困るので、ここで脱出
[383]1419 Case Else
1420 Exit Sub
1421 End Select
[384]1422 fmt = VarPtr(fmt[1]) 'po
[383]1423 Loop
1424End Sub
1425
1426/*!
[468]1427@brief efg変換用に、精度が指定されていないときに既定の精度を設定する。
1428@auther Egtra
1429@date 2008/03/07
1430*/
1431Sub AdjustPrecision(ByRef precision As DWord)
1432 If precision = DWORD_MAX Then
1433 precision = 6
1434 End If
1435End Sub
1436
1437/*!
[384]1438@biref Cのsprintfのような書式文字列出力関数
[383]1439@author Egtra
1440@date 2007/10/27
[384]1441@param[in] format 書式文字列。詳細は開発Wiki参照。
1442@param[in, out] params 変換対象の配列。n = 0のときにはNULLも可。
1443@param[in] n paramsの個数。
1444@return 書式化された文字列。
[383]1445@todo %nへの対応
1446*/
1447Function SPrintf(format As String, params As *Object, n As SIZE_T) As String
[386]1448 Dim i = 0 As SIZE_T
[383]1449 Dim paramsCount = 0 As SIZE_T
1450 Dim fmt = StrPtr(format)
1451 Dim s = New System.Text.StringBuilder
1452 Do
[468]1453 Dim last = format.Length - (((fmt - StrPtr(format)) \ SizeOf (Char)) As LONG_PTR) As Long 'po
1454 Dim pos = ChrFind(fmt, last, &h25 As Char) As Long '&h25 = %
[383]1455 If pos = -1 Then
1456 s.Append(fmt, 0, last)
1457 Exit Do
1458 End If
1459 '%以前の部分
1460 s.Append(fmt, 0, pos)
[384]1461 fmt = VarPtr(fmt[pos + 1]) 'po
[383]1462 'フラグの読取
1463 Dim flags = None As FormatFlags
1464 If ReadFlags(fmt, flags) = False Then
1465 Exit Do
1466 End If
1467 'フィールド幅
1468 Dim fieldWidth As DWord
1469 ReadFieldWidth(fmt, params, i, fieldWidth, flags)
1470 '精度
1471 Dim precision = ReadPrecision(fmt, params, i)
1472 '幅指定の読取
1473 Dim typeWidth As Long
1474 ReadLength(fmt, typeWidth)
1475
1476 Select Case fmt[0]
1477 Case &h64 'd
1478 FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags)
1479 Case &h69 'i
1480 FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags)
1481 Case &h75 'u
1482 FormatInteger(s, TraitsIntegerU, params[i], False, typeWidth, precision, fieldWidth, flags)
[468]1483 Case &h4f 'O
1484 flags Or= Cap
1485 Goto *O
[383]1486 Case &h6f 'o
[468]1487 *O
[383]1488 FormatInteger(s, TraitsIntegerO, params[i], False, typeWidth, precision, fieldWidth, flags)
[468]1489 Case &h58 'X
1490 flags Or= Cap
1491 Goto *X
[383]1492 Case &h78 'x
[468]1493 *X
[383]1494 FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags)
[384]1495'現状ではVoidPtrを引数にする手段は無いはず
1496' Case &h58 'p
1497' FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags Or Cap)
[468]1498 Case &h45 'E
1499 flags Or= Cap
1500 Goto *E
[383]1501 Case &h65 'e
[468]1502 *E
1503 AdjustPrecision(precision)
1504 FormatFloat(s, AddressOf(FormatFloatE_Convert), params[i], precision, fieldWidth, flags)
1505 Case &h46 'F
1506 flags Or= Cap
1507 Goto *F
[383]1508 Case &h66 'f
[468]1509 *F
1510 AdjustPrecision(precision)
1511 FormatFloat(s, AddressOf(FormatFloatF_Convert), params[i], precision, fieldWidth, flags)
1512 Case &h47 'G
1513 flags Or= Cap
1514 Goto *G
[383]1515 Case &h67 'g
[468]1516 *G
1517 AdjustPrecision(precision)
1518 FormatFloat(s, AddressOf(FormatFloatG_Convert), params[i], precision, fieldWidth, flags)
1519 Case &h41 'A
1520 flags Or= Cap
1521 Goto *A
[383]1522 Case &h61 'a
[468]1523 *A
[383]1524 FormatFloat(s, AddressOf(FormatFloatA), params[i], precision, fieldWidth, flags)
1525 Case &h73 's
[468]1526 FormatString(s, params[i] As String, precision, fieldWidth, flags)
[383]1527 Case &h63 'c
[468]1528 FormatCharacter(s, params[i] As BoxedStrChar, precision, fieldWidth, flags)
[383]1529' Case &h6e 'n
1530 Case &h25 '%
[468]1531 s.Append(&h25 As Char)
[383]1532 i--
1533 Case 0
1534 Exit Do
1535 End Select
[384]1536 fmt = VarPtr(fmt[1]) 'po
[383]1537 i++
1538 Loop
1539 SPrintf = s.ToString
1540End Function
1541
[335]1542End Namespace 'Detail
1543
[383]1544/*!
1545@brief Cのsprintfのような書式化関数10引数版
1546@author Egtra
1547@date 2007/10/27
1548@param[in] format 書式指定
1549@param[in] paramN 引数
1550@return 書式化された文字列
1551*/
1552
1553Function SPrintf(format As String, param0 As Object,
1554 param1 As Object, param2 As Object, param3 As Object,
1555 param4 As Object, param5 As Object, param6 As Object,
1556 param7 As Object, param8 As Object, param9 As Object) As String
[386]1557
[383]1558 Dim params = VarPtr(param0) As *Object
[386]1559
[383]1560 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 10)
1561End Function
1562
1563/*!
1564@brief Cのsprintfのような書式化関数9引数版
1565@author Egtra
1566@date 2007/10/27
1567@param[in] format 書式指定
1568@param[in] paramN 引数
1569@return 書式化された文字列
1570*/
1571Function SPrintf(format As String, param0 As Object,
1572 param1 As Object, param2 As Object, param3 As Object,
1573 param4 As Object, param5 As Object, param6 As Object,
1574 param7 As Object, param8 As Object) As String
[386]1575
[383]1576 Dim params = VarPtr(param0) As *Object
[386]1577
[383]1578 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 9)
1579End Function
1580
1581/*!
1582@brief Cのsprintfのような書式化関数8引数版
1583@author Egtra
1584@date 2007/10/27
1585@param[in] format 書式指定
1586@param[in] paramN 引数
1587@return 書式化された文字列
1588*/
1589Function SPrintf(format As String, param0 As Object,
1590 param1 As Object, param2 As Object, param3 As Object,
1591 param4 As Object, param5 As Object, param6 As Object,
1592 param7 As Object) As String
[386]1593
[383]1594 Dim params = VarPtr(param0) As *Object
[386]1595
[383]1596 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 8)
1597End Function
1598
1599/*!
1600@brief Cのsprintfのような書式化関数7引数版
1601@author Egtra
1602@date 2007/10/27
1603@param[in] format 書式指定
1604@param[in] paramN 引数
1605@return 書式化された文字列
1606*/
1607Function SPrintf(format As String, param0 As Object,
1608 param1 As Object, param2 As Object, param3 As Object,
1609 param4 As Object, param5 As Object, param6 As Object) As String
[386]1610
[383]1611 Dim params = VarPtr(param0) As *Object
[386]1612
[383]1613 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 7)
1614End Function
1615
1616/*!
1617@brief Cのsprintfのような書式化関数6引数版
1618@author Egtra
1619@date 2007/10/27
1620@param[in] format 書式指定
1621@param[in] paramN 引数
1622@return 書式化された文字列
1623*/
1624Function SPrintf(format As String, param0 As Object,
1625 param1 As Object, param2 As Object, param3 As Object,
1626 param4 As Object, param5 As Object) As String
[386]1627
[383]1628 Dim params = VarPtr(param0) As *Object
[386]1629
[383]1630 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 6)
1631End Function
1632
1633/*!
1634@brief Cのsprintfのような書式化関数5引数版
1635@author Egtra
1636@date 2007/10/27
1637@param[in] format 書式指定
1638@param[in] paramN 引数
1639@return 書式化された文字列
1640*/
1641Function SPrintf(format As String, param0 As Object,
1642 param1 As Object, param2 As Object, param3 As Object,
1643 param4 As Object) As String
[386]1644
[383]1645 Dim params = VarPtr(param0) As *Object
[386]1646
[383]1647 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 5)
1648End Function
1649
1650/*!
1651@brief Cのsprintfのような書式化関数4引数版
1652@author Egtra
1653@date 2007/10/27
1654@param[in] format 書式指定
1655@param[in] paramN 引数
1656@return 書式化された文字列
1657*/
1658Function SPrintf(format As String, param0 As Object,
1659 param1 As Object, param2 As Object, param3 As Object) As String
[386]1660
[383]1661 Dim params = VarPtr(param0) As *Object
[386]1662
[383]1663 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 4)
1664End Function
1665
1666/*!
1667@brief Cのsprintfのような書式化関数3引数版
1668@author Egtra
1669@date 2007/10/27
1670@param[in] format 書式指定
1671@param[in] paramN 引数
1672@return 書式化された文字列
1673*/
1674Function SPrintf(format As String, param0 As Object,
1675 param1 As Object, param2 As Object) As String
[386]1676
[383]1677 Dim params = VarPtr(param0) As *Object
[386]1678
[383]1679 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 3)
1680End Function
1681
1682/*!
1683@brief Cのsprintfのような書式化関数2引数版
1684@author Egtra
1685@date 2007/10/27
1686@param[in] format 書式指定
1687@param[in] paramN 引数
1688@return 書式化された文字列
1689*/
1690Function SPrintf(format As String, param0 As Object,
1691 param1 As Object) As String
[386]1692
[383]1693 Dim params = VarPtr(param0) As *Object
[386]1694
[383]1695 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 2)
1696End Function
1697
1698/*!
1699@brief Cのsprintfのような書式化関数1引数版
1700@author Egtra
1701@date 2007/10/27
1702@param[in] format 書式指定
1703@param[in] paramN 引数
1704@return 書式化された文字列
1705*/
1706Function SPrintf(format As String, param0 As Object) As String
1707 Dim params = VarPtr(param0) As *Object
1708 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 1)
1709End Function
1710
1711/*!
1712@brief Cのsprintfのような書式化関数0引数版
1713@author Egtra
1714@date 2007/10/27
1715@param[in] format 書式指定
1716@param[in] paramN 引数
1717@return 書式化された文字列
1718*/
1719Function SPrintf(format As String) As String
1720 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, 0, 0)
1721End Function
1722
[335]1723End Namespace 'Strings
1724End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.