Index: trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab
===================================================================
--- trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab	(revision 359)
+++ trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab	(revision 364)
@@ -16,5 +16,5 @@
 仮数は1の位から下へ17桁で、小数点を含まない。そのため、誤差を無視すればVal(仮数) * 10 ^ (e - 17) = Abs(x)が成り立つ。
 
-xに無限大、無限小、非数を渡した場合の動作は未定義。
+xに無限大、非数を渡した場合の動作は未定義。
 */
 Function FloatToChars(x As Double, ByRef e As Long, ByRef sign As Boolean) As String
@@ -76,5 +76,9 @@
 	'! 何も指定がない。
 	None = &h0
-	'! 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
+	/*!
+	符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
+	AdjustFieldWidthの仕様から、Format関数郡内からAdjustFieldWidthにかけて、
+	単に数値が符号付である（負の値である）ことを示す意味でも用いられる。
+	*/
 	Sign = &h1
 	/*! 空白、空白文字。
@@ -101,5 +105,5 @@
 
 /*!
-@brief	浮動小数点数をprintfの%e, %E相当の変換で文字列化する関数。
+@brief	浮動小数点数をprintfの%e, %E（指数形式、十進法）相当の変換で文字列化する関数。
 @author	Egtra
 @date	2007/09/18
@@ -110,25 +114,18 @@
 @return xの文字列表現
 
-@todo 末尾桁四捨五入
+@todo 他の実装での末尾桁の扱いを調べる（このコードでは何もしていないので切捨となっている）。
 */
 Function FormatFloatE(x As Double, d As DWord, field As DWord, flags As FormatFlags) As String
+	If d = DWORD_MAX Then
+		d = 6
+	End If
+
+	Dim e As Long, negative As Boolean
+	Dim s = FloatToChars(x, e, negative)
+
 	Dim sb = New System.Text.StringBuilder
 	With sb
-		If d = DWORD_MAX Then
-			d = 6
-		End If
-
-		Dim e As Long, negative As Boolean
-		Dim s = FloatToChars(x, e, negative)
-
-		If negative Then
-			.Append("-")
-		Else
-			If flags And Sign Then
-				.Append("+")
-			ElseIf flags And Blank Then
-				.Append(" ")
-			End If
-		End If
+
+		AppendSign(sb, negative, flags)
 
 		.Append(s[0])
@@ -153,14 +150,97 @@
 		.Append(FormatIntegerD(e, 2, 0, Sign Or Zero))
 
-		AdjustFieldWidth(sb, field, negative, flags)
+		AdjustFieldWidth(sb, field, flags)
 	End With
 	FormatFloatE = sb.ToString()
 End Function
 
+/*!
+@brief	浮動小数点数をprintfの%f（小数点数形式、十進法）相当の変換で文字列化する関数。
+@author	Egtra
+@date	2007/10/23
+@param[in]	x	文字列化する浮動小数点数値。
+@param[in]	precision	精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
+@param[in]	field	フィールド幅。
+@param[in]	flags	書式フラグ。
+@return xの文字列表現
+*/
+Function FormatFloatF(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String
+	If precision = DWORD_MAX Then
+		precision = 6
+	End If
+
+	Dim e As Long, negative As Boolean
+	Dim s = FloatToChars(x, e, negative)
+
+	Dim sb = New System.Text.StringBuilder
+	With sb
+		AppendSign(sb, negative, flags)
+
+		Dim intPartLen = e + 1
+		Dim outputDigit = 0 As DWord
+		If intPartLen >= 17 Then
+			'有効桁が全て整数部に収まる場合
+			.Append(s)
+			.Append(&h30 As StrChar, intPartLen - 17)
+			outputDigit = 17
+		ElseIf intPartLen > 0 Then
+			'有効桁の一部が整数部にかかる場合
+			.Append(s, 0, intPartLen)
+			outputDigit = intPartLen
+		Else
+			'有効桁が全く整数部にかからない場合
+			.Append(&h30 As StrChar)
+		End If
+
+		If precision > 0 Or (flags And Alt) Then
+			.Append(".")
+
+			Dim lastDigit = s.Length - outputDigit
+			If lastDigit >= precision Then '変換して得られた文字列の桁数が精度以上ある場合
+				Dim zeroDigit = 0
+				If intPartLen < 0 Then
+					'1.23e-4 = 0.000123のように指数が負のため小数点以下に0が続く場合
+					zeroDigit = System.Math.Min(-intPartLen As DWord, precision)
+					.Append(&h30 As StrChar, zeroDigit As Long)
+				End If
+				.Append(s, outputDigit, (precision - zeroDigit) As Long)
+			Else
+				.Append(s, outputDigit, lastDigit)
+				.Append(&h30 As StrChar, (precision - lastDigit) As Long) '残りの桁は0埋め
+			End If
+		End If
+		AdjustFieldWidth(sb, field, flags)
+	End With
+	FormatFloatF = sb.ToString()
+End Function
+
+/*!
+@brief 先頭に符号もしくはその分の空白を出力する。FormatFloat用。
+@author	Egtra
+@date 2007/10/23
+@param[in, out] sb	出力先
+@param[in] negative	符号
+@param[in, out] flags	フラグ。negative = Trueなら、Signを立てて返す。
+*/
+Sub AppendSign(sb As System.Text.StringBuilder, negative As Boolean, ByRef flags As FormatFlags)
+	With sb
+		If negative Then
+			.Append("-")
+			flags Or= Sign
+		Else
+			If flags And Sign Then
+				.Append("+")
+			ElseIf flags And Blank Then
+				.Append(" ")
+			End If
+		End If
+	End With
+End Sub
+
 '! DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。
 Const MaxSizeU = 9
 
 /*!
-@brief	符号無し整数をprintfの%u相当の変換で文字列化する関数。
+@brief	符号無し整数をprintfの%u（十進法表現）相当の変換で文字列化する関数。
 @author	Egtra
 @date	2007/09/18
@@ -182,5 +262,5 @@
 
 /*!
-@brief	符号有り整数をprintfの%u相当の変換で文字列化する関数。
+@brief	符号有り整数をprintfの%d（十進法表現）相当の変換で文字列化する関数。
 @author	Egtra
 @date	2007/10/13
@@ -198,4 +278,5 @@
 		dwX = (-x) As DWord
 		signChar = Asc("-")
+		flags Or= Sign
 	Else
 		dwX = x As DWord
@@ -220,4 +301,7 @@
 @param[in]	signChar	符号部分の文字。\0なら存在しないとして扱われる。
 @return xの文字列表現
+
+signCharに何らかの値を指定するときには、必ずflagsにSignまたはBlankを指定すること。
+さもないと、フィールド幅を指定したときに正しく整形されなくなる。
 */
 Function FormatInteger(x As DWord, d As DWord, field As DWord, flags As FormatFlags, signChar As StrChar) As String
@@ -245,17 +329,24 @@
 		.Append(buf, i + 1, len)
 
-		AdjustFieldWidth(sb, field, signChar <> 0, flags)
+		AdjustFieldWidth(sb, field, flags)
 	End With
 	FormatInteger = sb.ToString()
 End Function
 
-
-/*!
-DWordの最大値の八進法表現37777777777の文字数 - 1。FormatIntegerO内で使用。
-*/
-Const MaxSizeO = 10
-
-/*!
-@brief	整数をprintfの%o相当の変換で文字列化する関数。
+/*!
+DWordの最大値の八進法表現37777777777の文字数 - 1 + 1。FormatIntegerO内で使用。
+上の式で1を加えているのは、八進接頭辞の分。
+*/
+Const MaxSizeO = 11
+
+Dim TraitsIntegerO As IntegerConvertTraits
+With TraitsIntegerO
+	.Convert = AddressOf(IntegerO_Convert)
+	.Prefix = AddressOf(IntegerO_Prefix)
+	.MaxSize = MaxSizeO
+End With
+
+/*!
+@brief	符号無し整数をprintfの%o（八進法表現）相当の変換で文字列化する関数。
 @author	Egtra
 @date	2007/10/19
@@ -267,32 +358,23 @@
 */
 Function FormatIntegerO(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
-	PreProcessFormatInteger(d, flags)
-
-	Dim sb = New System.Text.StringBuilder
-	With sb
-		Dim buf[MaxSizeO] As StrChar
-		Dim i = MaxSizeO
-		While x <> 0
-			buf[i] = ((x And &o7) + &h30) As StrChar
-			x >>= 3
-			i--
-		Wend
-		
-		Dim len = (MaxSizeO - i) As Long
-
-		If flags And Alt Then
-			.Append(&h30 As StrChar)
-			len++
-		End If
-
-		If len < d Then
-			.Append(&h30 As StrChar, d - len)
-		End If
-
-		.Append(buf, i + 1, len)
-
-		AdjustFieldWidth(sb, field, False, flags And (Not (Sign Or Blank)))
-	End With
-	FormatIntegerO = sb.ToString()
+	FormatIntegerO = FormatIntegerEx(TraitsIntegerO, x, d, field, flags)
+End Function
+
+Function IntegerO_Convert(buf As *StrChar, xq As QWord, flags As FormatFlags) As DWord
+	Dim x = xq As DWord
+	Dim i = MaxSizeO
+	While x <> 0
+		buf[i] = ((x And &o7) + &h30) As StrChar
+		x >>= 3
+		i--
+	Wend
+	If flags And Alt Then
+		buf[i] = &h30
+		i--
+	End If
+	IntegerO_Convert = i
+End Function
+
+Function IntegerO_Prefix(x As QWord, flags As FormatFlags) As String
 End Function
 
@@ -302,6 +384,13 @@
 Const MaxSizeX = 7
 
-/*!
-@brief	整数をprintfの%x, %X相当の変換で文字列化する関数。
+Dim TraitsIntegerX As IntegerConvertTraits
+With TraitsIntegerX
+	.Convert = AddressOf(IntegerX_Convert)
+	.Prefix = AddressOf(IntegerX_Prefix)
+	.MaxSize = MaxSizeX
+End With
+
+/*!
+@brief	整数をprintfの%x, %X（十六進法）相当の変換で文字列化する関数。
 @author	Egtra
 @date	2007/10/19
@@ -313,38 +402,73 @@
 */
 Function FormatIntegerX(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
+	FormatIntegerX = FormatIntegerEx(TraitsIntegerX, x, d, field, flags)
+End Function
+
+Function IntegerX_Convert(buf As *StrChar, xq As QWord, flags As FormatFlags) As DWord
+	Dim i = MaxSizeX
+	Dim x = xq As DWord
+	While x <> 0
+		buf[i] = _System_HexadecimalTable[x And &h0f]
+		x >>= 4
+		i--
+	Wend
+	IntegerX_Convert = i
+End Function
+
+Function IntegerX_Prefix(x As QWord, flags As FormatFlags) As String
+	If flags And Alt Then
+		If x <> 0 Then
+			IntegerX_Prefix = "0X"
+		End If
+	End If
+End Function
+
+Type IntegerConvertTraits
+	Convert As *Function(buf As *StrChar, x As QWord, flags As FormatFlags) As DWord
+	Prefix As *Function(x As QWord, flags As FormatFlags) As String
+	MaxSize As DWord
+End Type
+
+/*!
+@brief	整数変換全てを行う関数。これを雛形とし、形式毎の差異はIntegerConvertTraitsで表現する。
+@author	Egtra
+@date 2007/10/22
+@param[in] tr	特性情報。
+@param[in] x	変換元の数値。
+@param[in] d	精度。ここでは最低限出力する桁数。
+@param[in] field	フィールド幅。
+@param[in] flags	フラグ。
+*/
+Function FormatIntegerEx(ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String
 	PreProcessFormatInteger(d, flags)
 
 	Dim sb = New System.Text.StringBuilder
 	With sb
+		Dim prefixFunc = tr.Prefix
+		Dim prefix = prefixFunc(x, flags)
+		sb.Append(prefix)
+
 		Dim prefixLen = 0 As DWord
-		If (flags And Alt) Then
-			If x <> 0 Then
-				.Append("0X")
-				prefixLen = 2
-			End If
-		End If
-
-		Dim buf[MaxSizeX] As StrChar
-		Dim i = MaxSizeX
-		While x <> 0
-			buf[i] = _System_HexadecimalTable[x And &h0f]
-			x >>= 4
-			i--
-		Wend
-		
-		Dim len = (MaxSizeX - i) As Long
-
+		If String.IsNullOrEmpty(prefix) = False Then
+			prefixLen = prefix.Length As DWord
+		End If
+
+		Dim buf = GC_malloc_atomic((tr.MaxSize + 1) * SizeOf (StrChar)) As *StrChar
+		Dim convertFunc = tr.Convert
+		Dim bufStartPos = convertFunc(buf, x, flags)
+
+		Dim len = (tr.MaxSize - bufStartPos) As Long
 		If len < d Then
 			.Append(&h30 As StrChar, d - len)
 		End If
 
-		.Append(buf, i + 1, len)
-
-		AdjustFieldWidth(sb, field, False, flags And (Not (Sign Or Blank)), prefixLen)
+		.Append(buf, bufStartPos + 1, len)
+
+		AdjustFieldWidth(sb, field, flags And (Not (Sign Or Blank)), prefixLen)
 	End With
-	FormatIntegerX = sb.ToString()
+	FormatIntegerEx = sb.ToString()
 	
 	If (flags And Cap) = 0 Then
-		FormatIntegerX = FormatIntegerX.ToLower()
+		FormatIntegerEx = FormatIntegerEx.ToLower()
 	End If
 End Function
@@ -365,5 +489,5 @@
 	Else
 		'精度が指定されているとき、ゼロフラグは無視される。
-		'左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
+		'仕様上、左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
 		flags And= Not Zero
 	End If
@@ -377,6 +501,7 @@
 @param [in]	flags	フラグ
 @param [in]	prefixLen	（あれば）接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
-*/
-Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, hasSign As Boolean, flags As FormatFlags, prefixLen = 0 As DWord)
+sbが"-1"のように負符号を持っている場合は、呼出元でSignフラグ（またはBlank）を立てること。
+*/
+Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, flags As FormatFlags, prefixLen = 0 As DWord)
 	With sb
 		If .Length < field Then
@@ -387,5 +512,5 @@
 				Dim insPos As Long
 				If (flags And Zero) <> 0 Then
-					If ((flags And Blank) Or (flags And Sign) Or hasSign) Then
+					If (flags And Blank) Or (flags And Sign) Then
 						insPos++
 					End If
