/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: expand.c 1.5 89/10/10 $@(#)sh:expand.c	1.18"
/*
 *	UNIX shell
 *
 */

#include	"defs.h"
#include	<sys/types.h>
#include	<sys/stat.h>
#ifdef	SVAE
#define		direct	dirent
#include	<dir.h>
#else	/* SVAE */
#include	<dirent.h>
#endif	/* SVAE */



/*
 * globals (file name generation)
 *
 * "*" in params matches r.e ".*"
 * "?" in params matches r.e. "."
 * "[...]" in params matches character class
 * "[...a-z...]" in params matches a through z.
 *
 */
extern int	addg();


expand(as, rcnt)
	unsigned char	*as;
{
	int	count; 
	DIR	*dirf;
	BOOL	dir = 0;
	unsigned char	*rescan = 0;
	unsigned char 	*slashsav = 0;
	register unsigned char	*s, *cs;
	int quotflag = 0;
	int quotflag2 = 0;
	unsigned char *s2 = 0;
	struct argnod	*schain = gchain;
	struct stat statb;
	BOOL	slash;

	if (trapnote & SIGSET)
		return(0);
	s = cs = as;
	/*
	 * check for meta chars
	 */
	{
		register BOOL open;

		slash = 0;
		open = 0;
		do
		{
			switch (*cs++)
			{
			case 0:
				if (rcnt && slash)
					break;
				else
					return(0);

			case '/':
				slash++;
				open = 0;
				continue;

			case '[':
				open++;
				continue;

			case ']':
				if (open == 0)
					continue;

			case '?':
			case '*':
				if (rcnt > slash)
					continue;
				else
					cs--;
				break;


			case '\\':
				cs++;
			default:
				continue;
			}
			break;
		} while (TRUE);
	}

	for (;;)
	{
		if (cs == s)
		{
			s = nullstr;
			break;
		}
		else if (*--cs == '/')
		{
			cs--;
			if(cs >= s && *cs == '\\') {
				*cs = 0; /* null out backslash before / */
				slash++; /* increment slash count because
					    slash will be unquoted in expansion
					    string */
				quotflag = 1;
			} else
				*++cs = 0;
			if (s == cs)
				s = (unsigned char *)"/";
			else {
				s2 = cpystak(s);
				trim(s2);
				s = s2;
			}
			break;
		}
	}

	if ((dirf = opendir(*s ? (char *)s : ".")) != 0)
		dir++;

	/* Let s point to original string because it will be trimmed later */
	if(s2)
		s = as;
	count = 0;
	if (*cs == 0) {
		slashsav = cs++; /* remember where first slash in as is */
		if(quotflag)
			cs++; /* advance past / */
	}
	if (dir)		/* check for rescan */
	{
		register unsigned char *rs;
		struct dirent *e;

		rs = cs;
		do /* find next / in as */
		{
			if (*rs == '/')
			{
				if(*--rs != '\\') {
					rescan = ++rs;
					*rs = 0;
				} else {
					quotflag2 = 1;
					*rs = 0;
					rescan = rs + 1; /* advance past / */
				}
				gchain = 0;
			}
		} while (*rs++);

		while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0)
		{
			if (e->d_name[0] == '.' && *cs != '.')
				continue;

			if (gmatch(e->d_name, cs))
			{
				addg(s, e->d_name, rescan, slashsav);
				count++;
			}
		}
		(void)closedir(dirf);

		if (rescan)
		{
			register struct argnod	*rchain;

			rchain = gchain;
			gchain = schain;
			if (count)
			{
				count = 0;
				while (rchain)
				{
					count += expand(rchain->argval, slash + 1);
					rchain = rchain->argnxt;
				}
			}
			if(quotflag2)
				*--rescan = '\\';
			else
				*rescan = '/';
		}
	}

	if(slashsav) {
		if(quotflag)
			*slashsav = '\\';
		else
			*slashsav = '/';
	}
	return(count);
}

#ifdef notdef
/*
	opendir -- C library extension routine

*/

extern int	open(), close(), fstat();

#define NULL	0

DIR *
opendir(filename)
unsigned char		*filename;	/* name of directory */
{
	static DIR direct;
	static unsigned char dirbuf[DIRBUF];
	register DIR	*dirp = &direct;		/* static storage */
	register int	fd;		/* file descriptor for read */
	struct stat	sbuf;		/* result of fstat() */

	if (stat(filename, &sbuf) < 0
	  || (sbuf.st_mode & S_IFMT) != S_IFDIR 
	  || (fd = open(filename, 0)) < 0 )	
		return NULL;		

	dirp->dd_fd = fd;
	dirp->dd_loc = dirp->dd_size = 0;	/* refill needed */
	dirp->dd_buf = (char *)dirbuf;
	return dirp;
}

/*
	closedir -- C library extension routine

*/


extern int	close();

closedir(dirp) 
register DIR	*dirp;		/* stream from opendir() */
{
	return close(dirp->dd_fd);
}
#endif	/* undef */

static int
addg(as1, as2, as3, as4)
unsigned char	*as1, *as2, *as3, *as4;
{
	register unsigned char	*s1, *s2;

	s2 = locstak() + BYTESPERWORD;
	s1 = as1;
	if(as4) {
		while (*s2 = *s1++)
			s2++; 
	/* Restore first slash before the first metacharacter if as1 is not "/" */
		if(as4 + 1 == s1)
			*s2++ = '/';
	}
/* add matched entries, plus extra \\ to escape \\'s */
	s1 = as2;
	while (*s2 = *s1++) {
		if(*s2 == '\\')
			*++s2 = '\\';
		s2++;
	}
	if (s1 = as3)
	{
		*s2++ = '/';
		while (*s2++ = *++s1);
	}
	makearg(endstak(s2));
}

makearg(args)
	register struct argnod *args;
{
	args->argnxt = gchain;
	gchain = args;
}


