/* @(#)testtape.c	19.1 (ES0-DMD) 02/25/03 14:33:06 */
/*===========================================================================
  Copyright (C) 1995 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <osparms.h>
#include <osudef.h>

char *osmsg();

int opentape(), closetape(), rewtape(), rstatape(), skiptape(), skbctape();
int wfmtape(), readtape(), writetape(), skipeom(), quit(), nothing();
int forwblk(), backblk(), infodev();
int returnhere();


	/* Definition of Functions */

#define ioinfo(f,b,fn,bn)	(ops[U_INFO])(f,b,fn,bn)
#define ioopen(f,m,d)		(ops[U_OPEN])(f,m,d)
#define ioclose(f)		(ops[U_CLOSE])(f)
#define ioread(f,b,l)		(ops[U_READ])(f,b,l) 
#define iowrite(f,b,l)		(ops[U_WRITE])(f,b,l) 
#define iorew(f)		(ops[U_REWIND])(f) 
#define ioeom(f)		(ops[U_EOM])(f) 
#define ioweof(f)		(ops[U_WEOF])(f)
#define iofsf(f,n)		(ops[U_FMF])(f,n)	
#define iobsf(f,n)		(ops[U_FMB])(f,n)	
#define iofsr(f,n)		(ops[U_BMF])(f,n)	
#define iobsr(f,n)		(ops[U_BMB])(f,n)	
#define iosread(f,s,ss,b,l)	(ops[U_SREAD])(f,s,ss,b,l) 
#define ioswrite(f,s,ss,b,l)	(ops[U_SWRITE])(f,s,ss,b,l)	


	/* This structure, created for each device, allows to know
	 	the current position on any device
	 */
typedef int (*FCT_PTR)();		/* Pointer to function */
FCT_PTR ops[U_MAX+1];			/* Available Operations	*/
#define NULL_PTR(x)	(x *)0

#define READ_WRITE 2 	/* as in osparms.h */

static char name[80] = "ip1:/dev/nrst1"; 
static char class[20] = "remote"; 

static int fd=0xffff;
static int mode=0xffff;
static jmp_buf env;

struct msg_cmd {
	char *msg;
	int (*cmd)();
	} msg_cmd[] = {
	"\n0-	*****  MENU *****\n",	nothing,
	"1-	Open a tape device\n",	opentape,
	"2-	Close a tape device\n",	closetape,
	"3-	Rewind the tape\n",	rewtape,
	"4-	Skip forward tape marks\n",	skiptape,
	"5-	Skip backward tape marks\n",	skbctape,
	"6-	Write a tape mark\n",	wfmtape,
	"7-	Read a buffer\n",	readtape,
	"8-	Write a buffer\n",	writetape,
	"9-	Skip forward block\n",	forwblk,
	"10-	Skip backward block\n",	backblk,
	"11-	Retrieve device info\n",	infodev,
	"12-	Skip end of media\n",	skipeom,
	"13-	Exit\n",		quit,
	(char *)0,			nothing
	};

main()
{
	struct msg_cmd *m_c;
	int opt;
	char buff[80];
	setjmp(env);
	signal(SIGINT,returnhere);
	while(1) {
		m_c = msg_cmd;
		while(m_c->msg != (char *)0)
			printf(m_c++->msg);
		printf("\nOption: ");
		if ((opt=atoi(gets(buff))) >= (sizeof(msg_cmd)/sizeof(struct msg_cmd))) 
			printf("Bad option\n");
		else
			(*msg_cmd[opt].cmd)();
/*		printf("\nPress RETURN to continue"); */
/*		gets(buff); */
		}
}

opentape()
{
	char aname[80], aclass[20], input[80];
	char *pclass;
	int pfd;

	printf("\nOPEN TAPE\n");

	printf("Enter name of device (%s): ",name);
	gets(aname);

	if (strlen(aname) != 0)
		strcpy(name,aname);

	printf("Enter open mode (2:READ_WRITE): ");
	mode=atoi(gets(input));
	if (strlen(input) == 0)
		mode=READ_WRITE;

	printf("Enter class for this device (%s): ",class);
	gets(aclass);
	pclass=class;

	if (strlen(aclass) != 0)
		strcpy(class,aclass);

	if (getclass() < 0) {
		printf("Error finding class %s, %s\n",
			class, osmsg());
		return;
		}

	pfd = ioopen(name,mode,0);

	if (pfd == -1) {
		printf("Error opening %s, %s\n",
			name,osmsg());
		return;
		}

	fd=pfd;
	printf("OPEN %s succeded.\n",name);
}

closetape()
{
	printf("\nCLOSE TAPE\n");
	if (ioclose(fd) == -1) {
		printf("Error closing device, %s\n",osmsg());
		return;
		}
	printf("CLOSE succeded\n");
}

rewtape()
{
	printf("\nREWIND TAPE\n");
	if (iorew(fd) == -1) {
		printf("Error rewinding device, %s\n",
			osmsg());
		return;
		}
	printf("REWIND succeded.\n");
}

skiptape()
{
	char name[80];
	int ntm;
	int ret;
	printf("Enter number of tape marks to be skipped (1): ");

	gets(name);
	if ( strlen(name) == 0)
		ntm=1;
	else
		ntm = atoi(name);

	printf("\nSKIP FORWARD %d TAPE MARKS\n",ntm);
	if ((ret = iofsf(fd,ntm)) == -1) {
		printf("Error skipping %d tape marks, %s\n",
			ntm,osmsg());
		return;
		}
	printf("SKIP succeded\n");
}

skbctape()
{
	char name[80];
	int ntm;
	printf("Enter number of tape marks to be skipped (1): ");

	gets(name);
	if ( strlen(name) == 0)
		ntm=1;
	else
		ntm = atoi(name);

	printf("\nSKIP BACKWARD %d TAPE MARKS\n",ntm);
	if (iobsf(fd,ntm) == -1) {
		printf("Error skipping %d tape marks, %s\n",
			ntm,osmsg());
		return;
		}
	printf("SKIP succeded\n");
}

wfmtape()
{
	printf("\nWRITE A TAPE MARK\n");
	if (ioweof(fd) == -1) {
		printf("Error writing a tape mark, %s\n", osmsg());
		return;
		}
	printf("WRITE A TAPE MARK succeded.\n");
}

writetape()
{
	char *malloc();
	char *pbuf;
	char name[80];
	int n_bytes;
	char pattern;
	int i;

	printf("\nWRITE A BUFFER\n");
	printf("Enter number of bytes to be written (1024): ");
	n_bytes = atoi(gets(name));
	if ( strlen(name) == 0)
		n_bytes=1024;

	if ((pbuf = malloc(n_bytes)) == (char *)0 ) { 
		printf("Max. memory allocation: %d bytes\n",n_bytes);
		return;
		}

	printf("Buffer allocated\n");
	printf("Enter pattern for buffer ('A'): ");
	if (strlen(gets(name)) == 0)
		pattern='A';
	else
		pattern=name[0];

	printf("Pattern=%c\n",pattern);

	for (i=0; i<n_bytes; i++)
		pbuf[i]=pattern;

/*	for(i=0; i<n_bytes; i++) 
/*		printf("%c ",pbuf[i]);
/*	getchar();
*/
	if (iowrite(fd,pbuf,n_bytes) == -1) {
		printf("Error writing %d bytes, %s\n",
			n_bytes,osmsg());
		return;
		}
	printf("WRITE %d bytes succeded.\n",n_bytes);
	free(pbuf);
}

readtape()
{
	char *malloc();
	char *pbuf;
	char name[80];
	int n_bytes, length;
	char pattern;
	int i;

	printf("\nREAD A BUFFER\n");
	printf("Enter number of bytes to be read (1024): ");
	n_bytes = atoi(gets(name));
	if ( strlen(name) == 0)
		n_bytes=1024;

/*	if ((pbuf = malloc(8192)) == (char *)0 ) {  */
	if ((pbuf = malloc(n_bytes)) == (char *)0 ) {  
		printf("Max. memory allocation: %d bytes\n",n_bytes);
		return;
		}

	printf("Buffer allocated\n");

/*	for (i=0; i<n_bytes; i++)
/*		pbuf[i]='0';
/*	for(i=0; i<n_bytes; i++) 
/*		printf("%c ",pbuf[i]);
/*	getchar();
*/

	if ((length = ioread(fd,pbuf,n_bytes)) == -1) {
		printf("Error reading %d bytes, %s\n",
			n_bytes,osmsg());
		return;
		}

/*	for(i=0; i<length; i++) 
/*		printf("%c ",pbuf[i]);
*/

	printf("\nREAD %d bytes succeded.\n",length);
	if (length > 0) {
		printf("Pattern=%c\n",pbuf[0]);
		pattern=pbuf[0];
		for(i=0; i<length; i++) 
			if (pattern != pbuf[i])
				fprintf(stderr,"Byte %d (%c) differs of pattern(%c)\n",
					i,pbuf[i],pattern);
		}
	free(pbuf);
}

backblk()
{
	char name[80];
	int ntm;
	printf("Enter number of blocks to be skipped backward (1): ");

	gets(name);
	if ( strlen(name) == 0)
		ntm=1;
	else
		ntm = atoi(name);

	printf("\nSKIP BACKWARD %d BLOCKS\n",ntm);
	if (iobsr(fd,ntm) == -1) {
		printf("Error skipping backward %d blocks, %s\n",
			ntm,osmsg());
		return;
		}
	printf("SKIP succeded\n");
}

forwblk()
{
	char name[80];
	int ntm;
	printf("Enter number of blocks to be skipped forward (1): ");

	gets(name);
	if ( strlen(name) == 0)
		ntm=1;
	else
		ntm = atoi(name);

	printf("\nSKIP FORWARD %d BLOCKS\n",ntm);
	if (iofsr(fd,ntm) == -1) {
		printf("Error skipping forward %d blocks, %s\n",
			ntm,osmsg());
		return;
		}
	printf("SKIP succeded.\n");
}

infodev()
{
	struct osustat s;
	int filenum;
	long blkno;
	printf("\nRETRIEVE INFO FROM OPENED TAPE\n");
	if ( ioinfo(fd,&s, &filenum, &blkno) == -1) {
		printf("Error getting status from device, %s\n",
			osmsg());
		return;
		}
	printf("RETRIEVE INFO succeded\n");
	printf("s.usize= %d\n", s.usize);
	printf("s.blocksize= %d\n", s.blocksize);
	printf("s.density= %d\n", s.density);
	printf("s.isda= %d\n", s.isda);
	printf("s.istm= %d\n", s.istm);
	printf("filenum= %d\n", filenum);
	printf("blkno= %d\n", blkno);
}

skipeom()
{
	printf("\nSKIP TO END OF MEDIA\n");
	if (ioeom(fd) == -1) {
		printf("Error skipping to end of media, %s\n",
			osmsg());
		return;
		}
	printf("SKIP EOM succeded\n");
}

nothing()
{
}

returnhere()
{
	longjmp(env,0);
}

quit()
{
	ospexit(0);
}

struct iolist *findclass(aclass)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve the class name
.RETURNS Pointer to found class / NULL
.REMARKS 
----------------------------------------------------------------------*/
	char	*aclass;	/* IN: Class to look for */
{
	struct iolist *plist, *iodevr();
	struct iolist *(*def)();
	char	*p, *q;
	
	/* Follow the linked list of iolist's */

   for (def = iodevr; def; def = plist->next)
   {
	plist = (*def)();
	for(q=aclass, p=plist->klass; (*p == *q) && (*p); p++, q++) ;
	if ((*q == '\0') && (*p == '\0'))	break;
   }
   if (!def)	/* Class Not Found */
   	plist = NULL_PTR(struct iolist);
   
   return(plist);
}

int getclass()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve the class name, to retrieve operators.
.RETURNS 0 / -1 (class doesn't exist)
.REMARKS Functions added in FCB
----------------------------------------------------------------------*/
{
	struct 	iolist *plist;
	int	i;
	OPITEM	*pop;
	
   plist = findclass(class);
   if (!plist)	
   {
   	oserror = -1;
	oserrmsg = "Bad DEVCAP cl=";
   	return(-1);
   }
   
   /*
   ** We have just to insert the functions in the list
   */

   for (pop = plist->oplist, i = plist->nop; --i >= 0; pop++)
   	ops[pop->opid] = pop->opf;
   
   return(0);
}

/*=====================================================================
		Callable Routines
 *=====================================================================*/

char *osuname(f)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve name of current unit (when f = -1)
.RETURNS Name / NULL pointer if failed
----------------------------------------------------------------------*/
	int f;		/* IN: The unit number	*/
{ 
    if (f != -1)
	return((char *)0);	/* Bad unit number...	*/

    return(name);
}

int osumode(f)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve opening mode of current unit (when f = -1)
.RETURNS Mode / -1 when error
----------------------------------------------------------------------*/
	int f;		/* IN: The unit number	*/
{ 
    if (f != -1)
	return(-1);	/* Bad unit number...	*/

    return(mode);
}

int osugrep (class_name, item)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Get the item function in a class of devices
.RETURNS 0 / -1
----------------------------------------------------------------------*/
	char	*class_name;	/* IN: Class of Devices (NULL for any) */
	OPITEM	*item;		/* OUT: op_code + Function Pointer */
{ 
	struct iolist *plist, *iodevr();
	struct iolist *(*def)();
	int	i;
	OPITEM	*pop;
	
   			
   for (def = iodevr; def; def = plist->next)
   {
   	if (!class_name)	/* Class not specified: look to next one */
   		plist = (*def)();
   	else	plist = findclass(class_name);
   	if (!plist)	   	return(-1);

		/* Retrieve the item in list */
	
   	for (pop = plist->oplist, i = plist->nop; 
		(--i >= 0) && (pop->opid != item->opid);  pop++)  ;

	if (i >= 0)		/* I found the relevant item... */
	{ 	item->opf = pop->opf;
		return(0);
	}
   	if (class_name)		break;
	
   }
   return(-1);
}
