/* sys/filefind.c (emx+gcc) -- Copyright (c) 1992-1996 by Eberhard Mattes */

#include <string.h>
#include <errno.h>
#include <os2emx.h>
#include <emx/syscalls.h>
#include "syscalls.h"

/* Close the directory handle. */

static void find_close (struct find_data *fd)
{
  if (fd->find_handle != HDIR_CREATE)
    {
      DosFindClose (fd->find_handle);
      fd->find_handle = HDIR_CREATE;
    }
  fd->find_count = 0;
  fd->find_next = NULL;
}

/* Build a `struct _find' structure from a FILEFINDBUF3 structure and
   move to the next one. */

static int find_conv (struct find_data *fd, struct _find *fp)
{
  const FILEFINDBUF3 *src;

  /* Check if there are any entries.  Close the handle and return
     ENOENT if there are no entries.  (Checking SRC is redundant.) */

  src = fd->find_next;
  if (fd->find_count < 1 || src == NULL)
    {
      find_close (fd);
      errno = ENOENT;
      return -1;
    }

  /* Fill-in target object. */

  fp->attr = (unsigned char)src->attrFile;
  fp->time = XUSHORT (src->ftimeLastWrite);
  fp->date = XUSHORT (src->fdateLastWrite);
  fp->size_lo = (unsigned short)(src->cbFile & 0xffff);
  fp->size_hi = (unsigned short)(src->cbFile >> 16);
  strcpy (fp->name, src->achName);

  /* Move to the next entry. */

  if (src->oNextEntryOffset == 0)
    {
      fd->find_next = NULL;
      fd->find_count = 0;
    }
  else
    {
      fd->find_next = (FILEFINDBUF3 *)((char *)src + src->oNextEntryOffset);
      fd->find_count -= 1;
    }

  return 0;
}


int __findfirst (const char *name, int attr, struct _find *fp)
{
  ULONG rc;
  struct find_data *fd;

  fd = &SYS_THREAD->fd;

  if (fd->find_handle != HDIR_CREATE)
    {
      /* Closing the handle is not strictly required as DosFindFirst
         can reuse an open handle.  However, this simplifies error
         handling below (will DosFindFirst close the handle on error
         if it is open?). */

      DosFindClose (fd->find_handle);
      fd->find_handle = HDIR_CREATE;
    }

  fd->find_count = FIND_COUNT;
  rc = DosFindFirst (name, &fd->find_handle, attr & 0x37,
                     &fd->find_buf[0], sizeof (fd->find_buf),
                     &fd->find_count, FIL_STANDARD);
  if (rc != 0)
    {
      fd->find_handle = HDIR_CREATE; /* Perhaps modified by DosFindFirst */
      fd->find_count = 0;
      fd->find_next = NULL;
      _sys_set_errno (rc);
      return -1;
    }
  fd->find_next = &fd->find_buf[0];
  return find_conv (fd, fp);
}


int __findnext (struct _find *fp)
{
  ULONG rc;
  struct find_data *fd;

  fd = &SYS_THREAD->fd;
  if (fd->find_count < 1)
    {
      fd->find_count = FIND_COUNT;
      rc = DosFindNext (fd->find_handle, &fd->find_buf[0],
                        sizeof (fd->find_buf), &fd->find_count);
      if (rc != 0)
        {
          find_close (fd);
          _sys_set_errno (rc);
          return -1;
        }
      fd->find_next = &fd->find_buf[0];
    }

  return find_conv (fd, fp);
}
