source: trunk/ab5.0/ablib/src/Classes/ActiveBasic/Strings/SPrintF.ab@ 521

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

表記揺れ、ミスなど修正

File size: 48.2 KB
Line 
1/*!
2@file Include/Classes/ActiveBasic/Strings/SPrintF.ab
3@brief SPrintfとその補助ルーチンが含まれるファイル。
4
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
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
36xに無限大、非数を渡した場合の動作は未定義。
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
84 FloatToChars = FormatIntegerLU((x As Int64) As QWord, 17, 0, None)
85End Function
86
87/*!
88@brief 書式化関数群で使用するフラグ。
89@author Egtra
90@date 2007/09/18
91*/
92Const Enum FormatFlags
93 '! 何も指定がない。
94 None = &h0
95 /*!
96 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
97 AdjustFieldWidthの仕様から、Format関数郡内からAdjustFieldWidthにかけて、
98 単に数値が符号付である(負の値である)ことを示す意味でも用いられる。
99 */
100 Sign = &h1
101 /*! 空白、空白文字。
102 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。
103 */
104 Blank = &h2
105 /*! ゼロ、0。
106 [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。
107 */
108 Zero = &h4
109 '! 左揃え、-。フィールド内で左揃えにする。
110 LeftSide = &h8
111 /*! 代替表記、#。
112 @li [OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul>
113 @li [AaEeFfGg]では、精度0でも小数点を付ける。</ul>
114 @li [Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul>
115 */
116 Alt = &h10
117 '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。
118 Cap = &h20
119
120 '!BASIC接頭辞。&h, &oなど。
121 BPrefix = &h40
122
123 /*!
124 内部処理用に予約。
125 @note Minusとして使用されている。
126 */
127 Reserved = &h80000000
128End Enum
129
130/*!
131@brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。
132@author Egtra
133@date 2007/09/18
134@param[in] x 文字列化する浮動小数点数値。
135@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
136@param[in] field フィールド幅。
137@param[in] flags 書式フラグ。
138@return xの文字列表現
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
143
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 書式フラグ。
167@todo 他の実装での末尾桁の扱いを調べる(このコードでは何もしていないので切捨となっている)。
168*/
169Sub FormatFloatE_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags)
170 If precision = DWORD_MAX Then
171 precision = 15
172 End If
173 Dim e As Long, negative As Boolean
174 Dim s = FloatToChars(x, e, negative)
175 FormatFloatE_Base(sb, s, negative, precision, flags)
176 FormatFloatE_Exponent(sb, e, flags)
177End Sub
178
179/**
180@brief FormatFloatEの符号・基数部の出力用。
181@author Egtra
182@date 2007/10/27
183*/
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)
187 .Append(s[0])
188 If (flags And Alt) Or precision > 0 Then
189 .Append(".")
190 Dim outputLen = s.Length - 1
191 If outputLen >= precision Then
192 .Append(s, 1, precision)
193 Else 'sで用意された桁が指定された精度より少ないとき
194 .Append(s, 1, outputLen)
195 .Append(&h30 As Char, precision - outputLen) '足りない桁は0埋め
196 End If
197 End If
198 End With
199End Sub
200
201/**
202@brief FormatFloatEの指数部の出力用。
203@author Egtra
204@date 2007/10/27
205*/
206Sub FormatFloatE_Exponent(sb As System.Text.StringBuilder, e As Long, flags As FormatFlags)
207 With sb
208 If flags And Cap Then
209 .Append("E")
210 Else
211 .Append("e")
212 End If
213 FormatIntegerD(sb, e, 2, 0, Sign Or Zero)
214 End With
215End Sub
216
217/*!
218@brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。
219@author Egtra
220@date 2007/10/23
221@param[in] x 文字列化する浮動小数点数値。
222@param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値15となる。
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
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)
256 If precision = DWORD_MAX Then
257 precision = 15
258 End If
259 Dim e As Long, negative As Boolean
260 Dim s = FloatToChars(x, e, negative)
261 FormatFloatF_Core(sb, s, e, negative, precision, flags)
262End Sub
263
264/**
265@author Egtra
266@date 2007/10/27
267*/
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)
271
272 Dim intPartLen = e + 1
273 Dim outputDigit = 0 As DWord
274 If intPartLen >= 17 Then
275 '有効桁が全て整数部に収まる場合
276 .Append(s)
277 .Append(&h30 As Char, intPartLen - 17)
278 outputDigit = 17
279 ElseIf intPartLen > 0 Then
280 '有効桁の一部が整数部にかかる場合
281 .Append(s, 0, intPartLen)
282 outputDigit = intPartLen
283 Else
284 '有効桁が全く整数部にかからない場合
285 .Append(&h30 As Char)
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)
297 .Append(&h30 As Char, zeroDigit As Long)
298 End If
299 .Append(s, outputDigit, (precision - zeroDigit) As Long)
300 Else
301 .Append(s, outputDigit, lastDigit)
302 .Append(&h30 As Char, (precision - lastDigit) As Long) '残りの桁は0埋め
303 End If
304 End If
305 End With
306End Sub
307
308/*!
309@brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。
310@author Egtra
311@date 2007/10/23
312@param[in] x 文字列化する浮動小数点数値。
313@param[in] precision 精度。小数点以下の桁数。DWORD_MAXまたは0のとき、指定なしとして既定値15となる。
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
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)
349 'GではE/Fと違い整数部も有効桁数に数えるのでその分を引いておく。
350 If precision = DWORD_MAX Or precision = 0 Then
351 precision = 14
352 Else
353 precision--
354 End If
355 Dim lastLength = sb.Length
356 Dim e As Long, negative As Boolean
357 Dim s = FloatToChars(x, e, negative)
358 If -5 < e And e < precision Then
359 FormatFloatF_Core(sb, s, e, negative, -e + precision, flags)
360 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
361 Else
362 FormatFloatE_Base(sb, s, negative, precision, flags)
363 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
364 FormatFloatE_Exponent(sb, e, flags)
365 End If
366End Sub
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*/
376Sub FormatFloatG_RemoveLowDigit(sb As System.Text.StringBuilder, start As Long, flags As FormatFlags)
377 Imports ActiveBasic.Strings
378
379 Dim count = sb.Length
380 If (flags And Alt) = 0 Then
381 Dim p = StrPtr(sb)
382 Dim point = ChrFind(VarPtr(p[start]), (count - start) As SIZE_T, Asc("."))
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
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)
445 If precision = DWORD_MAX Then
446 precision = 13
447 End If
448 Dim lastLength = sb.Length
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(".")
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)
484 Else
485 FormatIntegerLX(sb, fraction, 13, 0, flags And Cap)
486 .Append(&h30, precision - 13)
487 End If
488 End If
489 FormatFloatG_RemoveLowDigit(sb, lastLength, flags)
490 .Append("P")
491 FormatIntegerD(sb, exp, 1, 0, Sign)
492 AdjustAlphabet(sb, flags, lastLength)
493 End With
494End Sub
495
496/*!
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
519/*!
520@brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。
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
530 Return FormatIntegerEx(TraitsIntegerU[0], x, d, field, flags And (Not (Sign Or Blank)))
531End Function
532
533/*!
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/*!
548@brief FormatIntegerUのQWord版
549@author Egtra
550@date 2007/10/26
551*/
552Function FormatIntegerLU(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
553 Return FormatIntegerEx(TraitsIntegerU[1], x, d, field, flags And (Not (Sign Or Blank)))
554End Function
555
556/*!
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/*!
571@brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。
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
581 Return FormatIntegerEx(TraitsIntegerD[0], (x As Int64) As QWord, d, field, flags)
582End Function
583
584/*!
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/*!
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
604 Return FormatIntegerEx(TraitsIntegerD[1], x As QWord, d, field, flags)
605End Function
606
607/*!
608@brief FormatIntegerDのInt64版
609@author Egtra
610@date 2007/10/26
611*/
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*/
620Dim TraitsIntegerU[1] As IntegerConvertTraits
621With TraitsIntegerU[0]
622 .Convert = AddressOf(IntegerU_Convert)
623 .Prefix = AddressOf(IntegerU_Prefix)
624End With
625
626With TraitsIntegerU[1]
627 .Convert = AddressOf(IntegerLU_Convert)
628 .Prefix = AddressOf(IntegerU_Prefix)
629End With
630
631/*!
632@author Egtra
633@date 2007/10/28
634*/
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)
644End With
645
646/*!
647@brief 負数を表すフラグ。FormatIntegerD, LDからIntegerDU_Prefixまでの内部処理用。
648@author Egtra
649@date 2007/10/26
650*/
651Const Minus = Reserved
652
653/*!
654@author Egtra
655@date 2007/10/26
656*/
657Function IntegerU_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
658 Dim x = xq As DWord
659 Dim i = MaxSizeLO
660 While x <> 0
661 buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策
662 x \= 10
663 i--
664 Wend
665 Return i
666End Function
667
668/*!
669@brief IntegerU_ConvertのQWord版
670@author Egtra
671@date 2007/10/26
672@bug #117のため、現在Int64の最大値を超える値を正しく処理できない。
673*/
674Function IntegerLU_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
675 Dim i = MaxSizeLO
676 While x <> 0
677 buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策
678 x \= 10
679 i--
680 Wend
681 Return i
682End Function
683
684/*!
685@author Egtra
686@date 2007/10/26
687*/
688Function IntegerU_Prefix(x As QWord, flags As FormatFlags) As String
689End Function
690
691/*!
692@author Egtra
693@date 2007/10/28
694*/
695Function IntegerD_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
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*/
704Function IntegerLD_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
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 = "-"
715 ElseIf flags And Sign Then
716 IntegerD_Prefix = "+"
717 ElseIf flags And Blank Then
718 IntegerD_Prefix = " "
719 End If
720End Function
721
722
723
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*/
736Dim TraitsIntegerO[1] As IntegerConvertTraits
737With TraitsIntegerO[0]
738 .Convert = AddressOf(IntegerO_Convert)
739 .Prefix = AddressOf(IntegerO_Prefix)
740End With
741
742With TraitsIntegerO[1]
743 .Convert = AddressOf(IntegerLO_Convert)
744 .Prefix = AddressOf(IntegerO_Prefix)
745End With
746
747/*!
748@brief 符号無し整数をprintfの%o(八進法表現)相当の変換で文字列化する関数。
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
758 Return FormatIntegerEx(TraitsIntegerO[0], x, d, field, flags)
759End Function
760
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
767 Return FormatIntegerEx(TraitsIntegerO[1], x, d, field, flags)
768End Function
769
770/*!
771@author Egtra
772@date 2007/10/22
773*/
774Function IntegerO_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
775 Dim x = xq As DWord
776 Dim i = MaxSizeLO
777 While x <> 0
778 buf[i] = ((x And &o7) + &h30) As Char
779 x >>= 3
780 i--
781 Wend
782 If flags And Alt Then
783 buf[i] = &h30
784 i--
785 End If
786 Return i
787End Function
788
789/*!
790@brief IntegerO_ConvertのQWord版。
791@author Egtra
792@date 2007/10/26
793*/
794Function IntegerLO_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
795 Dim i = MaxSizeLO
796 While x <> 0
797 buf[i] = ((x And &o7) + &h30) As Char
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*/
813Function IntegerO_Prefix(x As QWord, flags As FormatFlags) As String
814 If flags And BPrefix Then
815 If x <> 0 Then
816 IntegerO_Prefix = "&O"
817 End If
818 End If
819End Function
820
821/*!
822@author Egtra
823@date 2007/10/24
824*/
825Dim TraitsIntegerX[1] As IntegerConvertTraits
826With TraitsIntegerX[0]
827 .Convert = AddressOf(IntegerX_Convert)
828 .Prefix = AddressOf(IntegerX_Prefix)
829End With
830
831With TraitsIntegerX[1]
832 .Convert = AddressOf(IntegerLX_Convert)
833 .Prefix = AddressOf(IntegerX_Prefix)
834End With
835
836/*!
837@brief 整数をprintfの%x, %X(十六進法)相当の変換で文字列化する関数。
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
847 Return FormatIntegerEx(TraitsIntegerX[0], x, d, field, flags)
848End Function
849
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
856 Return FormatIntegerEx(TraitsIntegerX[1], x, d, field, flags)
857End Function
858
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
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
874/*!
875@author Egtra
876@date 2007/10/22
877*/
878Function IntegerX_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord
879 Dim i = MaxSizeLO
880 Dim x = xq As DWord
881 While x <> 0
882 buf[i] = HexadecimalTable[x And &h0f]
883 x >>= 4
884 i--
885 Wend
886 Return i
887End Function
888
889/*!
890@brief IntegerX_ConvertのQWord版。
891@author Egtra
892@date 2007/10/22
893*/
894Function IntegerLX_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord
895 Dim i = MaxSizeLO
896 While x <> 0
897 buf[i] = HexadecimalTable[x And &h0f]
898 x >>= 4
899 i--
900 Wend
901 Return i
902End Function
903
904/*!
905@author Egtra
906@date 2007/10/24
907*/
908Function IntegerX_Prefix(x As QWord, flags As FormatFlags) As String
909 If x <> 0 Then
910 If flags And Alt Then
911 IntegerX_Prefix = "0X"
912 ElseIf flags And BPrefix Then
913 IntegerX_Prefix = "&H"
914 End If
915 End If
916End Function
917
918/*!
919@brief IntegerConvertTraits用。変換関数へのポインタ。
920@author Egtra
921@date 2008/06/08
922*/
923TypeDef ConvertFunc = *Function(buf As *Char, x As QWord, flags As FormatFlags) As DWord
924
925/*!
926@brief IntegerConvertTraits用。接頭辞取得関数へのポインタ。
927@author Egtra
928@date 2008/06/08
929*/
930TypeDef PrefixFunc = *Function(x As QWord, flags As FormatFlags) As String
931
932/*!
933@brief FormatIntegerExへ渡す変換特性を表す構造体型。
934@author Egtra
935@date 2007/10/22
936
937FormatIntegerの都合上、このファイル内で宣言しているIntegerConvertTraits型の
938変数は全て配列となっている;[0]が32ビット変換、[1]が64ビット変換である。
939*/
940Type IntegerConvertTraits
941 '!変換を行う関数へのポインタ。
942 Convert As ConvertFunc
943 '!接頭辞を取得する関数へのポインタ。
944 Prefix As PrefixFunc
945End Type
946
947/*!
948@brief 整数変換全てを行う関数。
949@author Egtra
950@date 2007/10/22
951@param[in] tr 特性情報。
952@param[in] x 変換元の数値。
953@param[in] d 精度。ここでは最低限出力する桁数。
954@param[in] field フィールド幅。
955@param[in] flags フラグ。
956@return 変換された文字列
957*/
958Function FormatIntegerEx(ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
959 Dim sb = New System.Text.StringBuilder(32)
960 FormatIntegerEx(sb, tr, x, d, field, flags)
961 FormatIntegerEx = sb.ToString
962End Function
963
964/*!
965@brief 整数変換全てを行う関数。これを雛形とし、形式毎の差異はIntegerConvertTraitsで表現する。
966@author Egtra
967@date 2008/03/06
968@param[in,out] sb 書式化した文字列を追加するバッファ。
969@param[in] tr 特性情報。
970@param[in] x 変換元の数値。
971@param[in] d 精度。ここでは最低限出力する桁数。
972@param[in] field フィールド幅。
973@param[in] flags フラグ。
974*/
975Sub FormatIntegerEx(sb As System.Text.StringBuilder, ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags)
976 If d = DWORD_MAX Then
977 d = 1
978 Else
979 '精度が指定されているとき、ゼロフラグは無視される。
980 '仕様上、左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
981 flags And= Not Zero
982 End If
983
984 Dim lastLength = sb.Length
985
986 With sb
987 Dim prefixFunc = tr.Prefix
988 Dim prefix = prefixFunc(x, flags)
989 sb.Append(prefix)
990
991 Dim prefixLen = 0 As DWord
992 If String.IsNullOrEmpty(prefix) = False Then
993 prefixLen = prefix.Length As DWord
994 End If
995
996 'バッファの量は最も必要文字数の多くなるUInt64の8進法変換にあわせている
997 Dim buf[MaxSizeLO] As Char
998 Dim convertFunc = tr.Convert
999 Dim bufStartPos = convertFunc(buf, x, flags)
1000
1001 Dim len = (MaxSizeLO - bufStartPos) As Long
1002 If len < 0 Then
1003 Debug
1004 End If
1005 If len < d Then
1006 .Append(&h30 As Char, d - len)
1007 End If
1008 .Append(buf, bufStartPos + 1, len)
1009 AdjustFieldWidth(sb, field, flags And (Not (Sign Or Blank)), prefixLen, lastLength)
1010 AdjustAlphabet(sb, flags, lastLength)
1011 End With
1012End Sub
1013
1014/*!
1015@brief 浮動小数点数変換全てを行う関数。これを雛形とし、実際の変換関数は引数converterで与える。
1016@author Egtra
1017@date 2008/03/07
1018@param[in,out] sb 書式化した文字列を追加するバッファ。
1019@param[in] converter 変換関数。
1020@param[in] x 変換元の数値。
1021@param[in] d 精度。ここでは最低限出力する桁数。
1022@param[in] field フィールド幅。
1023@param[in] flags フラグ。
1024*/
1025Sub FormatFloatEx(sb As System.Text.StringBuilder, converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags)
1026 Dim lastLength = sb.Length
1027 If Math.IsNaN(x) Then
1028 sb.Append("NAN")
1029 AdjustAlphabet(sb, flags, lastLength)
1030 ElseIf Math.IsInf(x) Then
1031 AppendSign(sb, (GetQWord(VarPtr(x)) >> 63) As Boolean, flags)
1032 sb.Append("INFINITY")
1033 AdjustAlphabet(sb, flags, lastLength)
1034 Else
1035 converter(sb, x, precision, field, flags)
1036 End If
1037 AdjustFieldWidth(sb, field, flags, 0, lastLength)
1038End Sub
1039
1040
1041/*!
1042@brief 浮動小数点数変換全てを行う関数。
1043@author Egtra
1044@date 2008/03/08
1045@param[in] converter 変換関数。
1046@param[in] x 変換元の数値。
1047@param[in] d 精度。ここでは最低限出力する桁数。
1048@param[in] field フィールド幅。
1049@param[in] flags フラグ。
1050@return 変換された文字列。
1051*/
1052Function FormatFloatEx(converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
1053 Dim sb = New System.Text.StringBuilder
1054 FormatFloatEx(sb, converter, x, precision, field, flags)
1055 FormatFloatEx = sb.ToString
1056End Function
1057
1058/*!
1059@brief 書式化の仕上げとして、Capフラグが指定されていないときに小文字化する作業を行う。
1060@author Egtra
1061@date 2008/03/06
1062@param[in,out] sb 書式化した文字列を格納しているバッファ。
1063@param[in] flags フラグ。
1064@param[in] offset 書式変換した部分の開始位置。
1065*/
1066Sub AdjustAlphabet(sb As System.Text.StringBuilder, flags As FormatFlags, offset As Long)
1067 If (flags And Cap) = 0 Then
1068 Dim len = sb.Length
1069 Dim i As Long
1070 For i = offset To ELM(len)
1071 sb[i] = CType.ToLower(sb[i])
1072 Next
1073 End If
1074End Sub
1075
1076/*!
1077@brief 書式化の仕上げとして、変換部分がフィールド幅まで満たされるように空白などを挿入する。
1078@author Egtra
1079@date 2007/10/13
1080@param[in,out] sb 対象文字列
1081@param[in] field フィールド幅
1082@param[in] hasSign 符号を持っている(負の値か)か否か
1083@param[in] flags フラグ
1084@param[in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
1085@param[in] offset 変換した部分へのオフセット。AppendではなくInsertを行う際に用いられる。
1086sbが"-1"のように負符号を持っている場合は、呼出元でSignフラグ(またはBlank)を立てること。
1087*/
1088Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, flags As FormatFlags, prefixLen = 0 As DWord, offset = 0 As Long)
1089 With sb
1090 Dim len = .Length - offset
1091 If len < field Then
1092 Dim embeddedSize = field - len
1093 If flags And LeftSide Then
1094 .Append(&h20, embeddedSize)
1095 Else
1096 If (flags And Zero) <> 0 Then
1097 offset += prefixLen
1098 If (flags And Blank) Or (flags And Sign) Then
1099 offset++
1100 End If
1101 .Insert(offset, String$(embeddedSize, "0"))
1102 Else
1103 .Insert(offset, String$(embeddedSize, " "))
1104 End If
1105 End If
1106 End If
1107 End With
1108End Sub
1109
1110/*!
1111@brief 文字列をprintfの%s相当の変換で書式化する関数。
1112@author Egtra
1113@date 2007/10/27
1114@param[in] x 文字列。
1115@param[in] d 精度、最大の文字数。
1116@param[in] field フィールド幅。
1117@param[in] flags 書式フラグ。
1118@return 書式化された文字列。
1119*/
1120Function FormatString(x As String, d As DWord, field As DWord, flags As FormatFlags) As String
1121 Imports System
1122 Dim sb = New System.Text.StringBuilder(
1123 Math.Max(Math.Min(x.Length As DWord, d), field) As Long + 1)
1124 FormatString(sb, x, d, field, flags)
1125 AdjustFieldWidth(sb, field, flags And LeftSide)
1126 FormatString = sb.ToString()
1127End Function
1128
1129/*!
1130@brief 文字列をprintfの%s相当の変換で書式化する関数。
1131@author Egtra
1132@date 2008/03/07
1133@param[in,out] sb 書式化した文字列を追加するバッファ。
1134@param[in] x 文字列。
1135@param[in] d 精度、最大の文字数。
1136@param[in] field フィールド幅。
1137@param[in] flags 書式フラグ。
1138@return 書式化された文字列。
1139*/
1140Sub FormatString(sb As System.Text.StringBuilder, x As String, d As DWord, field As DWord, flags As FormatFlags)
1141 Dim len = sb.Length
1142 sb.Append(x, 0, System.Math.Min(x.Length As DWord, d) As Long)
1143 AdjustFieldWidth(sb, field, flags And LeftSide, 0, len)
1144End Sub
1145
1146/*!
1147@brief 文字をprintfの%c相当の変換で書式化する関数。
1148@author Egtra
1149@date 2007/10/27
1150@param[in] x 文字。
1151@param[in] d 精度、最大の文字数。
1152@param[in] field フィールド幅。
1153@param[in] flags 書式フラグ。
1154@return 書式化された文字列。
1155*/
1156Function FormatCharacter(x As Char, d As DWord, field As DWord, flags As FormatFlags) As String
1157 Dim sb = New System.Text.StringBuilder(field + 2)
1158 FormatCharacter(sb, x, d, field, flags)
1159 FormatCharacter = sb.ToString()
1160End Function
1161
1162/*!
1163@brief 文字列をprintfの%s相当の変換で書式化する関数。
1164@author Egtra
1165@date 2008/03/07
1166@param[in,out] sb 書式化した文字列を追加するバッファ。
1167@param[in] x 文字。
1168@param[in] d 精度、最大の文字数。
1169@param[in] field フィールド幅。
1170@param[in] flags 書式フラグ。
1171@return 書式化された文字列。
1172*/
1173Sub FormatCharacter(sb As System.Text.StringBuilder, x As Char, d As DWord, field As DWord, flags As FormatFlags)
1174 Dim len = sb.Length
1175 sb.Append(x)
1176 AdjustFieldWidth(sb, field, flags And LeftSide, 0, len)
1177End Sub
1178
1179/*!
1180@author Egtra
1181@date 2007/10/28
1182*/
1183TypeDef FormatFloatProc = *Sub(sb As System.Text.StringBuilder, x As Double, precision As DWord, fieldWidth As DWord, ByRef flags As FormatFlags)
1184
1185/*!
1186@brief SPrintfから呼ばれる浮動小数点数用書式文字列化関数
1187@author Egtra
1188@date 2007/10/28
1189*/
1190Sub FormatFloat(s As System.Text.StringBuilder, formatProc As FormatFloatProc,
1191 param As Object, precision As DWord, field As DWord, flags As FormatFlags)
1192
1193 Dim x As Double
1194 Dim typeName = param.GetType().FullName
1195 If typeName = "System.Double" Then
1196 x = param As System.Double
1197 ElseIf typeName = "System.Single" Then
1198 x = param As System.Single
1199 End If
1200 FormatFloatEx(s, formatProc, x, precision, field, flags)
1201End Sub
1202
1203/*!
1204@brief SPrintfから呼ばれる整数用書式文字列化関数
1205@author Egtra
1206@date 2007/10/28
1207*/
1208Sub FormatInteger(s As System.Text.StringBuilder, traits As *IntegerConvertTraits,
1209 param As Object, signed As Boolean, typeWidth As Long, precision As DWord, field As DWord, flags As FormatFlags)
1210
1211 Dim x As QWord
1212 Dim typeName = param.GetType().FullName
1213 If typeName = "System.UInt64" Then
1214 x = param As System.UInt64
1215 ElseIf typeName = "System.Int64" Then
1216 x = (param As System.Int64) As QWord
1217 ElseIf typeName = "System.UInt32" Then
1218 x = param As System.UInt32
1219 ElseIf typeName = "System.Int32" Then
1220 x = (param As System.Int32) As QWord
1221 ElseIf typeName = "System.UInt16" Then
1222 x = param As System.UInt16
1223 ElseIf typeName = "System.Int16" Then
1224 x = (param As System.Int16) As QWord
1225 ElseIf typeName = "System.UInt8" Then
1226 x = param As System.Byte
1227 ElseIf typeName = "System.Int8" Then
1228 x = (param As System.SByte) As QWord
1229 End If
1230 '一旦縮めた後、符号・ゼロ拡張させる。
1231 'また、64ビット整数なら64ビット変換Traitsを選択する。
1232 If signed Then
1233 If typeWidth = 1 Then
1234 traits = VarPtr(traits[1])
1235 ElseIf typeWidth = 0 Then
1236 x = (((x As DWord) As Long) As Int64) As QWord
1237 ElseIf typeWidth = -1 Then
1238 x = (((x As Word) As Integer) As Int64) As QWord
1239 ElseIf typeWidth = -2 Then
1240 x = (((x As Byte) As SByte) As Int64) As QWord
1241 End If
1242 Else
1243 If typeWidth = 1 Then
1244 traits = VarPtr(traits[1])
1245 ElseIf typeWidth = 0 Then
1246 x = x As DWord
1247 ElseIf typeWidth = -1 Then
1248 x = x As Word
1249 ElseIf typeWidth = -2 Then
1250 x = x As Byte
1251 End If
1252 End If
1253 FormatIntegerEx(s, ByVal traits, x, precision, field, flags)
1254End Sub
1255
1256'Format関数群ここまで
1257'----
1258
1259/*!
1260@brief 文字列から数値への変換。さらに変換に使われなかった文字列の位置を返す。
1261@author Egtra
1262@date 2007/11/11
1263@param[in] s 変換する文字
1264@param[out] p 変換に使われなかった部分の先頭を指すポインタ
1265@return 変換して得られた数値。変換できなければ0。
1266*/
1267Function StrToLong(s As *Char, ByRef p As *Char) As Long
1268 Dim negative As Boolean
1269 Dim i = 0 As Long
1270 If s[i] = &h2d Then 'Asc("-")
1271 i++
1272 negative = True
1273 End If
1274 Do
1275 Dim c = s[i]
1276 If Not CType.IsDigit(c) Then Exit Do
1277 StrToLong *= 10
1278 StrToLong += ((c As DWord) And &h0f) As Long
1279 i++
1280 Loop
1281 If negative Then
1282 StrToLong = -StrToLong
1283 End If
1284 p = VarPtr(s[i])
1285End Function
1286
1287/*!
1288@brief フィールド幅、精度用の数値読取
1289@author Egtra
1290@date 2007/11/11
1291@param[in, out] fmt 読み途中の書式指定
1292@param[in] params
1293@param[in, out] paramsCount
1294@param[out] ret 読み取った数値。読み取られなかったときの値は不定。
1295@retval True 読取を行った
1296@retval False 行わなかった
1297fmt[0]が*のときにはparamsから1つ読み取る。
1298そうでなく、fmtに数字(先頭に-符号があっても可)が並んでいれば、それを読み取る。
1299*/
1300Function ReadInt(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T, ByRef ret As Long) As Boolean
1301 If fmt[0] = &h2a Then '*
1302 fmt = VarPtr(fmt[1]) 'po
1303 ret = params[paramsCount] As System.Int32
1304 paramsCount++
1305 ReadInt = True
1306 Else
1307 Dim p As *Char
1308 ret = StrToLong(fmt, p)
1309 If fmt <> p Then
1310 fmt = p
1311 ReadInt = True
1312 Else
1313 ReadInt = False
1314 End If
1315 End If
1316End Function
1317
1318/*!
1319@brief フラグ指定の読み込み
1320@author Egtra
1321@date 2007/10/28
1322@param[in, out] fmt
1323@param[out] flags
1324@retval True 読み込みが完了した。
1325@retval False 読み取り中に文字列が終了した(ヌル文字が現れた)。
1326*/
1327Function ReadFlags(ByRef fmt As *Char, ByRef flags As FormatFlags) As Boolean
1328 ReadFlags = False
1329 Do
1330 Select Case fmt[0]
1331 Case &h23 '#
1332 flags Or= Alt
1333 Case &h30 '0
1334 flags Or= Zero
1335 Case &h20 '空白
1336 flags Or= Blank
1337 Case &h2b '+
1338 flags Or= Sign
1339 Case &h2d '-
1340 flags Or = LeftSide
1341 Case &h26 '&
1342 flags Or= BPrefix
1343 Case 0
1344 Exit Function
1345 Case Else
1346 Exit Do
1347 End Select
1348 fmt = VarPtr(fmt[1]) 'po
1349 Loop
1350 ReadFlags = True
1351End Function
1352
1353/*!
1354@brief フィールド幅指定の読み込み
1355@author Egtra
1356@date 2007/10/29
1357@param[in, out] fmt
1358@param[in] params
1359@param[in, out] paramsCount
1360@param[out] fieldWidth
1361@param[in, out] flags
1362*/
1363Sub ReadFieldWidth(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T,
1364 ByRef fieldWidth As DWord, ByRef flags As FormatFlags)
1365 Dim t As Long
1366 If ReadInt(fmt, params, paramsCount, t) Then
1367 If t < 0 Then
1368 flags Or= LeftSide
1369 fieldWidth = -t As DWord
1370 Else
1371 fieldWidth = t As DWord
1372 End If
1373 Else
1374 fieldWidth = 0
1375 End If
1376End Sub
1377
1378/*!
1379@brief 精度の読み込み
1380@author Egtra
1381@date 2007/10/29
1382@param[in, out] fmt
1383@param[in] params
1384@param[in, out] paramsCount
1385@return 読み取った精度。指定がなかったときには、DWORD_MAX。
1386*/
1387Function ReadPrecision(ByRef fmt As *Char,
1388 params As *Object, ByRef paramsCount As SIZE_T) As DWord
1389
1390 If fmt[0] = &h2e Then '.
1391 fmt = VarPtr(fmt[1]) 'po
1392 Dim t As Long
1393 ReadPrecision = 0
1394 If ReadInt(fmt, params, paramsCount, t) Then
1395 If t > 0 Then
1396 ReadPrecision = t As DWord
1397 End If
1398 End If
1399 Else
1400 ReadPrecision = DWORD_MAX
1401 End If
1402End Function
1403
1404#ifdef _WIN64
1405Const PtrLength = 1
1406#else
1407Const PtrLength = 0
1408#endif
1409
1410/*!
1411@biref 長さ指定の読み込み
1412@author Egtra
1413@date 2007/10/29
1414@param[in, out] fmt
1415@param[out] lengthSpec
1416*/
1417Sub ReadLength(ByRef fmt As *Char, ByRef lengthSpec As Long)
1418 Do
1419 Select Case fmt[0]
1420 Case &h6c 'l
1421 lengthSpec++
1422 Case &h68 'h
1423 lengthSpec--
1424 Case &h6a 'j (u)intmax_t = QWord, Int64
1425 lengthSpec = 1
1426 Case &h74 't ptrdiff_t
1427 lengthSpec = PtrLength
1428 Case &h7a 'z (s)size_t
1429 lengthSpec = PtrLength
1430 Case &h70 'p VoidPtr 本来は変換指定子だが、ここで先読み
1431 lengthSpec = PtrLength
1432 Exit Sub 'fmtを進められると困るので、ここで脱出
1433 Case Else
1434 Exit Sub
1435 End Select
1436 fmt = VarPtr(fmt[1]) 'po
1437 Loop
1438End Sub
1439
1440/*!
1441@brief efg変換用に、精度が指定されていないときに既定の精度を設定する。
1442@auther Egtra
1443@date 2008/03/07
1444*/
1445Sub AdjustPrecision(ByRef precision As DWord)
1446 If precision = DWORD_MAX Then
1447 precision = 6
1448 End If
1449End Sub
1450
1451/*!
1452@biref Cのsprintfのような書式文字列出力関数
1453@author Egtra
1454@date 2007/10/27
1455@param[in] format 書式文字列。詳細は開発Wiki参照。
1456@param[in, out] params 変換対象の配列。n = 0のときにはNULLも可。
1457@param[in] n paramsの個数。
1458@return 書式化された文字列。
1459@todo %nへの対応
1460*/
1461Function SPrintf(format As String, params As *Object, n As SIZE_T) As String
1462 Dim i = 0 As SIZE_T
1463 Dim paramsCount = 0 As SIZE_T
1464 Dim fmt = StrPtr(format)
1465 Dim s = New System.Text.StringBuilder
1466 Do
1467 Dim last = format.Length - (((fmt - StrPtr(format)) \ SizeOf (Char)) As LONG_PTR) As Long 'po
1468 Dim pos = ChrFind(fmt, last, &h25 As Char) As Long '&h25 = %
1469 If pos = -1 Then
1470 s.Append(fmt, 0, last)
1471 Exit Do
1472 End If
1473 '%以前の部分
1474 s.Append(fmt, 0, pos)
1475 fmt = VarPtr(fmt[pos + 1]) 'po
1476 'フラグの読取
1477 Dim flags = None As FormatFlags
1478 If ReadFlags(fmt, flags) = False Then
1479 Exit Do
1480 End If
1481 'フィールド幅
1482 Dim fieldWidth As DWord
1483 ReadFieldWidth(fmt, params, i, fieldWidth, flags)
1484 '精度
1485 Dim precision = ReadPrecision(fmt, params, i)
1486 '幅指定の読取
1487 Dim typeWidth As Long
1488 ReadLength(fmt, typeWidth)
1489
1490 Select Case fmt[0]
1491 Case &h64 'd
1492 FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags)
1493 Case &h69 'i
1494 FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags)
1495 Case &h75 'u
1496 FormatInteger(s, TraitsIntegerU, params[i], False, typeWidth, precision, fieldWidth, flags)
1497 Case &h4f 'O
1498 flags Or= Cap
1499 Goto *O
1500 Case &h6f 'o
1501 *O
1502 FormatInteger(s, TraitsIntegerO, params[i], False, typeWidth, precision, fieldWidth, flags)
1503 Case &h58 'X
1504 flags Or= Cap
1505 Goto *X
1506 Case &h78 'x
1507 *X
1508 FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags)
1509'現状ではVoidPtrを引数にする手段は無いはず
1510' Case &h58 'p
1511' FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags Or Cap)
1512 Case &h45 'E
1513 flags Or= Cap
1514 Goto *E
1515 Case &h65 'e
1516 *E
1517 AdjustPrecision(precision)
1518 FormatFloat(s, AddressOf(FormatFloatE_Convert), params[i], precision, fieldWidth, flags)
1519 Case &h46 'F
1520 flags Or= Cap
1521 Goto *F
1522 Case &h66 'f
1523 *F
1524 AdjustPrecision(precision)
1525 FormatFloat(s, AddressOf(FormatFloatF_Convert), params[i], precision, fieldWidth, flags)
1526 Case &h47 'G
1527 flags Or= Cap
1528 Goto *G
1529 Case &h67 'g
1530 *G
1531 AdjustPrecision(precision)
1532 FormatFloat(s, AddressOf(FormatFloatG_Convert), params[i], precision, fieldWidth, flags)
1533 Case &h41 'A
1534 flags Or= Cap
1535 Goto *A
1536 Case &h61 'a
1537 *A
1538 FormatFloat(s, AddressOf(FormatFloatA), params[i], precision, fieldWidth, flags)
1539 Case &h73 's
1540 FormatString(s, params[i] As String, precision, fieldWidth, flags)
1541 Case &h63 'c
1542 FormatCharacter(s, params[i] As BoxedStrChar, precision, fieldWidth, flags)
1543' Case &h6e 'n
1544 Case &h25 '%
1545 s.Append(&h25 As Char)
1546 i--
1547 Case 0
1548 Exit Do
1549 End Select
1550 fmt = VarPtr(fmt[1]) 'po
1551 i++
1552 Loop
1553 SPrintf = s.ToString
1554End Function
1555
1556End Namespace 'Detail
1557
1558/*!
1559@brief Cのsprintfのような書式化関数10引数版
1560@author Egtra
1561@date 2007/10/27
1562@param[in] format 書式指定
1563@param[in] paramN 引数
1564@return 書式化された文字列
1565*/
1566
1567Function SPrintf(format As String, param0 As Object,
1568 param1 As Object, param2 As Object, param3 As Object,
1569 param4 As Object, param5 As Object, param6 As Object,
1570 param7 As Object, param8 As Object, param9 As Object) As String
1571
1572 Dim params = VarPtr(param0) As *Object
1573
1574 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 10)
1575End Function
1576
1577/*!
1578@brief Cのsprintfのような書式化関数9引数版
1579@author Egtra
1580@date 2007/10/27
1581@param[in] format 書式指定
1582@param[in] paramN 引数
1583@return 書式化された文字列
1584*/
1585Function SPrintf(format As String, param0 As Object,
1586 param1 As Object, param2 As Object, param3 As Object,
1587 param4 As Object, param5 As Object, param6 As Object,
1588 param7 As Object, param8 As Object) As String
1589
1590 Dim params = VarPtr(param0) As *Object
1591
1592 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 9)
1593End Function
1594
1595/*!
1596@brief Cのsprintfのような書式化関数8引数版
1597@author Egtra
1598@date 2007/10/27
1599@param[in] format 書式指定
1600@param[in] paramN 引数
1601@return 書式化された文字列
1602*/
1603Function SPrintf(format As String, param0 As Object,
1604 param1 As Object, param2 As Object, param3 As Object,
1605 param4 As Object, param5 As Object, param6 As Object,
1606 param7 As Object) As String
1607
1608 Dim params = VarPtr(param0) As *Object
1609
1610 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 8)
1611End Function
1612
1613/*!
1614@brief Cのsprintfのような書式化関数7引数版
1615@author Egtra
1616@date 2007/10/27
1617@param[in] format 書式指定
1618@param[in] paramN 引数
1619@return 書式化された文字列
1620*/
1621Function SPrintf(format As String, param0 As Object,
1622 param1 As Object, param2 As Object, param3 As Object,
1623 param4 As Object, param5 As Object, param6 As Object) As String
1624
1625 Dim params = VarPtr(param0) As *Object
1626
1627 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 7)
1628End Function
1629
1630/*!
1631@brief Cのsprintfのような書式化関数6引数版
1632@author Egtra
1633@date 2007/10/27
1634@param[in] format 書式指定
1635@param[in] paramN 引数
1636@return 書式化された文字列
1637*/
1638Function SPrintf(format As String, param0 As Object,
1639 param1 As Object, param2 As Object, param3 As Object,
1640 param4 As Object, param5 As Object) As String
1641
1642 Dim params = VarPtr(param0) As *Object
1643
1644 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 6)
1645End Function
1646
1647/*!
1648@brief Cのsprintfのような書式化関数5引数版
1649@author Egtra
1650@date 2007/10/27
1651@param[in] format 書式指定
1652@param[in] paramN 引数
1653@return 書式化された文字列
1654*/
1655Function SPrintf(format As String, param0 As Object,
1656 param1 As Object, param2 As Object, param3 As Object,
1657 param4 As Object) As String
1658
1659 Dim params = VarPtr(param0) As *Object
1660
1661 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 5)
1662End Function
1663
1664/*!
1665@brief Cのsprintfのような書式化関数4引数版
1666@author Egtra
1667@date 2007/10/27
1668@param[in] format 書式指定
1669@param[in] paramN 引数
1670@return 書式化された文字列
1671*/
1672Function SPrintf(format As String, param0 As Object,
1673 param1 As Object, param2 As Object, param3 As Object) As String
1674
1675 Dim params = VarPtr(param0) As *Object
1676
1677 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 4)
1678End Function
1679
1680/*!
1681@brief Cのsprintfのような書式化関数3引数版
1682@author Egtra
1683@date 2007/10/27
1684@param[in] format 書式指定
1685@param[in] paramN 引数
1686@return 書式化された文字列
1687*/
1688Function SPrintf(format As String, param0 As Object,
1689 param1 As Object, param2 As Object) As String
1690
1691 Dim params = VarPtr(param0) As *Object
1692
1693 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 3)
1694End Function
1695
1696/*!
1697@brief Cのsprintfのような書式化関数2引数版
1698@author Egtra
1699@date 2007/10/27
1700@param[in] format 書式指定
1701@param[in] paramN 引数
1702@return 書式化された文字列
1703*/
1704Function SPrintf(format As String, param0 As Object,
1705 param1 As Object) As String
1706
1707 Dim params = VarPtr(param0) As *Object
1708
1709 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 2)
1710End Function
1711
1712/*!
1713@brief Cのsprintfのような書式化関数1引数版
1714@author Egtra
1715@date 2007/10/27
1716@param[in] format 書式指定
1717@param[in] paramN 引数
1718@return 書式化された文字列
1719*/
1720Function SPrintf(format As String, param0 As Object) As String
1721 Dim params = VarPtr(param0) As *Object
1722 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 1)
1723End Function
1724
1725/*!
1726@brief Cのsprintfのような書式化関数0引数版
1727@author Egtra
1728@date 2007/10/27
1729@param[in] format 書式指定
1730@param[in] paramN 引数
1731@return 書式化された文字列
1732*/
1733Function SPrintf(format As String) As String
1734 SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, 0, 0)
1735End Function
1736
1737End Namespace 'Strings
1738End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.