static	char	dumpbpages_c[] = "$Header: /private/postgres/src/test/RCS/dumpbpages.c,v 1.8 1990/04/28 16:24:21 mao Version_2 $";

#include <sys/file.h>
#include <stdio.h>
#include <strings.h>

#include "magic.h"

#include "c.h"
#include "os.h"
#include "clib.h"

#include "block.h"
#include "btree.h"
#include "bufmgr.h"
#include "bufpage.h"
#include "htup.h"
#include "itemid.h"
#include "page.h"
#include "part.h"
#include "tim.h"
#include "xid.h"

#define DEFAULT_TYPE	'r'

char		*Progname;
/* int	Version; */
int		Type;
char		Buf[BLCKSZ];

/*
 * ItemPointerFormExternal --
 */
extern
String
ItemPointerFormExternal ARGS((
	ItemPointer	pointer
));

main(argc, argv)
int	argc;
char	*argv[];
{
	int		s;
	int		errors = 0;
	char		*cp;
	extern		dumprelation();

	Progname = rindex(argv[0], '/');
	Progname = (Progname != (char *)NULL) ? Progname + 1 : argv[0];
	Type = DEFAULT_TYPE;
	if (! --argc)
		dumprelation(fileno(stdin), "<stdin>");
	while (argc--) {
		argv++;
		if (**argv != '-') {
			if ((s = open(*argv, O_RDONLY, 00)) < 0) {
				perror(*argv);
				continue;
			}
			dumprelation(s, *argv);
			close(s);
			continue;
		}
		cp = *argv;
		if ((Type = *++*argv) == '\0' || *++*argv != '\0') {
			Type = DEFAULT_TYPE;
			errors++;
			fprintf(stderr, "%s: bad argument %s", Progname, cp);
			continue;
		}
	}
	if (errors)
		fprintf(stderr, "Usage: %s {[-(b|r|i)] relpath}+\n", Progname);
}

dumprelation(fd, path)
int	fd;
char	path[];
{
	int		nr, pageno = 0;
	int		someBlocks;
	extern		dumppage();

	someBlocks = 0;
	while ((nr = read(fd, Buf, sizeof Buf)) == sizeof Buf) {
		if (someBlocks) {
			putchar('\n');
		}
		DumpBlock(path, pageno++);
		someBlocks = 1;
	}
	if (nr > 0)
		fprintf(stderr, "%s: %d bytes after last block\n", path, nr);
}

DumpBlock(path, blockNumber)
	char	path[];
	int	blockNumber;
{
	PageSize	pageSize;
	int		pageNumber;
	Page		page;

	pageSize = PageGetPageSize((Page)Buf);

	printf("%s[block=%d]:pageSize=%d\n", path, blockNumber, pageSize);

	for (pageNumber = 0; pageNumber < sizeof Buf / pageSize;
			pageNumber += 1) {
		page = (Page)&Buf[pageNumber * pageSize];
		if (pageSize != PageGetPageSize(page)) {
			fprintf(stderr, "DumpBlock: page %d: pageSize %d\n",
				pageNumber, PageGetPageSize(page));
		}
		DumpPage(page, blockNumber, pageNumber);
	}
}	

DumpPage(page, blockNumber, pageNumber)
	Page	page;
	int	blockNumber;
	int	pageNumber;
{
	ItemId		lp;
	HeapTuple	tup;
	int		flags, i, nline;
	PagePartition	partition;
	ItemPointerData	pointerData;
	int		hikeyfound;

	partition = CreatePagePartition(sizeof Buf, PageGetPageSize(page));

	printf("\t[subblock=%d]:lower=%d:upper=%d:special=%d\n", pageNumber,
		((PageHeader)page)->pd_lower, ((PageHeader)page)->pd_upper,
		((PageHeader)page)->pd_special);

	printf("\t:MaxOffsetIndex=%d:InternalFragmentation=%d\n",
		(int16)PageGetMaxOffsetIndex(page),
		PageGetInternalFragmentation(page));

	nline = 1 + (int16)PageGetMaxOffsetIndex(page);

	/* add printing of the specially allocated fields */
{
	int	i;
	char	*cp;

	i = PageGetSpecialSize(page);
	cp = PageGetSpecialPointer(page);

	printf("\t:SpecialData=");

	while (i > 0) {
		printf(" 0x%02x", *cp);
		cp += 1;
		i -= 1;
	}
	printf("\n");
}
	hikeyfound = 0;

	for (i = 0; i < nline; i++) {
		lp = ((PageHeader)page)->pd_linp + i;
		flags = (*lp).lp_flags;
		ItemPointerSet(&pointerData, partition, blockNumber, pageNumber,
			1 + i);
		printf("%s:off=%d:flags=0x%x:len=%d",
			ItemPointerFormExternal(&pointerData), (*lp).lp_off,
			flags, (*lp).lp_len);
		if (flags & LP_USED)
			printf(":USED");
		if (flags & LP_IVALID)
			printf(":IVALID");
		if (flags & LP_DOCNT) {
			ItemPointer	pointer;

			pointer = (ItemPointer)(uint16 *)
				((char *)page + (*lp).lp_off);
			
			printf(":DOCNT@%s", ItemPointerFormExternal(pointer));
		}
		if (flags & LP_CTUP)
			printf(":CTUP");
		if (flags & LP_LOCK)
			printf(":LOCK");

		/* XXX not really all indices, just btree indices */
		if (Type == 'i' && (flags & LP_USED) && !(flags & LP_CTUP)) {
			BTreeItemData	btitem;
			ItemPointer	iptr;

			bcopy((char *) &((char *)page)[(*lp).lp_off],
				(char *) &btitem, sizeof(btitem));

			iptr = &btitem.header.ituple.t_tid;

			printf(" :: ");
			if (btitem.header.flags & BTREE_ITEM_IS_LEAF)
				printf(":LEAF");
			else
				printf(":INTERNAL");
			if (btitem.header.flags & BTREE_ITEM_IS_HIGHKEY) {
				printf(":HIKEY");
				hikeyfound++;
			}

			printf(":[%d,%d,%d]:key %ld\n",
				ItemPointerGetBlockNumber(iptr),
				ItemPointerGetPageNumber(iptr),
				ItemPointerGetOffsetNumber(iptr),
				btitem.form.filler);
		} else if (Type == 'r' && (flags & LP_USED
			   && !(flags & LP_CTUP)
			   && !(flags & LP_LOCK))) {

			HeapTupleData	htdata;

			bcopy((char *) &((char *)page)[(*lp).lp_off],
				(char *) &htdata, sizeof(htdata));

			tup = &htdata;

			if (flags & LP_DOCNT) {
				bcopy((char *) &((char *)tup)[TCONTPAGELEN],
					(char *) &htdata, sizeof(tup));
			}

			printf("\n\t:ctid=%s:oid=%ld",
				ItemPointerFormExternal(&tup->t_ctid),
				tup->t_oid);
			printf(":natts=%d:thoff=%d:vtype=`%c' (0x%02x):",
				tup->t_natts,
				tup->t_hoff, tup->t_vtype, tup->t_vtype);

			printf("\n\t:tmin=%d:cmin=%u:",
				tup->t_tmin, tup->t_cmin);
			printf("xmin=0x%02x%02x%02x%02x%02x:",
				(unsigned char) tup->t_xmin[0],
				(unsigned char) tup->t_xmin[1],
				(unsigned char) tup->t_xmin[2],
				(unsigned char) tup->t_xmin[3],
				(unsigned char) tup->t_xmin[4]);

			printf("\n\t:tmax=%d:cmax=%u:",
				tup->t_tmax, tup->t_cmax);
			printf("xmax=0x%02x%02x%02x%02x%02x:",
				(unsigned char) tup->t_xmax[0],
				(unsigned char) tup->t_xmax[1],
				(unsigned char) tup->t_xmax[2],
				(unsigned char) tup->t_xmax[3],
				(unsigned char) tup->t_xmax[4]);

			printf("\n\t:chain=%s:anchor=%s:\n",
				ItemPointerFormExternal(&tup->t_chain),
				ItemPointerFormExternal(&tup->t_anchor));
		} else
			putchar('\n');
	}
	if (Type == 'i')
		printf("\tfound %d high key%s\n",
			hikeyfound, (hikeyfound == 1 ? "" : "s"));
}

String
ItemPointerFormExternal(pointer)
	ItemPointer	pointer;
{
	static char	itemPointerString[32];

	if (!ItemPointerIsValid(pointer)) {
		bcopy("<-,-,->", itemPointerString, sizeof "<-,-,->");
	} else {
		sprintf(itemPointerString, "<%lu,%u,%u>",
			ItemPointerGetBlockNumber(pointer),
			ItemPointerSimpleGetPageNumber(pointer),
			ItemPointerSimpleGetOffsetNumber(pointer));
	}

	return (itemPointerString);
}
