/*
 * fposval - Determine information about the file position type
 *
 *
 * usage:
 *	fposval tmpfile
 *
 *	tmpfile is a writbale temporary file
 *
 * The include file have_pos.h, as built during the make process will
 * define the type FILEPOS as the type used to describe file positions.
 * We will print information regarding the size and byte order
 * of this definition.
 *
 * The stat system call returns a stat structure.  One of the elements
 * of the stat structure is the st_size element.  We will print information
 * regarding the size and byte order of st_size.
 *
 * We will first print the #define of 2 symbols:
 *
 *	FILEPOS_BITS 		length in bits of the type FILEPOS
 *	STSIZE_BITS		length in bits of the st_size stat element
 *
 * On some systems, file offsets and seek offsets are complex structures
 * instead of simple numeric types.  Worse, the byte order of the offset
 * may not match native mode!  We truncate and then seek to and write
 * byte 0x10002 in tmpfile.  Next we will determine the current stream
 * offset (via fgetpos or ftell) and the file offset (via fstat).
 * Finally we will print the #define of 2 symbols:
 *
 *	FILEPOS_ffvalue		byte layout of FILEPOS
 *	STSIZE_ffvalue		byte layout of st_size
 *
 * where ffvalue is the hex value of each byte.  The actual symbol defined
 * depends on the byte order relative to the native byte order as well as
 * the size.
 *
 * Some common examples of FILEPOS_ffvalue are:
 *
 *	FILEPOS_00010002		32 bit filepos in native byte order
 *	FILEPOS_02000100		32 bit filepos in opposite byte order
 *	FILEPOS_0000000000010002	64 bit filepos in native byte order
 *	FILEPOS_0200010000000000	64 bit filepos in opposite byte order
 *	FILEPOS_0001000200000000	swapped 64 bit filepos in native order
 *	FILEPOS_0000000000020001	swapped 64 bit filepos in opposite order
 */
/*
 * Copyright (c) 1994 by Landon Curt Noll.  All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright, this permission notice and text
 * this comment, and the disclaimer below appear in all of the following:
 *
 *	supporting documentation
 *	source copies
 *	source works derived from this source
 *	binaries derived from this source or from derived source
 *
 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
 * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * chongo was here	/\../\
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "have_fpos.h"
#include "endian_calc.h"

void bytedump();		/* dump value in big endian order */

char *program;			/* our name */

main(argc, argv)
	int argc;		/* arg count */
	char *argv[];		/* the args */
{
	FILEPOS	pos;		/* file position */
	int fileposlen;		/* byte length of FILEPOS */
	struct stat buf;	/* file status */
	int stsizelen;		/* byte length of st_size in buf */
	char *tmp_name;		/* tmp filename */
	FILE *tmp;		/* tmp open file stream */

	/*
	 * parse args
	 */
	program = argv[0];
	if (argc != 2) {
		fprintf(stderr, "usage: %s tmpfile\n", program);
		exit(1);
	}
	tmp_name = argv[1];

	/*
	 * open the temp file for truncation
	 */
	tmp = fopen(tmp_name, "w");
	if (tmp == NULL) {
		fprintf(stderr, "%s: cannot open: %s\n", program, tmp_name);
		perror(program);
		exit(2);
	}

	/*
	 * print sizes
	 */
	fileposlen = sizeof(FILEPOS);
	printf("#undef FILEPOS_BITS\n");
	printf("#define FILEPOS_BITS %d\n", fileposlen*8);
	stsizelen = sizeof(buf.st_size);
	printf("#undef STSIZE_BITS\n");
	printf("#define STSIZE_BITS %d\n\n", stsizelen*8);

	/*
	 * write the 2^16+1-th byte (location 2^16+2)
	 */
	if (fseek(tmp, (long)0x10001, 0) < 0) {
		fprintf(stderr, "%s: cannot seek: %s\n", program, tmp_name);
		perror(program);
		exit(3);
	}
	if (fputc('!', tmp) < 0) {
		fprintf(stderr, "%s: cannot write: %s\n", program, tmp_name);
		perror(program);
		exit(4);
	}
	if (fflush(tmp) < 0) {
		fprintf(stderr, "%s: cannot flush: %s\n", program, tmp_name);
		perror(program);
		exit(5);
	}

	/*
	 * determine byte order for FILEPOS
	 */
#if defined(HAVE_FPOS)
	/* get the position */
	if (fgetpos(tmp, (fpos_t *)&pos) < 0) {
		fprintf(stderr, "%s: cannot get file position of: %s\n",
		  program, tmp_name);
		perror(program);
		exit(6);
	}
#else /* HAVE_FPOS */
	pos = ftell(tmp);
	if (pos < 0) {
		fprintf(stderr, "%s: cannot find file position of: %s\n",
		  program, tmp_name);
		perror(program);
		exit(7);
	}
#endif /* HAVE_FPOS */
	printf("#undef FILEPOS_");
	bytedump((char *)&pos, fileposlen);
	putchar('\n');
	printf("#define FILEPOS_");
	bytedump((char *)&pos, fileposlen);
	printf(" 1\n");

	/*
	 * determine the byte order for st_size
	 */
	if (fstat(fileno(tmp), &buf) < 0) {
		fprintf(stderr, "%s: cannot stat: %s\n", program, tmp_name);
		perror(program);
		exit(8);
	}
	printf("#undef STSIZE_");
	bytedump((char *)&(buf.st_size), fileposlen);
	putchar('\n');
	printf("#define STSIZE_");
	bytedump((char *)&(buf.st_size), fileposlen);
	printf(" 1\n");
	exit(0);
}

/*
 * bytedump - wriyte the byte dump of an object in big endian order
 *
 * given:
 *	loc	location of object to dump
 *	len	length of object to dump
 *
 * Print the value each byte in hex in big endian order.  No return
 * is printed after the value.
 */
void
bytedump(loc, len)
	char *loc;	/* object to dump */
	int len;	/* length of object */
{
	char *p;
	int i;

#if BYTE_ORDER == BIG_ENDIAN
	/* big endian order */
	for (p = loc, i=0; i < len; ++i, ++p) {
		printf("%1x%1x", ((int)((*p)>>4))&0xf, ((int)(*p))&0xf);
	}
#else
	/* big endian order */
	for (p = loc+len-1, i=0; i < len; ++i, --p) {
		printf("%1x%1x", ((int)((*p)>>4))&0xf, ((int)(*p))&0xf);
	}
#endif
	return;
}
