/*---------------------------------------------------------------*/
/*   Copyright (c) 1988 Regents of the University of California  */
/*                 All Rights Reserved                           */
/*---------------------------------------------------------------*/
/* -- GLOB  ------------------------------------------------ */
/*                                                           */
/* ENTRY REQUIREMENTS:                                       */
/*   A pathname or filename that may contain wildcards.      */
/*                                                           */
/* RETURN VALUES:                                            */
/*   A null-terminated array of character pointers to the    */
/*   the names that the parameter expanded to.  If there are */
/*   none, or an error occurs, NULL will be returned.        */
/*                                                           */
/* LIMITATIONS:                                              */
/*   Wild-cards are only allowed after the last '/'.  For    */
/*   example, "/usr2/z*a/*.c" is not allowed, although       */
/*   "/usr2/z*" is allowed.                                  */
/*                                                           */
/* Development History:                                      */
/*   Begun:   2/10/88 - Marco Zagha                          */
/*          Under GY49 support.                              */
/*   Edited: 03/16/94 - Gilbert Hyatt                        */
/*         no longer uses scandir and alphasort which are BSD*/
/*         also no more memory leeks                         */
/*                                                           */
/*  Version:                                                 */
/*     @(#)glob.c	1.4      (UCLA/IGPP)     14 Apr 1994                          */
/* --------------------------------------------------------- */
#include <stdlib.h>
#ifndef _MSDOS
#include <dirent.h>
#include <pwd.h>
#endif
#include <ctype.h>
#include <string.h>
#include "filetype.h"

#define MAX_USER_NAME	64
#define MAX_FILE_NAME	64 /* without path */
#define MAX_PATH	128

static char File_pattern[MAX_FILE_NAME];
static char *Glob_chars = "*?["; /* Tilde ('~') is handled differently */


static user_name_char(c)
char c;
{
  return(isalnum(c) || (c == '_') || (c == '-'));
}


static get_user_home(user, home)
char user[];
char home[];
{
#ifdef _MSDOS
  strcpy(home, "");
  return(1);
#else
  struct passwd *pass_entry;
  pass_entry = getpwnam(user);
  if (pass_entry == NULL) {
    strcpy(home, "");
    return (-1);
  } 
  strcpy(home, pass_entry->pw_dir);
  return(0);
#endif
}


/* returns 0 if everything went OK, -1 otherwise */
static expand_tilde(in, out)
char *in;
char *out;
{
  char *home_dir();
  char *home, *u;
  char user[MAX_USER_NAME];

  *out = '\0';
  if (*in == '~') {
    in++; 
    if ((*in == '/') || (*in == '\0')) {
      if ((home = home_dir()) == NULL) {
        strcpy(out, ""); 
	return(-1);
      } else { 
        strcpy(out, home);
      }  
    } else {
      u = user;
      while (user_name_char(*in) && (*in != '\0')) {
        *u++ = *in++;     
      }  
      *u = '\0'; 
      if (get_user_home(user, out) == -1) {
	return(-1);  
      }
    }   
  }
  strcat(out, in);
  return(0);
}

/* make an array of n character pointers */
static char **
make_array(n)
int n;
{
  return((char **) (malloc((unsigned)((sizeof (char *)) * n))));
}
#ifdef _MSDOS
/* Function not needed */
#else
/* This routine passed to scandir */
static selected(entry)
struct dirent *entry;
{
 if ((File_pattern[0] != '.') && (entry->d_name[0] == '.')) return(0);
 return(ismatch(entry->d_name, File_pattern));
}
#endif

char **
glob(s)
char *s;
{                 
#ifdef _MSDOS
  return(NULL);	/* It's not supported */
#else
  int j, len, path_len, ret =0;
  char s2[MAX_PATH], dir[MAX_PATH];
  extern int selected();
  char **make_array();
  char **array;
  char *space;
  DIR  *dirp;
  struct dirent *direntp;

  if (expand_tilde(s, s2) == -1) return((char **)NULL);

  if (strpbrk(s2, Glob_chars) == NULL) { /* if no glob chars */
    if ((array = make_array(2)) == NULL) return ((char **) NULL);
    if ((space = malloc((unsigned)(strlen(s2)+1))) == NULL) 
      return((char **) NULL);
    array[0] = space;
    strcpy(array[0], s2);
    array[1] = NULL;
    return(array);
  } else if ((len = strlen(s2)) == 0) {
    if ((array = make_array(2)) == NULL) return ((char **) NULL);
    array[0] = "";
    array[1] = NULL;
    return(array);
  } else {
    for (j = len-1; (j >= 0) && (s2[j] != '/'); j--) ; /* Find the last slash in path */
    if (j < 0) {
      strcpy(dir, ".");
      path_len = 0;
      strcpy(File_pattern, s2);
    } else {
      strcpy(dir, "");
      strncat(dir, s2, j+1); /* get terminating '/' */
      path_len = strlen(dir);
      strcpy(File_pattern, &s2[j+1]);
    }
    
    dirp = opendir(dir);
    while ((direntp = readdir(dirp)) != NULL) if(selected(direntp)) ret++;
    if(ret == 0) { closedir(dirp); return((char **)NULL); }
    rewinddir(dirp);        
    if ((array = make_array(ret+1)) == NULL) return ((char **) NULL);
    j = 0;
    while ((direntp = readdir(dirp)) != NULL) 
      if(selected(direntp)) {
	j++;
	if (path_len == 0) array[j] = strdup(direntp->d_name);
	else {
	  if((array[j] =malloc((unsigned)(strlen(direntp->d_name)+path_len+1))) ==NULL)
	    return ((char **) NULL);
	  strcpy(array[j], dir);
	  strcat(array[j], direntp->d_name);
	}
      }
    array[ret] = NULL;
    closedir(dirp);
    return(array);
  }  
#endif
}

