/*
        This file is part of the cFos project,
        Copyright (c) 1993 by Martin Winkler, Christoph Lders

        This file contains utility functions.


        You are allowed to use, copy, distribute, publish, redistribute
        and/or modify this program under the terms of the 'cFos public
        licence and warranty'.

        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 COPYING.CF for the 'cFos public license and warranty'.
*/


#include "vars.h"


word myint86 (word intno, union REGS _FAR *inregs, union REGS _FAR *outregs)
{
   struct SREGS s;
   mysegread (&s);

   return myint86x (intno, (void _FAR *) inregs, (void _FAR *) outregs, (void _FAR *) &s);
}


word myintdosx (union REGS _FAR *inregs, union REGS _FAR *outregs, struct SREGS _FAR *sregs)
{
   return myint86x (0x21, (void _FAR *) inregs, (void _FAR *) outregs, (void _FAR *) sregs);
}


word myintdos (union REGS _FAR *inregs, union REGS _FAR *outregs)
{
   struct SREGS s;
   mysegread (&s);

   return myint86x (0x21, (void _FAR *) inregs, (void _FAR *) outregs, (void _FAR *) &s);
}


word mybdos (word dosfn, word dosdx, word dosal)
{
   union REGS r;

   r.x.dx = dosdx;
   r.h.al = dosal;
   r.h.ah = dosfn;
   return myintdos (&r, &r);
}


char *get_currdir (char *drive)
{
   short drv;
   union REGS r;
   struct SREGS s;
   static char dir[3+64+1];

   if (drive && drive[0] != 0 && drive[1] == ':')
      drv = toupper (drive[0]) - 'A';
   else
      drv = mybdos (0x19, 0, 0) & 0xff;

   dir[0] = drv+'a';
   dir[1] = ':';
   dir[2] = '\\';

   mysegread (&s);
   r.h.ah = 0x47;
   r.h.dl = drv+1;              /* 0 is default drive */
   r.x.si = FP_OFF (dir+3);
   s.ds = FP_SEG (dir);
   myintdosx (&r, &r, &s);

   return dir;
}


int myread (int handle, void _FAR * p, word len) {

   struct SREGS s;
   union REGS r;

   mysegread (&s);
   r.x.ax = 0x3f00; r.x.bx = handle; r.x.cx = len;
   s.ds = FP_SEG (p); r.x.dx = FP_OFF (p);
   myintdosx (&r, &r, &s);
   return r.x.cflag ? -1 : r.x.ax;
}

int mywrite (int handle, void _FAR * p, word len) {

   struct SREGS s;
   union REGS r;

   mysegread (&s);
   r.x.ax = 0x4000; r.x.bx = handle; r.x.cx = len;
   s.ds = FP_SEG (p); r.x.dx = FP_OFF (p);
   myintdosx (&r, &r, &s);
   return r.x.cflag ? -1 : r.x.ax;
}

long mylseek (int handle, long offset, int from) {
/* from = 0 : start at beginning of file */
   struct SREGS s;
   union REGS r;

   mysegread (&s);
   r.x.ax = 0x4200 | from; r.x.bx = handle;
   r.x.cx = (word) (offset >> 16); r.x.dx = (word) (offset & 0xffffUL);
   myintdosx (&r, &r, &s);
   return r.x.cflag ? -1L : (r.x.dx << 16) | r.x.ax;
}

int myclose (int handle) {

   struct SREGS s;
   union REGS r;

   mysegread (&s);
   r.x.ax = 0x3e00; r.x.bx = handle;
   myintdosx (&r, &r, &s);
   return r.x.cflag ? -1 : 0;
}

int myopen (char _FAR * path, int mode) {
/* mode : 0 = read only, 1 = create/open/read/write */

   struct SREGS s;
   union REGS r;

   mysegread (&s);
   r.x.ax = 0x3d00;
   r.x.dx = FP_OFF (path); s.ds = FP_SEG (path);
   r.x.ax |= mode == 0 ? 0x20 : 0x02 | 0x10;
   myintdosx (&r, &r, &s);
   if (r.x.cflag) {
      if (mode == 0) return -1;
      else {
         if (r.x.ax == 2) {  /* file not found */
            r.x.ax = 0x3c00;
            r.x.dx = FP_OFF (path); s.ds = FP_SEG (path);
            r.x.cx = 0;
            myintdosx (&r, &r, &s);
            return r.x.cflag ? -1 : r.x.ax;
         }
         else return -1;
      }
   }
   else return r.x.ax;
}


int toupper (int c)
{
   return (c >= 'a' && c <= 'z') ? (c-('a' - 'A')) : c;
}


int isdigit (int c)
{
   return (c >= '0' && c <= '9');
}


#if 0
int mystrnicmp (char _FAR *s1, char _FAR *s2, int len)
{
   for (;len>0; len--) {
      if (toupper (*s1) != toupper (*s2)) {
         return (toupper (*s1) - toupper (*s2));
      }
   }
   return 0;
}
#endif


static mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };

dword unixdate (word year, word mon, word day, word hour, word min, word sec)
{
   unsigned short i, days;

   days = (year-1970)*365 + ((year-1970+1)>>2);       /* 1972 was a leap year */

   for (i=1; i<mon; i++)
      days += mdays [i-1];
   if (year%4 == 2 && mon>2)
      days++;
   days += day;

   return (((dword) (days-1) * 24L + (dword) hour + 7L) * 60L + (dword) min) * 60L
          + (dword) sec;   /* unix date is relative to PDT, not GMT */
}


dword dosdate (void)
{
   union REGS t, d;

   d.h.ah = 0x2a;
   myintdos (&d, &d);

   t.h.ah = 0x2c;
   myintdos (&t, &t);

#ifndef NDEBUG
   myaprintf ("%i %i %i %i %i %i\n", d.x.cx, d.h.dh, d.h.dl, t.h.ch, t.h.cl, t.h.dh);
#endif

   return unixdate (d.x.cx, d.h.dh, d.h.dl, t.h.ch, t.h.cl, t.h.dh);
}


void set_dosdate (dword date)
{
   int day, year, i;
   union REGS r;

   r.h.dl = 0;                          /* 1/100 sec */
   r.h.dh = date % 60L;                 /* sec */
   date /= 60L;
   r.h.cl = date % 60L;                 /* min */
   date /= 60L;
   date -= 7L;
   r.h.ch = date % 24L;                 /* hours */
   date /= 24L;
   r.h.ah = 0x2d;
   myintdos (&r, &r);

   year = (int) (date / 365L);
   day = (int) (date % 365L);
   day -= (year+1) / 4;
   if (day < 0) {
      year--;
      day += year%4==2? 366: 365;
   }
   r.x.cx = year+1970;

   day++;
   for (i=0; day>mdays[i]; i++)
      day -= mdays[i];
   if (year%4 == 2 && i>1) {            /* is leap year and month>feb */
      day--;
      if (day < 1) {                    /* 0th of the month = last day of preceeding month */
         i--;
         day += mdays [i] + i==1? 1: 0; /* add num/o/days; if feb add 1 more */
      }
   }
   r.h.dh = (byte) i+1;
   r.h.dl = (byte) day;
   r.h.ah = 0x2b;
   myintdos (&r, &r);
}


#if 0
int getch (void)
{
   union REGS r;

   r.h.ah = 0;
   myint86 (0x16, &r, &r);

   return r.h.al? r.h.al: r.x.ax;
}


int kbhit (void)
{
   union REGS r;

   r.h.ah = 1;
   myint86 (0x16, &r, &r);

   return !(r.x.flags & 0x40);
}
#endif


word xms_func (union REGS *in)
{
   union REGS r;
   struct SREGS s;
   static _FAR *xms_entry=0L, xms_checked=0;

   if (xms_checked == 0 && use_mpx) {
      xms_checked = 1;
      if (use_xms) {
         r.x.ax = 0x4300;
         myint86 (0x2f, &r, &r);
         if (r.h.al == 0x80) {
            mysegread (&s);
            r.x.ax = 0x4310;
            myint86x (0x2f, &r, &r, &s);
            xms_entry = MK_FP (s.es, r.x.bx);
         }
      }
   }
   if (xms_entry != 0L) {
      mysegread (&s);
      mycallf (xms_entry, in, in, &s);
      return in->x.ax;
   } else
      return 0;
}


int dos_free (void _FAR * vp)
{
   union REGS r;
   struct SREGS s;

   if ((word) FP_SEG (vp) > 0x9fffU) {
      r.h.ah = 0x11;
      r.x.dx = FP_SEG (vp);
      xms_func (&r);                    /* free upper memory block */
      return r.x.ax;

   } else {
      mysegread (&s);
      r.h.ah = 0x49;
      s.es = FP_SEG (vp);
      myintdosx (&r, &r, &s);           /* dos free segment */
      return !r.x.cflag;
   }
}


void _FAR * dos_malloc (long bytes)
{
   union REGS r;
   word paras = (bytes+15) >> 4;

   r.h.ah = 0x10;                     
   r.x.dx = paras;
   if (xms_func (&r) != 1) {            /* XMS request upper memory block */

      r.h.ah = 0x48;
      r.x.bx = paras;
      myintdos (&r, &r);                /* DOS allocate memory */
      return (void _FAR *) (r.x.cflag? NULL: MK_FP (r.x.ax, 0));
   }

   return (void _FAR *) (r.x.ax == 0? NULL: MK_FP (r.x.bx, 0));
}



/* --- eof myutil.c */
