/*
 * Fwild and fnext for vms.  See rmsio.c for more information.
 */

#include	<stdio.h>
#include	<rms.h>
#include	<ssdef.h>
#include	<descrip.h>
#include	<ctype.h>

#define	TRUE		1
#define	FALSE		0
#define	EOS		0

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

static RMSSTUFF *wilddata[_NFILE];	/* RMS struct for each file	*/

/*
 * rms->flag can take on the following values:
 *	ISWILD		A file with wild-card bytes.
 *	UNWILD		A file without wild-cards, unopened.
 *	UNWILD_OPENED	A file without wild-cards, opened.
 */
#define	ISWILD		0
#define	UNWILD		1
#define	UNWILD_OPENED	2

extern FILE	*cleanup();

FILE *
fwild(filename, mode)
char		*filename;
char		*mode;
/*
 * Do wildcard setup
 */
{
	register FILE		*fd;
	register RMSSTUFF	*r;
	register int		index;

	/*
	 * First get a file to work with
	 */	
	if ((fd = fopen("_nl:", "r")) == NULL) {
		return (NULL);
	}
	/*
	 * Warning: the package depends on fileno(fd) remaining unchanged
	 * after calls to freopen().
	 */
	index = fileno(fd);
	/*
	 * 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)
	    return(cleanup(index));
	strcpy(r->wildmode, mode);
	wilddata[index] = r;
	/*
	 * Setup the fab and nam blocks.
	 */
	r->fab = cc$rms_fab;			/* Initialize fab	*/
	r->nam = cc$rms_nam;			/*   and nam blocks	*/
	r->fab.fab$l_nam = &r->nam;		/* fab -> nam		*/
	r->fab.fab$l_fna = filename;		/* Argument filename	*/
	r->fab.fab$b_fns = strlen(filename);	/* filename size	*/
	r->nam.nam$l_esa = r->starname;		/* Expanded file name	*/
	r->nam.nam$b_ess = NAM$C_MAXRSS + 1;	/* ... size		*/
	r->nam.nam$l_rsa = r->filename;		/* Result filename	*/
	r->nam.nam$b_rss = NAM$C_MAXRSS + 1;	/* ... size		*/
	/*
	 * Parse the file name
	 */
	if (sys$parse(&r->fab) != RMS$_NORMAL)
	    return (cleanup(index));
	/*
	 * Success.  Null-terminate expanded file name and set flag to
	 * distinguish between "wild" and "non-wild" filenames.
	 */
	((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
	r->flag = ((r->nam.nam$l_fnb & NAM$M_WILDCARD) == 0) ? UNWILD : ISWILD;
	return (fd);
}

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;

	index = fileno(fd);
	if ((r = wilddata[index]) == NULL || r->flag == UNWILD_OPENED) {
	    /*
	     * It wasn't ours, or wasn't a wildcard and
	     * has already been processed.
	     */
	    fclose(fd);
	    fd = NULL;
	}
	else if (r->flag == UNWILD) {
	    /*
	     * Not a wildcard file, first time through
	     */
	    fd = freopen(r->starname, r->wildmode, fd);
	    r->flag = UNWILD_OPENED;
	}
	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.
		 */
		r->fab.fab$w_ifi = 0;		/* Internal file index	*/
		if ((errorcode = sys$search(&r->fab)) == RMS$_NORMAL) {
		    /*
		     * We have a file.  Open it if we have access rights.
		     */
		    ((char *)r->nam.nam$l_rsa)[r->nam.nam$b_rsl] = EOS;
		    if (access(r->filename, 4) != 0) {
			/*
			 * The file exists, but we don't have read access.
			 * Try for another.
			 */
			continue;
		    }
		    else {
			/*
			 * We should be able to open the file.  It this
			 * fails, something is wrong inside the C library.
			 */
			fd = freopen(r->filename, r->wildmode, fd);
			break;
		    }
		}
		else if (errorcode == RMS$_PRV) {
		    /*
		     * sys$search() found something, but we don't have
		     * privileges to open it.  Look for another.
		     */
		    continue;
		}
		else {
		    /*
		     * Can't find a file.  This should be RMS$_NMF.
		     */
		    fclose(fd);
		    fd = NULL;
		    break;
		}
	    }
	}
	/*
	 * Cleanup if any errors
	 */
	if (fd == NULL) {
	    cleanup(index);
	}
	return (fd);
}

static FILE *
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;
	}
	return (NULL);
}
