#ifdef	ournix
#include "ournix.h"
#endif
#ifndef LINT	/* { */
char sccsID[] ="@(#) testblock.c V2.15 Copyright Julian H. Stacey, Munich, 1990-03-09 to 2023-03-31.\n";
#endif		/* } */
/* A manual exists. */
#include	<sys/types.h>
#ifndef MSDOS	/* { unix */
#include	<sys/file.h>
#else		/* } { */
#define L_SET		0	/* absolute offset */
#endif		/* } */
#include	<sys/stat.h>
#include	<stdio.h>
#include <stdlib.h>
#if ( MSDOS || pc532 )	/* { */
#include	<fcntl.h>
#endif		/* } */
#ifdef	i386	/* { */
#include	<sys/fcntl.h>
#endif		/* } */
#include	<ctype.h>
#undef	HARDWARE_DEBUG
#ifdef	HARDWARE_DEBUG	/* { */
	/* Define HARDWARE_DEBUG only if you want to prove that
	   when a tape is damaged, and repaired, does have a leader
	   at the beginning of tape, but not at the end, and then
	   stalls, although the driver sends a stall message to
	   /dev/console, no signal is received by this program, and
	   neither this program, nor dd can rewind the tape, before
	   the tape is first removed & re-inserted.
	*/
#include	<signal.h>
#endif			/* } */
#ifdef	scs
#define BSD4_2
#endif
#include <string.h>	/* for strlen */
#include <stdlib.h>	/* for malloc & long	atoll() */

extern int	atoi() ;
#if MSDOS	/*{*/
extern char	*malloc() ;
#endif		/*}*/

typedef char	FLAG ;
char	**ARGV;
FLAG	fixed_f = 0 ;	/* 1 = all block bytes are to have a fixed value */
FLAG	pipe_f = 0 ;	/* 1 = tape data is to be connected to a process pipe */
FLAG	write_f = 0 ;	/* 1 = write tape (& possibly then read tape) */
FLAG	read_f = 0 ;	/* 1 = read tape (possibly after writing tape) */
FLAG	verbose_f = 0 ; /* 1 = provide verbose diagnostics */
FLAG	ignore_f = 0 ;	/* 1 = ignore single isolated errors */
FLAG	ignoreall_f = 0 ;	/* 1 = ignore all errors to get by bursts */
FLAG	no_rewind_f = 0 ; /* 1 = dont rewind before testing tape,
			   allows user to skip tape label by reading
			   a no_rewind_on_close device from a shell script,
			   before then calling testblock */
FLAG	no_rotate_f = 0 ; /* 1 = force byte number zero in every block to be
				zero; default is to let each succesive block
				have its byte #0 start with an incrementally
				higher value */
FLAG		announce_f = 0 ; /* 1 = announce test file name */
unsigned	count ;
unsigned	display_ln ;
unsigned	byte_data ;
unsigned	block_size = 1024 *
#ifdef	scs
		8	/* same size as tar B */
	/* Symmetric Unix device driver actually appears to write 8192 bytes
	   at a time to /dev/rcst2, regardless of the block size this user
	   program passes to the system */
#else
#if (( defined i386 ) || ( defined amd64))
		60	/* my QIC 525 egM SCSI streamer tape drive doesnt stream with 8K */
#else
		8
#endif
#endif
		;

#if ( __FreeBSD_cc_version > 460001 ) 	/*{*/
/* For __FreeBSD_cc_version:	cpp -dM /dev/null
 *	460001 on FreeBSD-4.11-RELEASE with gcc -v
 *		Using builtin specs.
 *		gcc version 2.95.4 20020320 [FreeBSD]
 *		does not have man atoll.
 * 	6.2-RELEASE does have man atoll.
 *    FreeBSD-7.1 #include <stdlib.h>:
 *     	long atol(const char *nptr);
 *     	long long atoll(const char *nptr);
 */
#define	longjlong unsigned long long
	/* long on FreeBSD is 4 bytes, long long is 8 */
#define atoljl	atoll
#else
#define	longjlong unsigned long
#define atoljl	atol
#endif          /*}*/

longjlong	user_limit = (longjlong)0 ; /* user specified limit on number of bytes */
longjlong	fail_limit = (longjlong)0 ; /* user specified threshold (in bytes),
				 * below which, we dont bother to do a read
				 * after write (because tape is too short)
				 * 0=unset, ie never inhibit read after write
				 */
longjlong	written_limit ;		/* reduced limit discovered on writing,
					that we pass to subsequent read */
unsigned char	*base_out_p ;	/* read pointer */
unsigned char	*base_in_p ;	/* read pointer */
char	default_tape[] =
#ifdef	unix	/* { */
	"/dev/rtape" ; /*use a symbolic link /dev/rtape --> /dev/rmt8 or rsa0*/
#endif		/* } */
#ifdef	MSDOS	/* { */
		"/dev/ct0" ;
#endif		/* } */
#ifndef pc532
	FILE *my_out ;
#else
	struct _iobuf *my_out ;
#endif
int	sleep_time = 0 ;

	void
my_exit(val)
	int	val ;
	{
	/* if (verbose_f) fprintf(my_out,"Finished.\n"); */
	exit(val) ;
	}

	void
syntax()
	{
	fprintf(stderr, "%s\n%s %s %s [-- or special_file[s]]\n",
		"Syntax error, correct syntax is:", *ARGV,
		"[-i] [-I] [-n] [-r] [-s seconds] [-v] [-w] [-u]",
		"[-b block_size] [-d data_byte] [-f fail_size] [-l byte_limit]"
		) ;
	my_exit(1) ;
	}

/* Convert longjlong to a comma separated digit string, of form
	 18,446,74x,xxx,xxx,xxx,xxx
 Bytes	Bits	Name	String				Scientific
 1	 8				       256
 2-	10	1 K			     1,024
 2	16	64 K			    65,536
 3-	20	1 M		         1,048,576
 3	24	16 M			16,777,216
 4-	30	1 G		     1,073,741,824
 4-	31	2 G		     2,147,483,648
 4	32	4 G		     4,294,967,296	4.294967e+09
 5	40	1 T		 1,099,511,xxx,xxx	1.099511e+12
 6	48	256 T	       281,474,9xx,xxx,xxx	2.814749e+14
 7	56	64 KT	    72,057,59x,xxx,xxx,xxx	7.205759e+16
 8	64	16 MT	18,446,74x,xxx,xxx,xxx,xxx	1.844674e+19
*/
#define L2COMMA (( 7 * 4 ) + 1)
	/* 7 * {3 digit chunk + comma}, less no terminal comma, plus null,
	plus negative sign.  Allows up to "-999,999,999,999,999,999,999" */

	void
l2comma(number,out)
	longjlong	number ;	/* Input */
	char		*out ;	/* Output, supplied by caller, >= L2COMMA */
	{
	char		tmp[L2COMMA ] ;
	char		*out_p, *tmp_p ;
	short		comma ;
	longjlong	num = number ;

	if (num == (longjlong)0) { out[0] = '0' ; out[1] = '\0' ; return ; }
	if (num < (longjlong)0)
		{ out[0] = '-' ; out[1] = '\0' ; num = (longjlong)0 - num ; }
	/* make a reverse digit string with commas */
	tmp_p = tmp ; comma = 0 ;
	do	{
		*tmp_p++ = '0' + (num % 10) ;
		num /= 10 ;
		if ((++comma == 3) && num ) { comma = 0 ; *tmp_p++ = ',' ; }
		}
		while ( num ) ;
	out_p = out ;
	while ( tmp_p > tmp ) *out_p++ = *--tmp_p ;
	*out_p = '\0' ;
	}

	void
show_size(size)
	longjlong	size ;
	{
	char		array[L2COMMA] ;
	unsigned	length ;

	// printf("DEBUG:%d X %l X\n", __LINE__, (long)size); (void)fflush(stdout) ;
	// if (size >= (longjlong)0)	// old bad code that when called
					// with "show_size((longjlong)-1)"
					// DEBUG above showed FFFFFFFFFFFFFFFF
	if (size != (longjlong)-1)
		{
		/* (void) sprintf(array,"%ld",size) ; */
		l2comma(size,array) ;
		printf("\r%s",array) ;
		display_ln = strlen(array) ;
		}
	else	{	/* negative */
		// printf("DEBUG:%d %d\n", __LINE__, (int)display_ln);
		for ( length = display_ln ; length-- ; putchar('\b') ) ;
		for ( length = display_ln ; length-- ; putchar(' ') ) ;
		for ( length = display_ln ; length-- ; putchar('\b') ) ;
		display_ln = 0 ;
		}
	(void)fflush(stdout) ;
	}

#ifdef	HARDWARE_DEBUG	/* { */
 my_sigint()	{ printf("%s caught signal sigint() \n",*ARGV)	; my_exit(1); }
#ifndef MSDOS	/* { */
 my_sighup()	{ printf("%s caught signal sighup() \n",*ARGV)	; my_exit(1); }
 my_sigquit()	{ printf("%s caught signal sigquit() \n",*ARGV) ; my_exit(1); }
 my_sigill()	{ printf("%s caught signal sigill() \n",*ARGV)	; my_exit(1); }
 my_sigiot()	{ printf("%s caught signal sigiot() \n",*ARGV)	; my_exit(1); }
 my_sigemt()	{ printf("%s caught signal sigemt() \n",*ARGV)	; my_exit(1); }
 my_sigfpe()	{ printf("%s caught signal sigfpe() \n",*ARGV)	; my_exit(1); }
 my_sigalrm()	{ printf("%s caught signal sigalrm() \n",*ARGV) ; my_exit(1); }
 my_sigbus()	{ printf("%s caught signal sigbus() \n",*ARGV)	; my_exit(1); }
 my_sigsegv()	{ printf("%s caught signal sigsegv() \n",*ARGV) ; my_exit(1); }
 my_sigterm()	{ printf("%s caught signal sigterm() \n",*ARGV) ; my_exit(1); }
#ifdef BSD4_2	/* { */
 my_sigtstp()	{ printf("%s caught signal sigtstp() \n",*ARGV) ; my_exit(1); }
#endif		/* } */
#endif		/* } */

sigs_assign(where_to)
	int	(*where_to)() ;
	{
	if (where_to == SIG_DFL)
		{
		(void)signal(SIGINT,where_to)	;
#ifndef MSDOS	/* { */
		(void)signal(SIGHUP,where_to)	;
		(void)signal(SIGQUIT,where_to)	;
		(void)signal(SIGILL,where_to)	;
		(void)signal(SIGIOT,where_to)	;
		(void)signal(SIGEMT,where_to)	;
		(void)signal(SIGFPE,where_to)	;
		(void)signal(SIGALRM,where_to)	;
		(void)signal(SIGBUS,where_to)	;
		(void)signal(SIGSEGV,where_to)	;
		(void)signal(SIGTERM,where_to)	;
#ifdef BSD4_2	/* { */
		(void)signal(SIGTSTP,where_to)	;
#endif		/* } */
#endif		/* } */
		}
	else
		{
		(void)signal(SIGINT,my_sigint)	; /* ^C, or DEL */
#ifndef MSDOS	/* { */
		(void)signal(SIGHUP,my_sighup)	;
		(void)signal(SIGQUIT,my_sigquit); /* ^\ = core dump */
		(void)signal(SIGILL,my_sigill)	;
		(void)signal(SIGIOT,my_sigiot)	;
		(void)signal(SIGEMT,my_sigemt)	;
		(void)signal(SIGFPE,my_sigfpe)	;
		(void)signal(SIGALRM,my_sigalrm);
		(void)signal(SIGBUS,my_sigbus)	;
		(void)signal(SIGSEGV,my_sigsegv);
		(void)signal(SIGTERM,my_sigterm);
#ifdef BSD4_2	/* { */
		(void)signal(SIGTSTP,my_sigtstp); /* Job suspend ^Z */
#endif		/* } */
#endif		/* } */
		}
	}

my_sigdummy()
	{
	printf("%s caught signal sigdummy() \n",*ARGV) ;
	}
#endif			/* } */

extern int read() ;
extern int write() ;
extern int close() ;
extern u_int sleep() ;

/* Open & close device to ensure if the physical device was previously
 * used as `a no rewind on completion' tape drive, that it will now be
 * rewound prior to use.
 * fd is not left open because although it would be slightly more effecient
 * on cpu, it would complicate the code too much, and anyway, compared
 * with the real physical device work we are doing, a couple more system
 * calls dont make much difference
 */
	int
my_rewind(name)
	char	*name ;
	{
	int	fd ;			/* file descrip */
	if (verbose_f)
		{
		fprintf(my_out, "Rewind started") ;
		if (announce_f) fprintf(my_out, " %s",name) ;
		fprintf(my_out, ", ") ;
		fflush(my_out) ;
		}
	if ((fd = open(name, O_RDONLY )) == EOF)
		{
		fprintf(my_out,
		"\nError: failed to open %s to ensure rewound.\n", name) ;
		perror(*ARGV) ;
		return(1) ;
		}
	/* now rewind tape */
	/* used to do an lseek, but maybe this doesnt retention tape,
	 *	so after a tape got mangled, repaired, mangled again,
	 *	i decided to do a real read followed by close, to ensure
	 *	tape is rewound, but I dont really know how the
	 *	TEAC drive is controlled, so this read may be
	 *	superfluous, however before taking it out, consider
	 *	the possibility of multiple system crashes whilst the
	 *	tape is inserted, and or multiple insertions before
	 *	the tape is actually used.
	 *	Only problem with a read is that if it is virgin media,
	 *	tape driver reports an error on /dev/console.
	 */
	if (
#if 0
		lseek(fd,(off_t)0,L_SET) != (off_t)0
#else
		read(fd,base_in_p,block_size) != block_size
#endif
		)
		{
		fprintf(my_out, "Error: failed to rewind %s.\n", name) ;
		fprintf(my_out,
	"(If when writing you get \"failed to open\", try using \"-n\".)\n"
			) ;
			/* if no correct sized data block previously on tape,
			   the rewind fails */
		perror(*ARGV) ;
		return(1) ;
		}
	(void) close(fd) ;
	if (verbose_f) fprintf(my_out, "finished.\n") ;
	return(0);
	}

/* Initialise reference block ? */
	void
init_ref(block_offset)
	unsigned block_offset ;
	{
	unsigned char	*var_out_p ;	/* write pointer */
	unsigned data, count ;
	count = block_size; var_out_p = base_out_p ;
	if (fixed_f) for ( ; count-- ; data++ ) *var_out_p++ = byte_data ;
	else if (no_rotate_f) for (data = 0 ; count-- ; data++ )
			*var_out_p++ = ( 0xFF & data) ;
	else for (data = block_offset ; count-- ; data++ )
			*var_out_p++ = ( 0xFF & data) ;
	}

	void
show_it(r_w,remainder,name,total)
	char	*r_w ;
	int	remainder;
	char	*name ;
	longjlong	total ;
	{
	char	buf[L2COMMA] ;

	fprintf(my_out, "\n" ) ;
	if (announce_f) fprintf(my_out, "%s: ", name ) ;
	fprintf(my_out, "%s %d",r_w, remainder ) ;
	if (remainder > 9L) /* print hex too */
		fprintf(my_out, " (0x%x)", (unsigned)remainder ) ;
	l2comma(total,buf) ;
	fprintf(my_out, " bytes, after previous %s", buf ) ;
	if (total > 9) /* print hex too */
		fprintf(my_out, 
#if ( __FreeBSD_cc_version > 460001 )   /*{*/
			// See above:	#define longjlong unsigned long long
			" (0x%llx)",
#else
			// See above:	#define longjlong unsigned long
			" (0x%lx)",
#endif          /*}*/
			 total);
	// fprintf(my_out, " bytes");
	if (total > block_size)
		/* show in blocks */
		fprintf(my_out, "\n\t(%ld blocks * %d bytes)",
			(long)(total/block_size), block_size );
	}

	/* return 0 = ok, 1 = error */
	int
do_tape(name)
	char	*name ;
	{
	int	fd ;			/* file descrip */
	longjlong cumulative ;		/* byte count, increments in block_size,
							eg 0,60K,120K */
	char	*message ;
	unsigned char	*var_in_p ;	/* read pointer */
	unsigned char	*var_out_p ;	/* write pointer */
	int	do_tape_tmp_int ;
	int	errs = 0 ;
	char	buf_a[L2COMMA] ;
	char	buf_b[L2COMMA] ;
	FLAG	count_fail ;	/* detect sequential byte count failures */
	FLAG	check_fail ;	/* detect sequential data check failures */
	FLAG	old_check_fail; /* detect sequential data check failures */
	unsigned block_offset ;

	if (write_f)
		{
		if (read_f) message = "Writing then reading" ;
		else message = "Writing (with no subsequent Reading)" ;
		}
	else message = "Reading (no prior writing)" ;
	if (verbose_f)
		{
		fprintf(my_out,"%s", message);
		if (announce_f) fprintf(my_out," %s", name);
		/* fprintf(my_out,".\n"); */
		fprintf(my_out,". ");
		}

	if (write_f)
		{
#ifdef	HARDWARE_DEBUG	/* { */
		sigs_assign(my_sigdummy) ;	/* mask signals */
#endif			/* } */
		if (!pipe_f && !no_rewind_f) (void) my_rewind(name);
		if (verbose_f && !pipe_f)
			fprintf(my_out, "Writing %s.\n", name) ;
		if (pipe_f) fd = fileno(stdout) ; else
		if ((fd = open(name,O_WRONLY | O_CREAT | O_TRUNC
#ifdef	MSDOS	/* { */
			| O_BINARY , S_IWRITE
#else		/* } { */
			,0640
#endif		/* } */
			)) == EOF )
			{
			perror(*ARGV) ;
			fprintf(my_out,
				"%s: Error: failed to open %s for writing.\n",
				*ARGV, name) ;
			return(1) ;
			}
		// printf("DEBUG:%d\n", __LINE__);
		cumulative = (longjlong)0 ;
		display_ln = 0 ;
		count_fail = 0 ;
		block_offset = 0 ;
		for (;;)
			{
			init_ref(block_offset++);
			if ( (do_tape_tmp_int = write(fd, (char *)base_out_p,
				(int)block_size ) ) == block_size )
				count_fail = 0 ;
			else	{
				if (verbose_f) show_size((longjlong)-1) ;
				show_it("Wrote",do_tape_tmp_int,name,
					cumulative);
				if ( (user_limit != (longjlong)0) ||
					(cumulative == (longjlong)0) )
					{
					l2comma(user_limit - cumulative
						,buf_a) ;
					fprintf(my_out,
						", %s unwritten.\n",buf_a);
					errs++ ;
					}
				else fprintf(my_out,".\n");
				/* note an error if write fails either
				 *	- before expected limit is reached, or
				 *	- if you over run threshold, for
				 *	  instance by using 7 byte blocks
				 *	  on a 50 byte limit.
				 */
				if ( count_fail++ || !ignore_f) break ;
				}
			if (!count_fail) cumulative += block_size ;
			if (verbose_f) show_size(cumulative) ;
			if ((user_limit != (longjlong)0) &&
				( cumulative >= user_limit ) )
				{
				if (verbose_f) show_size((longjlong)-1) ;
				break ;
				}
			}
		// printf("DEBUG:%d\n", __LINE__);
		written_limit = cumulative ;
		if (!pipe_f) (void) close(fd) ;
		/* Normal unix philosophy - no news is good news.
		 * Make no announcement of bytes succesfully written,
		 * only if we failed will an announcement appear.
		 */
#ifdef	HARDWARE_DEBUG	/* { */
		sigs_assign(SIG_DFL) ;
#endif			/* } */
		}
	if (read_f)
		{
		if ((fail_limit) && (written_limit < fail_limit))
			{
			fprintf(my_out,
		"Not bothering to read after write as tape too short.\n" );
			return(1) ;
			}
#ifdef	HARDWARE_DEBUG	/* { */
		sigs_assign(my_sigdummy) ;	/* mask signals */
#endif			/* } */
		if (write_f)
			{
			/* We were previously writing the tape,
			 * allow drive to start rewinding.
			 * (On SCS this avoids error message of data mismatch.)
			 * havent tested to see if sleep needed for 486pc.
			 * No point in calling my_rewind(), either the device
			 * will of its own accord, or if this program
			 * was passed a `no rewind on close` device name,
			 * then calling my_rewind() wont help anyway.
			 */
#ifndef MSDOS	/* { */
			sleep(sleep_time) ;
#else		/* } { */
			my_sleep(sleep_time) ;
			/* sleep() is not available on msdos,
				I've not written sleep for msdos. */
#endif		/* } */
			}
		else	{
			/* rewind if not a pipe, & if user has not forbiden us,
			 * user may have forbidden us because he's stepped past
			 * a tape label written as a seperate file before data
			 * created by this program
			 */
			if (!pipe_f && !no_rewind_f) (void) my_rewind(name);
			}

		if (!write_f) written_limit = user_limit ;
		cumulative = (longjlong)0 ;
		if (verbose_f && !pipe_f)
			fprintf(my_out, "Reading %s.\n", name) ;
		if (pipe_f) fd = fileno(stdin) ; else
		if ((fd = open(name,O_RDONLY
#ifdef	MSDOS	/* { */
			| O_BINARY , S_IREAD
#else		/* } { */
			,0640
#endif		/* } */
			)) == EOF )
			{
			perror(*ARGV) ;
			my_exit(1) ;
			}
		check_fail = old_check_fail = count_fail = display_ln = 0 ;
		block_offset = 0 ;
		for (;;)
			{
			init_ref(block_offset++);
			if ( (do_tape_tmp_int = read(fd, (char *)base_in_p,
				(int)block_size ) ) == block_size )
				count_fail = 0 ;
			else	{
				show_size((longjlong)-1) ;
				show_it("Read",do_tape_tmp_int,name,
					cumulative);
				fprintf(my_out,".\n");
				errs++ ;
				if (count_fail++ || !ignore_f) break ;
				}
			/* if (verbose_f) fprintf(my_out,"%s: read %d.\n",
				*ARGV,do_tape_tmp_int) ; */
			/* check each byte read is what it should be*/
			if ( !count_fail )
				{
				old_check_fail = check_fail ;
				check_fail = 0 ;
				for (count = 0, var_in_p = base_in_p,
					var_out_p = base_out_p ;
					count < block_size ; count++ )
					{
					if (*var_in_p++ != ((fixed_f) ?
						byte_data : *var_out_p++) )
						{
						if (verbose_f)
						  show_size((longjlong)-1) ;
						check_fail++;
						break ;
						}
					}
				}
			if (check_fail)
				{
				l2comma(cumulative,buf_a) ;
				fprintf(my_out,"\n");
				if (announce_f) fprintf(my_out,
					"%s: ", name ) ;
				fprintf(my_out, "Error at byte %u ",
					count ) ;
				if (count > 9)
					fprintf(my_out, "(0x%x), ", count ) ;
				fprintf(my_out, "after %s ", buf_a);
				if (cumulative > 9)
				  fprintf(my_out,
#if ( __FreeBSD_cc_version > 460001 )   /*{*/
			// See above:	#define longjlong unsigned long long
					 "(0x%llx)",
#else
			// See above:	#define longjlong unsigned long
					 "(0x%lx)",
#endif          /*}*/
					 cumulative ) ;
				fprintf(my_out, " previous,\n");
				fprintf(my_out,
					"Byte read: 0x%x, Expected: 0x%x.\n",
					*--var_in_p, ((fixed_f) ?
					byte_data : *--var_out_p) ) ;
				errs++ ;
				if (!ignore_f) break ;
				else if (old_check_fail &&
					 !ignoreall_f) break ;
				}
			if (!count_fail) cumulative += block_size ;
			if (verbose_f) show_size(cumulative) ;
			if ((user_limit != (longjlong)0) &&
				( cumulative >= written_limit ) )
				{
				// printf("DEBUG:%d\n", __LINE__);
				if (verbose_f) show_size((longjlong)-1) ;
				// printf("DEBUG:%d\n", __LINE__);
				break ;
				}
			}
		if (verbose_f) printf("\n");
		// printf("DEBUG:%d\n", __LINE__);
		if (!pipe_f) (void) close(fd) ;
		if ((user_limit != (longjlong)0) &&
			(written_limit != cumulative))
			{
			// printf("DEBUG:%d\n", __LINE__);
			l2comma( cumulative ,buf_a) ;
			l2comma( written_limit - cumulative ,buf_b) ;
			fprintf(my_out,
				"%s: only checked %s bytes, %s failed.\n",
					name, buf_a, buf_b ) ;
			errs++;
			}
#ifdef	HARDWARE_DEBUG	/* { */
		sigs_assign(SIG_DFL) ;
#endif			/* } */
		}
	return(errs?1:0) ;
	}

	int
main(argc,argv)
	int	argc ;
	char	**argv ;
	{
	int	errs = 0 ;	/* cumulative error count */
	int	main_tmp_int ;
	char	*p_tmp ;

	ARGV = argv ;
#ifdef	VSL	/* { */
#include	"../../include/vsl.h"
#endif		/* } */
	my_out = stdout ;
	while (--argc)
		{
		if (**++argv == '-')
			{
			switch ( *++*argv )
				{
				case 'i' :	ignore_f = 1 ;	break ;
				case 'I' :	ignore_f = ignoreall_f = 1 ;
						break ;
				case 'n' :	no_rewind_f = 1 ;	break ;
				case 'r' :	read_f = 1 ;	break ;
				case 'v' :	verbose_f = 1 ;	break ;
				case 'w' :	write_f = 1 ;	break ;
				case '-':	pipe_f = 1 ;	break ;
				case '0':	no_rotate_f = 1 ; break ;
				case 'b' :	if (--argc <= 0) syntax() ;
						++argv ;
						if (!(isdigit(**argv)))
							syntax() ;
						p_tmp = *argv+strlen(*argv) -1 ;
						main_tmp_int = 1 ;
						if ((*p_tmp == 'g') ||
							(*p_tmp == 'G') )
							{
							main_tmp_int = 1024
								* 1024 * 1024 ;
							*p_tmp = '\0' ;
							/* ridiculous really */
							}
						else if ((*p_tmp == 'm') ||
							(*p_tmp == 'M') )
							{
							main_tmp_int = 1024
								* 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'k') ||
							(*p_tmp == 'K') )
							{
							main_tmp_int = 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'b') ||
							(*p_tmp == 'B') )
							{
							main_tmp_int = 512 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'w') ||
							(*p_tmp == 'W') )
							{
							main_tmp_int = 2 ;
							*p_tmp = '\0' ;
							}
						main_tmp_int = main_tmp_int *
							 atoi(*argv);
						if (main_tmp_int < 0 ) syntax();
						block_size = main_tmp_int ;
						// printf(
						//  "DEBUG: block_size=%u\n",
						//   block_size);
						break ;
				case 's' :	
						if (--argc <= 0) syntax() ;
						sleep_time = atoi(*++argv) ;
						break ;
				case 'd' :	/* numeric value for all bytes*/
						fixed_f = 1 ;
						if (--argc <= 0) syntax() ;
						if ((1 != sscanf(*++argv,"%x",
							&main_tmp_int))
							|| (main_tmp_int < 0)
							|| (main_tmp_int > 0xFF)
							) syntax() ;
						/* if ((main_tmp_int =
							atoi(*++argv))
							< 0 ) syntax ;
							*/
						byte_data = main_tmp_int ;
						break ;
				case 'f' :	if (--argc <= 0) syntax() ;
						++argv ;
						if (!(isdigit(**argv)))
							syntax() ;
						p_tmp = *argv+strlen(*argv) -1 ;
						fail_limit = 1 ;
						if ((*p_tmp == 'g') ||
							(*p_tmp == 'G') )
							{
							fail_limit = 1024 *
								1024 * 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'm') ||
							(*p_tmp == 'M') )
							{
							fail_limit = 1024 *
								1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'k') ||
							(*p_tmp == 'K') )
							{
							fail_limit = 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'b') ||
							(*p_tmp == 'B') )
							{
							fail_limit = 512 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'w') ||
							(*p_tmp == 'W') )
							{
							fail_limit = 2 ;
							*p_tmp = '\0' ;
							}
						fail_limit = fail_limit *
							atoljl(*argv);
						if (fail_limit < 0 ) syntax() ;
						break ;
				case 'l' :	if (--argc <= 0) syntax() ;
						++argv ;
						if (!(isdigit(**argv)))
							syntax() ;
						p_tmp = *argv+strlen(*argv) -1 ;
						user_limit = 1 ;
						if ((*p_tmp == 'g') ||
							(*p_tmp == 'G') )
							{
							user_limit = 1024
								* 1024 * 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'm') ||
							(*p_tmp == 'M') )
							{
							user_limit = 1024
								* 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'k') ||
							(*p_tmp == 'K') )
							{
							user_limit = 1024 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'b') ||
							(*p_tmp == 'B') )
							{
							user_limit = 512 ;
							*p_tmp = '\0' ;
							}
						else if ((*p_tmp == 'w') ||
							(*p_tmp == 'W') )
							{
							user_limit = 2 ;
							*p_tmp = '\0' ;
							}
						user_limit = user_limit *
							atoljl(*argv);
						if (user_limit < 0 ) syntax() ;
						/* old code
						if ((user_limit = atol(*++argv))
							< (longjlong)0 ) syntax ;
						*/
						break ;
				default:	syntax() ;
						break ;
				}
			}
		else break ;
		}

	if (!read_f && !write_f )
		{ /* Neither -w or -r specified */
		fprintf(my_out, "Will write then read.\n" );
		read_f = write_f = 1 ;
		}
	if (verbose_f)
		{
		fprintf(my_out,"Block size %d (0x%x)",
			block_size,block_size);
		if (user_limit > (longjlong)0)
			fprintf(my_out,", to a limit of %llu.\n", user_limit);
		else fprintf(my_out,".\n");
		if (fail_limit > (longjlong)0)
			fprintf(my_out,
#if ( __FreeBSD_cc_version > 460001 )   /*{*/
			// See above:	#define longjlong unsigned long long
				"Short tape failure limit %lld.\n",
#else
			// See above:	#define longjlong unsigned long
				"Short tape failure limit %ld.\n",
#endif          /*}*/
				fail_limit);
		}
	if ((argc == 0) && !pipe_f)
		/* user has not specified file names or pipe IO, we will use
			default name, but in case user actually wanted pipe
			IO, we warn him */
		fprintf(my_out, "%s %s,\nso using %s.\n",
			"Neither file name",
			" nor pipe IO specified",
			default_tape) ;
	if (pipe_f && read_f && write_f)
		{
		fprintf(stderr, "%s: Cannot read and write pipes.\n",*ARGV) ;
		/* no point, as would first be writing output pipe,
			then reading input pipe - which would be rather
			weird, and not in the tradition of unix pipes
		*/
			syntax() ;
		}
	if ((argc >= 1) && pipe_f)
		{
		fprintf(stderr,
		"%s: Pipes output and file output not allowed together.\n",
			*ARGV) ;
		syntax() ;
		}
	if (pipe_f && write_f)
		{
		/* Avoid errors going into pipe */
		fprintf(stderr,
	"Status info will go to <stderr>, avoiding data on <stdout> pipeline.\n"
			);
		my_out = stderr ;
		}
	if (no_rewind_f && read_f && write_f)
		fprintf(my_out,
		"Caution: Unusual combination of options -n, -w, & -r.\n") ;

	/* End of checking parameters */
	if (((base_in_p = (unsigned char *)malloc(block_size)) ==
		(unsigned char *)0) ||
		((base_out_p = (unsigned char *)malloc(block_size)) ==
		(unsigned char *)0) )
		{
		fprintf(stderr,"%s: malloc(%u) failed.\n",*ARGV,block_size) ;
		perror(*ARGV) ;
		my_exit(1) ;
		}
	if (pipe_f) my_exit(do_tape("pipe")) ;
	else if ((argc == 0) && !pipe_f) my_exit(do_tape(default_tape)) ;
	else	{
		if (argc > 1 ) announce_f = 1 ;
		while (argc--) errs += do_tape(*argv++) ;
		}
	my_exit(errs) ;
	/* NEVER REACHED, to satisfy gcc -Wall */ return(errs) ;
	}
