summaryrefslogtreecommitdiffstats
path: root/tools
Commit message (Expand)AuthorAgeFilesLines
* Install modules required by packdrake and gendistrib in MISC_DESTRafael Garcia-Suarez2005-03-241-2/+5
* - remove ddcxinfos, replaced by monitor-edid (which is in a separate package)Pascal Rigaux2005-02-2852-29780/+2
* Fix ddcxinfos build on PPC that I broke with XBox mods.Stew Benedict2005-02-281-1/+5
* Support for XBox. Original code up the machine.Stew Benedict2005-02-234-7/+110
* fix typoPascal Rigaux2005-02-151-1/+1
* add peroyvindThierry Vignaud2005-02-151-0/+1
* ppc fixes (danny)Gwenolé Beauchesne2005-02-111-1/+1
* fix typoPascal Rigaux2005-01-141-1/+1
* remove obsolete dirPascal Rigaux2005-01-111-1/+0
* Add a new check script in tools. It compares the perl modules used by the .pmRafael Garcia-Suarez2004-12-231-0/+22
* ppc & ppc64 fixesGwenolé Beauchesne2004-12-154-2/+21
* use perldoc -l instead of perl -M + %INCPascal Rigaux2004-12-031-3/+3
* - drop oem & recovery code (which was broken)Pascal Rigaux2004-11-291-477/+0
* make_mdkinst_stage2 is no more, hail mdkinst_stage2_toolPascal Rigaux2004-11-161-1/+1
* major switch from ramdisk to clpPascal Rigaux2004-11-162-79/+44
* disable ddcprobe again - it doesn't work right, causing the installer to haltPascal Rigaux2004-11-121-1/+1
* specific_arch will now return only the specific arch file, not the main onePascal Rigaux2004-10-051-1/+1
* - added RomainDaouda Lo2004-10-011-1/+2
* Nuke use of conditional expressions as lvaluesGwenolé Beauchesne2004-09-091-5/+6
* Remake x86emu & int10 subdirs if sources have changedGwenolé Beauchesne2004-09-091-2/+2
* add one more translatorThierry Vignaud2004-09-031-0/+1
* Some arrangements for IA-64Gwenolé Beauchesne2004-08-263-5/+10
* PowerPC arrangements from Christiaan WelvaartGwenolé Beauchesne2004-08-263-27/+32
* warn if driver not available, print available driversOlivier Blin2004-08-251-0/+7
* delete obsolete filesOlivier Blin2004-08-2512-0/+0
* upgrade to grub-0.95Olivier Blin2004-08-25108-0/+0
* add new drivers, upgrade to grub-0.95Olivier Blin2004-08-2517-0/+0
* use grub-0.95Olivier Blin2004-08-251-3/+3
* don't be a bastard, keep CVS directoryOlivier Blin2004-08-251-1/+1
* Some cleanupsGwenolé Beauchesne2004-08-252-1/+10
* Raw merge from Kudzu for PPC. Christian, can you get something of it?Gwenolé Beauchesne2004-08-251-0/+3
* Get EDID block from OF (kudzu)Gwenolé Beauchesne2004-08-253-0/+265
* Only use VBE parsing code on x86 and x86_64.Gwenolé Beauchesne2004-08-251-1/+18
* Extensive rewrite and cleanups to use the new int10 interface. Plus addGwenolé Beauchesne2004-08-254-615/+235
* VGA softbootloader for Linux, uses an x86 CPU emulator on non x86 arches.Gwenolé Beauchesne2004-08-2513-0/+3402
* Add remaining x86 CPU emulator bitsGwenolé Beauchesne2004-08-254-0/+764
* Add x86 CPU emulator for BIOS int10 emulation on non x86 arches.Gwenolé Beauchesne2004-08-2517-0/+22783
* don't remove /usr/share/locale anymore, we use the same locale for all langsPascal Rigaux2004-08-171-6/+0
* sync with soft/common/usernameThierry Vignaud2004-08-121-0/+38
* list a few more contributorsThierry Vignaud2004-08-101-1/+4
* umount mount point instead of umounting the loopback filePascal Rigaux2004-08-101-1/+1
* update (Christiaan Welvaart)Pascal Rigaux2004-08-051-14/+5
* better descriptionPascal Rigaux2004-08-031-1/+1
* adapt to new directories layout:Pascal Rigaux2004-07-263-18/+17
* obsolete since 4 yearsPascal Rigaux2004-07-231-16/+0
* remove fpons only toolPascal Rigaux2004-07-231-10/+0
* MandrakeSoft -> MandrakesoftPascal Rigaux2004-07-207-7/+7
* replace "Mandrake Linux" with "Mandrakelinux"Pascal Rigaux2004-07-191-2/+2
* ask perl where to find package.pm and URPM.pm, this is more versatile than us...Pascal Rigaux2004-07-091-3/+3
* sortThierry Vignaud2004-07-091-19/+20
a id='n596' href='#n596'>596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
/* file intrinsics for S-Lang */
/* Copyright (c) 1992, 1999, 2001 John E. Davis
 * This file is part of the S-Lang library.
 *
 * You may distribute under the terms of either the GNU General Public
 * License or the Perl Artistic License.
 */

#include "slinclud.h"

#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
# include <sys/types.h>
#endif

#ifdef HAVE_IO_H
# include <io.h>		       /* for chmod */
#endif

#if defined(__BORLANDC__)
# include <process.h>
# include <dos.h>
#endif

#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_FCNTL_H
# include <sys/fcntl.h>
#endif

#ifdef __unix__
# include <sys/file.h>
#endif

#if defined(__BORLANDC__)
# include <dir.h>
#endif

#if defined(_MSC_VER)
# include <io.h>
#endif

#if defined(__DECC) && defined(VMS)
# include <unixio.h>
# include <unixlib.h>
#endif

#ifdef VMS
# include <stat.h>
#else
# include <sys/stat.h>
#endif

#if defined(VMS)
# define USE_LISTDIR_INTRINSIC	0
#else
# define USE_LISTDIR_INTRINSIC	1
#endif

#if USE_LISTDIR_INTRINSIC

#if defined(__WIN32__)
# include <windows.h>
#else
# if defined(__OS2__) && defined(__IBMC__)
#  define INCL_DOS
#  define INCL_ERRORS
#  include <os2.h>
#  include <direct.h>
#  include <ctype.h>
# else
#  ifdef HAVE_DIRENT_H
#   include <dirent.h>
#  else
#   ifdef HAVE_DIRECT_H
#    include <direct.h>
#   else
#    define dirent direct
#    define NEED_D_NAMLEN
#    if HAVE_SYS_NDIR_H
#     include <sys/ndir.h>
#    endif
#    if HAVE_SYS_DIR_H
#     include <sys/dir.h>
#    endif
#    if HAVE_NDIR_H
#     include <ndir.h>
#    endif
#   endif
#  endif
# endif
#endif

#endif				       /* USE_LISTDIR_INTRINSIC */

#include <errno.h>

#include "slang.h"
#include "_slang.h"

static int push_stat_struct (struct stat *st, int opt_attrs)
{
   char *field_names [12];
   unsigned char field_types[12];
   VOID_STAR field_values [12];
   int int_values [12];
   unsigned int i;

   field_names [0] = "st_dev"; int_values [0] = (int) st->st_dev;
   field_names [1] = "st_ino"; int_values [1] = (int) st->st_ino;
   field_names [2] = "st_mode"; int_values [2] = (int) st->st_mode;
   field_names [3] = "st_nlink"; int_values [3] = (int) st->st_nlink;
   field_names [4] = "st_uid"; int_values [4] = (int) st->st_uid;
   field_names [5] = "st_gid"; int_values [5] = (int) st->st_gid;
   field_names [6] = "st_rdev"; int_values [6] = (int) st->st_rdev;
   field_names [7] = "st_size"; int_values [7] = (int) st->st_size;
   field_names [8] = "st_atime"; int_values [8] = (int) st->st_atime;
   field_names [9] = "st_mtime"; int_values [9] = (int) st->st_mtime;
   field_names [10] = "st_ctime"; int_values [10] = (int) st->st_ctime;

   field_names [11] = "st_opt_attrs"; int_values[11] = opt_attrs;

   for (i = 0; i < 12; i++)
     {
	field_types [i] = SLANG_INT_TYPE;
	field_values [i] = (VOID_STAR) (int_values + i);
     }

   return SLstruct_create_struct (12, field_names, field_types, field_values);
}

static void stat_cmd (char *file)
{
   struct stat st;
   int status;
   int opt_attrs;

   status = stat (file, &st);

#if defined(__MSDOS__) || defined(__WIN32__)
   if (status == -1)
     {
	unsigned int len = strlen (file);
	if (len && ((file[len-1] == '\\') || (file[len-1] == '/')))
	  {
	     file = SLmake_nstring (file, len-1);
	     if (file == NULL)
	       return;

	     status = stat (file, &st);
	     SLfree (file);
	  }
     }
#endif
   if (status == -1)
     {
	_SLerrno_errno = errno;
	SLang_push_null ();
	return;
     }

#ifdef __WIN32__
   opt_attrs = GetFileAttributes (file);
#else
   opt_attrs = 0;
#endif

   push_stat_struct (&st, opt_attrs);
}

static void lstat_cmd (char *file)
{
#ifdef HAVE_LSTAT
   struct stat st;
   int opt_attrs;

   if (-1 == lstat (file, &st))
     {
	_SLerrno_errno = errno;
	SLang_push_null ();
	return;
     }

#ifdef __WIN32__
   opt_attrs = GetFileAttributes (file);
#else
   opt_attrs = 0;
#endif
   
   push_stat_struct (&st, opt_attrs);
#else
   stat_cmd (file);
#endif
}

/* Well, it appears that on some systems, these are not defined.  Here I
 * provide them.  These are derived from the Linux stat.h file.
 */

#ifdef __os2__
# ifdef __IBMC__
/* IBM VA3 doesn't declare S_IFMT */
#  define	S_IFMT	(S_IFDIR | S_IFCHR | S_IFREG)
# endif
#endif

#ifndef S_ISLNK
# ifdef S_IFLNK
#   define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
# else
#   define S_ISLNK(m) 0
# endif
#endif

#ifndef S_ISREG
# ifdef S_IFREG
#   define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# else
#   define S_ISREG(m) 0
# endif
#endif

#ifndef S_ISDIR
# ifdef S_IFDIR
#   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# else
#   define S_ISDIR(m) 0
# endif
#endif

#ifndef S_ISCHR
# ifdef S_IFCHR
#   define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
# else
#   define S_ISCHR(m) 0
# endif
#endif

#ifndef S_ISBLK
# ifdef S_IFBLK
#   define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
# else
#   define S_ISBLK(m) 0
# endif
#endif

#ifndef S_ISFIFO
# ifdef S_IFIFO
#   define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
# else
#   define S_ISFIFO(m) 0
# endif
#endif

#ifndef S_ISSOCK
# ifdef S_IFSOCK
#   define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
# else
#   define S_ISSOCK(m) 0
# endif
#endif

static char stat_is_cmd (char *what, int *mode_ptr)
{
   int ret;
   int st_mode = *mode_ptr;

   if (!strcmp (what, "sock")) ret = S_ISSOCK(st_mode);
   else if (!strcmp (what, "fifo")) ret = S_ISFIFO(st_mode);
   else if (!strcmp (what, "blk")) ret = S_ISBLK(st_mode);
   else if (!strcmp (what, "chr")) ret = S_ISCHR(st_mode);
   else if (!strcmp (what, "dir")) ret = S_ISDIR(st_mode);
   else if (!strcmp (what, "reg")) ret = S_ISREG(st_mode);
   else if (!strcmp (what, "lnk")) ret = S_ISLNK(st_mode);
   else
     {
	SLang_verror (SL_INVALID_PARM, "stat_is: Unrecognized type: %s", what);
	return -1;
     }

   return (char) (ret != 0);
}

#ifdef HAVE_READLINK
static void readlink_cmd (char *s)
{
   char buf[2048];
   int n;

   n = readlink (s, buf, sizeof (buf)-1);
   if (n == -1)
     {
	_SLerrno_errno = errno;
	s = NULL;
     }
   else
     {
	buf[n] = 0;
	s = buf;
     }

   (void) SLang_push_string (s);
}
#endif

static int chmod_cmd (char *file, int *mode)
{
   if (-1 == chmod(file, (mode_t) *mode))
     {
	_SLerrno_errno = errno;
	return -1;
     }
   return 0;
}

#ifdef HAVE_CHOWN
static int chown_cmd (char *file, int *owner, int *group)
{
   int ret;

   if (-1 == (ret = chown(file, (uid_t) *owner, (gid_t) *group)))
     _SLerrno_errno = errno;
   return ret;
}
#endif

/* add trailing slash to dir */
static void fixup_dir (char *dir)
{
#ifndef VMS
   int n;

   if ((n = strlen(dir)) > 1)
     {
	n--;
#if defined(IBMPC_SYSTEM)
      if ( dir[n] != '/' && dir[n] != '\\' )
      	strcat(dir, "\\" );
#else
      if (dir[n] != '/' )
      	strcat(dir, "/" );
#endif
     }
#endif /* !VMS */
}

static void slget_cwd (void)
{
   char cwd[1024];
   char *p;

#ifndef HAVE_GETCWD
   p = getwd (cwd);
#else
# if defined (__EMX__)
   p = _getcwd2(cwd, 1022);	       /* includes drive specifier */
# else
   p = getcwd(cwd, 1022);	       /* djggp includes drive specifier */
# endif
#endif

   if (p == NULL)
     {
	_SLerrno_errno = errno;
	SLang_push_null ();
	return;
     }

#ifndef VMS
#ifdef __GO32__
   /* You never know about djgpp since it favors unix */
     {
	char ch;
	p = cwd;
	while ((ch = *p) != 0)
	  {
	     if (ch == '/') *p = '\\';
	     p++;
	  }
     }
#endif
   fixup_dir (cwd);
#endif
   SLang_push_string (cwd);
}

static int chdir_cmd (char *s)
{
   int ret;

   while (-1 == (ret = chdir (s)))
     {
#ifdef EINTR
	if (errno == EINTR)
	  continue;
#endif
	_SLerrno_errno = errno;
	break;
     }
   return ret;
}

#ifdef VMS
static int remove_cmd (char *);
/* If the file looks like xxx, then change it to xxx.dir.  If
 * it looks like A:[B.xxx] then change it to A:[B]xxx.dir.
 */

static char *vms_convert_dirspec_to_vms_dir (char *str)
{
   char *s;
   char *version;
   unsigned int len;
   char *dot;

   len = strlen (str);

   version = strchr (str, ';');
   if (version == NULL)
     version = str + len;
   /* version points to the version of the input string */

   
   if (NULL == (s = SLmalloc (len + 8)))/* allow extra space to work with */
     return NULL;

   len = (unsigned int) (version - str);
   strncpy (s, str, len);
   s[len] = 0;
   str = s;
   
   /* Lowercase the whole thing */
   while (*s != 0)
     {
	*s = LOWER_CASE(*s);
	s++;
     }

   if ((s > str)
       && (s[-1] != ']'))
     {
	if ((s >= str + 4)
	    && (0 == strcmp (s - 4, ".dir")))
	  s -= 4;
	goto add_dir_version;
     }

   /* Check for one of two possibilities:
    * 
    *     dev:[x]   --> dev:x
    *     dev:[a.x] --> dev:[a]x
    */
   
   if (NULL == (dot = strchr (str, '.')))
     {
	/* First possibility */
	if (NULL == (s = strchr (str, '[')))
	  return str;		       /* let someone else figure this out */
	while (s[1] != ']')
	  {
	     s[0] = s[1];
	     s++;
	  }
	*s = 0;
	goto add_dir_version;
     }
   
   while (NULL != (s = strchr (dot + 1, '.')))
     dot = s;
   
   *dot = ']';
   s = str + (len - 1);
   
   /* Drop */

   add_dir_version:
   strcpy (s, ".dir");
   strcpy (s+4, version);
   return str;
}
#endif

static int rmdir_cmd (char *s)
{
#ifdef VMS
   int status;

   if (NULL == (s = vms_convert_dirspec_to_vms_dir (s)))
     return -1;
   
   status = remove_cmd (s);
   SLfree (s);
   
   return status;

#else
   int ret;

   while (-1 == (ret = rmdir (s)))
     {
#ifdef EINTR
	if (errno == EINTR)
	  continue;
#endif
	_SLerrno_errno = errno;
	break;
     }
   return ret;
#endif
}

static int remove_cmd (char *s)
{
   int ret;
#ifdef VMS
# define REMOVE delete
#else
# ifdef REAL_UNIX_SYSTEM
#  define REMOVE unlink
# else
#  define REMOVE remove
# endif
#endif

   while (-1 == (ret = REMOVE (s)))
     {
#ifdef EINTR
	if (errno == EINTR)
	  continue;
#endif
	_SLerrno_errno = errno;
	break;
     }
   return ret;
}

static int rename_cmd (char *oldpath, char *newpath)
{
   int ret;
   while (-1 == (ret = rename (oldpath, newpath)))
     {
#ifdef EINTR
	if (errno == EINTR)
	  continue;
#endif
	_SLerrno_errno = errno;
	break;
     }
   return ret;
}

static int mkdir_cmd (char *s, int *mode_ptr)
{
   int ret;

   (void) mode_ptr;
   errno = 0;

#if defined (__MSDOS__) && !defined(__GO32__)
# define MKDIR(x,y) mkdir(x)
#else
# if defined (__os2__) && !defined (__EMX__)
#  define MKDIR(x,y) mkdir(x)
# else
#  if defined (__WIN32__) && !defined (__CYGWIN32__)
#   define MKDIR(x,y) mkdir(x)
#  else
#   define MKDIR mkdir
#  endif
# endif
#endif

   while (-1 == (ret = MKDIR(s, *mode_ptr)))
     {
#ifdef EINTR
	if (errno == EINTR)
	  continue;
#endif
	_SLerrno_errno = errno;
	break;
     }
   return ret;
}

#ifdef HAVE_MKFIFO
static int mkfifo_cmd (char *path, int *mode)
{
   if (-1 == mkfifo (path, *mode))
     {
	_SLerrno_errno = errno;
	return -1;
     }
   return 0;
}
#endif

#if USE_LISTDIR_INTRINSIC

static void free_dir_list (char **list, unsigned int num)
{
   unsigned int i;

   if (list == NULL)
     return;

   for (i = 0; i < num; i++)
     SLang_free_slstring (list[i]);
   SLfree ((char *) list);
}

#if defined(__WIN32__) || defined(__os2__) && defined(__IBMC__)
static int build_dirlist (char *file, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
{
# ifdef __WIN32__
   DWORD status;
   HANDLE h;
   WIN32_FIND_DATA fd;
# else
   APIRET rc;
   FILESTATUS3 status;
   HDIR h;
   FILEFINDBUF3 fd;
   ULONG cFileNames;
# endif
   char *pat;
   unsigned int len;
   char **list;
   unsigned int num;
   unsigned int max_num;
   int hok;

   /* If an option is present, assume ok to list hidden files.  Later
    * I will formalize this.
    */
   hok = (opt != NULL);

# ifdef __WIN32__
   status = GetFileAttributes (file);
# else
   rc = DosQueryPathInfo(file, FIL_STANDARD, &status, sizeof(FILESTATUS3));
# endif


# ifdef __WIN32__
   if (status == (DWORD)-1)
     {
	_SLerrno_errno = ENOENT;
	return -1;
     }
   if (0 == (status & FILE_ATTRIBUTE_DIRECTORY))
     {
	_SLerrno_errno = ENOTDIR;
	return -1;
     }
# else
   if ((rc != 0) || (status.attrFile & FILE_DIRECTORY) == 0)
     {
	/* ENOTDIR isn't defined in VA3. */
	_SLerrno_errno = ENOENT;
	return -1;
     }
# endif

   len = strlen (file);
   pat = SLmalloc (len + 3);
   if (pat == NULL)
     return -1;

   strcpy (pat, file);
   file = pat;
   while (*file != 0)
     {
	if (*file == '/') *file = '\\';
	file++;
     }

   if (len && (pat[len-1] != '\\'))
     {
	pat[len] = '\\';
	len++;
     }
   pat[len++] = '*';
   pat[len] = 0;

   num = 0;
   max_num = 50;
   list = (char **)SLmalloc (max_num * sizeof(char *));
   if (list == NULL)
     {
	SLfree (pat);
	return -1;
     }

# ifdef __WIN32__
   h = FindFirstFile(pat, &fd);
   if (h == INVALID_HANDLE_VALUE)
     {
	if (ERROR_NO_MORE_FILES != GetLastError())
	  {
	     SLfree (pat);
	     SLfree ((char *)list);
	     return -1;
	  }
     }
# else
   h = HDIR_CREATE;
   cFileNames = 1;
   rc = DosFindFirst(pat, &h, FILE_READONLY | FILE_DIRECTORY |
		     FILE_ARCHIVED, &fd, sizeof(fd), &cFileNames, FIL_STANDARD);
   if (rc != 0)
     {
	if (rc != ERROR_NO_MORE_FILES)
	  {
	     SLfree (pat);
	     SLfree ((char *)list);
	     return -1;
	  }
     }
# endif   
   else while (1)
     {
	/* Do not include hidden files in the list.  Also, do not
	 * include "." and ".." entries.
	 */
#ifdef __WIN32__
	file = fd.cFileName;
#else
	file = fd.achName;
#endif
	if (
#ifdef __WIN32__
	    (hok || (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
#else
	    (hok || (0 == (fd.attrFile & FILE_HIDDEN)))
#endif
	    && ((*file != '.')
		|| ((0 != strcmp (file, "."))
		    && (0 != strcmp (file, "..")))))
	  {
	     if (num == max_num)
	       {
		  char **new_list;

		  max_num += 100;
		  new_list = (char **)SLrealloc ((char *)list, max_num * sizeof (char *));
		  if (new_list == NULL)
		    goto return_error;

		  list = new_list;
	       }

	     file = SLang_create_slstring (file);
	     if (file == NULL)
	       goto return_error;

	     list[num] = file;
	     num++;
	  }

#ifdef __WIN32__
	if (FALSE == FindNextFile(h, &fd))
	  {
	     if (ERROR_NO_MORE_FILES == GetLastError())
	       {
		  FindClose (h);
		  break;
	       }

	     _SLerrno_errno = errno;
	     FindClose (h);
	     goto return_error;
	  }
#else
        cFileNames = 1;
        rc = DosFindNext(h, &fd, sizeof(fd), &cFileNames);
        if (rc != 0)
	  {
	     if (rc == ERROR_NO_MORE_FILES)
	       {
		  DosFindClose (h);
		  break;
	       }

	     _SLerrno_errno = errno;
	     DosFindClose (h);
	     goto return_error;
	  }
#endif
     }

   SLfree (pat);
   *maxnum = max_num;
   *nump = num;
   *listp = list;
   return 0;

   return_error:
   free_dir_list (list, num);
   SLfree (pat);
   return -1;
}

#else				       /* NOT __WIN32__ */

static int build_dirlist (char *dir, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
{
   DIR *dp;
   struct dirent *ep;
   unsigned int num_files;
   unsigned int max_num_files;
   char **list;

   (void) opt;

   if (NULL == (dp = opendir (dir)))
     {
	_SLerrno_errno = errno;
	return -1;
     }

   num_files = max_num_files = 0;
   list = NULL;
   while (NULL != (ep = readdir (dp)))
     {
	unsigned int len;
	char *name;

	name = ep->d_name;
#  ifdef NEED_D_NAMLEN
	len = ep->d_namlen;
#  else
	len = strlen (name);
#  endif
	if ((*name == '.') && (len <= 2))
	  {
	     if (len == 1) continue;
	     if (name [1] == '.') continue;
	  }

	if (num_files == max_num_files)
	  {
	     char **new_list;

	     max_num_files += 100;
	     if (NULL == (new_list = (char **) SLrealloc ((char *)list, max_num_files * sizeof(char *))))
	       goto return_error;

	     list = new_list;
	  }

	if (NULL == (list[num_files] = SLang_create_nslstring (name, len)))
	  goto return_error;

	num_files++;
     }

   closedir (dp);
   *nump = num_files;
   *maxnum = max_num_files;
   *listp = list;
   return 0;

   return_error:
   if (dp != NULL)
     closedir (dp);
   free_dir_list (list, num_files);
   return -1;
}
# endif				       /* NOT __WIN32__ */

static void listdir_cmd (char *dir, char *opt)
{
   SLang_Array_Type *at;
   unsigned int num_files;
   unsigned int max_num_files;
   int inum_files;
   char **list;

   if (-1 == build_dirlist (dir, opt, &list, &num_files, &max_num_files))
     {
	SLang_push_null ();
	return;
     }
   /* If max_num_files == 0, then num_files == 0 and list == NULL.  
    * The realloc step below will malloc list for us.
    */
   if (num_files + 1 < max_num_files)
     {
	char **new_list;
	if (NULL == (new_list = (char **) SLrealloc ((char *)list, (num_files + 1)* sizeof(char*))))
	  {
	     free_dir_list (list, num_files);
	     SLang_push_null ();
	     return;
	  }
	list = new_list;
     }

   inum_files = (int) num_files;
   if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) list, &inum_files, 1)))
     {
	free_dir_list (list, num_files);
	SLang_push_null ();
	return;
     }

   /* Allow the array to free this list if push fails */
   if (-1 == SLang_push_array (at, 1))
     SLang_push_null ();
}

static void listdir_cmd_wrap (void)
{
   char *s, *sopt;

   sopt = NULL;
   switch (SLang_Num_Function_Args)
     {
      case 2:
	if (-1 == SLang_pop_slstring (&sopt))
	  return;
      case 1:
	if (-1 == SLang_pop_slstring (&s))
	  {
	     SLang_free_slstring (sopt);
	     return;
	  }
	break;
      default:
	SLang_verror (SL_INVALID_PARM, "usage: listdir (string, [opt-string]");
	return;
     }

   listdir_cmd (s, sopt);
   SLang_free_slstring (s);
   SLang_free_slstring (sopt);
}

#endif				       /* USE_LISTDIR_INTRINSIC */

#ifdef HAVE_UMASK
static int umask_cmd (int *u)
{
   return umask (*u);
}
#endif

static SLang_Intrin_Fun_Type PosixDir_Name_Table [] =
{
#ifdef HAVE_READLINK
   MAKE_INTRINSIC_S("readlink", readlink_cmd, SLANG_VOID_TYPE),
#endif
   MAKE_INTRINSIC_S("lstat_file", lstat_cmd, SLANG_VOID_TYPE),
   MAKE_INTRINSIC_S("stat_file", stat_cmd, SLANG_VOID_TYPE),
   MAKE_INTRINSIC_SI("stat_is", stat_is_cmd, SLANG_CHAR_TYPE),
#ifdef HAVE_MKFIFO
   MAKE_INTRINSIC_SI("mkfifo", mkfifo_cmd, SLANG_INT_TYPE),
#endif
#ifdef HAVE_CHOWN
   MAKE_INTRINSIC_SII("chown", chown_cmd, SLANG_INT_TYPE),
#endif
   MAKE_INTRINSIC_SI("chmod", chmod_cmd, SLANG_INT_TYPE),
#ifdef HAVE_UMASK
   MAKE_INTRINSIC_I("umask", umask_cmd, SLANG_INT_TYPE),
#endif
   MAKE_INTRINSIC_0("getcwd", slget_cwd, SLANG_VOID_TYPE),
   MAKE_INTRINSIC_SI("mkdir", mkdir_cmd, SLANG_INT_TYPE),
   MAKE_INTRINSIC_S("chdir", chdir_cmd, SLANG_INT_TYPE),
   MAKE_INTRINSIC_S("rmdir", rmdir_cmd, SLANG_INT_TYPE),
   MAKE_INTRINSIC_S("remove", remove_cmd, SLANG_INT_TYPE),
   MAKE_INTRINSIC_SS("rename", rename_cmd, SLANG_INT_TYPE),
#if USE_LISTDIR_INTRINSIC
   MAKE_INTRINSIC("listdir", listdir_cmd_wrap, SLANG_VOID_TYPE, 0),
#endif
   SLANG_END_INTRIN_FUN_TABLE
};

static SLang_IConstant_Type PosixDir_Consts [] =
{
#ifndef S_IRWXU
# define S_IRWXU 00700
#endif
   MAKE_ICONSTANT("S_IRWXU", S_IRWXU),
#ifndef S_IRUSR
# define S_IRUSR 00400
#endif
   MAKE_ICONSTANT("S_IRUSR", S_IRUSR),
#ifndef S_IWUSR
# define S_IWUSR 00200
#endif
   MAKE_ICONSTANT("S_IWUSR", S_IWUSR),
#ifndef S_IXUSR
# define S_IXUSR 00100
#endif
   MAKE_ICONSTANT("S_IXUSR", S_IXUSR),
#ifndef S_IRWXG
# define S_IRWXG 00070
#endif
   MAKE_ICONSTANT("S_IRWXG", S_IRWXG),
#ifndef S_IRGRP
# define S_IRGRP 00040
#endif
   MAKE_ICONSTANT("S_IRGRP", S_IRGRP),
#ifndef S_IWGRP
# define S_IWGRP 00020
#endif
   MAKE_ICONSTANT("S_IWGRP", S_IWGRP),
#ifndef S_IXGRP
# define S_IXGRP 00010
#endif
   MAKE_ICONSTANT("S_IXGRP", S_IXGRP),
#ifndef S_IRWXO
# define S_IRWXO 00007
#endif
   MAKE_ICONSTANT("S_IRWXO", S_IRWXO),
#ifndef S_IROTH
# define S_IROTH 00004
#endif
   MAKE_ICONSTANT("S_IROTH", S_IROTH),
#ifndef S_IWOTH
# define S_IWOTH 00002
#endif
   MAKE_ICONSTANT("S_IWOTH", S_IWOTH),
#ifndef S_IXOTH
# define S_IXOTH 00001
#endif
   MAKE_ICONSTANT("S_IXOTH", S_IXOTH),
#ifdef __WIN32__
   MAKE_ICONSTANT("FILE_ATTRIBUTE_ARCHIVE", FILE_ATTRIBUTE_ARCHIVE),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_COMPRESSED", FILE_ATTRIBUTE_COMPRESSED),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_NORMAL", FILE_ATTRIBUTE_NORMAL),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_DIRECTORY", FILE_ATTRIBUTE_DIRECTORY),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_HIDDEN", FILE_ATTRIBUTE_HIDDEN),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_READONLY", FILE_ATTRIBUTE_READONLY),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_SYSTEM", FILE_ATTRIBUTE_SYSTEM),
   MAKE_ICONSTANT("FILE_ATTRIBUTE_TEMPORARY", FILE_ATTRIBUTE_TEMPORARY),
#endif
   SLANG_END_ICONST_TABLE
};

static int Initialized;

int SLang_init_posix_dir (void)
{
   if (Initialized)
     return 0;

   if ((-1 == SLadd_intrin_fun_table(PosixDir_Name_Table, "__POSIX_DIR__"))
       || (-1 == SLadd_iconstant_table (PosixDir_Consts, NULL))
       || (-1 == _SLerrno_init ()))
     return -1;

   Initialized = 1;

   return 0;
}