#include <stdio.h>
#include "fab.h"
#include "nam.h"

#define	TRUE		1
#define	FALSE		0

typedef struct rmsstuff {
	int			flag;	/* Flag for nonwildcard calls	*/
	char			*wildmode;
	struct	RMS$FAB		fab;
	struct	RMS$NAM		nam;
	char			starname[NAM_MAXRSS + 1];
	char			filename[NAM_MAXRSS + 1];
} RMSSTUFF;

static RMSSTUFF *wilddata[_NFILE];	/* -> what we for fwild/fnext	*/

FILE *
fwild(name, mode)
char		*name;
char		*mode;
/*
 * Do wildcard setup
 */
{
	register FILE		*fd;
	register RMSSTUFF	*r;
	register int		index;
	globalvalue int		RMS$_NORMAL;

	/*
	 * First get a file to work with
	 */	
	if ((fd = fopen("_nl:", "r")) == NULL) {
		return (NULL);
	}
	index = fd - _iob;
	/*
	 * If we've been here before, make sure buffers are released/
	 */
	cleanup(index);
	if ((r = malloc(sizeof (RMSSTUFF))) == NULL
	 || (r->wildmode = malloc(strlen(mode) + 1)) == NULL)
		goto fail;
	strcpy(r->wildmode, mode);
	wilddata[index] = r;
	r->fab.fab_bid = FAB_BID;
	r->fab.fab_bln = sizeof(struct RMS$FAB);
	r->fab.fab_dna = 0;			/* Default filename	*/
	r->fab.fab_dns = 0;			/* ... size		*/
	r->fab.fab_fna = name;			/* Argument filename	*/
	r->fab.fab_fns = strlen(name);		/* ... size		*/
	r->fab.fab_fop = 0;			/* file proc. options	*/
	r->fab.fab_ifi = 0;			/* Internal id. == 0	*/
	r->fab.fab_nam = &r->nam;		/* -> name block	*/
	r->nam.nam_bid = NAM_BID;
	r->nam.nam_bln = sizeof(struct RMS$NAM);
	r->nam.nam_esa = &r->starname;		/* Expanded filename	*/
	r->nam.nam_ess = NAM_MAXRSS + 1;	/* ... size		*/
	r->nam.nam_rsa = &r->filename;		/* Result filename	*/
	r->nam.nam_rss = NAM_MAXRSS + 1;	/* ... max size		*/
	r->nam.nam_rlf = 0;
	r->nam.nam_wcc = 0;			/* Wild context init	*/
	/*
	 * Parse the file name
	 */
	if (sys$parse(&r->fab) != RMS$_NORMAL) {
		goto fail;
	}
	/*
	 * Success
	 */
	r->fab.fab_fna = NULL;			/* No arg. filename now	*/
	r->starname[r->nam.nam_esl] = '\0';	/* Terminate filename	*/
	/*
	 * Set flag to 2 for non-wildcard calls
	 */
	r->flag = (r->nam.nam_fnb.nam_wildcard == 0) ? 2 : 0;
	return (fd);

fail:	
	cleanup(index);
	fclose (fd);
	return (NULL);
}

FILE *
fnext(fd)
FILE		*fd;
/*
 * Open the next valid file. return fd if successful, NULL if finished.
 */
{
	register int		index;
	register RMSSTUFF	*r;
	register int		errorcode;
	globalvalue int		RMS$_PRV;	/* Protection violation	*/
	globalvalue int		RMS$_NORMAL;	/* Successful		*/

	index = fd - _iob;
	if ((r = wilddata[index]) == NULL || r->flag == 1) {
		/*
		 * It wasn't a wildcard and has already been processed
		 */
		fclose(fd);
		fd = NULL;
	}
	else if (r->flag == 2) {
		/*
		 * Not a wildcard file, first time through
		 */
		fd = freopen(r->starname, r->wildmode, fd);
		r->flag = 1;
	}
	else {
		/*
		 * Look for the next match -- who says you can't write
		 * obscure structured code?
		 */
		for (;;) {
			/*
			 * Look 'em up but skip any with
			 * protection violation errors.
			 */
			errorcode = sys$search(&r->fab);
			if (errorcode == RMS$_PRV)
				continue;	/* Look for another	*/
			else if (errorcode == RMS$_NORMAL) {
				/*
				 * Gotcha?
				 */
				r->filename[r->nam.nam_rsl] = '\0';
				if (access(r->filename, 4) != 0) {
					/*
					 * Try for another if the file
					 * exists but isn't readable by us.
					 */
					continue;
				}
				/*
				 * If this fails, something is seriously
				 * wrong.
				 */
				fd = freopen(r->filename, r->wildmode, fd);
				break;		/* Exit for loop	*/
			}
			else {
				/*
				 * give up on errors
				 */
				fclose(fd);
				fd = NULL;
				break;
			}
		}
	}
	/*
	 * Cleanup if any errors
	 */
	if (fd == NULL) {
		cleanup(index);
	}
	return (fd);
}

static
cleanup(index)
register int	index;
/*
 * Empty out any stored information
 */
{
	register RMSSTUFF	*r;

	r = wilddata[index];
	if (r != NULL) {
		if (r->wildmode != NULL) {
			free(r->wildmode);
		}
		free(r);
		wilddata[index] = NULL;
	}
}
