Hi,
I've started to do an implementation of 'od' - it is most of the way
there, but I'm not particularly happy with the method I've used for
determining which 'printf' format string and which data alignment to
use. At the moment I'm essentially reparsing the -t XX parameters each
time you want to print a new character, which has pretty hideous
performance (and currently doesn't support the -to2o4 syntax). I'm
debating about pre-parsing these, and then a list of function
pointers. This would also require me to have ~20 tiny stub functions,
which basically just do a printf with a different format string & data
type, and return the length of data that they've consumed (or possibly
iterate over an entire line, I haven't decided).

Does anyone have any comments about an alternative method to do this?

Thanks,
Andre

-- 
Bluewater Systems - An Aiotec Company

Andre Renaud
[email protected]          5 Amuri Park, 404 Barbadoes St
www.bluewatersys.com            PO Box 13 889, Christchurch 8013
www.aiotec.co.nz                New Zealand
Phone: +64 3 3779127            Freecall: Australia 1800 148 751
Fax:   +64 3 3779135            USA 1800 261 2934
/* vi: set sw=4 ts=4:
 *
 * od.c - Provide octal/hex dumps of data
 *
 * Copyright 2012 Andre Renaud <[email protected]>
 *
 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html

USE_OD(NEWTOY(od, "j#vN#xsodbA:t*", TOYFLAG_USR|TOYFLAG_BIN))

config OD
	bool "od"
	default y
	help
          usage: od
*/

#include "toys.h"

#define OD_BLOCK_SIZE 16

#define FLAG_t	(1 << 0)
#define FLAG_A	(1 << 1)
#define FLAG_b	(1 << 2)
#define FLAG_d	(1 << 3)
#define FLAG_o	(1 << 4)
#define FLAG_s	(1 << 5)
#define FLAG_x	(1 << 6)
#define FLAG_N	(1 << 7)
#define FLAG_v  (1 << 8)


DEFINE_GLOBALS(
		struct arg_list *output_base;
		char *address_base;
		long max_count;
		long jump_bytes;
)

#define TT this.od

static const char *ascii[] = {
	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", "bs", "ht",
	"nl", "vt", "ff", "cr", "so", "si", "dle", "dc1", "dc2", "dc3", "dc4",
	"nak", "syn", "etb", "can", "em", "sub", "esc", "fs", "gs", "rs",
	"us", "sp"};

static void display_line_1(char base, off_t offset, uint8_t *line, int len)
{
	while (len--) {
		switch (base) {
			case 'a': {
				int ch = *line & 0x7f;
				if (ch < sizeof(ascii)/sizeof(ascii[0]))
					printf(" %3s", ascii[ch]);
				else if (ch == 127)
					printf(" del");
				else
					printf("   %c", ch);
				break;
			}
			case 'o': printf(" %3.3o", *line); break;
			case 'x': printf(" %2.2x", *line); break;
			case 'd': printf(" %4d", *(int8_t *)line); break;
			case 'u': printf(" %3u", *line); break;
		}
		line++;
	}
}

static void display_line_2(char base, off_t offset, uint16_t *line, int len)
{
	while (len--) {
		switch (base) {
			case 'o': printf(" %6.6o", *line); break;
			case 'x': printf(" %4.4x", *line); break;
			case 'd': printf(" %6d", *(int16_t*)line); break;
			case 'u': printf(" %5u", *line); break;
		}
		line++;
	}
}

static void display_line_4(char base, off_t offset, uint32_t *line, int len)
{
	while (len--) {
		switch (base) {
			case 'o': printf(" %11.11o", *line); break;
			case 'x': printf(" %8.8x", *line); break;
			case 'd': printf(" %11d", *(int32_t *)line); break;
			case 'u': printf(" %10u", *line); break;
			case 'f': printf(" %15g", *(float *)line); break;
		}
		line++;
	}
}

static void display_line_8(char base, off_t offset, uint64_t *line, int len)
{
	while (len--) {
		switch (base) {
			//case 'o': printf(" %22.22o", *line); break;
			case 'x': printf(" %16.16" PRIx64, *line); break;
			case 'd': printf(" %21" PRId64, *(int64_t *)line); break;
			case 'u': printf(" %20" PRIu64, *line); break;
			case 'f': printf(" %23g", *(double *)line);
		}
		line++;
	}
}

static void display_line(off_t offset, uint8_t *line, int len)
{
	struct arg_list *output = TT.output_base;
	switch (*TT.address_base) {
		case 'o': printf("%8.8zo", offset); break;
		case 'd': printf("%7.7zd", offset); break;
		case 'x': printf("%6.6zx", offset); break;
		case 'n':
		default:
			  break;
	}
	while (output) {
		char base = *output->arg;
		int width = atoi(&output->arg[1]);

		switch (width) {
			case 1: display_line_1(base, offset, line, len); break;
			case 2: display_line_2(base, offset, (uint16_t *)line,
						(len + 1) / 2); break;
			case 4: display_line_4(base, offset, (uint32_t *)line,
						(len + 3) / 4); break;
			case 8: display_line_8(base, offset, (uint64_t *)line,
						(len + 7) / 8); break;
		}
		output = output->next;
	}

	printf("\n");
}

static void do_od(int fd, char *name)
{
	uint8_t *block[2];
	int index = 0;
	off_t offset = 0;
	int last_match = 0;

	block[0] = (uint8_t *)toybuf;
	block[1] = (uint8_t *)&toybuf[OD_BLOCK_SIZE];

	if (TT.jump_bytes) {
		xlseek(fd, TT.jump_bytes, SEEK_SET);
		offset = TT.jump_bytes;
	}

	do {
		int len;
		int max_len = OD_BLOCK_SIZE;
		if ((toys.optflags & FLAG_N) &&
				offset + OD_BLOCK_SIZE > TT.max_count)
			max_len = TT.max_count - offset;
		len = xread(fd, block[index], max_len);
		if (!len)
			break;

		memset(&block[index][len], 0, OD_BLOCK_SIZE - len);

		if (!(toys.optflags & FLAG_v) &&
				offset > 0 &&
				memcmp(block[0], block[1], OD_BLOCK_SIZE) == 0) {
			if (!last_match)
				puts("*");
			last_match = 1;
		} else {
			display_line(offset, block[index], len);
			last_match = 0;
		}
		offset += len;
		index = !index;

		if (len != OD_BLOCK_SIZE)
			break;
	} while (1);

	if (!(toys.optflags & FLAG_N) && offset != TT.max_count)
		display_line(offset, NULL, 0);
}

static void append_base(char *base)
{
	struct arg_list *arg, *prev;
	arg = xmalloc(sizeof(struct arg_list));
	prev = TT.output_base;
	TT.output_base = arg;
	arg->arg = base;
	arg->next = prev;
}

static void valid_bases(void)
{
	struct arg_list *arg = TT.output_base;
	while (arg) {
		char base = arg->arg[0];
		int width = 1;
		if (arg->arg[1])
			width = atoi(&arg->arg[1]);
		switch (base) {
		case 'a':
			if (width != 1)
				error_exit("invalid width for ascii base");
			break;
		case 'd': case 'x': case 'o': case'u':
			if (width != 1 && width != 2 &&
					width != 4 && width != 8)
				error_exit("this system doesn't provide a %d-byte type",
						width);
			break;
		case 'f':
			if (width != 4 && width != 8)
				error_exit("this system doesn't provide a %d-byte floating point type",
						width);
			break;
		default:
			error_exit("invalid base '%c'", base);
		}

		arg = arg->next;
	};
}

void od_main(void)
{
	if (!TT.address_base)
		TT.address_base = "o";
	if (toys.optflags & FLAG_b)
		append_base("o1");
	if (toys.optflags & FLAG_d)
		append_base("u2");
	if (toys.optflags & FLAG_o)
		append_base("o2");
	if (toys.optflags & FLAG_s)
		append_base("d2");
	if (toys.optflags & FLAG_x)
		append_base("x2");
	if (!TT.output_base)
		append_base("o2");
	valid_bases();
	loopfiles(toys.optargs, do_od);
}
_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to