[net.sources] general byte swapper/selector

henry@utzoo.UUCP (Henry Spencer) (07/26/84)

The following is the source and manual page for bytes(1), the latest
minor local innovation.  It's a general program for doing byte selection
and swapping in binary data.  It will swap bytes, swap words, etc., and
will let you pick out specific bytes of words.  (Why would you want to
do the latter?  Well, EPROMs are only a byte wide, so a 16-bit machine
needs an EPROM of high bytes and an EPROM of low bytes...).  It is public
domain.

Bytes uses four functions not in the standard C library:  getopt, strtok,
error, and efopen.  Getopt and strtok are from System V, but public-domain
implementations exist and have been posted to the net within the last six
months.  Error and efopen are trivial routines from Kernighan&Pike; if you
haven't already done so, type them in and put them in your library -- they
are useful!

[What, you don't have a copy of Kernighan&Pike?  Stop reading this minute,
run right down to your neighborhood Unix bookstore, buy one, and read it.
Then start typing things in.]

[Oh yes, you System V types will need to '#define index strchr', but
then you're probably used to that already.]

-----
/*
 * bytes - select and permute bytes
 */

#include <stdio.h>

int exact = 0;			/* Insist on exact number of records? */
int recsize = 0;		/* Record size. */
int bytenos[BUFSIZ];		/* Bytes to output; 0 terminates. */

char *progname;

/*
 * main - parse arguments and handle options
 */
main(argc, argv)
int argc;
char *argv[];
{
	register char *p;		/* For scanning byte list. */
	register int nb;		/* Number of byte numbers seen. */
	int c;
	int errflg = 0;
	FILE *in;
	extern int optind;
	extern char *optarg;
	extern FILE *efopen();
	extern char *index();
	extern char *strtok();

	progname = argv[0];

	while ((c = getopt(argc, argv, "e")) != EOF)
		switch (c) {
		case 'e':
			exact++;
			break;
		case '?':
		default:
			errflg++;
			break;
		}
	if (errflg || optind >= argc) {
		fprintf(stderr, "Usage: %s [-e] b,b,...[/size] [file] ...\n", progname);
		exit(2);
	}

	p = index(argv[optind], '/');
	if (p != NULL) {
		*p = '\0';
		p++;
		recsize = atoi(p);
		if (recsize < 1 || recsize >= BUFSIZ)
			error("invalid record size \"%s\"", p);
	}

	nb = 0;
	for (p = strtok(argv[optind], " \t,"); p != NULL; p = strtok((char *)NULL, " \t,")) {
		bytenos[nb] = atoi(p);
		if (bytenos[nb] < 1 || bytenos[nb] >= BUFSIZ)
			error("invalid byte number \"%s\"", p);
		if (bytenos[nb] > recsize)
			recsize = bytenos[nb];
		nb++;
	}
	bytenos[nb] = 0;

	optind++;

	if (optind == argc)
		process(stdin, "stdin");
	else
		for (; optind < argc; optind++) {
			in = efopen(argv[optind], "r");
			process(in, argv[optind]);
			fclose(in);
		}

	exit(0);
}

/*
 * process - process input file
 */
/* ARGSUSED */
process(in, inname)
FILE *in;
char *inname;
{
	char buf[BUFSIZ];
	register int n;
	register int i;

	while ((n = fread(buf, 1, recsize, in)) > 0) {
		if (n < recsize) {
			if (exact)
				error("partial record", "");
			for (; n < recsize; n++)
				buf[n] = '\0';
		}
		for (i = 0; bytenos[i] != 0; i++)
			putchar(buf[bytenos[i]-1]);
	}
}
-----
.TH BYTES 1 local
.DA 14 July 1984
.SH NAME
bytes \- select and permute bytes
.SH SYNOPSIS
.B bytes
[
.B \-e
]
b\fB,\fRb\fB,\fR...[\fB/\fRsize]
[ file ... ]
.SH DESCRIPTION
.I Bytes
selects bytes from its input
.IR file s
(default standard input)
and puts them out in a specified order.
Conceptually,
it repeatedly reads \fIn\fR bytes, numbers them from 1 to \fIn\fR,
and then outputs the bytes whose numbers appear in the list that is
the first argument, in the order they appear in the list.
Bytes not mentioned in the list are discarded.
.PP
The value of \fIn\fR can be set by appending a slash and a
.I size
value to the list.
The default is equal to the largest byte number in the list.
.PP
If an incomplete record is read
(e.g. at end-of-file),
.I bytes
normally pads it on the end with zeros.
The
.B \-e
option suppresses this padding,
in which case
.I bytes
complains if the input is not an exact number of records.
.PP
Note that byte numbers start at 1, not 0.
.SH EXAMPLES
.nf
.ta \w'\fBbytes 3,4,1,2\fR'u+2n
\fBbytes 1,2\fR	output identical to input
\fBbytes 2,1\fR	adjacent bytes swapped
\fBbytes 3,4,1,2\fR	adjacent two-byte words swapped
\fBbytes 1/2\fR	low-order bytes of pdp11 words
\fBbytes 1,2/4\fR	low-order halfwords of VAX words
\fBbytes 2,1/4\fR	same, with bytes swapped
.fi
.SH SEE ALSO
dd(1)
.SH HISTORY
Local product.
-----
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry