[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FDclone-users:00349] Re: FDclone でファイルサイズが 0 と表示される



 しらいです。

In Message-Id <OF24DFE037.3592B272-ON49256F5F.0008038D@tky.lightwell.co.jp>
        SHIOTA Shoichi <Shoichi.Shiota@lightwell.co.jp>さんwrites:
> 潮田です。

> もう一声足りないのは、 4GB over の方の表示です。
> 2GB over 同様 9 桁の 9 が表示されるのが仕様ですよね。

 long long が存在しないと思って compile してしまっている訳
ですから、その前提に基づいて compile された結果、4GB 以上の
数値というのは扱えないんですよ。
 そのため、64bit の off_t を 32bit の long に無理矢理 cast
した結果が表示されます。compiler の実装にも依存しますが、普
通だと下位 32bit だけ使われるんでしょうね。


> あれ、最下行はもっと長くないですか。
> いつも縦横とも広げた TeraTerm 越しに使用しているのでこの為かと、
> オリジナルの TeraTerm を default 状態で使用してみましたが、

 ごめんなさい。桁上限を設けているのはオリジナル版『FD』の
画面レイアウトにした場合のサイズ表示でした。普通だと画面サイ
ズの許す限りの幅で表示しますね。
 で、そっちの実装は「%u」でなく「%d」で受けてるので、正しく
表示されないんでしょう。

 そもそも「%u」だと表示されるものが「%d」だとおかしくなると
いうのも妙な話なのでよくよく調べてみると、「%d」の場合符号拡
張する必要があるのでそこでミスっていたようです。
 printf 関数呼出し側が渡した引数を、受け手側では一番大きい
型で受けている筈なのですが、long long が存在しないと思い込ん
でいる場合、32bit long で受けてしまいます。
 実際は off_t は 64bit ある訳で、受ける変数の幅の方が小さい
ので、符号拡張しようとすると桁数の計算でおかしな計算を行なっ
てしまうようです。
 具体的には負数分だけ算術シフトしようとして変な値を得ている
んでしょうね。負数分の算術シフトはどうも実装依存のようで、他
の環境ではなかなか再現しませんでした。


> 対応が面倒(困難)なら、 HAVELONGLONG を入れる方の対応で良いのでは
> ないかと思いはじめました。

 HAVELONGLONG は AIX に共通項目でない限り無闇に使えませんし、
他にも long long の存在を認識出来ない環境があるかも知れない
ので、上記の 4GB 以上は諦めるとしてもそれ以内は何とかしたい
ところですよね。
 という訳で、HAVELONGLONG が自動検出出来ない環境用の patch
です。

---- Cut Here ----
diff -u ../old/FD-2.06a/printf.c ./printf.c
--- ../old/FD-2.06a/printf.c	Wed Sep  8 00:00:00 2004
+++ ./printf.c	Sat Dec  4 05:34:29 2004
@@ -175,10 +175,7 @@
 	}
 	else if (n >= 0) sign = (pbufp -> flags & VF_PLUS) ? 1 : 0;
 #endif	/* !MINIMUMSHELL */
-	else {
-		sign = -1;
-		n = -n;
-	}
+	else sign = -1;
 
 #ifdef	MINIMUMSHELL
 	if (sign) width--;
@@ -193,11 +190,18 @@
 	}
 	else while (len < sizeof(num) / sizeof(char)) {
 #ifdef	MINIMUMSHELL
-		if (!bit) i = (n % base) + '0';
+		if (!bit) {
+			i = (n % base);
+			if (i < 0) i = -i;
+			i += '0';
+		}
 		else if ((i = (u & base)) < 10) i += '0';
 #else
-		if (!bit) i = '0'
-			+ (((pbufp -> flags & VF_UNSIGNED) ? u : n) % base);
+		if (!bit) {
+			if (pbufp -> flags & VF_UNSIGNED) i = u % base;
+			else if ((i = n % base) < 0) i = -i;
+			i += '0';
+		}
 		else if ((i = (u & base)) < 10) i += '0';
 		else if (cap) i += 'A' - 10;
 		else i += 'a' - 10;
@@ -495,6 +499,40 @@
 #endif
 			else u = va_arg(args, u_int);
 
+#ifndef	HAVELONGLONG
+			if (len > sizeof(long_t)) {
+				u_long_t hi, tmp;
+
+				while (len > sizeof(long_t)) {
+					hi = va_arg(args, long_t);
+					len -= sizeof(long_t);
+				}
+
+				tmp = 0x5a;
+				cp = (char *)(&tmp);
+				if (*cp != 0x5a) {
+					tmp = hi;
+					hi = u;
+					u = tmp;
+				}
+
+				if (pbufp -> flags & VF_UNSIGNED) {
+					if (hi) u = MAXUTYPE(u_long_t);
+				}
+				else {
+					mask = (MAXUTYPE(u_long_t) >> 1);
+					if (hi & ~mask) {
+						if (++hi || !(u & ~mask))
+							u = ~mask;
+					}
+					else {
+						if (hi || (u & ~mask))
+							u = mask;
+					}
+				}
+			}
+			else
+#endif	/* !HAVELONGLONG */
 			if (!(pbufp -> flags & VF_UNSIGNED)) {
 				mask = (MAXUTYPE(u_long_t)
 					>> ((sizeof(long_t) - len)
---- Cut Here ----

 ちゃんと上位 32bit の符号を見て、符号拡張の逆を行なうよう
にしました。その結果 MAXLONG や MINLONG を越えてしまった場合
には MAXLONG や MINLONG の値に丸めるようにしてあります。
 patch の前半は、実は実装をサボって -MAXLONG〜MAXLONG の範
囲しか表示出来ない仕様だったのを、ちゃんと MINLONG まで表示
させるようにしただけです。

 こんな感じで取り敢えずは凌げるんじゃないでしょうか?

                                               しらい たかし