/*
 * HISTORY
 * {1}	19-Mar-91  Henk D. Davids <hdavids@mswe.dnet.ms.philips.nl>
 * 	History started. Added default input file name so you do not
 *	have to specify name or type if you want it to be *.
 * 	Changes indicated by "-hdd" in comment.
 * 
 *  2.  4/4/91  John E. Davis
 *      I added code to read the teminal size for unix systems-- at least it
 *      works on a sun4 (BSD ?).  In addition I have also recently added file
 *      deletion code for both unix and vms.
 */
#include "sysdep.h"


/* 
 *  
 *  
 *                          SHELL COMMANDS
 *  
 */
  
#ifdef VMS

/* these two from emacs source */  
void define_logical_name (char *varname, char *string)
{
    struct dsc$descriptor_s strdsc =
      {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
    struct dsc$descriptor_s envdsc =
      {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
    struct dsc$descriptor_s lnmdsc =
      {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};

    LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
}

void delete_logical_name (char *varname)
{
    struct dsc$descriptor_s envdsc =
      {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
    struct dsc$descriptor_s lnmdsc =
      {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
    
    LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
}


int do_emacs_command()
{
    unsigned long pid;
    char *pidstr;
    
    if((pidstr = getenv("EMACS_PID")) != NULL)
      {
	  (void) sscanf(pidstr,"%X",&pid);
	  if (lib$attach(&pid) == SS$_NORMAL) /* we attach to emacs */
            return(1);
          else
            return(0);
          /* 	    printf("Can't attach to pid %X\n",pid); */
      }
    else return(0);
}

unsigned long SHELL_PID = 0;  

/* returns 0 on success */
int do_shell_command()
{
    /* here we try to attach to the parent otherwise just spawn a new one */
    unsigned long parent_pid;
    unsigned long status = 0;
    char str[80];
    
    
    parent_pid = getppid();
    
    if (parent_pid && parent_pid != 0xffffffff)  
      /* we attach to parent */
      status = lib$attach(&parent_pid);

    else if (SHELL_PID && SHELL_PID != 0xffffffff)
      /* try to attach to previous shell */
      status = lib$attach (&SHELL_PID);
      
    if (status != SS$_NORMAL)		/* others fail so spawn a new shell */
      {
          status = 0;
	  fputs("Spawning Subprocess...",stdout);
          fflush(stdout);
	  lib$spawn(0,0,0,0,0,&SHELL_PID,&status);
          /* if we attach back, status may come back unchanged */
          if ((status != 0) && (status != SS$_NORMAL))
            {
                sprintf(str,"Unable to spawn subprocess. Error = %X", status);
                message(str,1);
                return(0);
            }
      }
    return(1);
}


#endif /* VMS */

/* 
 *                            FILE IO
 *  
 */

#ifdef VMS
int expand_file_name(char *file,char *expanded_file)
{
    unsigned long status;
    static int context = 0;
    static char inputname[255] = "";
    $DESCRIPTOR(file_desc,inputname);
    $DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;");
    static struct dsc$descriptor_s  result = 
	    {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL};

    if (strcmp(inputname, file))
      {
	  if (context)
	    {
		lib$find_file_end(&context);
	    }
	  context = 0;
	  strcpy(inputname, file);
	  file_desc.dsc$w_length = strlen(inputname);
      }
    
    if (RMS$_NORMAL == lib$find_file(&file_desc,&result,&context,
	           		     &default_dsc,0,0,&0))
      {
	  memcpy(expanded_file, result.dsc$a_pointer, result.dsc$w_length);
	  expanded_file[result.dsc$w_length] = '\0';
          return (1);
      }
    else
      {
          expanded_file[0] = '\0';       /* so file comes back as zero width */
          return(0);
      }
}
#endif /* VMS */

/* 
 *  
 *  
 *         Terminal IO
 *  
 */

#ifdef VMS
/*
 *      Exit Handler Control Block
 */
static struct argument_block
    {
    int forward_link;
    int (*exit_routine)();
    int arg_count;
    int *status_address;
    int exit_status;
    } exit_block
      = {
        0,
        NULL,
        1,
        &exit_block.exit_status,
        0
        };
#endif
void init_tty()
{
#ifdef VMS
    $DESCRIPTOR ( Term, "SYS$ERROR");
    if (sys$assign ( &Term, &TTY_CHANNEL_GLOBAL, 0, 0 )
        != SS$_NORMAL)
      {
          fprintf(stderr,"Unable to assign input channel\n");
          exit(0);
      }
    if (NULL == exit_block.exit_routine)
	{
	void reset_tty();

	exit_block.exit_routine = reset_tty;
	SYS$DCLEXH(&exit_block);
	}
#else    
#ifdef BSD
    struct sgttyb  newtty;
    struct tchars tc;
    struct ltchars lc;

    ioctl(TTY_DESCR, TIOCGLTC,&OLDTTY_LC);
    ioctl(TTY_DESCR, TIOCGETC,&OLDTTY_TC);
    ioctl(TTY_DESCR, TIOCGETP, &OLDTTY);
    newtty = OLDTTY;
    newtty.sg_flags |= CBREAK;
    newtty.sg_flags &= ~(ECHO | XTABS);
    newtty.sg_erase = 0;
    newtty.sg_kill = 0;
    tc.t_intrc = 0;
    tc.t_quitc = 0;
    tc.t_eofc = 0;
    tc.t_brkc = 0;
    lc.t_suspc = 0;
    lc.t_dsuspc = 0;
    ioctl(TTY_DESCR, TIOCSETP, &newtty);
    ioctl(TTY_DESCR, TIOCSLTC,&lc);
    ioctl(TTY_DESCR, TIOCSETC,&tc);
#else /* other unix */    
    struct termio newtty;
	  
    ioctl(TTY_DESCR, TCGETA, &OLDTTY);
    ioctl(TTY_DESCR, TCGETA, &newtty);
    newtty.c_iflag &= ~(ECHO);  
    newtty.c_iflag &= ~(INLCR);  
    newtty.c_iflag &= ~(ICRNL);  
    newtty.c_lflag = 00000000; 
    newtty.c_cc[VMIN] = 1; 
    newtty.c_cc[VTIME] = 0;
    newtty.c_cc[VEOF] = 1;          
    ioctl(TTY_DESCR, TCSETA, &newtty);

#endif  /* other unix */
#endif
    fputs("\033=", stdout);  /* Enable the Application Keypad */
}

sys_flush(int fd)
{
#ifdef BSD
    ioctl(fd, TIOCFLUSH, (char *) NULL);
#else
#ifndef VMS    
    ioctl(fd, TCFLSH, (char *) NULL);
#endif    
#endif    
}

void reset_tty()
{
    fputs("\033=", stdout);  /* Enable the Numeric Keypad */
#ifndef VMS
#ifdef BSD
	ioctl(TTY_DESCR, TIOCSETP, &OLDTTY);
	ioctl(TTY_DESCR, TIOCSLTC, &OLDTTY_LC);
	ioctl(TTY_DESCR, TIOCSETC, &OLDTTY_TC);
#else        
    	ioctl(TTY_DESCR, TCSETA, &OLDTTY);
#endif /* BSD */
#endif /* not vms*/
}

int INPUT_BUFFER_LEN = 0;
char INPUT_BUFFER[80];

char sys_getkey()
{
    char c;
    
#ifndef VMS
    if (read(TTY_DESCR, &c, 1) < 0)
      {
          fprintf(stderr,"getkey():  read failed.\n");
          reset_tty();
          exit(0);
      }
    
#else
    /* VMS */
    /* see Guide to Programming VAX/VMS */
    int status;
    static int trmmsk [2] = { 0, 0 };
    short iosb [4];
	
    status = sys$qiow ( 0, TTY_CHANNEL_GLOBAL,
                       IO$_READVBLK + IO$M_NOECHO | IO$_TTYREADALL,
                       iosb, 0, 0,
                       &c, 1, 0, trmmsk, 0, 0 );

#endif  /* VMS */
	
    return(c); 
}

char getkey()
{
    int i;
    char ch;
    if (!INPUT_BUFFER_LEN) return(sys_getkey());
    ch = INPUT_BUFFER[0];
    INPUT_BUFFER_LEN--;
    for (i = 0; i < INPUT_BUFFER_LEN; i++)
      {
          INPUT_BUFFER[i] = INPUT_BUFFER[i + 1];
      }
    return(ch);
}

void ungetkey(char ch)
{
    int i;
    for (i = 0; i < INPUT_BUFFER_LEN; i++)
      {
          INPUT_BUFFER[i+1] = INPUT_BUFFER[i];
      }
    INPUT_BUFFER[0] = ch;
    INPUT_BUFFER_LEN++;
}


/* 
 *  
 *      Misc Termial stuff  
 *  
 *  
 */


/*  This is to get the size of the terminal  */
void get_term_dimensions(int *cols, int *rows)
{
#ifdef VMS
    int status;
    iosb iostatus;
    $DESCRIPTOR(devnam, "SYS$ERROR");
    struct
	{
	short row_buflen;
	short row_itmcod;
	int *row_bufadr;
	short *row_retlen;
	short col_buflen;
	short col_itmcod;
	int *col_bufadr;
	short *col_retlen;
	int listend;
	} itmlst =
	{
	sizeof(*rows), DVI$_TT_PAGE, rows, 0,
	sizeof(*cols), DVI$_DEVBUFSIZ, cols, 0,
	0
	};
    
    /* Get current terminal characteristics */
    status = sys$getdviw(0,           /* Wait on event flag zero  */
                         0,           /* Channel to input terminal  */
                         &devnam,     /* device name */
			 &itmlst,	  /* Item descriptor List */
                         &iostatus,   /* Status after operation */
                         0, 0,        /* No AST service   */
                         0);          /* nullarg */
    if (status&1)
	status = iostatus.i_cond;
    /* Jump out if bad status */
    if ((status & 1) == 0)
      exit(status);
#else    /* this may need work on other unix-- works for sun4 */
    struct winsize wind_struct;
      
    ioctl(2,TIOCGWINSZ,&wind_struct);
    *cols = (int) wind_struct.ws_col;
    *rows = (int) wind_struct.ws_row;
    
#endif /* VMS */
}

/* returns 0 on failure, 1 on sucess */
int sys_delete_file(char *filename)
{
#ifdef VMS
    return (1 + delete(filename));   /* 0: sucess; -1 failure */
#else  /* unix not ready yet */
    return(1 + unlink(filename));
#endif
}


/* This routine converts unix type names to vms names */
#ifdef VMS
int locate(char ch, char *string)
{
    int i;
    char c;

    i = 0;
    while (c = string[i++], (c != ch) && (c != '\0'));
    if (c == ch) return(i); else return (0);
}

char *unix2vms(char *file)
{
    int i,device,j,first,last;
    static char vms_name[80];
    char ch;

    if (locate('[',file)) return(file); /* vms_name syntax */
    if (!locate('/',file)) return(file); /* vms_name syntax */

    /* search for the ':' which means a device is present */
    device = locate(':',file);

    i = 0;
    if (device)
      {
          while (ch = file[i], i < device) vms_name[i++] = ch;
      }
    j = i;
    
    /* go from the  end looking for a '/' and mark it */
    i = strlen(file) - 1;
    while(ch = file[i], ch != '/' && i-- >= 0);
    if (ch == '/')
      {
          file[i] = ']';
          last = 0;
      }
    else last = 1;

    i = j;
    vms_name[j++] = '[';
    vms_name[j++] = '.';
    first = 0;
    while(ch = file[i++], ch != '\0')
      {
          switch (ch)
            {
              case '.':
                if (last) vms_name[j++] = '.';
                if (last) break;
                ch = file[i++];
                if (ch == '.')
                  {
                      if (!first) j--;  /* overwrite the dot */
                      vms_name[j++] = '-';
                  }
                else if (ch == '/'); /*  './' combinations-- do nothing */
                else if (ch == ']')
                  {
                      last = 1;
                      if (vms_name[j-1] == '.') j--;
                      vms_name[j++] = ']';
                  }
                
                else vms_name[j++] = '.';
                break;
              case '/':
                if (first)
                  {
                      vms_name[j++] = '.';
                  }
                else
                  {
                      first = 1;
                      /* if '/' is first char or follows a colon do nothing */
                      if ((i!=1) && (file[i-2] != ':'))
                        {
                            vms_name[j++] = '.';
                        }
                      else j--; /* overwrite the '.' following '[' */
                  }
                break;
              case ']':
                last = 1;
                if (vms_name[j-1] == '.') j--;
                vms_name[j++] = ']';
                break;
              default:
                vms_name[j++] = ch;
            }
      }
    return (vms_name);
}

/*
main(int argc, char **argv)
{
    puts(unix2vms(argv[1]));
}
*/     

#endif /* VMS */

#include <time.h>

char *get_time()
{ 
    time_t clock;
    char *the_time;

    clock = time((long *) 0);
    the_time = ctime(&clock); /* returns the form Sun Sep 16 01:03:52 1985\n\0 */
    the_time[24] = '\0';
    return(the_time);
}

