linuxだと、odにしてもhdにしても、同じ値が連続していると、途中のダンプ表示が省略できます。しかも省略するのにオプションは要らないので、とても便利です。
takk@deb9:~/tmp$ truncate -s 100 a.bin takk@deb9:~/tmp$ od a.bin 0000000 000000 000000 000000 000000 000000 000000 000000 000000 * 0000140 000000 000000 0000144 takk@deb9:~/tmp$ hd a.bin 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000064 takk@deb9:~/tmp$
どのような条件で省略されるのでしょうか。
作りやすさから考えると、行を表示する前に、前行と同じかチェックして、*を表示するか、値を表示するか決めているのではないかと思いますが。。。
1行 1Byteにして、確認してみます。
takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 0 * 0000100 takk@deb9:~/tmp$
さきほど作ったa.binは、100Byteのオール0なので、1行 1 Byteだと最初だけ値が表示されました。
次は1行2Byte。
takk@deb9:~/tmp$ od -td1 -Ad -w2 a.bin 0000000 0 0 * 0000100 takk@deb9:~/tmp$
同じく一番最後まで省略されました。
takk@deb9:~/tmp$ od -td1 -Ad -w3 a.bin 0000000 0 0 0 * 0000099 0 0000100 takk@deb9:~/tmp$
3Byte毎だと最後の1Byteが余って、前行と比較した結果不一致なので表示された、ということでしょう。
次は先頭に0以外の値を入れてみます。
takk@deb9:~/tmp$ dd of=a.bin bs=1 count=1 conv=notrunc a 1+0 レコード入力 1+0 レコード出力 1 byte copied, 1.37189 s, 0.0 kB/s takk@deb9:~/tmp$
1行 1Byteで確認。
takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 97 0000001 0 * 0000100 takk@deb9:~/tmp$
次は、3Byte目を1Byte目と同じ値にします。
takk@deb9:~/tmp$ dd of=a.bin bs=1 count=1 conv=notrunc seek=2 a 1+0 レコード入力 1+0 レコード出力 1 byte copied, 1.68292 s, 0.0 kB/s takk@deb9:~/tmp$ takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 97 0000001 0 0000002 97 0000003 0 * 0000100 takk@deb9:~/tmp$
1行1Byteだと97 00、97 00と、同じパターンの繰り返しであっても、省略はされてません。
takk@deb9:~/tmp$ od -td1 -Ad -w2 a.bin 0000000 97 0 * 0000004 0 0 * 0000100 takk@deb9:~/tmp$
1行2Byteの表示になることにより、2行目は1行目と一致するので、省略されました。
やはり、行を表示する時に、前回表示した内容と一致しているか判定してるっぽいですね。
では、odのソースで答え合わせをしてみます。coreutilsです。
odの省略表示するかどうかのオプションは、-vですので、オプション解析の定型文case オプション:で検索します。
takk@deb9:~/src/coreutils-8.26/src$ grep 'case.*v' -A3 od.c
case '\v':
s = "\\v";
break;
--
case '\v':
fputs ("\\v", stdout);
break;
--
case 'v':
modern = true;
abbreviate_duplicate_blocks = false;
break;
takk@deb9:~/src/coreutils-8.26/src$
-vオプションに該当するのは、一番下にあるcase ‘v’です。このcaseに入った時のフラグであるabbreviate_duplicate_blocksを追いかければ良いですね。
まあ、追いかけるのも面倒いので、やはりgrepです。
takk@deb9:~/src/coreutils-8.26/src$ grep 'abbrevi.*blocks' od.c
static bool abbreviate_duplicate_blocks = true;
if (abbreviate_duplicate_blocks
abbreviate_duplicate_blocks = false;
takk@deb9:~/src/coreutils-8.26/src$
ifで判定して使用してる箇所が怪しいので、 前後10行ぐらいを表示してみます。
takk@deb9:~/src/coreutils-8.26/src$ grep 'if.*abbrevi.*blocks' -C10 od.c
static void
write_block (uintmax_t current_offset, size_t n_bytes,
const char *prev_block, const char *curr_block)
{
static bool first = true;
static bool prev_pair_equal = false;
#define EQUAL_BLOCKS(b1, b2) (memcmp (b1, b2, bytes_per_block) == 0)
if (abbreviate_duplicate_blocks
&& !first && n_bytes == bytes_per_block
&& EQUAL_BLOCKS (prev_block, curr_block))
{
if (prev_pair_equal)
{
/* The two preceding blocks were equal, and the current
block is the same as the last one, so print nothing. */
}
else
{
takk@deb9:~/src/coreutils-8.26/src$
予想通りでした。
前のブロック(prev_block)と、今のブロック(curr_block)を比較してます。
EQUAL_BLOCKSというマクロを直前に定義しているのが面白いです。敢えてマクロを書くというテクニック、私的には大収穫です。


コメント