C言語でバイナリダンプ そのに

id:ha-tan:20050928:1127904220で書いたプログラムを改造して、同じ行が出力される場合には出力を省略するようにしました。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>

static int
hd_buf_printf(char *str, char const *fmt, ...)
{
    int ret;
    va_list ap;

    va_start(ap, fmt);
    ret = vsprintf(str, fmt, ap);
    va_end(ap);

    if (ret < 0) {
	perror("hd");
	exit(1);
    }

    return ret;
}

void
hd(const char *data, size_t len)
{
    char buf[128], fragdata[16], oldfragdata[16], str[17];
    char *p;
    int r16, padlen, sameline_f;
    size_t i;

    memset(oldfragdata, 0, sizeof(oldfragdata));
    sameline_f = 0;

    for (i = 0, r16 = 0; i < len; i++, r16 = i % 16) {
	switch (r16) {
	case 0:
	    p = buf;
	    p += hd_buf_printf(p, "%08x  ", i);
	    break;
	case 4: /* FALLTHROUGH */
	case 8: /* FALLTHROUGH */
	case 12:
	    p += hd_buf_printf(p, " ");
	    break;
	}

	p += hd_buf_printf(p, "%02x", data[i]);
	str[r16] = isprint(data[i]) ? data[i] : '.';
	fragdata[r16] = data[i];
	    
	if (r16 == 15) {
	    str[16] = '\0';
	    hd_buf_printf(p, "  %s\n", str);
	    if (memcmp(fragdata, oldfragdata, sizeof(fragdata)) == 0) {
		if (!sameline_f)
		    printf("*\n");
		sameline_f = 1;
	    } else {
		printf("%s", buf);
		sameline_f = 0;
		memcpy(oldfragdata, fragdata, sizeof(fragdata));
	    }
	}
    }

    if (r16 != 0) {
	str[r16] = '\0';
	padlen = (16 - r16) * 2 + (16 - r16) / 4 + 1;
	hd_buf_printf(p, "%*c %s\n", padlen, ' ', str);
	printf("%s", buf);
    }
}

int
main(int argc, char *argv[])
{
    int i;

    for (i = 1; i < argc; i++) {
	hd(argv[i], strlen(argv[i]));
    }

    return 0;
}

実行例:

$ ./hd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa        
00000000  61616161 61616161 61616161 61616161  aaaaaaaaaaaaaaaa
*
00000030  616161                               aaa