/* sglib system level i/o functions
*/

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#if _CRAY || __X1
#include <fortran.h>
#endif

#ifdef _VMS
#include <ssdef.h>	
#include <descrip.h>
#include <string.h>
#include <jpidef.h>
#include <fcntl.h>	
#include "sgtermios.h"
#else
#include <strings.h>
#include <fcntl.h>
#include <sys/un.h>
#include <termios.h>
#endif

#include <sys/socket.h>

#if __VMS || __IBM || __RS6000 || __HP || __ABS
#define usr_trnlog_ usr_trnlog
#define usr_getdvi_ usr_getdvi
#define usr_putmsg_ usr_putmsg
#define usr_dclexh_ usr_dclexh
#define tkeep_disk_ tkeep_disk
#define tback_disk_ tback_disk
#define sg_buff_ sg_buff
#define tmark_disk_ tmark_disk
#define tsend_ tsend
#define tname_term_ tname_term
#define topen_term_ topen_term
#define tclos_term_ tclos_term
#define tsend_term_ tsend_term
#define topen_auxl_ topen_auxl
#define tinput_ tinput
#define iowait_ iowait
#define agtgbm_ agtgbm
#define agtmhs_ agtmhs 
#define agths_ agths
#define agtmvs_ agtmvs
#define agtpurg_ agtpurg
#define agtchs_ agtchs
#define agtcvs_ agtcvs
#define ag_info_ ag_info
#define sg_flag_ sg_flag
#define tsend_disk_ tsend_disk
#define topen_disk_ topen_disk
#define tclos_disk_ tclos_disk
#define tname_disk_ tname_disk
#define agtrap_ agtrap
#define tname_auxl_ tname_auxl
#endif


#include <errno.h>
#include "sgbuff.h"
#define MAXCHAR 128
#define FALSE 0
#define TRUE  1
#define rw__r__r_ 0744

char dskfil[MAXCHAR];
char ttyfil[MAXCHAR];
char mbxfil[MAXCHAR];
int dsk_nr, tmp_nr, tty_nr, inp_nr;

#if _CRAY
USR_TRNLOG(_fcd table_dsc, _fcd log_dsc, _fcd phys_dsc, int *ltran,
 int *igood)
{
  char* table = _fcdtocp(table_dsc);
  int   ltabl = _fcdlen(table_dsc);
  char* loglnam = _fcdtocp(log_dsc);
  int   llog =    _fcdlen(log_dsc);
  char* physnam = _fcdtocp(phys_dsc);
  int   lphys = _fcdlen(phys_dsc);
  usr_trnlog_(*table, loglnam, physnam, ltran,igood, ltabl, llog, lphys);
}
#elif _VMS
USR_TRNLOG(struct dsc$descriptor *table_dsc, struct dsc$descriptor *log_dsc,
 struct dsc$descriptor *phys_dsc, int *ltran, int *igood)
{
  char* table = table_dsc->dsc$a_pointer;
  int   ltabl = table_dsc->dsc$w_length;
  char* loglnam = log_dsc->dsc$a_pointer;
  int   llog =    log_dsc->dsc$w_length;
  char* physnam = phys_dsc->dsc$a_pointer;
  int   lphys =   phys_dsc->dsc$w_length;
  usr_trnlog_(*table, loglnam, physnam, ltran,igood, ltabl, llog, lphys);
}
#else 
USR_TRNLOG(char *table, char *loglnam, char *physnam, int *ltran,
 int *igood, int ltabl, int llog, int lphys)
{
  usr_trnlog_(*table, loglnam, physnam, ltran,igood, ltabl, llog, lphys);
}
#endif
usr_trnlog_(char *table, char *loglnam, char *physnam, int *ltran,
 int *igood, int ltabl, int llog, int lphys)
{

  char *variable, loc_nam[MAXCHAR], *getenv();
  /* convert to null delimited string */
  to_C_nam(loc_nam, loglnam, llog);
  /* lookup environmental variables */
  if((variable = getenv(loc_nam)) == NULL) {
    *igood = FALSE;
    to_FORT_nam(physnam, lphys, " ");
    *ltran = 0;
  } else {
    *igood = TRUE;
    if(strcmp(loc_nam,"TERMINAL_TYPE")==0)
      to_up_str(variable); /* SGLIB wants upper case terminal type */
    /* convert to FORTRAN character string */
    to_FORT_nam(physnam, lphys, variable);
    *ltran = strlen(variable);
  }
}

to_up_str(char *str)
{
  for( ; *str != '\0'; str++){
    if(islower(*str)) *str = toupper(*str);
  }
  return;
}

to_C_nam(char *c_str, char *f_str, int flen)
{
  /* convert from FORTRAN character variable to NULL delimited string */
  int i;
  for(i = 0; i < flen && f_str[i] != '\0'; i++) c_str[i] = f_str[i];
  for(i--; i > 0 && c_str[i] == ' '; i--);
  c_str[++i] = '\0';
  if(i == flen) return(FALSE);
  return(TRUE);
}

to_FORT_nam(char *f_str, int flen, char *c_str)
{
  /* convert from NULL delimited character string to FORTRAN character
     variable */
  int i,j;
  for(i = 0; c_str[i] != '\0' && i < flen; i++) f_str[i] = c_str[i];
  for(j = i; j < flen; j++) f_str[j] = ' ';
  if(i == flen) return(FALSE);
  return(TRUE);
}

#ifdef _CRAY
USR_GETDVI(_fcd dev_dsc, int *klass, int *igood)
{
  char* devnam = _fcdtocp(dev_dsc);
  int   ldevn  = _fcdlen(dev_dsc);
#elif _VMS
USR_GETDVI(struct dsc$descriptor *dev_dsc, int *klass, int *igood)
{
  char* devnam = dev_dsc->dsc$a_pointer;
  int   ldevn  = dev_dsc->dsc$w_length;
#else

USR_GETDVI(char *devnam, int *klass, int *igood, int ldevn)
{
  usr_getdvi_(devnam, klass, igood, ldevn);
}
usr_getdvi_(char *devnam, int *klass, int *igood, int ldevn)
{
#endif
  char loc_nam[MAXCHAR];
  to_C_nam(loc_nam, devnam, ldevn);
  if(strstr(loc_nam,"xtc_mbx_")) {
    *klass = 5;	/* xtc */
  } else {
  if(strchr(loc_nam,'.')) {
    *klass = 1;  /* disk file */
  } else {
    *klass = 2;  /* terminal */
  }}
  *igood = TRUE;  /* errno */
  return;
}

usr_putmsg_(int *igood)
{
  printf("Fatal error in SGLIB %i\n", igood);
  return;
}
USR_DCLEXH()
{
  usr_dclexh_();
}
usr_dclexh_()
{
  /* signal(SIGINT, &handler) */
}

TKEEP_DISK()
{
  tkeep_disk_();
}
tkeep_disk_()
{
int tsize, ntmp;
char *tcopy;
  if(tmp_nr==0) return;
  /* size of file = current position */
  tsize = lseek(tmp_nr, 0L, 1);
  /* rewind temp file */
  lseek(tmp_nr, 0L, 0);
  /* copy from temp file to disk file */
  tcopy = (char *) malloc(tsize);
  if(tcopy==0) {
    printf("Can't copy page to disk file\n");
  } else {
    ntmp = read(tmp_nr, tcopy, tsize);
    if(ntmp<0) printf("%s\n", strerror(errno));
    ntmp = write(dsk_nr, tcopy, tsize);
    if(ntmp<0) printf("%s\n", strerror(errno));
    free(tcopy);
  }
  /* rewind temp file */
  lseek(tmp_nr, 0L, 0);
}

TBACK_DISK()
{
  tback_disk_();
}
tback_disk_()
{
  if(tmp_nr==0) return;
  /* rewind temp file */
  lseek(tmp_nr, 0L, 0);
  sg_buff_.kdptr = 0;
}

TMARK_DISK()
{
  tmark_disk_();
}
tmark_disk_()
{
}

TSEND()
{
  tsend_();
}
tsend_()
{
  /* empty io buffer to output device(s) */
  if(sg_flag_.outdsk>0) tsend_disk_();
  if(sg_flag_.outtrm>0 || sg_flag_.outaux>0) tsend_term_();
  return;
}

#ifdef _CRAY
TNAME_TERM(_fcd tty_dsc)
{
  char* ttynam = _fcdtocp(tty_dsc);
  int   ltty   = _fcdlen(tty_dsc);
#elif _VMS
TNAME_TERM(struct dsc$descriptor *tty_dsc)
{
  char* ttynam = tty_dsc->dsc$a_pointer;
  int   ltty   = tty_dsc->dsc$w_length;
#else
TNAME_TERM(char *ttynam, int ltty)
{
  tname_term_(ttynam, ltty);
}
tname_term_(char *ttynam, int ltty)
{
#endif
  to_C_nam(ttyfil, ttynam, ltty);  /* ttyfil = ttynam */
  return;
}

TOPEN_TERM(int *allo)
{
  topen_term_(allo);
}
topen_term_(int *allo)
{
  if(strcmp(ttyfil,"stdout")==0) {
    tty_nr = 1;
  } else {
    tty_nr = open(ttyfil, O_WRONLY, 0);
    if(tty_nr<0) printf("%s: %s\n", strerror(errno),ttyfil);
  }
#ifndef __f90
  if (*allo) sg_buff_.tbufa = (char *) malloc(sg_buff_.maxtb);
#endif
  sg_flag_.outtrm = 1;
  return;
}

static int sd_mbx;	/* xtc output socket descriptor */
static int sd_gin;	/* xtc input socket descriptor */

TOPEN_AUXL(int *allo)
{
  topen_auxl_(allo);
}
topen_auxl_(int *allo)
{
  /* Fill in socket names.  Full path names for sockets are
  ** /tmp/xtc_mbx_#_username and /tmp/xtc_gin_#_username.  */

  /*
Note: 05/26/99 CAL - sa_data size is only 14 char
*/
#if _CRAY 
  struct sockaddr socket_mbx;
  struct sockaddr socket_gin;

  sprintf( socket_mbx.sa_data, "/tmp/%s\0", mbxfil);
  sprintf( socket_gin.sa_data, "/tmp/%s\0", mbxfil);
  strncpy( &socket_gin.sa_data[9], "gin", 3);

  socket_mbx.sa_family = AF_UNIX;
  socket_gin.sa_family = AF_UNIX;
  sd_mbx = socket(AF_UNIX, SOCK_STREAM, 0);

  if(sd_mbx<0) printf("%s\n", strerror(errno));
  sd_gin = socket(AF_UNIX, SOCK_STREAM, 0);
  if(sd_gin<0) printf("%s\n", strerror(errno));

#elif _VMS
  struct sockaddr socket_mbx;
  struct sockaddr socket_gin;

  sprintf( socket_mbx.sa_data, "/tmp/%s\0", mbxfil);
  sprintf( socket_gin.sa_data, "/tmp/%s\0", mbxfil);
  strncpy( &socket_gin.sa_data[9], "gin", 3);

  socket_mbx.sa_family = AF_UNSPEC;
  socket_gin.sa_family = AF_UNSPEC;
  sd_mbx = socket(AF_UNSPEC, SOCK_STREAM, 0);

  if(sd_mbx<0) printf("%s\n", strerror(errno));
  sd_gin = socket(AF_UNSPEC, SOCK_STREAM, 0);
  if(sd_gin<0) printf("%s\n", strerror(errno));

#else

  struct sockaddr_un socket_mbx;
  struct sockaddr_un socket_gin;

  sprintf( socket_mbx.sun_path, "/tmp/%s\0", mbxfil);
  sprintf( socket_gin.sun_path, "/tmp/%s\0", mbxfil);
  strncpy( &socket_gin.sun_path[9], "gin", 3);

  socket_mbx.sun_family = AF_UNIX;
  socket_gin.sun_family = AF_UNIX;
  sd_mbx = socket(AF_UNIX, SOCK_STREAM, 0);

  if(sd_mbx<0) printf("%s\n", strerror(errno));
  sd_gin = socket(AF_UNIX, SOCK_STREAM, 0);
  if(sd_gin<0) printf("%s\n", strerror(errno));

#endif

  if (connect(sd_mbx, &socket_mbx, sizeof(socket_mbx)) == -1)
    printf("%s\n", strerror(errno));
  if (connect(sd_gin, &socket_gin, sizeof(socket_gin)) == -1)
    printf("%s\n", strerror(errno));
#ifndef __f90
  if (*allo) sg_buff_.tbufa = (char *) malloc(sg_buff_.maxtb);
#endif
  sg_flag_.outaux = 1;
  return;
}


TSEND_TERM()
{
  tsend_term_();
}
tsend_term_()
{
  char ch;
  int np, n_written;
  /* empty io buffer to tty */
  if((np = sg_buff_.ktptr)==0) return;
  if(sg_flag_.outtrm==1) {
    if((n_written = write(tty_nr, &sg_buff_.tbufa[0], np)) != np) {
      printf("SGLIB WRITE ERROR: n_written = %d, np = %d\n",
  	   n_written, np);
      exit(1);
    }
  }
  if(sg_flag_.outaux==1) {
    if((n_written = send(sd_mbx, sg_buff_.tbufa, np, 0)) != np) {
      printf("SGLIB SEND ERROR: n_written = %d, np = %d\n",
  	   n_written, np);
      exit(1);
    }
  }
  sg_buff_.ktptr = 0;
  return;
}

tback_term()
{
  tback_term_();
}
TBACK_TERM()
{
  tback_term_();
}
tback_term_()
{
  /* clear the terminal buffer */
   return;
}

#ifdef _CRAY
TNAME_AUXL(_fcd mbx_dsc)
{
  char* mbxnam = _fcdtocp(mbx_dsc);
  int   lmbx   = _fcdlen(mbx_dsc);
#elif _VMS 
TNAME_AUXL(struct dsc$descriptor * mbx_dsc)
{
  char* mbxnam = mbx_dsc->dsc$a_pointer;
  int   lmbx   = mbx_dsc->dsc$w_length;
#else
TNAME_AUXL(char *mbxnam, int lmbx)
{
  tname_auxl_(mbxnam, lmbx);
}
tname_auxl_(char *mbxnam, int lmbx)
{
#endif
  to_C_nam(mbxfil, mbxnam, lmbx);  /* mbxfil = mbxnam */
  return;
}

#ifdef _CRAY
TNAME_DISK(_fcd dsk_dsc)
{
  char* dsknam = _fcdtocp(dsk_dsc);
  int   ldsk   = _fcdlen(dsk_dsc);
#elif _VMS
TNAME_DISK(struct dsc$descriptor *dsk_dsc)
{
  char* dsknam = dsk_dsc->dsc$a_pointer;
  int   ldsk   = dsk_dsc->dsc$w_length;
#else
TNAME_DISK(char *dsknam, int ldsk)
{
  tname_disk_(dsknam, ldsk);
}
tname_disk_(char *dsknam, int ldsk)
{
#endif
  to_C_nam(dskfil, dsknam, ldsk);  /* dskfil = dsknam */
  return;
}

TOPEN_DISK(int *allo)
{
  topen_disk_(allo);
}
topen_disk_(int *allo)
{
  FILE *tfile;
  dsk_nr = creat(dskfil, rw__r__r_);
  if(dsk_nr<0) printf("%s: %s\n", strerror(errno),dskfil);
  tmp_nr = 0;
  /* if output to file and tty, open temp file for each page */
  if(sg_flag_.outtrm != 0) {
    tfile = tmpfile();
    tmp_nr = fileno(tfile);
    if(tmp_nr<0) printf("%s\n", strerror(errno));
  }
#ifndef __f90
  if (*allo) sg_buff_.dbufa = (char *) malloc(sg_buff_.maxdb);
#endif
  sg_flag_.outdsk = 1;
  return;
}

TSEND_DISK()
{
  tsend_disk_();
}
tsend_disk_()
{
  int np, n_written;
  /* empty io buffer to disk */
  if((np = sg_buff_.kdptr)==0) return;
  if(tmp_nr>0) {
    n_written = write(tmp_nr, sg_buff_.dbufa, np);
  } else {
    n_written = write(dsk_nr, sg_buff_.dbufa, np);
  }
  /* lseek(dsk_nr, 0L, 2);    set to end of file */
  if(n_written != np) {
    printf("SGLIB WRITE ERROR: n_written = %d, np = %d\n",
	   n_written, np);
    exit(1);
  }
  sg_buff_.kdptr = 0;
  return;
}

TVIEW_DISK()
{
  tview_disk_();
}
tview_disk_()
{
  dsk_nr = open(dskfil, O_RDONLY, 0 );
  if(dsk_nr<0){
    printf("%s\n", strerror(errno));
    printf("tview_disk: Error opening %s dsk_nr= %d\n",dskfil,dsk_nr);
  }
  return;
}

#if _CRAY
TREAD_DISK(_fcd buf_dsc, int *mfbuf, int *inblk, int *ngot)
{
  char* fbuf = _fcdtocp(buf_dsc);
#elif _VMS
TREAD_DISK(struct dsc$descriptor *buf_dsc, int *mfbuf, int *inblk, int *ngot)
{
  char* fbuf = buf_dsc->dsc$a_pointer;
#else
TREAD_DISK(char *fbuf, int *mfbuf, int *inblk, int *ngot)
{
  tread_disk_(fbuf, mfbuf, inblk, ngot);
#endif
}
tread_disk_(char *fbuf, int *mfbuf, int *inblk, int *ngot)
{

  int pos,n_read;
  if (dsk_nr <=0) {
    printf("tread_disk: Invalid File Descriptor =  %d\n",dsk_nr);
    *ngot = 0;
    return;
  }
  pos = lseek(dsk_nr, 0L, 1);
  pos = lseek(dsk_nr, (*inblk-1)*512, 0);
  n_read = read(dsk_nr, fbuf, *mfbuf);
  if(n_read<0){
    printf("%s\n", strerror(errno));
    printf("tread_disk: n_read =  %d\n",n_read);
  }
  *ngot = n_read;
  return;
}

#if _CRAY || _VMS
void TCLOS_DISK()
#else
void tclos_disk_()
#endif
{
  char command_string[100];
  close(dsk_nr);
  dsk_nr = 0;
  if (sg_flag_.outps == 1) {
   sprintf( command_string, "tek2ps_sh %s \0",dskfil );
   system( command_string ); 
  }
  return;
}

#if _CRAY || _VMS
void TCLOS_TERM()
#else
void tclos_term_()
#endif
{
  /* close terminal file ? */
  return;
}

struct termios init, new;

#if _CRAY || _VMS
void TINPUT(int *inchh)
#else
void tinput_(int *inchh)
#endif
{
  char trmnam[64];
  /* char *bufi[6]; */
  char bufi[6];  /* CAL 6/9/98 should be ? */
  int lnam,igood;
  int nin;

  tsend_term_();
  if(sg_flag_.inflg==0) {
    usr_trnlog_(" ","TERMINAL_INPUT",trmnam,&lnam,&igood,
	1,14,64);	/* string lengths */
    trmnam[lnam]='\0';
    if(strcmp(trmnam,"NONE")==0) {
      sg_flag_.inflg = 3;	/* no input */
      goto tin200;
    }
    if(sd_gin>0) {
      sg_flag_.inflg = 2;	/* XTC */
      goto tin200;
      }
    inp_nr = open("/dev/tty", O_RDONLY, 0);
    if(inp_nr>0)
      sg_flag_.inflg = 1;	/* tty input */
    else
      sg_flag_.inflg = 3;	/* error */
  }
tin200:
  if(sg_flag_.inflg==1) {
    /*  fflush(NULL); */
    /* get a single character */
    /* ocne(); set terminal to one character, no echo mode */
#ifdef _VMS
/*
  ioctl(0, TCGETP, &init); 
  ioctl(0, TCGETP, &new); 
*/
  ioctl(0, TCGETS, &init); 
  ioctl(0, TCGETS, &new); 
#else
    tcgetattr(0, &init);
    tcgetattr(0, &new);
#endif
    new.c_lflag = new.c_lflag & ~(ECHO); /* turn off echo */
    new.c_lflag = new.c_lflag & ~(ICANON); /* turn off canonical */
    new.c_cc[VMIN] = 1;		/* one character input */
    new.c_cc[VTIME] = 0;	/* timer off */
#ifdef _VMS
  ioctl(0, TCSANOW, &new); 
#else
    tcsetattr(0, TCSANOW, &new);
#endif
    *inchh = (int) getchar();
    /* canon(); reset to canonical mode */
#ifdef _VMS
  ioctl(0, TCSANOW, &init); 
#else
    tcsetattr(0, TCSANOW, &init);
#endif
  } else if(sg_flag_.inflg==2) {
    /* read from sd_gin */
    /* nin = recv(sd_gin,inchh,1,0); */
    nin = recv(sd_gin,bufi,1,0);	/* bufi,6 */
    *inchh = (int) *bufi; 
    /* *inchh = (int) bufi[0];  CAL 06/09/98 shold be ? */
  }
  return;
}

#if _CRAY || _VMS
void IOWAIT()
#else
void iowait_()
#endif
{
}

#if _CRAY || _VMS
void AGTRAP()
#else
void agtrap_()
#endif
{
}

#if _CRAY || _VMS
void AGTGBM(char *msg, int *lmsg)
#else
void agtgbm_(char *msg, int *lmsg)
#endif
{
  *lmsg = 0;
}

#if _CRAY || _VMS
void AGTPURG()
#else
void agtpurg_()
#endif
{
}

#ifdef _VMS
#include jpidef
void AG_INFO(int *mode, int *ipid, struct dsc$descriptor *term_dsc,
                                   struct dsc$descriptor *user_dsc)
{
     char* myterm =  term_dsc->dsc$a_pointer;
     int   lterm  =  term_dsc->dsc$w_length;
     char* user   =  user_dsc->dsc$a_pointer;
     int   luser  =  user_dsc->dsc$w_length;

     struct itmlst {
	  short buflen;
          short itmcod;
	  int   bufadr;
          int   retadr;
	};

     static struct itmlst jpi_list[5];
     int    sts;

	jpi_list[0].itmcod = JPI$_MODE;
	jpi_list[0].buflen = 4;
	jpi_list[0].bufadr = mode;
	jpi_list[1].itmcod = JPI$_PID;
	jpi_list[1].buflen = 4;
	jpi_list[1].bufadr = ipid;
	jpi_list[2].itmcod = JPI$_TERMINAL;
	jpi_list[2].buflen = term_dsc->dsc$w_length;
	jpi_list[2].bufadr = term_dsc->dsc$a_pointer;
	jpi_list[2].retadr = &lterm;
	jpi_list[3].itmcod = JPI$_USERNAME;
	jpi_list[3].buflen = user_dsc->dsc$w_length;
	jpi_list[3].bufadr = user_dsc->dsc$a_pointer;
	jpi_list[3].retadr = &luser;
	jpi_list[4].itmcod = 0;

	sts = sys$getjpi(0,0,0,jpi_list,0,0,0);
	if (sts != SS$_NORMAL) {
	  mode=0;
	  ipid=0;
	  strcpy(myterm," ");
	  strcpy(user," ");
	}
   }
#else
#ifdef _CRAY
void AG_INFO(int *mode, int *ipid, _fcd term_dsc, _fcd user_dsc)
{
     char* myterm =  _fcdtocp(term_dsc);
     int   lterm  = _fcdlen(term_dsc);
     char* user   =  _fcdtocp(user_dsc);
     int   luser  = _fcdlen(user_dsc);
#else
void ag_info_(int *mode, int *ipid, char *myterm, char *user, int lterm,
  int luser)
{
#endif

/*
  mode = 0(other), 1(network), 2(batch), 3(interactive)
*/
  *mode = 3;	/* interactive */
  *ipid = 0;
  to_FORT_nam(myterm, lterm, "stdout");
  to_FORT_nam(user, luser, "USER");
}
#endif

lib_get_vm(int *nbytes, char **addr)
{
  return lib_get_vm_(nbytes, addr);
}
lib_get_vm_(int *nbytes, char **addr)
{
  *addr = (char *) malloc(*nbytes);
  return(TRUE);
}

lib_free_vm(int *nbytes, char **addr)
{
  return lib_free_vm_(nbytes, addr);
}
lib_free_vm_(int nbytes, char **addr)
{
  free(*addr);
}

#if _CRAY || _VMS
int NFLOAT_SIZE()
#else
int nfloat_size_()
#endif
{
  float x;
  return sizeof(x);
}






