/* -*- Mode: C; c-file-style: "gnu" -*-
  scandir.c -- if scandir() is missing, make a replacement
  Created: Petter Reinholdtsen <pere@td.org.uit.no>, 1998-03-24
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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 the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_SCANDIR

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include "compat.h"
#ifdef HAVE_DIRENT_H
#  include <dirent.h>
#endif
#ifdef HAVE_WINDOWS_H
#  include <windows.h>
#endif

/*
 * XXX This is a simple hack version which doesn't sort the data, and
 * just passes all unsorted.
 */

#ifdef _WINDOWS
int
scandir(const char *dir, struct dirent ***namelist,
	int (*select)(const struct dirent *),
	int (*compar)(const void *, const void *))
{
  WIN32_FIND_DATA file_data;
  HANDLE handle;
  int count, pos;
  struct dirent **names;
  char *pattern;

  pattern = (char*)malloc(strlen(dir) + 3 /* for *.* */ +1 /* for the /, possibly */ + 1 /* for \0 */);
  strcpy(pattern, dir);
  if (pattern[ strlen(pattern) - 1] != '\\')
    strcat(pattern, "\\");
  strcat(pattern, "*.*");

  handle = FindFirstFile(pattern, &file_data);
  if (handle == INVALID_HANDLE_VALUE)
    {
      free(pattern);
      return -1;
    }

  count = 0;
  while (1)
    {
      count++;
      if (!FindNextFile(handle, &file_data))
	break;
    }
  FindClose(handle);

  names = (struct dirent**)malloc(sizeof(struct dirent*) * count);
  handle = FindFirstFile(pattern, &file_data);
  if (handle == INVALID_HANDLE_VALUE)
    {
      free(pattern);
      free(names);
      return -1;
    }

  pos = 0;
  while (1)
    {
      struct dirent current;

      strcpy(current.d_name, file_data.cFileName);

      if (select && select(&current))
	{
	  struct dirent *copyentry = malloc(sizeof(struct dirent));
	  strcpy(copyentry->d_name, current.d_name);
	  names[pos] = copyentry;
	  pos++;
	}

      if (!FindNextFile(handle, &file_data))
	break;
    }

  free(pattern);
  *namelist = names;
  return pos;
}
#else
int 
scandir(const char *dir, struct dirent ***namelist,
	int (*select)(const struct dirent *),
	int (*compar)(const void *, const void *))
{
  DIR *d = opendir(dir);
  struct dirent *current;
  struct dirent **names;
  int count = 0;
  int pos = 0;
  int result = -1;
  off_t start;

  if (NULL == d)
    return -1;

  start = telldir(d);

  while (NULL != readdir(d)) count++;

  names = malloc(sizeof(struct dirent *) * count);

  seekdir(d, start);

  while (NULL != (current = readdir(d))) {
    if ( NULL == select || select(current) ) {
      struct dirent *copyentry = malloc(current->d_reclen);

      memcpy(copyentry, current, current->d_reclen); 

      names[pos] = copyentry;
      pos++;
    }
  }
  result = closedir(d);

  if (pos != count)
    names = realloc(names, sizeof(struct dirent *)*pos);

  *namelist = names;

  return pos;
}
#endif
#endif /* HAVE_SCANDIR */
