!	SNM -- List names in SLD objects and X.OUT executables
!	Copyright (C) 1998,2000 Nils M Holm
!	See the file LICENSE for conditions of use.

#r5;

interface	readpacked(3) = 11,
		writepacked(3),
		reposition(4),
		rename(2),
		memcopy(3),
		memcomp(3);

!-------------------- IOSTREAM DEFINITIONS START --------------------!
struct IOS =	IOS_FD,
		IOS_BUFFER,
		IOS_FLAGS,
		IOS_LEN,
		IOS_PTR,
		IOS_END;

const		IOF_READ	= 00001,
		IOF_WRITE	= 00002,
		IOF_EOF		= 00004;

const		SEEK_SET	= 0,
		SEEK_REL	= 1,
		SEEK_END	= 2;


ios_create(iostream, fd, buffer, len, mode) do
	iostream[IOS_FD] := fd;
	iostream[IOS_BUFFER] := buffer;
	iostream[IOS_FLAGS] := mode;
	iostream[IOS_LEN] := len;
	iostream[IOS_PTR] := 0;
	iostream[IOS_END] := 0;
	return iostream;
end


ios_open(iostream, name, buffer, len, flags) do
	var	fd, mode;

	mode := flags = IOF_READ-> 0:
		flags = IOF_WRITE-> 1: %1;
	if (mode < 0) return %1;
	fd := open(name, mode);
	if (fd < 0) return %1;
	return ios_create(iostream, fd, buffer, len, flags);
end


ios_flush(iostream) do
	var	k;

	if (iostream[IOS_FLAGS] & IOF_WRITE) do
		k := writepacked(iostream[IOS_FD], iostream[IOS_BUFFER],
			iostream[IOS_PTR]);
		if (k \= iostream[IOS_PTR]) return %1;
	end
	iostream[IOS_PTR] := 0;
	iostream[IOS_END] := 0;
	return 0;
end


ios_close(iostream) do
	if (ios_flush(iostream) < 0) return %1;
	close(iostream[IOS_FD]);
	iostream[IOS_FLAGS] := 0;
	return 0;
end


ios_wrch(iostream, ch) do
	if (	iostream[IOS_PTR] >= iostream[IOS_LEN] /\
		ios_flush(iostream) < 0
	)
		return %1;
	iostream[IOS_BUFFER]::iostream[IOS_PTR] := ch;
	iostream[IOS_PTR] := iostream[IOS_PTR]+1;
	return ch;
end


ios_write(iostream, buffer, len) do
	var	i, p, l, b;

	i := 0;
	p := iostream[IOS_PTR];
	l := iostream[IOS_LEN];
	b := iostream[IOS_BUFFER];
	while (len) do
		if (p >= l) do
			iostream[IOS_PTR] := p;
			if (ios_flush(iostream) < 0) return %1;
			p := iostream[IOS_PTR];
			l := iostream[IOS_LEN];
		end
		b::p := buffer::i;
		p := p+1;
		i := i+1;
		len := len-1;
	end
	iostream[IOS_PTR] := p;
	return i;
end


ios_writes(iostream, str) do
	var	k;
	var	b[1024];

	k := 0;
	while (str[k]) k := k+1;
	if (k > 1024) return %1;
	pack(str, b);
	return ios_write(iostream, b, k);
end


ios_more(iostream) do
	var	k;

	if (iostream[IOS_FLAGS] & IOF_READ) do
		k := readpacked(iostream[IOS_FD], iostream[IOS_BUFFER],
			iostream[IOS_LEN]);
		if (k < 0) return %1;
		if (k = 0)
			iostream[IOS_FLAGS] := iostream[IOS_FLAGS] | IOF_EOF;
		iostream[IOS_END] := k;
		iostream[IOS_PTR] := 0;
	end
	return k;
end


ios_rdch(iostream) do
	var	c;

	if (iostream[IOS_FLAGS] & IOF_EOF) return %1;
	if (	iostream[IOS_PTR] >= iostream[IOS_END] /\
		ios_more(iostream) < 1
	)
		return %1;
	c := iostream[IOS_BUFFER]::iostream[IOS_PTR];
	iostream[IOS_PTR] := iostream[IOS_PTR]+1;
	return c;
end


ios__read(iostream, buffer, len, ckln) do
	var	i, p, e, b;

	i := 0;
	p := iostream[IOS_PTR];
	e := iostream[IOS_END];
	b := iostream[IOS_BUFFER];
	while (len) do
		if (p >= e) do
			iostream[IOS_PTR] := p;
			if (ios_more(iostream) < 1) leave;
			p := iostream[IOS_PTR];
			e := iostream[IOS_END];
		end
		buffer::i := b::p;
		p := p+1;
		i := i+1;
		len := len-1;
		if (ckln /\ buffer::(i-1) = '\n') leave;
	end
	if (ckln) buffer::i := 0;
	iostream[IOS_PTR] := p;
	iostream[IOS_END] := e;
	return i;
end


ios_read(iostream, buffer, len) return ios__read(iostream, buffer, len, 0);


ios_reads(iostream, buffer, len) return ios__read(iostream, buffer, len, 1);


ios_position(iostream, offh, offl, how) do
	var	delta;

	ie (how = SEEK_REL /\ iostream[IOS_FLAGS] & IOF_READ)
		delta := iostream[IOS_END] - iostream[IOS_PTR];
	else
		delta := 0;
	if (ios_flush(iostream) < 0) return %1;
	if (offl < delta) offh := offh - 1;
	offl := offl - delta;
	return reposition(iostream[IOS_FD], offh, offl, how);
end


ios_eof(iostream) return (iostream[IOS_FLAGS] & IOF_EOF) -> %1: 0;
!-------------------- IOSTREAM DEFINITIONS END --------------------!


const	BUFLEN =	1024;
const	OBJMAGIC_HI=	6513,
	OBJMAGIC_LO=	1046;
const	EXECMAGIC_HI=	6514,
	EXECMAGIC_LO=	1060;

const	HHMAGIC = 0, HLMAGIC = 1, HFLAGS = 2,
	HTEXTLEN = 3, HDATALEN = 4, HBSSLEN = 5,
	HPUBLEN = 6, HEXTLEN = 7, HRLCLEN = 8,
	HDR_LEN = 9;

const	XHMAGIC = 0, XLMAGIC = 1, XFLAGS = 2, XLTEXT = 3, XLDATA = 4,
	XLBSS = 5, XLSYM = 6, XHDR = 8;


error(m) do
	select(1, 2);
	writes("SNM: ");
	writes(m);
	newline();
	halt;
end


rdwrd(s) return ios_rdch(s) | (ios_rdch(s) << 8);


word(b, n) do
	var	digits;

	digits := "0123456789ABCDEF";
	b::0 := digits[(n>>8) / 16];
	b::1 := digits[(n>>8) mod 16];
	b::2 := digits[(n&255) / 16];
	b::3 := digits[(n&255) mod 16];
end


dumpnames(s, len, ext) do
	const	NLEN=0, ADDR=1, CLSS=2;
	var	sym[3];
	var	buf::81, i, k;
	var	lref;

	while (len) do
		if (len < 0) error("consistency check failed");
		sym[0] := rdwrd(s);
		sym[1] := rdwrd(s);
		sym[2] := rdwrd(s);
		for (i=0, 81) buf::i := '\s';
		buf::0 := ext-> 'X': 'P';
		buf::1 := sym[CLSS];
		word(@buf::3, sym[ADDR]);
		ios_read(s, @buf::8, sym[NLEN]);
		k := 8+sym[NLEN];
		if (ext) do
			lref := rdwrd(s);
			len := len-lref-2;
			buf::(k+1) := '*';
			word(@buf::(k+2), lref>>2);
			k := k+6;
			while (lref) do
				ios_rdch(s); lref := lref-1;
			end
		end
		writepacked(1, buf, k);
		newline();
		len := len-sym[NLEN]-6;
	end
end


obj_dump(s, hdr) do
	ios_position(s, 0, hdr[HTEXTLEN], SEEK_REL);
	ios_position(s, 0, hdr[HDATALEN], SEEK_REL);
	dumpnames(s, hdr[HPUBLEN], 0);
	dumpnames(s, hdr[HEXTLEN], 1);
end


exec_dump(s, hdr) do
	if (hdr[XLSYM] = 0) error("program has no symbol table");
	ios_position(s, 0, hdr[XLTEXT], SEEK_REL);
	ios_position(s, 0, hdr[XLDATA], SEEK_REL);
	dumpnames(s, hdr[HPUBLEN], 0);
end


do
	var	in[IOS], inbuf::BUFLEN;
	var	hdr[9];
	var	i;

	if (ios_create(in, 0, inbuf, BUFLEN, IOF_READ) = %1)
		error("cannot create input stream");
	for (i=0, 8) do
		hdr[i] := rdwrd(in);
		if (ios_eof(in)) error("short header");
	end
	ie (hdr[0] = OBJMAGIC_HI /\ hdr[1] = OBJMAGIC_LO) do
		hdr[8] := rdwrd(in);
		obj_dump(in, hdr);
	end
	else ie (hdr[0] = EXECMAGIC_HI /\ hdr[1] = EXECMAGIC_LO) do
		exec_dump(in, hdr);
	end
	else do
		error("unknown file type");
	end
	ios_close(in);
end

