/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */

/*************************************************************/
/* This is replacement for mktemp() for DJGPP port of gcc    */
/* Temporary file is created by this version so the          */
/* possibility of race conditions between 2 or more copies   */
/* of gcc when using mktemp is excluded.                     */
/* I also used biostime to set initial value for searching   */
/* available name to minimize need for more than one         */
/* try to get available name.                                 */
/*                                                           */
/* Andris Pavenis <pavenis@lanet.lv>       1998.04.28        */
/*************************************************************/

#include <dos.h>
#include <bios.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <libc/bss.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <go32.h>
#include <dpmi.h>
#include <libc/dosio.h>
#include <sys/fsext.h>


#define USES_BIOSTIME

static char * mktemp00 (char *_template);

static int
_creatnew00(const char* filename, int attrib, int flags);

char *
mktemp (char *_template)
{
  char tmp_name[FILENAME_MAX];
  int  fd = -1;

  /* Make sure we create a non-exisiting file, even
     if race conditions exist with other processes.  */
  do {
    strcpy(tmp_name, _template);
    errno = 0;
  } while ( mktemp00(tmp_name) != NULL
	   && (fd = _creatnew00(tmp_name, 0, SH_DENYRW)) == -1
	   && errno == EEXIST);

  if (fd == -1)
    {
       errno = ENOENT;
       *_template=0;
       return NULL;
    }
  else
    {
       close (fd);
       strcpy (_template,tmp_name);
       return _template;
    }
}

/*****************  mktemp.c  ********************************/
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */

static int mktemp_count = -1;

#ifdef USES_BIOSTIME
static int mktemp_start = 1;
static long mktemp_base;
#endif

static char *
mktemp00 (char *_template)
{
  static int count = 0;
  char *cp, *dp;
  int i, len, xcount, loopcnt;

  /* Reinitialize counter if we were restarted (emacs).  */
  if (__bss_count != mktemp_count)
    {
      mktemp_count = __bss_count;
      count = 0;
    }

#ifdef USES_BIOSTIME
  if (mktemp_start)
    {
      mktemp_start = 0;
      mktemp_base = biostime(0,0L)<<8;
    }
#endif

  len = strlen (_template);
  cp = _template + len;

  xcount = 0;
  while (xcount < 6 && cp > _template && cp[-1] == 'X')
    xcount++, cp--;

  if (xcount) {
    dp = cp;
    while (dp > _template && dp[-1] != '/' && dp[-1] != '\\' && dp[-1] != ':')
      dp--;

    /* Keep the first characters of the template, but turn the rest into
       Xs.  */
    while (cp > dp + 8 - xcount) {
      *--cp = 'X';
      xcount = (xcount >= 6) ? 6 : 1 + xcount;
    }

    /* If dots occur too early -- squash them.  */
    while (dp < cp) {
      if (*dp == '.') *dp = 'a';
      dp++;
    }

    /* Try to add ".tmp" to the filename.  Truncate unused Xs.  */
    if (cp + xcount + 3 < _template + len)
      strcpy (cp + xcount, ".tmp");
    else
      cp[xcount] = 0;

    /* This loop can run up to 2<<(5*6) times, or about 10^9 times.  */
    for (loopcnt = 0; loopcnt < (1 << (5 * xcount)); loopcnt++) {
#ifdef USES_BIOSTIME
      int c = mktemp_base + (count++);
#else
      int c = count++;
#endif
      for (i = 0; i < xcount; i++, c >>= 5)
	cp[i] = "abcdefghijklmnopqrstuvwxyz012345"[c & 0x1f];
      if (!__file_exists(_template))
	return _template;
    }
  }

  /* Failure:  truncate the template and return NULL.  */
  *_template = 0;
  return 0;
}


/* Needed if djdev201 is being used */


#include <libc/stubs.h>


static int
_creatnew00(const char* filename, int attrib, int flags)
{
  __dpmi_regs r;
  int rv;
  unsigned use_lfn = _USE_LFN;

  if (filename == 0)
  {
    errno = EINVAL;
    return -1;
  }

  if (__FSEXT_call_open_handlers(__FSEXT_creat, &rv, &filename))
    return rv;

  _put_path(filename);
  r.x.bx =
    0x2002 | (flags & 0xfff0);	/* r/w, no Int 24h, use caller-defined flags */
  r.x.dx = 0x0010;		/* Create, fail if exists */
  r.x.si = __tb_offset;
  if(use_lfn)
    r.x.ax = 0x716c;
  else
  {
    if (_osmajor == 0)
      _get_dos_version (0);
    if (_osmajor > 3)
      r.x.ax = 0x6c00;
    else
    {
      r.h.ah = 0x5b;
      r.x.bx = 0;		/* lose support for fancy flags in DOS 3.x */
      r.x.dx = __tb_offset;
      r.x.si = 0;
    }
  }
  r.x.cx = attrib & 0xffff;
  r.x.ds = __tb_segment;
  __dpmi_int(0x21, &r);
  if(r.x.flags & 1)
  {
    errno = __doserr_to_errno(r.x.ax);
    return -1;
  }
  __file_handle_set(r.x.ax, O_BINARY);
  return r.x.ax;
}

/*************************************************************/
/* This is startup check for DJGPP installation errors       */
/* (C) A.Pavenis  <pavenis@lanet.lv>       1998.06.06        */
/*************************************************************/


#include <crt0.h>
#include <stdlib.h>


static void  __attribute__((constructor)) CheckDJGPPEnvVar (void) 
{
  /* __dos_argv0; */
  char *djdir, *djgpp;
  djdir = getenv("DJDIR");
  if (djdir) return;   // is %DJDIR% is defined then don't check more

  /* Some installation problem found. Let's check slightly deeper */
  fprintf (stderr,"Fatal:\tError in DJGPP instalation\n");
  djgpp = getenv("DJGPP");
  if (!djgpp)
       fprintf (stderr,"\tEnvironment variable DJGPP is not defined\n");
  else if (!__file_exists(djgpp))
       fprintf (stderr,"\tEnvironment variable DJGPP point to file '%s',\n"
                       "\twhich does not exist\n",djgpp);
  else
       fprintf (stderr,"\tEnvironment variable DJGPP points to wrong or "
                       "corrupt file '%s'\n",djgpp);
  exit (16);
}
