/*
 *  Copyright (c) 1992, 1993 John E. Davis  (davis@amy.tch.harvard.edu)
 *  All Rights Reserved.
 */

/*  This file is the interface to system specific files */

#ifdef AIX
#define _ALL_SOURCE
#define POSIX
#endif

#ifdef POSIX
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#endif

#include <stdio.h>
#include <string.h>
#include "config.h"
#include "buffer.h"
#include "sysdep.h"
#include "display.h"
#include "screen.h"
#include "misc.h"
#include "mem.h"
#include "slang.h"

int Screen_Height = 24;
int Screen_Width = 80;

extern char *get_cwd(void);

#ifdef msdos
int Abort_Char = 34;		       /* scan code for G (control) */
#include <dir.h>
#include "ibmpc.c"
#endif

#ifdef VMS
int Abort_Char = 7;
#include "vms.c"
#endif

#ifdef __GO32__
#include "i386.c"
#else
#ifdef unix
int Abort_Char = 7;
int Flow_Control = 1;		       /* controls XON/XOFF */
#include "unix.c"
#endif
#endif

int INPUT_BUFFER_LEN = 0;
unsigned char INPUT_BUFFER[256];
unsigned char KeyBoard_Xlate[256] = 
{
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 
 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 
 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 
 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 
 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
 248, 249, 250, 251, 252, 253, 254, 255
};

void map_character(int *fromp, int *top)
{
   int from = *fromp, to = *top;
   if ((from > 255) || (to > 255) || (from < 0) || (to < 0)) return;
   KeyBoard_Xlate[from] = to;
}


/* if input char arrives with hi bit set, it is replaced by 2 characters:
   Meta_Char + char with hi bit off.  If Meta_Char is -1, then return 
   full 8 bits which self inserts */
      
/* By default, 8 bit chars self insert. */	 
int Meta_Char = -1;

int my_getkey()
{
   char buf[10];
   int i, imax;
   unsigned char ch;
   
   if (Batch)
     {
	fgets(buf, 9 ,stdin);
	return (int) *buf;
     }
   
   if (!INPUT_BUFFER_LEN)
     {
	/* if (Batch) ch = (unsigned char) getc(stdin); else ch = sys_getkey(); */
	ch = (unsigned char) KeyBoard_Xlate[sys_getkey()];
	if ((ch & 0x80) && (Meta_Char != -1))
	  {
	     i = ch & 0x7F;
	     ungetkey((int *) &i);
	     ch = Meta_Char;		       /* escape char */
	  }
	return((int) ch);
     }
   
   ch = INPUT_BUFFER[0];
   if ((ch & 0x80) && (Meta_Char != -1))
     {
	INPUT_BUFFER[0] = ch & 0x7F;
	return ((int) (unsigned int) Meta_Char);
     }

   INPUT_BUFFER_LEN--;
   imax = INPUT_BUFFER_LEN;
   for (i = 0; i < imax; i++)
     {
	INPUT_BUFFER[i] = INPUT_BUFFER[i + 1];
	imax = INPUT_BUFFER_LEN;
     }
   return((int) ch);
}

void ungetkey(int *ch)
{
   int i;
   if (INPUT_BUFFER_LEN > 253) return;
   for (i = INPUT_BUFFER_LEN; i > 0; i--)
     {
	INPUT_BUFFER[i] = INPUT_BUFFER[i - 1];
     }
   INPUT_BUFFER[0] = (unsigned char) *ch;
   INPUT_BUFFER_LEN++;
}

void flush_input()
{
   int quit = KeyBoard_Quit;
   INPUT_BUFFER_LEN = 0;
   KeyBoard_Quit = 0;
#ifdef msdos
   while (input_pending(&Number_Zero)) if (!my_getkey()) my_getkey();
#else
   while (input_pending(&Number_Zero)) my_getkey();
#endif
   KeyBoard_Quit = quit;
}

#include <time.h>

unsigned long sys_time(void)
{
   return((unsigned long) time((time_t *) 0));
}

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

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

#ifndef pc_system
#ifdef unix

/* use berkeley interface
#include <sys/dir.h>
*/

static char Unix_Dir[256];
static char Unix_File[256];
static int File_Len;

#ifdef sequent
# include <sys/dir.h>
# define NEED_D_NAMLEN
#else
# include <dirent.h>
#endif

static DIR *Dirp;

int sys_findnext(char *file)
{
#ifdef NEED_D_NAMLEN
#define dirent direct
#endif

   struct dirent *dp;

   while (1)
     {
	if (NULL == (dp = readdir(Dirp))) return(0);
#ifdef NEED_D_NAMLEN
	dp->d_name[dp->d_namlen] = 0;
#endif
	if (!strncmp(Unix_File, dp->d_name, File_Len)) break;
     }
   strcpy(file, Unix_Dir); strcat(file, dp->d_name);
   if (2 == file_status(file)) strcat(file, "/");
   return(1);
}

/* this routine returns a Static pointer which is considered volatile */
char *expand_filename(char *file)
{
   char *p, *p1, slash = '/', *home, ch = 0, *last;
   static char work[500];
   char workp[256];

    /* This converts ~/ to $HOME/ */
   int n;

   *work = 0;
   /* This bit removes any // combinations.  */
   p = file + strlen(file);
   while (p > file)
     {
	if ((*p == slash) && (*(p - 1) == slash))
	  {
	     file = p;
	     break;
	  }
	p--;
     }
   
   if (*file != slash) strcpy(work, get_cwd());  /* assume relative dir */
   strcat(work, file);
   file = work;

   p = file;
   while(*p) if (*p++ == '~') break;

   if (*p == '/')
     {
	/* at some point, I need to make this more generic for other users */
	if (NULL != (home = getenv("HOME")))
	  {
	     strcpy(workp, p);
	     strcpy(work, home);
	     n = strlen(home) - 1;
	     if (home[n] == '/') work[n] = 0;
	     strcat(work, workp);
	  }
     }

   /* remove ../ and ./ stuff */

   p = p1 = file;
   last = &ch;
   while(*p != 0)
     {
	if ((*p == '.') && (*(p + 1) == '.'))
	  {
	     p += 2;
	     if ((*p == slash) && (*last == slash))
	       {
		  while ((--last >= work) && (*last != slash));
		  p1 = last + 1;
	       }
	     else
	       {
		  *p1++ = '.'; *p1++ = '.'; *p1++ = *p;
	       }
	  }
	else if (*p == '.')
	  {
	     p++;
	     if ((*p == slash) && (*last == slash)); /* nil */
	     else
	       {
		  *p1++ = '.';  
		  *p1++ = *p;
	       }
	  }
	else if ((*p == slash) && (*(p + 1) == slash))
	  {
	     /* // is a signal that we go back to root */
	     p1 = file;
	     *p1++ = slash;
	     p++;
	  }
	else (*p1++ = *p);
	 
	last = p1 - 1;
	if (*p != 0) p++;
     }
   *p1 = 0;
   return(work);
}

int sys_findfirst(char *the_file)
{
   char *f, *file;

   file = expand_filename(the_file);
   f = extract_file(file);

   strcpy (Unix_Dir, file);
   strcpy (Unix_File, f);
   File_Len = strlen(f);

   Unix_Dir[(int) (f - file)] = 0;

   if (Dirp != NULL) closedir(Dirp);

   if (NULL == (Dirp = (DIR *) opendir(Unix_Dir))) return(0);
   strcpy(the_file, file);
   return sys_findnext(the_file);
}

#endif
#endif
/* msdos_and_i386 */

/* given a canonical filename, return pointer to its name */
char *extract_file(char *file)
{
   char *f;
#ifdef VMS
   char slash = ']';
#endif
#ifdef pc_system
   char slash = '\\';
#else
#ifdef unix
   char slash = '/';
#endif
#endif
   f = file + strlen(file);
   while (f >= file) if (*f == slash) return(++f); else f--;
   return(file);
}


#ifdef sequent
char *my_strstr(char *a, char *b)
{
   register char *bb, *aa, *amax;
   
   if (*b == 0) return(a);
   
   bb = b; while (*bb) bb++;
   aa = a; while (*aa++);
   
   amax = aa - (bb - b);
   
   while (a < amax)
     {
	bb = b;
	while ((a < amax) && (*a != *bb)) a++;
	if (a == amax) return((char *) NULL);
	
	aa = a;
	while (*aa && (*aa == *bb)) aa++, bb++;
	if (! *bb) return(a);
   
	a++;
     }
   return((char *) NULL);
}

#endif

int make_directory(char *path)
{
   char work[256];
   
#ifndef VMS
   int n;
#ifdef pc_system
   char slash = '\\';
#else
   char slash = '/';
#endif
#endif

   strcpy(work, path);
   
#ifndef VMS
   n = strlen(work) - 1;
   if (work[n] == slash) work[n] = 0;
#endif

#ifdef msdos
   return !mkdir(work);
#else
   return !mkdir(work, 0777);
#endif
}

int delete_directory(char *path)
{
   char work[256];
#ifndef VMS
   int n;
#ifdef pc_system
   char slash = '\\';
#else
   char slash = '/';
#endif
#endif
   
   strcpy(work, path);
#ifndef VMS
   n = strlen(work) - 1;
   if (work[n] == slash) work[n] = 0;
#endif   
   return !rmdir(work);
}

/* generate a random number */
int make_random_number(int *seed, int *max)
{
   if (*seed == -1)		       /* generate seed */
     {
#ifndef unix
	srand((unsigned int)(time(0) & getpid()));
#else
	srandom((int)(time(0) & getpid()));
#endif   
     }
   else if (*seed != 0)
     {
#ifndef unix
	srand(*seed);
#else
	srandom(*seed);
#endif   
     }

#ifndef unix
   return (int) rand() % *max;
#else
   return (int) random() % *max;
#endif   
}

#ifndef __GO32__
#ifdef unix
/* if non-zero, Flow control is enabled */
void enable_flow_control(int *mode)
{
   Flow_Control = *mode;
   reset_tty();
   init_tty();
}
#endif
#endif
