ftp.nice.ch/pub/next/unix/editor/jed.N.bs.tar.gz#/jed.N.bs/src/ibmpc.c

This is ibmpc.c in view mode; [Download] [Up]

/*
 *  Copyright (c) 1992, 1995 John E. Davis  (davis@space.mit.edu)
 *  All Rights Reserved.
 */
#include <config.h>

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include "sysdep.h"

#include <dir.h>
#include <dos.h>
#include <bios.h>
#include <io.h>
#include <conio.h>
#include <time.h>
#include <stddef.h>

/* for stat */
#include <sys/stat.h>
#include <errno.h>


#ifdef __cplusplus
#define _DOTS_ ...
#else
#define _DOTS_ void
#endif

void interrupt (*oldint9)(_DOTS_);

static unsigned char far *shift = (unsigned char far *) 0x417;
static unsigned int far *kbptr = (unsigned int far *) 0x41a;
static unsigned int far *kbnext = (unsigned int far *) 0x41c;
static unsigned int far *kbbeg = (unsigned int far *) 0x480;
static unsigned int far *kbend = (unsigned int far *) 0x482;

int Abort_Char = 34;

#include "dos_os2.c"

/* Macro to get char from BIOS not dos */
void interrupt int9_handler(_DOTS_)
{
   unsigned int scan = (unsigned int) Abort_Char; /* 34 = scan code for ^G */
   unsigned char s, s1;
   unsigned int offset, f1_scan = 0x3B00;  /* f1 key */
   unsigned int *p;
   unsigned int numlock = 0x45;
   

   s1 = *shift & 0xF;  /* ignoring caps, ins, num lock, scroll lock */
   s = inp(0x60);
   if (s1 & 0x04)      /* control key */
     {
	if (s == scan)
	  {
	     if (Ignore_User_Abort == 0) SLang_Error = 2;
	     SLKeyBoard_Quit = 1;
	  }
	else if (s == 28)   /* Control - enter, ignore it!! */
	  {
	     s = inp(0x61);
	     outportb(0x61, s | 0x80);
	     outportb(0x61, s);
	     outportb(0x20, 0x20);
	     return;
	  }
     }
   else if (NumLock_Is_Gold && ((s & 0x7F) == numlock))
     {
	if (s == numlock)
	  {
	     offset = *kbnext;
	     offset += 2;
	     if (offset == *kbend) offset = *kbbeg;
	     if (offset != *kbptr)  /* buffer not full */
	       {
		  p = (unsigned int *) (0x400L + (*kbnext));
		  *p = f1_scan;
		  *kbnext = offset;
	       }
	  }
	s = inp(0x61);
	outportb(0x61, s | 0x80);
	outportb(0x61, s);
	outportb(0x20, 0x20);
	return;
     }
   (*oldint9)();
}

void init_int9_handler(void)
{
   oldint9 = getvect(9);
   setvect(9, int9_handler);
}

void restore_int9_handler(void)
{
   setvect(9, oldint9);
}

static void set_ctrl_break(int state)
{
   static int prev = 0;

   asm {
      mov dl, byte ptr prev
      mov ax, state
      cmp ax, 0
      jne L1
      mov ah, 33h
      mov al, 0
      mov dl, byte ptr prev
      int 21h
      xor ax, ax
      mov al, dl
      mov prev, ax
      mov dl, 0
   }
   L1:
   asm {
      mov al, 1
      mov ah, 33h
      int 21h
   }   
}

#if 0
/* Here I just flag the error and return to the user-- hopefully jed will
   catch it and user will know what to do. */
static char *int24_errs[] = 
{
   "write protect",
   "bad unit",
   "drive not ready",
   "unknown",
   "CRC error",
   "request error",
   "seek error",
   "unknown media",
   "sector not found",
   "printer out of paper",
   "general write failure",
   "general read failure",
   "general failure", "reserved", "reserved", "invalid disk change"
};
 
int int24_handler(int err, int ax, int bp, int si)
{
   unsigned int di;
   
   di = _DI;
   (void) ax;
   (void) bp;
   msg_error(int24_errors[di & 0x000F]);
}
#endif

static int ctrl_break(void)
{
   msg_error("Control Break ignored!");
   return(1);
}


#define BIOSKEY(x) bioskey((x) | bios_key_f)
static int bios_key_f;
void init_tty (void)
{
   bios_key_f = peekb(0x40,0x96) & 0x10; /* enhanced keyboard flag */
   set_ctrl_break(0); 
   ctrlbrk(ctrl_break);
   init_int9_handler();
   if (Batch) return;
   if (X_Open_Mouse_Hook != NULL) (*X_Open_Mouse_Hook) ();
}

void reset_tty (void)
{
   restore_int9_handler();
   set_ctrl_break(1);
   if (Batch) return;
#ifdef HAS_MOUSE
   if (X_Close_Mouse_Hook != NULL) (*X_Close_Mouse_Hook) ();
#endif
   SLtt_reset_video();
}


/* Here I also map keys to edt keys */
unsigned char sys_getkey()
{
   unsigned int c0, c1, shft;
   unsigned int i;
   int timeout;
   char *normal = "!@#$%^&*()-=\t*\0177QWERTYUIOP[]\r*ASDFGHJKL;'`*\\ZXCVBNM<>/";
   
   timeout = 300;
   if (BIOSKEY(1) == 0) while (!sys_input_pending(&timeout, 0))
     {
	if (Display_Time)
	  {
	     JWindow->trashed = 1;
	     update((Line *) NULL, 0, 1);
	  }
     }
#ifdef HAS_MOUSE
   /* This can only be set by the mouse */
   if (Input_Buffer_Len) return my_getkey ();
   if (JMouse_Hide_Mouse_Hook != NULL) (*JMouse_Hide_Mouse_Hook) (0);
#endif
   
   i = BIOSKEY(0);
   shft = *shift & 0xF;
   
   switch (i)
     {
      case 0x0E08: return 127;
      case 0x0E7F: return 8;
      case 0xE02F: c1 = 'Q'; break;    /* KEYPAD SLASH */
      case 0x372A: c1 = 'R'; break;    /* KEYPAD STAR */
      case 0x4A2D: c1 = 'S'; break;    /* KEYPAD MINUS */
      case 0x4700: c1 = 'w'; break;    /* KEYPAD HOME */
      case 0x4800: c1 = 'x'; break;    /* KEYPAD UP */
      case 0x4900: c1 = 'y'; break;    /* KEYPAD PGUP */
      case 0x4B00: c1 = 't'; break;    /* KEYPAD LEFT */
      case 0x4C00: c1 = 'u'; break;    /* KEYPAD 5 */
      case 0x4D00: c1 = 'v'; break;    /* KEYPAD RIGHT */
      case 0x4F00: c1 = 'q'; break;    /* KEYPAD END */
      case 0x5000: c1 = 'r'; break;    /* KEYPAD DOWN */
      case 0x5100: c1 = 's'; break;    /* KEYPAD PGDN */
      case 0x4E2B: c1 = 'm'; break;    /* KEYPAD PLUS */
      case 0xE00D: c1 = 'M'; break;    /* KEYPAD ENTER */
      case 0x5300: c1 = 'n'; break;    /* KEYPAD DEL */
      case 0x5200: c1 = 'p'; break;    /* KEYPAD INSERT */
	
      case 0x3920: 
	if ((shft & 4) == 0) return ' ';
	i = 0x0300;
	/* drop */
	
      default:
	
	c0 = i & 0xFF;
	c1 = i >> 8;
	
	if ((c0 == 0) || (c0 == 0xE0))
	  {
	     if (PC_Alt_Char && (shft == 0x8)) 
	       {
		  if ((c1 >= 14) && (c1 <= 53))
		    {
		       c1 = (unsigned int) normal[c1];
		    }
		  else if ((c1 >= 120) && (c1 <= 131))
		    {
		       c1 = (unsigned int) normal[c1 - 120];
		    }
		  else if (c1 == 165) /* tab */
		    {
		       c1 = (unsigned int) normal[c1 - 165 + 12];
		    }
		  c0 = PC_Alt_Char;
	       }
	     ungetkey ((int *) &c1);
	  }
	return c0;
     }

   ungetkey ((int *) &c1);
   c0 = 'O';
   ungetkey ((int *) &c0);
   return 27;
}



/* sleep for *tsecs tenths of a sec waiting for input */
static int sys_input_pending(int *tsecs, int unused)
{
   int count = *tsecs * 5;
   
   (void) unused;
   
   if (Batch || Input_Buffer_Len) return(Input_Buffer_Len);
   
   if (count)
     {
	while(count > 0)
	  {
	     delay(20);		       /* 20 ms or 1/50 sec */
	     if (BIOSKEY(1)
#ifdef HAS_MOUSE
		 || ((JMouse_Event_Hook != NULL)
		     && ((*JMouse_Event_Hook)() > 0))
#endif
		 ) break;
	     count--;
	  }
	return(count);
     }
   else return(
	       BIOSKEY(1)
#ifdef HAS_MOUSE
	       || ((JMouse_Event_Hook != NULL)
		   && ((*JMouse_Event_Hook)() > 0))
#endif
	       );
   
}

/* Thanks to Robert Schmidt - robert@alkymi.unit.no - Buuud@IRC
   for some of code below */
int get_term_dimensions(int *w, int *h)
{
   int scan_lines = 8;
   
   *h = 0;

   /* Get BIOS's screenwidth, this works on ALL displays. */
   *w = *((int *)MK_FP(0x40, 0x4a));
   
   /* Use Ralf Brown test for EGA or greater */
   asm mov ah, 12h
   asm mov bl, 10h
   asm mov bh, 0xFF  /* EGA or greater will change this */
   asm int 10h
   asm cmp bh, 0xFF
   asm je L1
	/* if EGA or compatible: Get BIOS's number of rows. */      
     *h = *(char *)MK_FP(0x40, 0x84) + 1;
   scan_lines = *(int *) 0x485;
   
   L1:
      if (*h <= 0) *h = 25;
   return scan_lines;
}

int sys_chmod(char *file, int what, int *mode, short *dum1, short *dum2)
{
   int flag = 0, m = *mode;
   (void) dum1; (void) dum2;
   
   file = msdos_pinhead_fix_dir (file);
   
   asm mov ah, 43h
   asm mov al, byte ptr what
   asm mov cx, m
   asm push ds
   asm lds dx, dword ptr file
   asm int 21h
   asm pop ds
   asm mov m, cx
   asm jnc L1
   asm mov flag, ax
   
   /* Here if carry flag is set */
   if (flag == 0x2) return(0);     /* file not found */
   if (flag == 0x3) return(-2);
	/* msg_error("Path does not exist."); */
	/* else return (-3); */
	/* sprintf(buf, "chmod: Unknown Error. %d", out.x.ax);
	   msg_error(buf);
	*/
   return(-1);
    
   /* carry flag is 0 */
   L1:
   if (what == 0)
     {
	*mode = m;
     }

   if (m & 0x10)
     {
	/* msg_error("File is a directory."); */
	return(2);
     }

   return(1);
}

typedef struct Dos_DTA_Type
{
   unsigned char undoc[21];
   unsigned char attr;
   unsigned int time;
   unsigned int date;
   unsigned char low_size[2];
   unsigned char high_size[2];
   char name[13];
} Dos_DTA_Type;

static Dos_DTA_Type Dos_DTA;

static void set_dta (void)
{
   Dos_DTA_Type *dummy = &Dos_DTA;
   
   asm mov ah, 0x1A
   asm push ds
   asm lds dx, dword ptr dummy
   asm int 21h
   asm pop ds
}


static int File_Attr;

#define HIDDEN 0x2
#define SYSTEM 0x4
#define SUBDIR 0x10
#define READON 0x1

static char Found_Dir[256];

#define lcase(x) if (((x) >= 'A') && ((x) <= 'Z')) (x) |= 0x20

void dta_fixup_name(char *file)
{
   int dir;
   char *p, name[13];

   strcpy(file, Found_Dir);
   strcpy(name, Dos_DTA.name);
   dir = (Dos_DTA.attr & SUBDIR);
   p = name;
   while (*p)
     {
	lcase(*p);
	p++;
     }
   strcat(file, name);
   if (dir) strcat(file, "\\");
}

int sys_findfirst(char *thefile)
{
   char *f, the_path[256], *file, *f1;
   char *pat, *fudge;
   
   set_dta();
   File_Attr = READON | SUBDIR;

   file = expand_filename(thefile);
   f1 = f = extract_file(file);
   strcpy (Found_Dir, file);
   
   
   Found_Dir[(int) (f - file)] = 0;

   strcpy(the_path, file);
   
   while (*f1 && (*f1 != '*')) f1++;
   if (! *f1)
     {
	while (*f && (*f != '.')) f++;
	if (*f) strcat(the_path, "*"); else strcat(the_path, "*.*");
     }
   pat = the_path;
   
   /* Something is very wrong after this returns.  
    * thefile gets trashed for some reason.  Here I fudge until I figure 
    *  out what is going on 
    * 
    * Note: This has been fixed.  I am just too lazy to remove the fudge. 
    */
   fudge = thefile;
   
   asm mov ah, 0x4e
   asm mov cx, File_Attr
   asm push ds
   asm lds dx, dword ptr pat
   asm int 21h
   asm pop ds
   asm jc L1 
   
   thefile = fudge;
   
   /* fprintf(stderr, "asm:%lu\t|%s|\n", thefile, thefile); */
   
   dta_fixup_name(file);
   strcpy(thefile, file);
   return(1);
   L1:
   return 0;
}

int sys_findnext(char *file)
{
   asm mov ah, 0x4F
   asm int 21h
   asm jc L1
   dta_fixup_name(file);
   return(1);
   L1:
   return(0);
}



#if 0
unsigned long sys_file_mod_time(char *file)
{
   struct stat buf;
   
   if (stat(file, &buf) != 0) return(0);
   return ((unsigned long) buf.st_mtime);
   close(fd);
   return ((unsigned long) buf.st_mtime);
   /*
   asm mov ah, 57h
   asm mov al, 0
   asm mov bx, fd
   asm int 21h
   asm mov cx, d
   asm mov dx, t
   close(fd);
   fprintf(stderr, "Time ok.");
   return(1); */
}
#endif

/* Here we do a find first followed by calling routine to conver time */
unsigned long sys_file_mod_time(char *file)
{
   struct time t;
   struct date d;
   /* struct tm *local; */
   time_t secs;
   unsigned int dat, tim;
   
   File_Attr = READON | SUBDIR;
   
   set_dta();

   asm mov ah, 0x4e
   asm mov cx, File_Attr
   asm push ds
   asm lds dx, dword ptr file
   asm int 21h
   asm pop ds
   asm jnc A_LABEL
   return 0;
   
   A_LABEL:
   tim = Dos_DTA.time;
   dat = Dos_DTA.date;
   t.ti_min = (tim >> 5) & 63;
   t.ti_hour = (tim >> 11) & 31;
   t.ti_hund = 0;
   t.ti_sec = 2 * (tim & 31);
   d.da_day = dat & 31;
   d.da_mon = (dat >> 5) & 15;
   d.da_year = 1980 + ((dat >> 9) & 0x7F);
   secs = dostounix(&d, &t);
   return((unsigned long) secs);
}


These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.